2544. Data Fix with Javascript For Web Application
Rhino and Javascript


Use Rhino to run javascript to fix data for a web application.

1. Introduction

In the previous posting Building Website with JSP and MySQL, we built a web application with JSP and MySQL. Suppose it has been deployed on cloud service and Customer is using it right now. However, there are some issues with this web application, the price of the product is incorrect. Customer requests us to fix the wrong price. The problem is, for cloud service, you are not allowed to shut it down and apply any java patch to fix the data. We have to fix the data while the application is still running. One approach is to call Java from javascript and run the script at server side.

2. Prerequisite

If you haven’t installed Docker and Kitematic, please install Docker Toolbox by referring to my previous posting Install Docker Toolbox and Kitematic on Mac. We will use Docker to host MySQL database for this JSP Tutorial Application. Refer Creating MySQL Image with Docker File to learn how to use Dockerfile to create image.

3. Setting Up MySQL Container

I’ve already created the Dockerfile to quickly setup MySQL container in docker. Download it from here, save it to you local machine. Besides, download the MySQL backup file from here and put it with the Dockerfile in the same folder. In Docker terminal, run the following script to launch a MySQL container.

$ docker build -t datafix-mysql:0.1 .
$ docker run --detach --name=dfmysql --publish 10202:3306 datafix-mysql:0.1

image

4. Setting Up Project

Get the source file of JSP application from here, rename it to RhinoDataFix. The project in Eclipse looks like this. image Start this application and access http://localhost:8080/RhinoDataFix/productlist.jsp in web browser. Initially, there are three products. image

5. Enhancing Project by Adding Data Fix Function

Suppose the prices of the these products are incorrect, as customer requests, we need to double it through data fix.

5.1 Adding Reference of Rhino to Project

Go to https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Download_Rhino, select the latest version to download, for example, rhino1.7.7.2.zip. Extract the file rhino-1.7.7.2.jar from the downloaded zip, and copy it to the /WebContent/WEB-INF/lib subdirectory of ‘RhinoDataFix’ project.

5.2 Creating Servlet For Running Javascript

Right-click on RhinoDataFix->Java Resources->src, create a new package named ‘Johnny.RhinoDataFix.Servlet’. Then, right click on this package, New->Servlet, set name JavascriptServlet.java. Modify the doPost() method in JavascriptServlet.java as follows:

/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/plain");
    String code = request.getParameter("code");
    Context ctx = Context.enter();
    String packagesText = "var Johnny = Packages.Johnny; \n";
    packagesText += code;
    try {
        Scriptable scope = ctx.initStandardObjects();
        Object result = ctx.evaluateString(scope, packagesText, "<code>", 1, null);
        response.getWriter().print(Context.toString(result));
    } catch(RhinoException ex) {
        response.getWriter().println(ex.getMessage());
    } finally {
        Context.exit();
    }
}

5.3 Create JSP Page for Data Fix

In Project Explorer, right-click on RhinoDataFix->WebContent, New->JSP File. Specify file name datafix.jsp and add following content into it.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script type="text/javascript">
      function sendCode() {
        var code = $("#code").val();
        $("#output").load("/RhinoDataFix/JavascriptServlet", {"code": code});
      }
    </script>
    <title>Data Fix with Javascript</title>
  </head>

  <body>
  <jsp:include page="header.jsp" />
    <div class="container">
      <h1>Input scripts to fix data</h1>
      <form>
        <div class="form-group">
          <label for="code">Javascript:</label>
          <textarea class="form-control" rows="10" id="code"></textarea>
        </div>
        <button type="button" class="btn btn-primary" onclick="sendCode();" >Submit</button>
        <div class="form-group">
          <label for="output">Output:</label>
          <textarea class="form-control" rows="10" id="output" readonly="true"></textarea>
        </div>
      </form>
    </div>
  </body>
</html>

Edit ‘header.jsp’ in RhinoDataFix->WebContent. Add link for ‘datafix.jsp’.

<div class="container">
  <h2>Data Fix with Javascript - Product Management</h2>
  <a class="btn btn-info" href="productlist.jsp">List</a>
  <a class="btn btn-info" href="productadd.jsp">Create</a>
  <a class="btn btn-info" href="datafix.jsp">Data Fix</a>
</div>
<hr/>

5.5 Project Structure

Finally, the project structure looks like this. image

6. Running Data Fix

Right-click on RhinoDataFix->WebContent->datafix.jsp, Run As->Run On Server, specify Tomcat as web server and launch this servlet project with it. Open web browser, access http://localhost:8080/RhinoDataFix/datafix.jsp.

Input following content to the javascript textbox.

/*
   Data fix to set price = price * 2
*/

var ProductDao = Johnny.RhinoDataFix.Dao.ProductDao;

var gDebugText = "";
var Datafix = "Update products by doubling their prices";

dfOnProduct();

function dfOnProduct ()
{
    try {
        logDebug("Data Fix with JS: " + Datafix + ": START");
        var products = ProductDao.getList();
        for (var i=0; i< products.size(); i++) {
            var product = products.get(i);
            logDebug("[fixProduct]: #" + (i + 1) + " out of " + products.size() + ", Before fix: " + product);
            product.setPrice(product.getPrice() * 2);
            logDebug("[fixProduct]: After fix: " + product);
            ProductDao.update(product);
        }
        logDebug("Summary: Fixed " + products.size() + " Products.");
    }
    catch (ex) {
        logDebug("[dfOnProduct] DF Failed ! Exception: " + ex.toString());
    }
    finally {
        logDebug("Data Fix with JS: " + Datafix + ": END");
    }
}

function logDebug(msg) {
    gDebugText += (msg + "\n");
}

show = gDebugText;

Click the ‘Run’ button, the log of the data fix will be displayed in the output box.

Data Fix with JS: Update products by doubling their prices: START
[fixProduct]: #1 out of 3, Before fix: ProductId=1, ProductName=Xbox, Price=100.0
[fixProduct]: After fix: ProductId=1, ProductName=Xbox, Price=200.0
[fixProduct]: #2 out of 3, Before fix: ProductId=2, ProductName=PS4, Price=400.0
[fixProduct]: After fix: ProductId=2, ProductName=PS4, Price=800.0
[fixProduct]: #3 out of 3, Before fix: ProductId=3, ProductName=iPhone, Price=699.0
[fixProduct]: After fix: ProductId=3, ProductName=iPhone, Price=1398.0
Summary: Fixed 3 Products.
Data Fix with JS: Update products by doubling their prices: END

image

Switch to Product List page, the prices have been doubled successfully. image

7. Source Files

8. Reference