Monday, July 11, 2011

PAW - Dynamic DEX Class Loading

With PAW developers have the possibility to create dynamic pages using BeanSell scripts.
This is nice because pages can be developed very fast. On the downside BeanShell is not the fastest scripting language on the planet due to its heavy use of Java reflection. This was demonstrated in an earlier blog entry  where BeanShell code is between 10 and 50 times slower than the native equivalent.

One note beforehand:  Dynamic DEX class loading is currently not working on Honeycomb. This is due to a bug in the in the DexClassLaoder. Google has aknowledged the bug. This bug should be fixed in upcoming Honeycomb releases.

PAW now introduces a new directory called webconf/dex wich can contain JAR and APK files in DEX format. On server startup all files which are present in hat directory will be added to a new classloader. This classloader can be retrieved by calling getDexClassloader() on the service object. To make life easier the command useDexClasses() can be used in BeanShell pages.

To  convert an existing JAR file into a DEXed one the following dex command from the Android SDK (normally located in the platform-tools directory) can be used:
./dx --dex --output=output.jar --positions=lines input.jar

Note: In recent versions of the SDK the dx command has been moved to the build-tools/ directory of the SDK.

If you would like to keep the existing classes inside the JAR file, the additional option --keep-classes can be used. With this option the same JAR file can be used on Android or a PC running standard Java.

After the DEXed JAR file has been created it can be copied to the webconf/dex folder of the PAW installation.

Now to use the new classes you can either restart PAW or issue the following  command from the BeanShell Console:
server.props.get("serviceContext").buildDexClassLoader();

If the new classes should be used inside a BeanShell XHTML page the following command has to be executed:
useDexClasses()

That basically tells BeanShell to use the new classloader.

Example

Here is a very simple Java class that sums up two Intergers:
package dextest;

public class Math {
 public static int sum(int i, int j) {
  return i + j;
 }
}

After expopting the class as JAR file it can be converted into DEXed format using the following command (the JAR file dextest.jar is located in the /tmp directory) :
./dx --dex --output=/tmp/dextest_dex.jar --positions=lines dextest.jar

The resulting dextest_dex.jar JAR file is now placed inside the webconf/dex folder and PAW is restarted.

Now we can use the new class within the BeanShell Console like this:
useDexClasses();

import dextest.Math; 

print(Math.sum(1, 3));

No comments:

Post a Comment