Blog do projektu Open Source JavaHotel

sobota, 26 marca 2011

Windows and 64 bit

Next problem while migrating 32-bit application to 64 bit world.

Before migration (32 bit code)
SetWindowLongPtr( hwnd, GWLP_USERDATA, (long )this );
It is very common usage of GWLP_USERDATA property - keeping a pointer to struct of class containing more detailed information related to the window hwnd.

Later it can referenced:

static LRESULT CALLBACK WndProc (HWND hwnd, UINT _komunikaty, UINT wParam,LONG lParam) {
my_class *pointer;
pointer = (my_class *)GetWindowLongPtr(hwnd,GWLP_USERDATA);
// some logic related to window and my_class
....
}
Of course - it does not work after compiling as 64 bit application because 'long' data type is still 32 bit (different than in Linux where 'long' is 64 bit) but pointer is 64 bit.

In order to have this code working in 32 and 64 bit world it was necessary to modify this line:

  SetWindowLongPtr( hwnd, GWLP_USERDATA, ( LONG_PTR )this );

Also it was necessary to modify a simple function detecting if application is 32 or 64 bit - in MSVC I was unable to find any simple method (for instance : no compiler predefined constant).

#ifdef LINUX
inline bool is64Version() {
if (sizeof(long) == 8) { return true; }
else { return false; }
}
#else
inline bool is64Version() {
if (sizeof(void *) == 8) { return true; }
else { return false; }
}
#endif

wtorek, 15 marca 2011

GWT + CSS + JSON

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"/&l
t;
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