Show in Frame No Frame
Up Previous Next Title Page Contents Search

Metamodels
Models
Generators
Framework code

5.4.4 Changes to Support MIDP

Extending the Watch example to support MIDP required surprisingly few changes. In fact, more changes were made because of minor problems noticed in the initial code than because of MIDP.

One such problem was an area that we decided not to support initially, because of the lack of use: how should an alarm react when the clock time is changed. We had built metamodel support for this (alarms have a property to say whether they are dependent on local time: true for an alarm clock, false for a countdown timer), but had left out the implementation in the framework classes as being not worth the effort. “After all, who is likely to lug a PC around to use our watch application’s alarm?” we thought. How short-sighted we were!

Metamodels

No changes were required to the metamodels to support MIDP. In the course of improving the support for alarms in the context of a user changing the time on the watch, it was noticed that the existing metamodel allowed Roll roles to VariableRef objects: i.e. changing the value of a function result or variable from somewhere else. This was corrected with a constraint that Roll could only apply to a Variable (local to this graph), not a VariableRef.

An addition was made to the top-level graph for the included components (framework classes), to allow different framework classes for different ‘Generation target platforms’.

Models

No changes were required to the models to support MIDP. To support the improved alarm handling, we found we had to buffer the clockOffset VariableRef in the Time application, editing the buffered copy and then setting it back into clockOffset when the user exits the edit states. This improves the behavior too: otherwise all alarms would be updated on each Roll up or down of a digit, causing alarms to ring during editing.

Generators

We had made three different implementations of a Java state machine whilst making the original watch, with ideas sketched out for another two. The implementation we went with required the reflection abilities of Java, which unfortunately are not present in MIDP. Hence we moved to a switch case based implementation, using initialized static final variables as labels.

This required an addition to the _Variables generator to generate the new static final variable for each Action and DisplayFn. Similarly, a minor change was made to the _TransitionData generator to generate the variable names rather than a string containing the same text.

The _Actions and _DisplayFn generators were similarly changed to place their body inside a case statement, rather than a similarly named function.

These changes were all largely cosmetic, and only the generation of the initialization values for the static final variables required a little ingenuity, as Java limits these to being integer expressions which do not refer to any other variable – not even another static final. The addition of variables to the generator definition language has since made other, easier, approaches possible.

A larger amount of work was required for the new ‘_create make for MIDP’ generator. MIDP compiles its Java as for other platforms, but it also requires a pre-verify step, and a couple of configuration files naming and providing information about the MIDP suite (Watch family) and the MIDP applications (Watch models) it contains. Normally these configuration files would be written by hand, or filled in to a form, but in principle all the information needed can be obtained from the code (or in this case, the models).

The overly-tight constraints on these configuration files’ formats made generating them with only the MetaEdit+ 3.0 reporting language and DOS batch commands something of a challenge (more recent MetaEdit+ versions make this easy). Having to support several Windows versions, each with different DOS commands and behavior, hardly made the task any easier. In the end it was accomplished with a couple of helper batch files, which generate sequential numbers and report the size of a specified file.

Framework code

The original code was much in need of refactoring, having been the authors’ first Java application, and not really intended to be looked at. First we refactored out the mass of user-interface, control and state machine behavior from the applet into the classes of their own. From this, it was easier to see what had to be done.

The majority of classes were platform independent, requiring only basic Java functionality. The user interface and control APIs are different for MIDP, so a separate WatchCanvas class had to be made for MIDP. Being a second attempt at the same functionality, with more Java experience than before, it was soon noticed that the same solutions could be applied to the WatchCanvas class for applets too. This resulted in smoother updating in the applet, as well as keeping the applet and MIDP versions more visually similar. As a result, some behavior is still duplicated between the two platforms’ versions of that class, but not enough to merit refactoring it out into its own class.

MIDP does not have the Applet class, so our Applet was replaced with a Midlet, the MIDP equivalent. There appears to be no reason why an Applet should not have been used for MIDP: the same functions are present, just with different names. As our generated applet classes subclass from AbstractWatchApplet, our framework subclass of Applet, they work as subclasses of AbstractWatchApplet just fine, even when it is a subclass of Midlet. Thus, no changes were necessary to the generator that generates the applet/midlet for each WatchApplication.

Show in Frame No Frame
Up Previous Next Title Page Contents Search