Monday, June 20, 2011

NoClassDefFoundError in Blackberry

Since lastweek I spent couple of days trying to fix an issue: The application keep throwing NoClassDefFoundError Exception in a callback method. Through JDE debugger, I can figure out exactly where the exception is threw and which object cause the exception, but when I check the code back and forth, I could not find the problem, since the class file is there. Finally I realized that I also changed the build script: before I use antenna wtkbuild task to generate the library, the new build I use regular javac task, since I used the blackberry native API. Will it cause the problem? It does not make any sense to me. I tried to switch back the build script using twkbuild task and adding the rim api in the class path, this time everything works! No more NoClassDefFoundError any more!

Finding the root cause
I compared the wtktask and the javac task with blackberry build script:

build target(with issue):
<target name="compile_rim" depends="init">
  <javac destdir="${outputclasses}" encoding="${src.encoding}" source="1.3" srcdir="${src.dir}:${rim.src.dir}">
    <classpath location="${rimlib.loc}"/>
Created by Pretty R at

wtk build ( no issue)

Form the above, I can not tell the difference, and can not figure out why there is an issue. So I have to look at the antenna source code. When I looked at the, I noticed that antenna sets the javac target to 1.1 by default! This is interesting.

Check the ant document for javac task, for target attribute, it says:
Generate class files for specific VM version (e.g., 1.1 or 1.2). Note that the default value depends on the JVM that is running Ant. In particular, if you use JDK 1.4+ the generated classes will not be usable for a 1.1 Java VM unless you explicitly set this attribute to the value 1.1 (which is the default value for JDK 1.1 to 1.3). We highly recommend to always specify this attribute.
So based on the above statement, I suspect that the Ant require us to specify the target version, if we don't specify ant will use the default version.and the default target version cause the blackberry device throws the exception.

What is the target version for J2ME and Blackberry
In Antenna, the target is set to 1.1, is this the correct value for J2ME and Blackberry? To prove this, I googled and find some articles:
Managing Wireless Builds with Ant, this article from oracle mentioned that J2ME build requires target value to be 1.1:
<javac bootclasspath="${midp_lib}" destdir="build/classes" srcdir="src" target="1.1">

and I found this article in BlackBerry forum:javac -target parameter used by the rapc.exe tool
It shows that you need to use target 1.1 to build blackberry compatible application:
Rapc.exe automatically ensures that these .class files are targeted for BlackBerry® Java® Virtual Machine (BlackBerry JVM) 1.1 or later. This is done to maintain compatibility on the BlackBerry smartphones when the .class files are actually packaged in a .cod file.

If you are using a custom script that calls javac.exe and rapc.exe separately to package your application, you will have to make sure that you are calling javac.exe with -target option so that all generated .class files are compatible. This is a requirement to make sure that the generated .class files are consistent with Connected Limited Device configuration (CLDC) 1.1 BlackBerry JVM implementation.
Based on what I found, I know that Both J2ME and Blackberry Build need target option to 1.1. otherwise the blackberry application might have a weird issue like NoClassDefFoundError.

Saturday, June 11, 2011

How I improved my company's build system - build automation

Last 2 weeks I haven't check twitter, did not go to infoQ, all my spare time is focused on one thing: improve the build system, the goal - one button click triggered the build and deploy automation.
This goal is finally achieved last week. Now the build system is scheduled deployment once a day, the automation jobs include following:
  1. check out source code from CVS;
  2. build client and server artifacts;
  3. generate the change log
  4. update the wiki and download page
  5. upload the artifact into server and downloading repository
  6. execute the server deploy script
  7. send new release email 
Before only step 1) and 2) are automatic using the ANT script. All other steps are manual, I found this kind of job is boring,painful and quit easy to make mistakes.

I have the idea for build automation for a long time, especially I was inspired by the book "Continuous Delivery" and "Pragmatic Project automation".  My plan to implement the build automation is pretty simple: simulate the human deployment behaviour, implement an ANT target for each manual step. It sound easy, but when I actually did it, it was harder than imagined. But I finally I made it.
Right now everyday we will automatically release a new build, this is a milestone and a great improvement. I feel so happy and so proud of it.

The tools I used
- ANT,  I used scp, filterset, filterchain, sshexec, cvschangelog, I found Ant has lots of gem.
- Groovy, I used AntBuilder to integrate with the existing ANT task, parsing XML, generating text file, quite neat.
- Jenkins,  everyone recommend Hudson/Jenkins CI server, when I used it, it is so easy to use, and has lots of useful plugins. I use Jenkins to schedule and trigger the build.
- ViewVC, a very good tool to browse CVS source code from web, I configure the ViewVC in Jenkins, Jenkins will provide the actually source code link in the changes page.

What I learned
  • Pay more attention to your feeling. If you feel boring and painful, don't just complain, try to find a way to improve it. This is a good chance to improve your self, my previous blog describe this.
  • A good developer must be able to delegate the dirty jobs to the computers, it would be shame for a good developer to do the repetitive manual jobs over and over.
  • I implemented the automatic build script based on the manual process, so I learned: if you can define a repeatable step by step manual process, then you can automate it by program.
  • I finished this job usually in down time, I finished one small piece each time, so the improvement for the legacy system has to be emergent.
Next Actions
This is only the first step, there are way more things needs to be done, my next steps will be:
- Add Unit Test and Regression test automation
- Add the code quality analysis report
- Use Ivy for dependency management
- Use Puppet to manage the configuration