Introduction
I'd like to extend simple database application described in the previous post. Assume that it is a successful database application but some customers need customization. For instance one customer wants to have highlighted all employees earning more that 100000 euros and the next wants the same but for the employees earning less that 50000 euros. How to meet these expectation and avoid splitting out code into different branches.
So we want to achieve the following goals:
- Customization, make some improvement specific for the customer.
- Avoid splitting the business code into different branches, easy upgrade of the software without loosing the customization.
- Safe, do not open gate for the malicious code.
Purpose
Assume that our purpose is to provide a customization for
setRowStyles method. It gives the opportunity for highlighting some rows in the employee view.
Logic
The first question is how to provide logic for highlighting some rows without touching the main java code. The answer is simple - Java Script.
So if we want for provide customization for modifying the rows style the following code could be created.
DockMain
private class AddStyle implements RowStyles<EmployeeRecord> { |
|
@Override |
public String getStyleNames(EmployeeRecord row, int rowIndex) { |
|
.... return jsAddStyle(parseJson(jsString)); |
} |
|
} ....
public static native String jsAddStyle(JavaScriptObject o) /*-{ |
return $wnd.jsAddStyle(o); |
}-*/; |
|
We use GWT JSNI (Java Script Native Interface). Java Script function 'jsAddStyle' is invoked and should return NULL - no customization - or string with the css style which should be appended to the row.
Communication
The second question to answer is how to provide communication between employee view and Java Script function. The answer is simple : Java Script object containing necessary data and JSON as a mean to create such an object.
So I created auxiliary class which creates JSON script -
CreateJson.java. The next step is to create Java Script object using this function: (
GWT + JSON) :
/*
* Takes in a trusted JSON String and evals it.
* @param JSON String that you trust
* @return JavaScriptObject that you can cast to an Overlay Type
*/
public static native JavaScriptObject parseJson(String jsonStr) /*-{
return eval(jsonStr);
}-*/;
And then Java Script object containing data for one row (employee) can be passed as a parameter to the JS function.
So our JS function can look like that:
function jsAddStyle(o) {
var job = o.Employee.job;
if (job == 'MANAGER') { return 'addRow'; }
return null;
};
Easy to guess that our customer want to have all managers in employee view to be highlighted in some way. No problem to provide other logic - for instance to highlight all female customers.
Custom JS code and CSS sheet
Next step is obviously a safe way to transport our custom JS code (like function above) and CSS file to the web page.
In this example this data is transported via RPC from the server and applied to the web page via JS functions:
function addScript(s) {
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.text = s;
headID.appendChild(newScript);
}
function addStyle(s) {
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('style');
newScript.type = 'text/css';
newScript.textContent = s;
headID.appendChild(newScript);
The files are defined in the Tomcat server.xml configuration file.
<Environment name="jsFile" type="java.lang.String" value="/home/sbartkowski/workspace/SampleGwt/src/com/ibm/sampledb/server/resource/custom.js"/<
<Environment name="cssFile" type="java.lang.String" value="/home/sbartkowski/workspace/SampleGwt/src/com/ibm/sampledb/server/resource/custom.css"/<
<Environment name="customRow" type="java.lang.Boolean" value="true"/<
This way to customization is separated from the Java code and can be changed at the customer basis. Upgrade of the main application can be achieved without loosing our customization.
Conclusion
This way we can customize our database application achieving goals set at the beginning. Of course - it is very simple application and simple customization. Customization in this example is based on one row. Cannot customized using - for instance - the following logic: highlight two employees having the highest salary. To achieve this goal it is not enough to pass only one row to JS function but also the all rows.
The source code for the whole application