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

niedziela, 27 lutego 2011

DB2, Spring and GWT

I created simple GWT (2.2)  application trying to put together several different technologies :
DB2 (SAMPLE database), Spring JDBC as a layer between user interface and database (persistence) and GWT 2.2 as a user interface.
How to setup environment - read details from SampleGWT and source code.

I ended up with the following application:



Application displays one table (EMPLOYEE) from SAMPLE database. List box at the upper left of the screen allows data sorting - it is done by adding ORDER BY clause to SELECT * FROM EMPLOYEE statement. 'Incremental' check box does nothing with the statement - data are read incrementally by default. 'Decremental' check box adds 'DESC' clause to ORDER BY.
Of course - sorting can be done also by 'Column Sorting' - new feature added in GWT 2.2 to CellTable presentation widget.
It could be very interesting challenge which sorting method is more efficient. I dare say that more data are used than data sorting by database engine will be getting the upper hand.

I used Spring JDBC for data access layer. Of course - for such a small project (one statement) it is like to take a sledgehammer to crack a nut.
But I found it very useful - it is much more elegant to have in the main business stream something like:
  List mList = jdbc.query(query, new EmployeeRecordMapper());
and keep somewhere else :
private class EmployeeRecordMapper implements RowMapper {
        @Override
        public EmployeeRecord mapRow(ResultSet res, int arg1)
                throws SQLException {
            String empno = res.getString(1);
            String firstname = res.getString(2);
            String midinit = res.getString(3);
            String lastname = res.getString(4);
            String workdept = res.getString(5);
            String phoneno = res.getString(6);
            Timestamp hiredate = res.getTimestamp(7);
            String job = res.getString(8);
            int edlevel = res.getInt(9);
            String sex = res.getString(10);
            Timestamp birthdate = res.getTimestamp(11);
            BigDecimal salary = res.getBigDecimal(12);
            BigDecimal bonus = res.getBigDecimal(13);
            BigDecimal comm = res.getBigDecimal(14);
            EmployeeRecord el = new EmployeeRecord();
            el.setEmpno(empno);
            el.setFirstname(firstname);
            el.setMidinit(midinit);
            el.setLastname(lastname);
            el.setWorkdept(workdept);
            el.setPhoneno(phoneno);
            el.setHiredate(hiredate);
            el.setJob(job);
            el.setEdlevel(edlevel);
            el.setSex(sex);
            el.setBirthdate(birthdate);
            el.setSalary(salary);
            el.setBonus(bonus);
            el.setComm(comm);
            return el;
        }
    } 

 then this terrible JDBC code :
 ResultSet res = ....
 while (res.next()) {
   ...
}
What is more important   EmployeeRecordMapper class is reusable component - can be utilized everywhere statement on EMPLOYEE table is performed.

Of course - every JDBC developer sooner or later creates his (her) own JDBC framework - during my professional life I created dozen of them. But for what purpose create next framework if Spring JDBC is already created and ready to use for free ?

wtorek, 15 lutego 2011

GWT 2.2

Finally I upgraded to GWT 2.2. But not without adventures.
Firstly, I had to download new version of GIN (snapshot), the current is not liked by GWT 2.2 compiler.
Secondly, this new version of GIN works only with the new version of GUICE (3.0) and some additional jars are necessary.
Thirdly, this way I was forced also to upgrade the server code to GUICE 3.0.
Fourthly, GUICE 3.0 lost from its internals @Nullable annotation. I spent several hours trying to guess what was going on. Finally I ended up with mysterious Guava project and jsr305.jar. I was told that is was my mistake to reference Nullable annotation from GUICE internal. Hm..., ok.
But finnaly I'm the happy consumer of GWT 2.2. GWT2.1 to GWT 2.2, one small step for a humble man like me, but giant leap for mankind.

niedziela, 30 stycznia 2011

C/Python interface and 64 bit

I found very nasty bug in the application related to C/Python connection in 64 bit environment.

The code snippet is as follows:

PyArg_VaParse function.


unsigned long l;

char s[...];
....
PyArg_VaParse( (PyObject p, "si", &s, &l );
.....
if (l == 0) { do something if 0 }
else { do something if not 0 }


PyArg_VaParse (which is quite similar to C scanf function) replaces "i" position parameter with integer variable. In 32 bit environment it does not make any harm because both long and int are 32 bit variables. But in 64 bit environment long is 64 bit and int is 32 bit. Because 32 bit value is stored in 64 bit it did not raise any run-time errors.
It works if compiled as 32 bit application. But it was very nasty after compiling as 64 bit application. In most cases it worked also as expected but sometimes it behaves badly.

sobota, 29 stycznia 2011

GWT and java.util.ConcurrentModificationException:

Finally I was able to get rid of very annoying message:


20:34:57.598 [ERROR] [com.mygwt.test] Uncaught exception escaped
java.util.ConcurrentModificationException: null
    at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64)
    at com.gwtmodel.table.slotmodel.SlotListContainer$GeneralListener.signal(SlotListContainer.java:89)
    at com.gwtmodel.table.slotmodel.SlotListContainer.publish(SlotListContainer.java:126)
    at com.gwtmodel.table.slotmodel.SlotListContainer.publish(SlotListContainer.java:355)
    at com.gwtmodel.table.slotmodel.AbstractSlotContainer.publish(AbstractSlotContainer.java:122)
    at com.mygwt.client.MailOp.access$0(MailOp.java:1)



What more interesting -this message does not seem to make any harm.

It is caused by running through the collection and modifying it from RPC at the same time. The solution was very simple - just walk through the clone of the list, no the list itself.

Instead of:

.........
private final List listOfSubscribers;
........
for (SlotSubscriberType so : llistOfSubscribers) {
  ...
}


just use:

List li = (List) ((ArrayList)listOfSubscribers).clone();
for (SlotSubscriberType so : li) {
...
}


GWT, mail and RichText editor

I added mailing to my open source application ( Test demo ). The test is created inside Google App Engine environment.
For mailing I'm using standard JavaMail API. Look at the code. Because the Google App Engine provides Mail service there is a branch in the code:

String protocol = props.getProperty(PROTOCOL);
                if (protocol.equalsIgnoreCase(GAEMAIL)) {
                        Transport.send(msg);
                } else {

                        Transport transport = session.getTransport(props
                                        .getProperty(PROTOCOL)); .... }

If mail.transport.protocol property value is equal to "gae" then message is send directly. This way it is possible to keep consistent API for GAE and non-GAE mailing.

I also incorporated GWT RichTextArea widget - here for displaying and modifying mail content. As a RichText Toolbar (GWT does not provide it as a standard) I simply sucked in a toolbar from GWT samples. It required some modifications and needed also localization. Firstly I tried to use http://code.google.com/p/richtexttoolbar/ but I wasn't happy with it's look and feel.

For the time being attachment are not handled - may be I will add it in the future.

It is possible to have more than one mail account. For the test purpose mail account properties are looked for in resource directory. To my astonishment resource directory search works in the Google App Engine environment.
This code return path to the directory:


  public static File getResourceDir(Class cl) {
                String me = cl.getName().replace(".", "/") + ".class";
                URL u = cl.getClassLoader().getResource(me);
                String p = u.getFile();
                File f = new File(p);
                String s = f.getParent();
                return new File(s + File.separatorChar + "resources");
        }


And regular java code is looking for .properties file in this directory.

File f = FileUtil.getResourceDir(this.getClass());
FileFilter filter = new FileFilter() {
  public boolean accept(File pathname) {
     if (pathname.isDirectory()) {
     return false;
    }
    return pathname.getName().endsWith(".properties");
  }
};
File[] dir = f.listFiles(filter); 

..............