Currently I am using Rhodes framework to build mobile applications. Recently I just figured out how to request an Ajax call from view, and controller how to render a JSON object and return it to the view.
Sample code
Ajax call to request json object using jQuery:
code of rending json in controller
I found this solution in the Rhomobile launchpad forum, it works perfectly.
This exactly looks like render json behaviour in Ruby on Rails.
Showing posts with label mobile. Show all posts
Showing posts with label mobile. Show all posts
Sunday, October 21, 2012
Saturday, March 10, 2012
Presentation note - Continuous Integration in the Mobile World
Yesterday I watched the presentation Continuous Integration in the Mobile World by Godfrey Nolan in InfoQ. It is a very informative, the author covers the Jenkins CI server, Version Control and test tools for ios and Android mobile platform, and the author tells us how he integrates those tools in his company's mobile application development. Most of those tools he mentioned are first time for me. We use Jenkins, but I haven't realize that there are so many good tools available for you.
Here I just summarize the tools which are mentioned in the presentation.
Jenkins Plugins
- Android Emulator Plugin
- Xcode Plugin
Test tools
- Perfecto mobile, test real mobile device via the cloud, I feel it is quite similar with DeviceAnyWhere.
- TestFligh App, ios beta test on the fly.
- FoneMonkey, Functional test tool for ios and Android
- Robotium, like Selenium, it is for Android UI test framework
- OCUnit, Objective C unit test framework
- OCUnit2junit, a ruby script to convert OCUnit to Junit, which allows Jenkins to run the OCUnit.
I need to do more research on those tools, I really appreciate Godfrey provide such a informative and inspiring presentation.
Here I just summarize the tools which are mentioned in the presentation.
Jenkins Plugins
- Android Emulator Plugin
- Xcode Plugin
Test tools
- Perfecto mobile, test real mobile device via the cloud, I feel it is quite similar with DeviceAnyWhere.
- TestFligh App, ios beta test on the fly.
- FoneMonkey, Functional test tool for ios and Android
- Robotium, like Selenium, it is for Android UI test framework
- OCUnit, Objective C unit test framework
- OCUnit2junit, a ruby script to convert OCUnit to Junit, which allows Jenkins to run the OCUnit.
I need to do more research on those tools, I really appreciate Godfrey provide such a informative and inspiring presentation.
Tuesday, September 6, 2011
Developing Blackberry application using NetBeans Plugin - part 2, fixing debug issue
On my previous post, I reviewed the new blackberry Netbeans Plugin. Latre I found Shai also published his post about how to use the new plugin in developing the LWUIT blackberry application.
But I found the new plugin could not debug the blackberry application.
Reason
The reason is if you want to debug your blackberry application, you have to copy all the .debug files into the blackberry simulator folder, include xxx.debug, xxx-1.debug, xxx-2.debug, ... etc. From the generated build-impl.xml script file, we know that blackberry plugin only copied the xxx.debug file and missing all other debug files.
Solution
Add the following targets in the build.xml, which will override the same target in the build-impl.xml:
1. Update target blackberry-pre-debug, it will copy all the debug files into the simulator folder.
2. Update target clean-blackberry, it will delete all the files of the application in the simulator folder.
3. If you want to build BlackBerry CLDC application, you need to add the target create-cod:
The only difference with build MIDlet application is in <arg value="-cldc"/>, by default, the Blackberry plugin already choose MIDlet by using <arg value="-midlet"/>.
Wednesday, August 10, 2011
Developing Blackberry application using NetBeans Plugin - part 1, first impression
Updates: I got some feedbacks that the download link in Netbeans is not working anymore, I uploaded the plugin binary into my google doc, please try my link if you have problem to download.
Recently when I checked out the latest version of the source code of LWUIT, I realized that LWUIT used a new solution of developing blackberry application - using Netbeans Blackberry plugin. So today I tried to give an review about this new tool.
Plugin Installation
1. go to this link (or my link)to download the blackberry netbeans plugin, save it in your local drive.
2. In your Netbeans IDE, choose Tools - Plugins, click Downloaded tab, press "Add Plugins..." button, choose the downloaded blackberry plugin .nbm file,
3. Restart your Netbeans IDE, the thing is it seems the blackberry plugin has an issue, you can not see it under the Installed tab of the Plugins UI Form. I was confused it at the beginning as well.
Add BlackBerry SDK platforms
The plugin download link (or here)gives some screen shots about how to add blackberry SDK platform into your NetBeans IDE environment, here I just give an rough description, if you are familiar with the steps of adding other J2ME SDK into the NetBeans IDE, you will know it is the exactly the same steps.
Compare this step with the older solution, you will feel how easy it is.
After Adding the BlackBerry SDKs in your NetBeans IDE, you can use the same way as J2ME Mobility package for blackberry development. Really Nice!!! Good job for the author!
Test
To test how the Plugin works, I choose 2 tests, one is for MIDlet and the other is for CLDC application (RIMlet).
Test1 - build an BlackBerry MIDlet application
I imported an JavaME SDK sample application - SunSamples-Demos into my NetBeans IDE, then add another configuration, choose an BlackBerry platform, I just choose JDE 4.5, then everything else is copied from the default configuration.
1. Test Build
Click "Clean and Build", the IDE build successfully and generate .cod file and bunch of .debug files.
So Build test passes.
2. Test Run
When I click "Run", the IDE launches BlackBerry simulator, then I found the several applications (since SunSamples-Demos contains multiple MIDlets), I choose some apps, they work perfectly.
Application Running also passed.
3. Test Debug
I set several break points in the IDE, then I click "Debug", the IDE launches the BlackBerry JDWP application and the blackberry simulator, when choose an application, the application did not stop at a specific break point.
The debug test failed.
Test2 - build an BlackBerry CLDC application
This time I choose a LWUIT blackberry port demo application - LWUITDemoRIM, just check out the LWUIT source code from its SVN, open the LWUITDemoRIM project. If you installed the plugin and added the blackBerry SDK properly, it is very easy to configure the project in the NetBeans.
Here I would like to mention, for native CLDC application, you need to do a little extra work in your build script. Check this link for details: http://forums.netbeans.org/topic24475.html
1. Test Build
Click "Clean and Build", the IDE build successfully and generate .jad file, .cod file and bunch of .debug files. If you open the jad file, it will tell you the application is CLDC application.
So Build test passes.
2. Test Run
When I click "Run", the IDE launches BlackBerry simulator, you will find the familiar LWUIT demo icon, the application works perfectly as I saw before.
So running test passed.
3. Test Debug
When I click "Debug", I saw the same behaviour as the MIDlet application test, the application never stops at the break point.
Debug test failed as well.
Conclusion
Pros:
- The Blackberry Plugin for NetBeans is pretty easy to install and use. The developer will feel it looks pretty same as other J2ME SDK.
- The Build process is really simple and almost same as regular J2ME application, it will convert jar file into blackberry .cod file.
- The IDE can launch Blackberry native simulator and can run the application successfully.
- The plugin built-in support MIDlet build, need a little work for RIMlet.
Cons:
- Debug is not working, after I read the build script, I know why: based on my experience, you need to copy all the .debug files into the simulator folder, but in build-impl.xml, the target "blackberry-pre-debug" only copied 1 .debug file but missing others. I will post the detailed solution in future.
Next Action
In future, I will continue post my investigation about this plugin, includes:
- How to build the MIDlet and RIMlet
- Dig deeper on how it implement the blackberry build
- How to fix the debug issue
Recently when I checked out the latest version of the source code of LWUIT, I realized that LWUIT used a new solution of developing blackberry application - using Netbeans Blackberry plugin. So today I tried to give an review about this new tool.
Plugin Installation
1. go to this link (or my link)to download the blackberry netbeans plugin, save it in your local drive.
2. In your Netbeans IDE, choose Tools - Plugins, click Downloaded tab, press "Add Plugins..." button, choose the downloaded blackberry plugin .nbm file,
3. Restart your Netbeans IDE, the thing is it seems the blackberry plugin has an issue, you can not see it under the Installed tab of the Plugins UI Form. I was confused it at the beginning as well.
Add BlackBerry SDK platforms
The plugin download link (or here)gives some screen shots about how to add blackberry SDK platform into your NetBeans IDE environment, here I just give an rough description, if you are familiar with the steps of adding other J2ME SDK into the NetBeans IDE, you will know it is the exactly the same steps.
Compare this step with the older solution, you will feel how easy it is.
After Adding the BlackBerry SDKs in your NetBeans IDE, you can use the same way as J2ME Mobility package for blackberry development. Really Nice!!! Good job for the author!
Test
To test how the Plugin works, I choose 2 tests, one is for MIDlet and the other is for CLDC application (RIMlet).
Test1 - build an BlackBerry MIDlet application
I imported an JavaME SDK sample application - SunSamples-Demos into my NetBeans IDE, then add another configuration, choose an BlackBerry platform, I just choose JDE 4.5, then everything else is copied from the default configuration.
1. Test Build
Click "Clean and Build", the IDE build successfully and generate .cod file and bunch of .debug files.
So Build test passes.
2. Test Run
When I click "Run", the IDE launches BlackBerry simulator, then I found the several applications (since SunSamples-Demos contains multiple MIDlets), I choose some apps, they work perfectly.
Application Running also passed.
3. Test Debug
I set several break points in the IDE, then I click "Debug", the IDE launches the BlackBerry JDWP application and the blackberry simulator, when choose an application, the application did not stop at a specific break point.
The debug test failed.
Test2 - build an BlackBerry CLDC application
This time I choose a LWUIT blackberry port demo application - LWUITDemoRIM, just check out the LWUIT source code from its SVN, open the LWUITDemoRIM project. If you installed the plugin and added the blackBerry SDK properly, it is very easy to configure the project in the NetBeans.
Here I would like to mention, for native CLDC application, you need to do a little extra work in your build script. Check this link for details: http://forums.netbeans.org/topic24475.html
1. Test Build
Click "Clean and Build", the IDE build successfully and generate .jad file, .cod file and bunch of .debug files. If you open the jad file, it will tell you the application is CLDC application.
So Build test passes.
2. Test Run
When I click "Run", the IDE launches BlackBerry simulator, you will find the familiar LWUIT demo icon, the application works perfectly as I saw before.
So running test passed.
3. Test Debug
When I click "Debug", I saw the same behaviour as the MIDlet application test, the application never stops at the break point.
Debug test failed as well.
Conclusion
Pros:
- The Blackberry Plugin for NetBeans is pretty easy to install and use. The developer will feel it looks pretty same as other J2ME SDK.
- The Build process is really simple and almost same as regular J2ME application, it will convert jar file into blackberry .cod file.
- The IDE can launch Blackberry native simulator and can run the application successfully.
- The plugin built-in support MIDlet build, need a little work for RIMlet.
Cons:
- Debug is not working, after I read the build script, I know why: based on my experience, you need to copy all the .debug files into the simulator folder, but in build-impl.xml, the target "blackberry-pre-debug" only copied 1 .debug file but missing others. I will post the detailed solution in future.
Next Action
In future, I will continue post my investigation about this plugin, includes:
- How to build the MIDlet and RIMlet
- Dig deeper on how it implement the blackberry build
- How to fix the debug issue
Monday, June 20, 2011
NoClassDefFoundError in Blackberry
Background
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):
Created by Pretty R at inside-R.org
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 WtkBuild.java, 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:
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:
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:
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.
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}"/> </javac> </target>
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 WtkBuild.java, 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.Conclusion
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.
Friday, March 11, 2011
Blackberry trick: retrieving the MNC correctly
Recently I need to retrieve the MNC value from the blackberry device, but though the real network testing, I realize that the value might not be correct for some cases.
The 3 different solutions of retrieving the MNC
The 3 different solutions of retrieving the MNC
- via GPRSInfo
- via RadioInfo
- via GPRSCellInfo
int mnc = GPRSInfo.getHomeMNC();
int currentIndex = RadioInfo.getCurrentNetworkIndex();
int mnc = RadioInfo.getMNC(currentIndex); GPRSInfo.GPRSCellInfo cellInfo = GPRSInfo.getCellInfo();
int mnc = cellInfo.getMNC(); Note:in blackberry the returned MNC value is decimal, which is different with the MNC standard, which is hexadecimal.
I found that solution 1-2 are always consistent, they are always same if you are not in the roaming network. But in solution 3, in some cases you will get the wrong value. For example I tested the following UK carriers, the retrieved mnc values are all wrong:
From the above table, we can tell that all the mnc values are appended letter F at the end, if we removed the F, then the value is correct. This is the first time I have ever met. Actually I found this article mentioned this issue a little bit:
Conclusion
So the solution to get the correct MNC value from blackberry API should be: first check the last 4 bits value, if it is F (or more than 9), then right shift 4 bits, that is it!
I found that solution 1-2 are always consistent, they are always same if you are not in the roaming network. But in solution 3, in some cases you will get the wrong value. For example I tested the following UK carriers, the retrieved mnc values are all wrong:
| Carrier Name | MNC(Hex) | retrieved(dec) | retrieved(hex) |
|---|---|---|---|
| 3 UK | 20 | 527 | 20F |
| Orange UK | 33 | 831 | 33F |
| Vodafone UK | 15 | 351 | 15F |
| T-Mobile | 30 | 783 | 30F |
| O2 | 10 | 271 | 10F |
From the above table, we can tell that all the mnc values are appended letter F at the end, if we removed the F, then the value is correct. This is the first time I have ever met. Actually I found this article mentioned this issue a little bit:
...therefore the corresponding hexadecimal value returned by getMCC()or getMNC()may contain the letter F as padding. For example, for T-Mobile®, the MCCs can be identified as either 260 or 26F.If you want to use cellInfo ( ex. MCC, MNC, LAC, cellID) to get the current location via openCellID for example, then you need to be careful for this issue.
Conclusion
So the solution to get the correct MNC value from blackberry API should be: first check the last 4 bits value, if it is F (or more than 9), then right shift 4 bits, that is it!
Monday, January 17, 2011
The Facebook login & logout flow for Android platform
Recently I am working on a mobile application project using the FaceBook API. I never touched Facebook API before, for me the first thing is to understand how the Facebook login/logout works on the mobile apps, so I spent some time on figure out how does it work on the Android platform.
I just summarized the login and logout flow based on the Facebook android SDK source code and its sample app log output.
First you need to register your application and get your application ID from the facebook website.
Login Flow
Request format:
Here,
client_id is your application id.
display=touch means the device smart phone (android or iphone)
response:
You need to launch a browser inside your app to send the login the request, browser will display a login dialog let input the facebook account and password, then if login successful, the browser will return the redirected URL(fbconnect://success) with the access_token and expired value.
To retrieve these values, you need to intercept the redirected URL: check if it starts with fbconnect://success, then parse the response, get the access_token and expire value.
Logout Flow
format:
If logout successfully, the response will return text "true",
otherwise it will return a JSON text contains the detailed error message.
I just summarized the login and logout flow based on the Facebook android SDK source code and its sample app log output.
First you need to register your application and get your application ID from the facebook website.
Login Flow
Request format:
https://m.facebook.com/dialog/oauth?client_id=xxxx&redirect_uri=fbconnect://success&display=touch&type=user_agentexample:
https://m.facebook.com/dialog/oauth?client_id=175729095772478&redirect_uri=fbconnect://success&display=touch&type=user_agent
Here,
client_id is your application id.
display=touch means the device smart phone (android or iphone)
response:
fbconnect://success/#access_token=xxxxx&expires_in=xxxxxexample:
fbconnect://success/#access_token=175729095772478%7C2.vQIILuM8Bu_9nLKrl4yIew__.3600.1294938000-100000460660639%7Ch9OreeWmU4iUMB47UKwl20H64Gg&expires_in=4593
You need to launch a browser inside your app to send the login the request, browser will display a login dialog let input the facebook account and password, then if login successful, the browser will return the redirected URL(fbconnect://success) with the access_token and expired value.
To retrieve these values, you need to intercept the redirected URL: check if it starts with fbconnect://success, then parse the response, get the access_token and expire value.
Logout Flow
format:
https://api.facebook.com/restserver.php?access_token=[your access_token]
&method=auth.expireSession&format=json
example:https://api.facebook.com/restserver.php?access_token=175729095772478%7C2.mJlReipn5lu6jEJrKU2D6w__.3600.1295024400-100000460660639%7CE7f8hi-RkJtxOoJmGTyaWFgXHfI&method=auth.expireSession&format=json
If logout successfully, the response will return text "true",
otherwise it will return a JSON text contains the detailed error message.
Tuesday, November 30, 2010
Hacking the Wireless Toolkit for Mac
Today I spend a whole day trying to fix an J2ME build issue: the build script works on windows, but failed on Mac. My working environment is:
WTK
- Windows PC: WTK 2.5.2
- Mac: WTK 2.5.2 Linux version, copied preverify from JavaME SDK 3.0 Mac
Build tool is Antenna
- Windows: antenna 1.1.0
- Mac: antenna 1.2.1 ( the earlier versions have preverify issue on Mac )
Actually we usually build J2ME application on windows or Linux box, this is the first time to build on Mac. I checked the build log, the log shows the preverify error.
Since I used Sun's latest version of preverify file for Mac, I never suspect it might have issue. I thought issue might due to Mac is picky with the Antenna build script, so I spent lots of time trying to tweaking the build script, but no luck. So I started to thinking the problem might be the preverify file I used for Mac.
Finally I have to google and I was so lucky that I found Sam's blog post: J2ME Development on OS X, revisited. This is a fantastic article, the most important for me is he tells me how to get the Mac version of preverify: Download the phoneME project source code, and the preverify for mac is under phoneme_feature/cldc/build/share/bin/darwin_powerpc/, as the author suggested, I downloaded the PhoneME feature M2 source code, and I did found the preverify, and after I copied the preverify in my WTK /bin folder of my mac machine, then when I run the build script, it works, awesome. I really admire this guy, how could he find out this tool!
Now let me describe how to install WTK 2.5.2 on Mac in step by step, please note this only works if you still use WTK 2.5.x, and it is only useful for building the application, the emulator and other tools are not working, you can use JavaME SDK 3.0 for Mac, but based on my today's experience, its preverify still has issues:
Download and Install the WTK 2.5.2
Get the preverify binary
Today one of my colleague found this issue on this macbook, when I give him a copy of preverify binary file, when he run it on his machine, it prompt need to install Rosetta to run it. it said the Rosetta comes with the MacOS installation CD, so if you have the similar issue, then install it first.
Other tools:
Antenna: please use the latest version for Mac (1.2.1).
Gant: the groovy based DSL for build script, it built-in support all the ant tasks, but you don't need to write XML any more, I just started using it, and I love it.
WTK
- Windows PC: WTK 2.5.2
- Mac: WTK 2.5.2 Linux version, copied preverify from JavaME SDK 3.0 Mac
Build tool is Antenna
- Windows: antenna 1.1.0
- Mac: antenna 1.2.1 ( the earlier versions have preverify issue on Mac )
Actually we usually build J2ME application on windows or Linux box, this is the first time to build on Mac. I checked the build log, the log shows the preverify error.
Since I used Sun's latest version of preverify file for Mac, I never suspect it might have issue. I thought issue might due to Mac is picky with the Antenna build script, so I spent lots of time trying to tweaking the build script, but no luck. So I started to thinking the problem might be the preverify file I used for Mac.
Finally I have to google and I was so lucky that I found Sam's blog post: J2ME Development on OS X, revisited. This is a fantastic article, the most important for me is he tells me how to get the Mac version of preverify: Download the phoneME project source code, and the preverify for mac is under phoneme_feature/cldc/build/share/bin/darwin_powerpc/, as the author suggested, I downloaded the PhoneME feature M2 source code, and I did found the preverify, and after I copied the preverify in my WTK /bin folder of my mac machine, then when I run the build script, it works, awesome. I really admire this guy, how could he find out this tool!
Now let me describe how to install WTK 2.5.2 on Mac in step by step, please note this only works if you still use WTK 2.5.x, and it is only useful for building the application, the emulator and other tools are not working, you can use JavaME SDK 3.0 for Mac, but based on my today's experience, its preverify still has issues:
Download and Install the WTK 2.5.2
- Goto here to download the Sun's WTK 2.5.2 for Linux, file is called sun_java_wireless_toolkit-2_5_2-linux.bin
- Execute the downloaded file (sh sun_java_wireless_toolkit-2_5_2-linux.bin)
- When asked for a path to JDK, enter “/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/bin/”
- Follow the instructions, probably best to install into /Applications/WTK2.5.2
Get the preverify binary
- Download the PhoneME project feature source code, choose the M2 source bundle
- Extract phoneME build, it creates a directory called “phoneme_feature”
- Copy /phoneme_feature/cldc/build/share/bin/darwin_powerpc/preverify and overwrite the preverify binary in your WTK bin folder.
- You might need to change the permission to w+x of preverify.
Today one of my colleague found this issue on this macbook, when I give him a copy of preverify binary file, when he run it on his machine, it prompt need to install Rosetta to run it. it said the Rosetta comes with the MacOS installation CD, so if you have the similar issue, then install it first.
Other tools:
Antenna: please use the latest version for Mac (1.2.1).
Gant: the groovy based DSL for build script, it built-in support all the ant tasks, but you don't need to write XML any more, I just started using it, and I love it.
Saturday, October 16, 2010
Build J2ME app using Gant
These days I spent some time learning Groovy. Why I learn Groovy? Because I want to use Gant. Gant = Groovy + Ant. Gant is really powerful, since you can use Groovy script and Ant API to write your build script instead of XML. I struggle a long time in Ant, because I have to use Ant-Contrib plugin, and it is so hard to write an condition block and even for loop, it is much easier to do that in Gant script.
Now I am going to share the gant script of building J2ME app, this is just basic, but you can see the power of Gant.
Requirement:
1. You need to install Groovy and Gant, here is the link, I used 1.9.3 in Mac.
2. download the latest version of antenna, here is the download link, I used 1.2.1-beta.
3. install the JavaME SDK, I choose JavaME SDK 3, since it works on Mac.
The J2ME MIDlet class source code:
the build script build.gant:
From the above script, you can see how easy to write gant build script.
This is only the basic implementation, I am going to post more Gant based script in future.
In future I am going to consider:
1. How to integrate with ANT script;
2. How import multiple Gant script file.
Now I am going to share the gant script of building J2ME app, this is just basic, but you can see the power of Gant.
Requirement:
1. You need to install Groovy and Gant, here is the link, I used 1.9.3 in Mac.
2. download the latest version of antenna, here is the download link, I used 1.2.1-beta.
3. install the JavaME SDK, I choose JavaME SDK 3, since it works on Mac.
The J2ME MIDlet class source code:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloWorld extends MIDlet implements CommandListener {
private final Command exitCommand;
private final Form form;
public HelloWorld() {
exitCommand = new Command("Exit", Command.EXIT, 1);
form = new Form("Hello World!");
form.append("from Steve");
form.addCommand(exitCommand);
form.setCommandListener(this);
}
protected void startApp() {
Display.getDisplay(this).setCurrent(form);
}
protected void pauseApp() {}
protected void destroyApp(boolean force) {}
public void commandAction(Command cmd, Displayable disp) {
if (cmd == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}
}
The Ant script looks like:<project name="antenna-test" default="jar" basedir="."> <taskdef resource="antenna.properties" classpath="./antenna-bin-1.2.1-beta.jar" /> <property name="wtk.home" value="/Users/Steve/dev/wtk252" /> <property name="wtk.midp.version" value="2.0" /> <property name="wtk.cldc.version" value="1.1" /> <property name="src.dir" location="src" /> <property name="out.dir" location="out" /> <property name="dist.dir" location="dist" /> <property name="preverified.dir" location="preverified" /> <!-- Regular targets --> <target name="clean" description="cleans the target directory"> <delete dir="${out.dir}"/> <delete dir="${dist.dir}"/> <delete dir="${preverified.dir}"/> </target> <target name="compile" depends="init"> <wtkbuild source="1.3" srcdir="${src.dir}" destdir="${out.dir}"> </wtkbuild> </target> <target name="preverify" depends="compile"> <wtkpreverify srcdir="${out.dir}" destdir="${preverified.dir}"> </wtkpreverify> </target> <target name="jar" depends="compile,jad,preverify"> <wtkpackage jarfile="${dist.dir}/helloworld.jar" jadfile="${dist.dir}/helloworld.jad" obfuscate="false" preverify="false"> <fileset dir="${out.dir}"/> </wtkpackage> </target> <target name="jad" depends="compile"> <wtkjad version="0.01" name="hello" vendor="foo" jadfile="${dist.dir}/helloworld.jad" jarfile="${dist.dir}/helloworld.jar"> <midlet name="hello" class="HelloWorld"> </midlet> </wtkjad> </target> <target name="init" description="initialization for properties and paths" depends="clean"> <buildnumber/> <mkdir dir="${out.dir}"/> <mkdir dir="${dist.dir}"/> <mkdir dir="${preverified.dir}" /> </target> </project>
the build script build.gant:
ant.taskdef(resource:"antenna.properties", classpath:"./antenna-bin-1.2.1-beta.jar")
ant.property(name:"wtk.home", value:"/Applications/Java_ME_SDK_3.0.app/Contents/Resources")
ant.property(name:"wtk.midp.version", value:"2.0")
ant.property(name:"wtk.cldc.version", value:"1.1")
final srcDir = "src"
final outDir = 'out'
final distDir = 'dist'
final preverifiedDir = 'preverified'
//clean target
includeTargets << gant.targets.Clean
cleanPattern << '**/*~'
cleanDirectory << [ outDir, distDir, preverifiedDir]
target(name:"init", description:"initialization") {
depends(clean)
/*buildnumber() */
mkdir(dir:outDir)
mkdir(dir:distDir)
mkdir(dir:preverifiedDir)
}
target(name:"compile", description:"compile") {
depends(init)
wtkbuild( source:"1.3", srcdir:srcDir, destdir:outDir)
}
target(name:"preverify", description:"preverify") {
depends(compile)
wtkpreverify(srcdir:outDir, destdir:preverifiedDir)
}
//target jad file
target(name:"jad", description:"generate jad file") {
depends(compile)
wtkjad( version:"0.01", name:'hello', vendor:"foo", jadfile:"${distDir}/helloworld.jad", jarfile:"${distDir}/helloworld.jar" ) {
midlet(name:"hello", class:"HelloWorld")
}
}
//target jar
target(name:"jar", description:"generating jar file") {
depends(compile,jad)
wtkpackage( jadfile:"${distDir}/helloworld.jad", jarfile:"${distDir}/helloworld.jar", obfuscate:"false", preverify:"false") {
fileset(dir:outDir)
}
}
//target obfuscate
//target all
target(name:"all", description: "build the whole app") {
depends(jar)
}
setDefaultTarget(all)
From the above script, you can see how easy to write gant build script.
This is only the basic implementation, I am going to post more Gant based script in future.
In future I am going to consider:
1. How to integrate with ANT script;
2. How import multiple Gant script file.
Sunday, September 5, 2010
Be careful to use "Class.forName()" in J2ME
A couple weeks ago, I made another mistake: I tried to use Class.forName() method to solve the multiple platform issue, but unfortunately it did not work on the actual devices due to the issue caused by the obfuscation. This is my another blind spot, because of my ignorance of J2ME obfuscation.
Scenario
I need to provide an API to support multiple mobile platform, for example: Nokia, Blackberry, and simulator, etc.
What I implement is pretty easy:
Here I use a factory pattern to support multiple platform, no need to use preprocess, sound pretty simple, right?
But I found the above solution only works on BlackBerry platform, on other J2ME platform, the application will throw the ClassNotFound Exception.
The reason of failure
The problem is in obfuscation phase, we usually use Proguard to do preverification and obfuscation for the J2ME application. The proguard will remove the unused class file. (for detail please check this link ) In my solution above use class.forName() by passing different string values, which is not recognized in Proguard. For example: in Nokia platform, the NokiaService.class is used, but Proguard did not find the NokiaService.class is explicitly reference in the java code, so it think it is unused class file, then remove it from the final package. Then it cause the ClassNotFoundException.If you don't use obfuscation, the application works, but it is really rarely the commercial application does not have obfuscated.
But why it works on BlackBerry platform?
Because Blackberry is quite different with other J2ME platforms, it requires it own preverification and obfuscation using its own RAPC compiler. And I found that in Blackberry application package it usually keep all the class files in the package, which is different with the Proguard. That is the reason why it works in BlackBerry platform
Solution
I have to rewrite the above code, remove all the Class.forName(), replaced with the explicit method call.
To support multiple platform, I use javaassit to adjust the createService() method for different platform, while you can use pre-process if you want, even I really don't like the J2ME pre-process, because it will bring other more complicated issue in your application.
Conclusion
Class.forName() seems the only reflection that is support in the J2ME platform, but actually it will cause the problem during obfuscation phase, try not to use the Class.forName() in your J2ME application.
Scenario
I need to provide an API to support multiple mobile platform, for example: Nokia, Blackberry, and simulator, etc.
What I implement is pretty easy:
- define an interface: Service
- Implement the Service interface for each mobile platform, for example: NokiaService, BlackBerryService, SimualtorService
- At the build time, inject different Service class file in the package.
- At the run time, the application use the Class.forName() to create the Service objects.
public Service createService(int device)
{
Service service = null;
if( device == NOKIA)
{
service = Class.forName("NokiaService").newInstance();
}
else if( device == BLACKBERRY)
{
service = Class.forName("BlackBerryService").newInstance();
}
else if(device == SIMULATOR)
{
service = Class.forName("SimulatorService").newInstance();
}
else
service = Class.forName("GenericService").newInstance();
return service;
}
Here I use a factory pattern to support multiple platform, no need to use preprocess, sound pretty simple, right?
But I found the above solution only works on BlackBerry platform, on other J2ME platform, the application will throw the ClassNotFound Exception.
The reason of failure
The problem is in obfuscation phase, we usually use Proguard to do preverification and obfuscation for the J2ME application. The proguard will remove the unused class file. (for detail please check this link ) In my solution above use class.forName() by passing different string values, which is not recognized in Proguard. For example: in Nokia platform, the NokiaService.class is used, but Proguard did not find the NokiaService.class is explicitly reference in the java code, so it think it is unused class file, then remove it from the final package. Then it cause the ClassNotFoundException.If you don't use obfuscation, the application works, but it is really rarely the commercial application does not have obfuscated.
But why it works on BlackBerry platform?
Because Blackberry is quite different with other J2ME platforms, it requires it own preverification and obfuscation using its own RAPC compiler. And I found that in Blackberry application package it usually keep all the class files in the package, which is different with the Proguard. That is the reason why it works in BlackBerry platform
Solution
I have to rewrite the above code, remove all the Class.forName(), replaced with the explicit method call.
To support multiple platform, I use javaassit to adjust the createService() method for different platform, while you can use pre-process if you want, even I really don't like the J2ME pre-process, because it will bring other more complicated issue in your application.
Conclusion
Class.forName() seems the only reflection that is support in the J2ME platform, but actually it will cause the problem during obfuscation phase, try not to use the Class.forName() in your J2ME application.
Tuesday, January 26, 2010
My Vision of the future mobile platform framework
Develop a mobile application is painful, develop a portable mobile application is really hard. I've been a mobile developer for many years, and I am struggling many years to make them portable to different platforms. To deal with fragmentation, which is the nature of mobile platform, my vision of the future mobile platform framework would be:
Support multiple platforms
support J2ME, iPhone, android, blackberry, Windows Mobile, etc. One solution supports multiple platform, which will makes our life much easier. I hope new new framework will provide a more abstraction layer, then developer can only write one piece of code can support all.
Separation of concerns
- Separate platform independent logic from platform specific logic
- Separate application logic from specific user interface
The platform specific logic should be encapsulated as component modules, and developer should not care more about their details. Think about the IC and drivers, our mobile application is like a computer mother board which plug different cards and installing different drivers.
The concept of separation of concern reminds me of how GIS works, GIS map is composed of maps in different layer, each layer map focuses on a specific concern, same as the mobile application, the mobile app will be composed of different layers, UI layer, business logic layer, model layer, etc. And each layer can be easily modified and plug-in. Then graphic designer can focus UI, generate the rendering logic; BA focuses on business rules, generate business logic, then developer integrate them all into one application, and each layer can be easily changed and upgraded.
Easy to customization
The mobile framework should takes the advantage of different platforms technologies. we should not do the way of common denominator, like J2ME MIDP widget, which is a bad example.
Open and easy to integrate with other libraries
The new mobile platform should be open to other framework or library, it should be easily to integrate with other libraries. for example, developer can integrate different UI libray easily, like LWUIT, SVG, oepnGL, etc. and the mobile platform does not want to reinvent the wheels, it focuses on integration.
Follow agile
The mobile framework should be agile, which means
- support TDD, provide a mobile unit test framework or support 3rd party test framework
- Encourage short feedback, the mobile framework provides powerful simulator which can simulate different platforms, developer can easily to know what is going on for his application, and it is also a good demo and presentation to our costumer, the simulator can be run inside the browser so that it is a good demo for end users.
- provide build and deploy automation, since different platform has different SDK and build tools, manage them is a nightmare, having a build automation tool will greatly improve the developer's productivity and speed up the application development cycle.
Several possible technical paths:
- DSL/Code generation
Define a mobile Domain Specific Language, then generate the native source code for different platform. we can use Ruby or ANTLR. I like the idea of code generation, because it can meet the needs of different platform, and can easily to implement the AOP
- Use web based script languages
Using html, xml, CSS, java script, then render in the browser or using parser to generate the native source code. This is also a good concept, actually there are already have several open source project doing like this, for example PhoneGap,but what I really worry about are: 1) How to address the fragmentation for each platform; 2) to solve the question 1, may leads to common denominator issue. For this reason, I really doubt the JavaFX Mobile framework, because there is no way to handle the fragmentation issue in script language level.
I hope in the near future, I can do something for the new mobile platform. I have a dream, in future: UI designer, BA, developer and QA will share the same framework, each works on his own part, then developer integrates them by pressing a button, then generate mobile applications for different platforms, hope this won't take long.
Support multiple platforms
support J2ME, iPhone, android, blackberry, Windows Mobile, etc. One solution supports multiple platform, which will makes our life much easier. I hope new new framework will provide a more abstraction layer, then developer can only write one piece of code can support all.
Separation of concerns
- Separate platform independent logic from platform specific logic
- Separate application logic from specific user interface
The platform specific logic should be encapsulated as component modules, and developer should not care more about their details. Think about the IC and drivers, our mobile application is like a computer mother board which plug different cards and installing different drivers.
The concept of separation of concern reminds me of how GIS works, GIS map is composed of maps in different layer, each layer map focuses on a specific concern, same as the mobile application, the mobile app will be composed of different layers, UI layer, business logic layer, model layer, etc. And each layer can be easily modified and plug-in. Then graphic designer can focus UI, generate the rendering logic; BA focuses on business rules, generate business logic, then developer integrate them all into one application, and each layer can be easily changed and upgraded.
Easy to customization
The mobile framework should takes the advantage of different platforms technologies. we should not do the way of common denominator, like J2ME MIDP widget, which is a bad example.
Open and easy to integrate with other libraries
The new mobile platform should be open to other framework or library, it should be easily to integrate with other libraries. for example, developer can integrate different UI libray easily, like LWUIT, SVG, oepnGL, etc. and the mobile platform does not want to reinvent the wheels, it focuses on integration.
Follow agile
The mobile framework should be agile, which means
- support TDD, provide a mobile unit test framework or support 3rd party test framework
- Encourage short feedback, the mobile framework provides powerful simulator which can simulate different platforms, developer can easily to know what is going on for his application, and it is also a good demo and presentation to our costumer, the simulator can be run inside the browser so that it is a good demo for end users.
- provide build and deploy automation, since different platform has different SDK and build tools, manage them is a nightmare, having a build automation tool will greatly improve the developer's productivity and speed up the application development cycle.
Several possible technical paths:
- DSL/Code generation
Define a mobile Domain Specific Language, then generate the native source code for different platform. we can use Ruby or ANTLR. I like the idea of code generation, because it can meet the needs of different platform, and can easily to implement the AOP
- Use web based script languages
Using html, xml, CSS, java script, then render in the browser or using parser to generate the native source code. This is also a good concept, actually there are already have several open source project doing like this, for example PhoneGap,but what I really worry about are: 1) How to address the fragmentation for each platform; 2) to solve the question 1, may leads to common denominator issue. For this reason, I really doubt the JavaFX Mobile framework, because there is no way to handle the fragmentation issue in script language level.
I hope in the near future, I can do something for the new mobile platform. I have a dream, in future: UI designer, BA, developer and QA will share the same framework, each works on his own part, then developer integrates them by pressing a button, then generate mobile applications for different platforms, hope this won't take long.
Thursday, January 21, 2010
How to add a J2ME 3rd party library into your NetBeans project
Scenario
You need to port our J2ME application to a specific platform, either Nokia, Samsung or LG, etc. You have to use OEM's specific API to implement a feature, but that special API is not included J2ME standard library, nor included in the OEM's J2ME SDK. You got an ZIP or jar file of the API library, but mostly it they are just stub classes, the only real implementations are inside the actual devices. What you need to do is adding the library in your project class path, but without including them into the J2ME jar file.
Solution
In NetBeans IDE, You can add the libray of zip/jar file in your J2ME project without including in the packaged jar file. Here are the steps:
You need to port our J2ME application to a specific platform, either Nokia, Samsung or LG, etc. You have to use OEM's specific API to implement a feature, but that special API is not included J2ME standard library, nor included in the OEM's J2ME SDK. You got an ZIP or jar file of the API library, but mostly it they are just stub classes, the only real implementations are inside the actual devices. What you need to do is adding the library in your project class path, but without including them into the J2ME jar file.
Solution
In NetBeans IDE, You can add the libray of zip/jar file in your J2ME project without including in the packaged jar file. Here are the steps:
- Select your project, right click mouse, choose "Properties"
- Select Build - Libraries & Resources, click button "Add Jar/Zip ...", then select the libray file you want to add, press "Open"
- You will see the library file is included the file/folder list, pleases make sure uncheck the "Package" checkbox, this is the most important step, it will tell IDE don't include this jar/zip file into your J2ME jar file, or IDE will not build successfully, because it can not find dependencies packages for the libraries. The screen shot is attached at the end of this article.
- Select OK, and build your J2ME application
Java ME SDK 3.0 review
Last week I spent some time on Java ME SDK 3.0. One of my application need to support both landscape mode and portrait mode, currently J2ME wireless toolkit does not support the feature of changing the screen orientation, I heard that Sun's new JavaME SDK V3.0 emulator support changing the screen orientation, so I installed it and hope it will help my work. but unfortunately I feel disappointed.
Issue of integration with NetBeans IDE
After installing it successfully on my windows machine, I tried to add the SDK into My NetBeans 6.1 IDE, and then later I realize that the all the tools and Prefrence setting of the SDK 3.0 are disabled in my NetBeans IDE. which means you can not profile, clear database, change emulator settings inside the NetBeans IDE.
At first I thought maybe due to my NetBeans version is old, so I installed the Netbeans 6.8, which integrates the Java ME SDK 3.0, but I found the same thing; and I also tried the NetBeans 6.5.1, it is still not working. I also found this thread in a forum about the same issue I found in NetBeans 6.7. I don't know when Sun will fix this issue, but I do know that if this issue is not fixed, then few developer will use the new SDK, since so many mobile developers are tied with the NetBeans IDE.
Lack of the options to launch the emulator
For the emulator, I need a scenario that my application launched in a landscape mode, but I did not find there is any setting in the SDK allow you to do that, it always start as portrait mode.While Nokia S60 3rd SDK already supports this feature. Sun should provide this feature both in GUI menu settings and command line.
Failed to debug
I tried to debug my application by setting a break point using the SDK 3.0,I tried twice, but no luck.
No document to describe how to customize the emulator
Compare to WTK 2.5.x, the SDK 3 changed a lot for the emulator file structures, I realize it becomes much more complicated than before. For WTK 2.5.x, it is really easy to customize the emulator, I now how to change screen size, how to enable touch screen; but for SDK 3, I don't where I can start,I hope Sun could provide an official document to describe the architecure of the new emulator. I found this article about customizing the emulator in SDK 3 in Java ME SDK team blog, it might be useful.
Based on the reasons of above, I don't think the current version of the JavaME SDK can help me for my application development, so I have to change back to WTK 2.5, and use Nokia's S60 emulator, even if it is slow,but at least it works. It seems Sun has a long way to improve its new mobile SDK.
This artcile is based on windows version, I haven't touch the Mac version and Linux version yet.
Related links:
Issue of integration with NetBeans IDE
After installing it successfully on my windows machine, I tried to add the SDK into My NetBeans 6.1 IDE, and then later I realize that the all the tools and Prefrence setting of the SDK 3.0 are disabled in my NetBeans IDE. which means you can not profile, clear database, change emulator settings inside the NetBeans IDE.
At first I thought maybe due to my NetBeans version is old, so I installed the Netbeans 6.8, which integrates the Java ME SDK 3.0, but I found the same thing; and I also tried the NetBeans 6.5.1, it is still not working. I also found this thread in a forum about the same issue I found in NetBeans 6.7. I don't know when Sun will fix this issue, but I do know that if this issue is not fixed, then few developer will use the new SDK, since so many mobile developers are tied with the NetBeans IDE.
Lack of the options to launch the emulator
For the emulator, I need a scenario that my application launched in a landscape mode, but I did not find there is any setting in the SDK allow you to do that, it always start as portrait mode.While Nokia S60 3rd SDK already supports this feature. Sun should provide this feature both in GUI menu settings and command line.
Failed to debug
I tried to debug my application by setting a break point using the SDK 3.0,I tried twice, but no luck.
No document to describe how to customize the emulator
Compare to WTK 2.5.x, the SDK 3 changed a lot for the emulator file structures, I realize it becomes much more complicated than before. For WTK 2.5.x, it is really easy to customize the emulator, I now how to change screen size, how to enable touch screen; but for SDK 3, I don't where I can start,I hope Sun could provide an official document to describe the architecure of the new emulator. I found this article about customizing the emulator in SDK 3 in Java ME SDK team blog, it might be useful.
Based on the reasons of above, I don't think the current version of the JavaME SDK can help me for my application development, so I have to change back to WTK 2.5, and use Nokia's S60 emulator, even if it is slow,but at least it works. It seems Sun has a long way to improve its new mobile SDK.
This artcile is based on windows version, I haven't touch the Mac version and Linux version yet.
Related links:
Sunday, January 10, 2010
Customize Your J2ME Emulator
Why do we need to customize J2ME emulator ?
As a J2ME mobile developer, you have to port application to different devices, while the J2ME default emulator only provide 4 different profiles, which can not meet our needs, and also some platforms like BlackBerry, Nokia S60 etc, the J2ME emulator they provided are really slow to launch, which is really inconvenient. If you can customize the emulator to support the device you are porting, which will improve your developing productivity.
Where are the emulator device profiles located?
For example, if you installed wireless toolkit 2.5 in c:\WTK25, then the device folder is:
C:\WTK25\wtklib\devices
The mobility package is included in the NetBeans 6.5 or later version, the wireless toolkit folder is like this:
C:\Program Files\NetBeans 6.x\mobility8\Java_ME_platform_SDK_x.x
Create a new emulator device profile
I like to choose Sun Wireless Toolkit 2.5, because its Qwerty Device emulator looks better. For example, if I want to create a device for Black Berry 9000:
1. Copy the entire folder of “QwertyDevice” to a new folder, rename the new folder name to “BlackBerry9000”
2. Go inside the folder, rename the Qwerty.properies file to BlackBerry9000.properties
Enable the touch screen
The touch screen feature is disabled for J2ME default emulators. If you want to enable it, you need to modify the .properties file. In properties file, find following statement:
touch_screen=false
Change false to true will enable the touch screen.
Change the screen size
For example, for BlackBerry 9000, its screen size is 480x320, then go to .prperties file, update the following values:
screenPaintableRegion.width=480
screenPaintableRegion.height=320
and ..
screen.width=480
screen.width=480
screen.height=332
Please note that you need to make sure:
screen.height > screenPaintableRegion.height + screenPaintableRegion.y
In the properties file, screenPaintableRegion.y=11, so the screen.height value is 332.
If you don’t put the correct value, the emulator will throw exception once it is launched.
Make your customization available in NetBeans IDE
Once You finished the customization, you need to update your NetBeans IDE environment:
- Select Tools – Java Platform, choose Sun wireless toolkit 2.5, click Refresh button
- You will see the device names you added in the device folder
Conclusion
You can easily customize J2ME emulator by modifying the .properties file, even it is really simple, it can improve your productivity considerably.
Further steps
This article is only focused on Wireless Toolkit 2.5.x , Sun released the new wireless toolkit 3.0, the device emulators are changed a lot. I need to do more investigation on 3.0 emulator in future..
Tuesday, December 22, 2009
The Evil of Java ME preprocess
Developing Java ME application is painful, because of Java ME's own fragmentation in nature. Java Mobile developers have to deal with different devices, and each device or platform has different implementation. Writing a portable application to support different devices is really hard, and some time it is really a torture.
To solve the fragment issue, NetBeans IDE provides a solution - Preprocess, it is similar to pre-compile in C and C++. Actually preprocess in NetBeans is quite perfect, quite powerful. When I first use it, I feel it is so powerful, so easy to use. Several years later, when I look at our code, which have #if, #else every where, I just feel the code are so ugly, seems to return to the c code era. I really feel preprocess is an evil! Following are my reasons.
Violate OO Principles
Since preprocess is so easy to use, just add something like comments, it gives developer a backdoor to break OO principles easily and brutally. It is so easy to hack the program, so there is no need to care about abstraction, no need to care about design patterns. And the problem is my colleagues like to overuse preprocess, mostly even use preprocess for constants! I saw so many code full of magic numbers, and so many preprocess directive scattered every where to change those values.
It also violates OCP principle, OCP means "Open for extension, closed for modification". But preprocess is modifying the existing source code when you add new preprocess configuration. It is quite common that the change works for the new configuration, but will break the old ones.
I found if we use more design patterns deliberately, like strategy pattern, abstract factory pattern etc, and use constant class instead of magic number directly, we can minimize the preprocess greatly.
Hard to Refactor
Refactoring the preprocessed code is really difficult, for example when you rename a method name or variable name, you can only refactor the current active preprocessed code, because others are commented out. If in your project need 4 different devices type, so every time when you refactor, you have to test 4 times to make sure the change is working. It is really painful!
Hard to Reuse
If you want to reuse a class or a component to another project, but when you see so many preprocess scattered in the code, probably you will not use it. Either you have to add all those preprocess into your new project which might does not make any sense, or you have to manually remove them, which is even harder to test.
Hard to understand
When you read the code has so many #if #else statement, it is ugly to read, more difficult to understand, code is not clean.
Hard to maintain
When you want to port the current application to a new device, you have to understand how the previous preprocess work; when you want to fix a bug for specific device, you have to make sure it won't break the others. Manage so many preprocess configuration is really painful. So preprocess is good for short-term, but really painful for long term.
IDE Lock-in
Because of widely use of preprocess, our projects are locked in NetBeans IDE, we can not use other IDE, like Eclipse. For my experience, NetBeans IDE has some problems for example:
Conclusions
Java ME preprocess is easy for short-term, but painful for long term, it solves one issue by generating more issues in future; it delay your pain in a short term, but you will be more painful for long term.
Suggestions for anti-preprocess
To solve the fragment issue, NetBeans IDE provides a solution - Preprocess, it is similar to pre-compile in C and C++. Actually preprocess in NetBeans is quite perfect, quite powerful. When I first use it, I feel it is so powerful, so easy to use. Several years later, when I look at our code, which have #if, #else every where, I just feel the code are so ugly, seems to return to the c code era. I really feel preprocess is an evil! Following are my reasons.
Violate OO Principles
Since preprocess is so easy to use, just add something like comments, it gives developer a backdoor to break OO principles easily and brutally. It is so easy to hack the program, so there is no need to care about abstraction, no need to care about design patterns. And the problem is my colleagues like to overuse preprocess, mostly even use preprocess for constants! I saw so many code full of magic numbers, and so many preprocess directive scattered every where to change those values.
It also violates OCP principle, OCP means "Open for extension, closed for modification". But preprocess is modifying the existing source code when you add new preprocess configuration. It is quite common that the change works for the new configuration, but will break the old ones.
I found if we use more design patterns deliberately, like strategy pattern, abstract factory pattern etc, and use constant class instead of magic number directly, we can minimize the preprocess greatly.
Hard to Refactor
Refactoring the preprocessed code is really difficult, for example when you rename a method name or variable name, you can only refactor the current active preprocessed code, because others are commented out. If in your project need 4 different devices type, so every time when you refactor, you have to test 4 times to make sure the change is working. It is really painful!
Hard to Reuse
If you want to reuse a class or a component to another project, but when you see so many preprocess scattered in the code, probably you will not use it. Either you have to add all those preprocess into your new project which might does not make any sense, or you have to manually remove them, which is even harder to test.
Hard to understand
When you read the code has so many #if #else statement, it is ugly to read, more difficult to understand, code is not clean.
Hard to maintain
When you want to port the current application to a new device, you have to understand how the previous preprocess work; when you want to fix a bug for specific device, you have to make sure it won't break the others. Manage so many preprocess configuration is really painful. So preprocess is good for short-term, but really painful for long term.
IDE Lock-in
Because of widely use of preprocess, our projects are locked in NetBeans IDE, we can not use other IDE, like Eclipse. For my experience, NetBeans IDE has some problems for example:
- you can't use different source code folder for different configuration, you can easily do that in Eclipse MTJ;
- Build automation is difficult, I don't understand the NetBeans generated build xml, I have to build inside the IDE, I never tried to run build file outside the IDE, and I don't know how create a customized ant build file, I think it is really hard;
- Difficult for team work. NetBeans project use absolute path, and private project properties. Which means it works in your computer, but might not work in your co-workers environment, or you have to take a while to set up the environment correctly.
Conclusions
Java ME preprocess is easy for short-term, but painful for long term, it solves one issue by generating more issues in future; it delay your pain in a short term, but you will be more painful for long term.
Suggestions for anti-preprocess
- Try to minimize the use of preprocess, we can't 100% percent remove the preprocess, but be ware to use it, only use it when no other options.
- Have the discipline of writing clean code, readable code and maintainable code, before you use preprocess, think it carefully, if there is better solution;
- Use OO design patterns, for example strategy pattern and abstract factory can remove lots of preprocess;
- Try to use configuration file instead of preprocess, if we put the constant value into resource property file instead of hardcoded using preprocess, we can also make the code cleaner;
- Centralize the preprocess, if you have to use preprocess, don't allow them scattering every where in the code, try to put those preprocess specific logic together, even better to put them into one class, it would be easier to read, understand and maintain;
- DSL/Meta programming, if fragmentation is unavoidable, why not use code generation technology to generate source code for each specific platform for us? This needs compiler skills and Domain Specific Language knowledge, it is really an interesting topic.
Subscribe to:
Posts (Atom)