Creating a New Module
This document describes how to create a new module, which is essentially a folder containing j2me code that can be used by or independently as, a JavaRosa library. The standard use case for this procedure is to create a module that contains one or more activities, along with the code that they rely on.
This document will currently rely on using Eclipse to create the necessary components. There are many other valid ways to complete these tasks, and they would be welcome additions to the doc.
Creating the directory in SVN
- Go to the SVN Repository Editing perspective
- Expand the code.javarosa.org (or code.dimagi.com/svn/JavaRosa) repository, and expand 'branches/dev' (Or whatever branch you are using
- Right Click on 'dev' and select new->new remote folder
- Ensure that the box underneath "Enter or select the url of parent folder : " is the path to the /dev/ branch (Or the branch you are using), and enter the name of your project. This should be the lowest common namespace in your source (IE: org.javarosa.patient)
- Enter a commit comment by pressing 'next'. Then click Finish.
Creating the basic stub project configuration
- Checkout the project by right clicking on the newly created folder (You may need to refresh first), and hitting 'checkout'.
- On the next dialog, select "Check out as a project configured using the New Project Wizard" and hit 'finish'
- Select 'Java Project', and click next. (Don't select j2me midlet suite, it's more effort)
- Enter your project's name (should be the exact same as the folder name in svn), and click 'next'
- On the libraries page, remove the reference to the JRE library that is provided.
- Click 'Finish'. You may get a warning. Just press 'ok'
Configuring j2me and collecting other project references
- Your new project should only contain a 'src' folder and some dotfiles. Go to the 'navigator' view, and right click on .classpath, and open it with a text editor.
- Add the line <classpathentry kind="con" path="J2MELIB"/>
- Save and close the file.
- Copy and paste the .eclipseme file from one of the other projects (Or if you don't have them, create a new file in the root of your project called '.eclipseme' and put the following text inside of it
<?xml version="1.0" encoding="UTF-8"?> <eclipsemeMetadata jad="" version="1.7.9"> <device group="Sun Java(TM) Wireless Toolkit 2.5.2 for CLDC" name="DefaultColorPhone"/> <signing signProject="false"/> </eclipsemeMetadata>
- Return to the package view. Right click on the project and select build path->configure build path. Make sure you are on the 'Projects' tab.
- Click on 'add', and select all of the projects that your code will depend on. Generally all code will depend on 'org.javarosa.core'.
Including your new code in a building project
The Ant build files that are used to build our projects do not use the .classpath files to find source files. You will have to open the build.xml file manually, and include your project's source under the list of source directories to be included. There should be a comment in the correct place to show you where to add your code.
Be sure to edit the build.xml not only for your own custom application (if you have one), but for the master demo application as well. The build server only compiles the demo app, so if your code is not included there, build errors will not be automatically caught.
Using the IModule Interface to Unify Registration
Many Modules will need to perform a complicated set of registrations before they are capable of being used in a project. The Referral module, for instance, requires adding a bind handler to the XForms parser, registering an RMS Utility, adding a set of property rules, and initializing properties.
In order to allow these modules to be used more or less painlessly, registration code can be placed in an IModule implementing class. The method registerModule will be used to register the necessary elements.
As an example, the code for the Referral Module (which allows forms to have certain questions be marked as triggering a referral to the doctor) looks like
public void registerModule(Context context) {
ReportingBindHandler reportingHandler = new ReportingBindHandler();
XFormParser.registerBindHandler(reportingHandler);
ReferralRMSUtility referralRms = new ReferralRMSUtility(ReferralRMSUtility.getUtilityName());
JavaRosaServiceProvider.instance().getStorageManager().getRMSStorageProvider().
registerRMSUtility(referralRms);
JavaRosaServiceProvider.instance().getPropertyManager().addRules(new ReferralPropertyRules());
PropertyUtils.initializeProperty(ReferralPropertyRules.REFERRALS_ENABLED_PROPERTY,
ReferralPropertyRules.REFERRALS_ENABLED);
}
One the Module class is created, it can be called from an application in a couple of different ways. One method is the straightforward manner of calling the module directly, IE:
new ReferralModule().registerModule(context);
It is worth noting that these modules do not enforce hierarchical dependence at all. IE: If the referral module depends on the RMSStorageModule and XFormsModule being registered first, it will fail out.
Another way that modules can be registered is using dynamic properties. For example, assume that we have a string obtained from a device property called moduleNameList, which is a list of module names separated by commas. We could load the modules dynamically with code similar to
String[] moduleNames = Utils.split(modulesProperty, ',', 0);
for (int i = 0; i < moduleNames.length; ++i) {
try {
((IModule) Class.forName(moduleNames[i]).newInstance()).registerModule(context);
} catch (InstantiationException e) {
throw new ModuleUnavailableException(e.getMessage());
} catch (IllegalAccessException e) {
throw new ModuleUnavailableException(e.getMessage());
} catch (ClassNotFoundException e) {
throw new ModuleUnavailableException(e.getMessage());
}
}
It's important to note that on j2me in order to use this kind of dynamic reference, the module class names will need to not be obfuscated. This can be accomplished by adding a line to the obfuscator section of the ant build file. Under the obfuscator task, a parameter should be added of the format
<parameter name="keep , allowshrinking" value="class org.javarosa.referral.ReferralModule" />
IMPORTANT NOTE: The ant target has a known problem where you can't add more than one of these lines which have hte same parameter name, as such the amount of whitespace before and after the comma should be different for each name.
