Monday, October 08, 2007

Kubuntu/ubuntu run command dialog doesn't run script.

I put together a Eclipse launch script to start eclipse with JDK 1.6 while my system's default JDK is 1.5. Some extra VM parameters are also used to make eclipse run a little bit faster because I live in it all day long.

The script loads Eclipse fine in bash console. But when I try to launch it from run command dialog by pressing Alt-F2, nothing happens. Eventually I figured out that the problem is in my launch script: I forgot to push "#!/bin/sh" at the beginning of the file.

I am not sure why nothing happens when the sha-bang '#!' is left out, but if you encounter something similar, it might be cause.

Wednesday, September 19, 2007

Saving datetime into database, what timezone is it in?

Moments ago I posted a review on Amazon.com and returned to the product's page, it shows the review was posted 7 hours ago. It seems like Amazon is having a timezone conversion issue.

I am not trying to pick on Amazon. The funny part is that right this afternoon I was asked by a coworker about what timezone a datetime column of our database table is in. Then we had a discussion about how to handle timezones.

Timezone in databases is a delicate issue, and a tricky one to fully understand. Conversion is one issue. Others issues include moving data between database servers running in different timezones, moving data between different database dialects, interpret archived data, etc.

In the past I tried a couple approaches besides blindly saving the Date object through JDBC regardless of the timezone information. In one application I converted the datetime property into UTC time before saving it. In another application I converted time into milliseconds and saved it into database as long number.

I don't have a clear understanding of the relationship among the JVM's timezone, the Date object's timezone, the database server's timezone, the Timestamp's timezone in JDBC result set, and the Datetime column's timezone is MS SQL Studio's result set.

I have the full intension to study this topic in depth and report back.

Stay tuned.

Tuesday, September 18, 2007

the sneaky OutOfMemoryError: PermGen space error

Today I ran into several VERY nice posts which talk about the PermGen errors.

Here are Frank Kieviet's two blogs: classloader leakers and how to fix it (more like how to find it, fixing is likely to be the easy part).

Here is an excellent list of known offenders and links from Spring forum. link.

I cannot wait to modify jhat to map out the heap of my applications. We actually have two applications that are suffering from PermGen errors. One interesting point is that both applications suffer this error when they are hot deployed (unload then load while the application server is running) and when they run for a prolonged period of time. It seems like the first scenario is well examined. It will be very interesting to see what I can find out on the second scenario.

Tuesday, July 31, 2007

Custom sort of rows and columns without writing comparator

When doing JasperReports, I am often asked to sort the rows and columns in a particular ways other than alphabetical. JasperReports does support customized comparators for sorting. But I found it quite complicated to implement and not very easy to update in the future. Today I figured out a trick that can do arbitrary sorting easily.

In my sql statement, I concatenate the sequence number and the actually value together, for example, '01Banana', '02Orange', '03Apple'. Then in my report, I chop off the sequence number before displaying it, such as $F{field}.subString(2).

This trick works fine for small number of values.

Thursday, May 24, 2007

Responsive UI: do the heavy lifting in backgroup thread

Slow wireless connection, less processing power, less memory, all these factors make JavaME applications tend to feel sluggish. One trick we developers can play is to use background thread to do the heavy lifting parts.

The sample code below shows how one can use a separate thread to perform the time consuming task, while the UI still interacts with user, and update the UI when the task is completed.

Please note that the Runnable object passed to UiApplication.invokeLater() should return quickly. The Runnable object is put into the event queue to be executed by the event dispatcher thread. During the time this runnable is executing, all new UI events are queued so the UI will not respond to any input.


package com.mycompany.sample;

import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.AutoTextEditField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.container.MainScreen;

public final class DemoBackgroundThread extends UiApplication {
public DemoBackgroundThread(){
super();
pushScreen(new EditorScreen());
}

public static void main(String[] args) {
new DemoBackgroundThread().enterEventDispatcher();
}

private static class EditorScreen extends MainScreen {
private AutoTextEditField _firstNameField;
private AutoTextEditField _lastNameField;
private ObjectChoiceField _timezoneField;
public EditorScreen()
{
super();
_firstNameField = new AutoTextEditField("First Name: ", "");
_lastNameField = new AutoTextEditField("Last Name: ", "");
_timezoneField = new ObjectChoiceField("Timezone: ", new String[]{"Loading Timezones"});
add(_firstNameField);
add(_lastNameField);
add(_timezoneField);
new Thread(new Runnable() {
public void run() {
final String[] zones = new String[6];
zones[0] = "-Select Timezone-";
for(int i = 1; i < zones.length; i++) {
try {
//do the heavy lifting here, like fetching data from remote server or heavy calculations.
Thread.sleep(1000);
} catch (InterruptedException e) {
//who cares
}
zones[i] = "GMT-"+i;
}
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run() {
_timezoneField.setChoices(zones);
}
});
}
}).start();
}
}
}

Tuesday, May 22, 2007

Debug Blackberry app inside Eclipse

Once you get your eclipse environment setup, it is pretty straight forward to debug your app, thanks to Blackberry JDE, 4.1 and higher comes with JDWP implementation.

Let's first start JDWP, from Start --> All Programs --> Research In Motion --> Blackberry JDE 4.?.? --> JDWP. In this interface, the first main tab "Simulator" configures the simulator to lanch when debugger connects and the other behaviors. Please make sure that in the "General" tab "Launch simulator when debugger connects" is checked. In the second main tab "Communications", you can change the port JDWP listens to. This is the port we will connect to from our eclipse debugger.

With JDWP running, we can go back eclipse. Before we get started, we should increase the debugger's timeout threshold. Start elcipse, go to Window --> Preferences --> Java --> Debug, at the bottom of the dialog, increase the "Debugger timeout" and "Launch timeout" to 10 times longer. :) It is much needed unless you have a monster computer with multiple cores and multiple gigs of memory.

To config the debugger, go to Run --> Debug... In the dialog, select "Remote Java Application" from left hand list, then click on the "New" button; now at the right hand pane, give it a meaningful name, check the remote host and port matches JDWP's, then go to the third tab "Common", check "Debug" option in "Display in Favorites menu" so you don't have to open this dialog next time. Click "Debug" button if you are ready, otherwise click "Close" button to save the configuration.

Now the fun part begins. Edit code, run the ant task to deploy, set break point, click on the debug icon, and repeat this cycle.

Monday, May 21, 2007

Eclipse setup for blackberry development

These are proven-to-work steps to setup your eclipse environment for developing Blackberry applications. I hope this post will make somebody's entry into the RIM development easier.

To get started, do the following if you haven't done so:

  1. Download and install Eclipse
  2. Download and install BlackBerry JDE
  3. Download and install Apache ant
  4. Download RAPC ant task jar file
Now let's setup our eclipse environment.
  1. Start your eclipse, switch to a brand-new workspace, for example: c:\RIM\workspace
  2. go to Window --> Preferences --> Java --> Installed JREs, click on "Add" button.
  3. In the dialog, leave the default "Standard VM" option for JRE type;
  4. Type in a "JRE name" as you like, such as 'RIM JRE';
  5. In "JRE Home Directory", navigate to your installed JDK home, such as 'C:\Program Files\Java\jdk1.6.0';
  6. Leave "Default VM Arguments" blank;
  7. Now select all the jar files in "JRE System Libraries", then click "Remove" button to remove all of them; Click "Add External JARs", navigate to you Blackberry JDE installation folder, select lib/net_rim_api.jar, such as 'C:\Program Files\Research In Motion\BlackBerry JDE 4.2.1\lib\net_rim_api.jar'.
  8. Click "OK" button to add the new JRE.
  9. Check the checkbox of your newly added JRE to make it the default (Optional: select this JRE, click on "Edit" button to see if the system libraries are still like you set. It happened to me a couple times that eclipse added the jars in JRE home back into the list.)
With the eclipse setup, we are ready to create our first project:
  1. Goto File --> New --> Project, select "Java Project", enter Project Name "HelloWorld", Make sure in the JRE group the "RIM JRE" is selected. In the "Project Layout" group, I prefer to have src and class output into separate folders. Click "Finish" button.
  2. Right click the project, select New --> Folder, create a folder named "lib"
  3. Right click the project, select New --> Folder, create a folder named "resources"
  4. Right click "lib" folder, select "import"; in the dialog, select "general" --> "file system", import the anttask-rapc-1.?.jar you downloaded. Right click the jar file and select "Build Path" --> "Add to Build Path".
  5. Follow the same step to import an icon file in GIF format into "resources" folder. (other image formats work too, we use GIF for demo).
  6. Create a package named "com.mycompany.sample"
  7. Create a class named "HelloWorld.java" in this package and paste these code:
    package com.mycompany.sample;

    import net.rim.device.api.ui.UiApplication;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.container.MainScreen;

    public final class HelloWorld extends UiApplication {

    public HelloWorld(){
    super();
    MainScreen screen = new MainScreen();
    screen.add(new LabelField("Hello world!"));
    pushScreen(screen);
    }
    public static void main(String[] args) {
    new HelloWorld().enterEventDispatcher();
    }
    }
  8. Now right click on the project name and create a new file named "build.xml", copy and paste the following code and edit the JRE and RIM JDK pathes accordingly, also search and replace the simulator batch file "8800.bat" to one that exists in your JDE (this ant build script is modified based on a post in Blackberry Java Forum.)

    <?xml version="1.0" encoding="UTF-8"?>

    <project name="HelloWorld" default="buildRIM" basedir=".">

    <taskdef name="rim" classname="com.etaras.anttask.rapc.RAPC" classpath="lib/anttask-rapc-1.8.jar" />

    <property name="jdehome" value="C:\Program Files\Research In Motion\BlackBerry JDE 4.2.1" />
    <property name="javahome" value="C:\Program Files\Java\jdk1.5.0_11"></property>
    <property name="simulator" value="${jdehome}\simulator" />
    <property name="bin" value="${jdehome}\bin" />

    <target name="debug" depends="buildRIM">
    <copy todir="${simulator}" overwrite="true">
    <fileset dir=".">
    <include name="*.cod" />
    <include name="*.debug" />
    <include name="*.csl" />
    <include name="*.cso" />
    </fileset>
    </copy>
    <exec executable="cmd.exe" dir="${bin}" spawn="true">
    <arg value="/c" />
    <arg value="jdwp.bat" />
    </exec>
    </target>

    <target name="simulate" depends="deploy">
    <exec executable="cmd.exe" dir="${simulator}" spawn="true">
    <arg value="/c" />
    <arg value="8800.bat" />
    </exec>
    </target>

    <target name="deploy" depends="buildRIM">
    <copy todir="${simulator}" overwrite="true">
    <fileset dir=".">
    <include name="*.cod" />
    <include name="*.debug" />
    <include name="*.csl" />
    <include name="*.cso" />
    </fileset>
    </copy>
    </target>

    <target name="buildRIM" description="Composes RIM">
    <rim jdehome="${jdehome}" javahome="${javahome}">
    <workspace src="helloworld.jdw" build="true" update="true">
    <cldc src="helloworld.jdp"
    title="HelloWorld"
    vendor="my company"
    version="0.1"
    description="HelloWorld"
    arguments=""
    systemmodule="false"
    runonstartup="false"
    startuptier="7"
    ribbonposition="0"
    output="helloworld"
    options="-quiet"
    update="true">
    <files dir=".">
    <include name="**/*.java" />
    <include name="resources/**/*.*" />
    </files>
    <icons dir=".">
    <include name="resources/**/*.png" />
    <include name="resources/**/*.gif" />
    </icons>
    </cldc>
    </workspace>
    </rim>
    </target>

    </project>

  9. Open a DOS window, change to the directory where you have your build.xml file, type "ant simulate", this task will build the project, deploy it and start the simulator.
  10. Look for the logo you picked for your HelloWorld app and open it, you should see a blank screen displaying "Hello World!". How exciting!
I will write down my experience of debugging applications inside eclipse in the next couple of days.

Thursday, May 03, 2007

Downgrade default JRE on windows XP

When installing Blackberry signature keys yesterday, I need to downgrade my default JRE on windows XP from 1.6 to 1.5. (Java is so good at maintaining backward compatibility, I seriously want to figure out what made the installation process not working in Java1.6. If you have a clue, please comment. Thanks.)

The complexity of this process caught me off guard. As a linux user, I instinctively went to My Computer --> Properties --> Advanced --> Environment Variables, and set the pathes. It doesn't work this way though. (Gentoo users, enjoy your java-config util and laught at me)

After some digging, here are the steps worked for me.

  1. Copy java.exe, java2.exe, javaws.exe from C:\Program Files\Java\jdk1.5.0_??\bin to C:\WINDOWS\system32\ to overwrite existing 1.6 version files.
  2. Open registry editor, goto Start --> Run, type in "regedit" and enter.
  3. Do a search for "JavaSoft", you should find something under HKEY_LOCAL_MACHINE -->SOFTWARE --> JavaSoft --> Java Runtime Environment, modify "CurrentVersion" key to "1.5" or the version you want.
  4. Update the correspondent environment variables.

Install RIM Blackberry signature keys and sign .cod file

Waited one week after placing the signature key order with RIM, we finally lost our patience and contacted them. And shortly after that, we received our keys. :)

Three ".csi" files were emailed to us. Installation is straight forward unless you have incompatible Java version. Downloading files onto hard drive, double click on one, you should see a dialog popping up saying "cannot find private key pair file, blah blah" and a "Yes" button at the end to create one. Click on the "Yes" button, if nothing happens you probably have JDK1.6 running and need to downgrade to JDK1.5. Otherwise another dialog will pop up and ask for the registration pin (the 10 digit number you entered when ordering the key) and select a password. Follow the steps to get your first key registered with RIM. Then do the same for the other two. You are done.

Signing your .cod file is straight. Double click on the .cod file, the Signature Tool window with a table listing all the signatures that you need and need not to request for your cod file will pop up. The signatures you need to request depends on the APIs you used in your cod file. Select the rows with category "required" and status "not signed", click the "Request" button, the Signature Tool will talk to RIM server to get the signature needed. Voila, you just got your application signed.

Wednesday, April 25, 2007

Blackberry 7290 application OutOfMemory exception

After testing my application on the simulator, I finally loaded it onto a real blackberry device, model 7290. It was very exciting to see the cute little logo shown up on the screen. Rolling the trackwheel and click, I got an "OutOfMemory" exception thrown right at my face!!! What a bummer.

Both from the Blackberry documentation and the Internet posts, I got the impression that mobile devices have VERY limited memory, just enough to hold some objects and some object references (handlers). So it must be my application using too much memory. I guess there can only be one response from any developer: I need to optimize my code.

So I started optimizing my code, reducing all object creations and references that are not absolutely necessary, sometimes even sacrifice design patterns, best practices and code readability. I guess that is the price you have to pay for efficiency. Did it help? NO.

I was just about to start doing object grouping when I ran over a post on Internet saying it is not your application, it is the JDE version you are using. For the particular device model (7290) and OS version, I need to use Blackberry JDE4.0 versions. The mystery and embarassing OutOfMemory problem was solved just like that.

Eclipse BlackBerry JDE ClassNotFound Exception

Environment: Eclipse 3.1.1, BlackBerry JDE 4.2.1

When I first set up my eclipse for BlackBerry development, I got this exception: The type net.rim.device.internal.ui.Cursor cannot be resolved. It is indirectly referenced from required .class files. After searching the the Internet and the blackberry java forum, I figured out that it is caused by the java compliance level setting. To fix it, go to Window - Preferences - Java - Compiler, set the Java Compliance Level to 1.4.

Monday, April 23, 2007

DocumentBuilderFactory code signing issue

After resolving the outofmemory issue, my code still won't run. I got another exception saying: Error starting : Module must be signed with the RIM Runtime Code Signing Key (RRT).

Hmm, I was pretty sure that I am not using any signed API, but out of 3000 lines of code, it is very much possible to miss one or two. JDE 4.2.1 has a feature that can outline all the signed API calls. It helps only if I can get it working.

Before I eyeball the code line by line, I did a google search and found this post. Ahha, it is a bug in JDE. The DocumentBuilderFactory falsely requires code signing (fixed in 4.2 and higher). Now my only way out is to buy a sign key from RIM.

Accessing remote X-window from windows box

This is not pretty, but it's needed sometimes. (Yeah, I know, your company made you use windows)

There is a good deal of information on this wiki page about Cygwin/X. But to me it seems like too much information so I simplified it for my own reference.

Here are three simple steps to access remote X after you get Cygwin with X installed:

  1. open a Cygwin window and start X server: X -multiwindow &
  2. export DISPLAY=127.0.0.1:0.0
  3. ssh -X username@remote.server
  4. run xclock (personally I prefer xeyes) to test
One thing to keep in mind is that the remote server has to enable X11 forwarding. It is configed in sshd config file /etc/ssh/sshd_config. Search for X11Forwarding.

That is it. If you prefer putty which is another nice tool I use occationally. You can do this:
  1. open a Cygwin window and start X server: X -multiwindow &
  2. Open putty, in Connection --> SSH --> X11 tab, check the box "Enable X11 Forwarding".
  3. Login and you are done, now open an X app like xclock or xeyes, you should see it.