On top of Java classes generated by Relaxer, programmers have to add their own programs, which provide application-specific behaviours. In the HelloWorld example, the application program is external to the generated Java classes, and an XML document was handled as merely passive data from the application program.
This approach certainly works for simple programs. But more complicated programs require more advanced techniques for combining programs and data.
To demonstrate more advanced techniques, we use a RELAX model list[menu.rlx] as an example.
<?xml version="1.0"?> <!DOCTYPE module SYSTEM "relaxCore.dtd"> <module moduleVersion="1.0"> <interface> <export label="menubar"/> </interface> <elementRule label="menubar" role="menubar"> <ref label="menu" occurs="*"/> </elementRule> <tag name="menubar"/> <elementRule label="menu" role="menu"> <sequence> <ref label="title"/> <choice occurs="*"> <ref label="item"/> <ref label="menu"/> </choice> </sequence> </elementRule> <tag name="menu"/> <elementRule label="title" role="title" type="string"/> <tag name="title"/> <elementRule label="item" role="item" type="string"/> <tag name="item"> <attribute name="className" type="NMTOKEN"/> <attribute name="method" type="NMTOKEN"/> </tag> </module>
The simplest approach to combine generated Java classes and user programs is to handle the generated classes as passive data from user programs.
The HelloWorld explained above uses this approach.
Figure[Object tree]is the class generated from list[menu.rlx] without any options.
Use of generated Java classes as merely passive data does not take full advantage of object-oriented programming, since programs (written by programmers) and data (created by Relaxer) are separated.
A more powerful approach is to combine user programs and Relaxer-generated classes.
To support this approach, Relaxer provides the "factory" option.
C:\tmp>relaxer -factory sample.rlx
The "factory" option is designed on the basis of design patterns.
Collaboration icons in figure[Example of factory] represent three patterns as below:
The "AbstractFactory" pattern and the "FactoryMethod" pattern were introduced in the book "Design Patterns". They are patterns for creating objects. In this figure, these patterns are used to create instances of programmer-defined classes, namely MyMenubar
,MyMenu
, and MyItem
, rather than Relaxer-generated classes, namely Menubar
, Menu
, and Item
.
The "GenerationGap" pattern is a pattern for automatic program generation introduced by the book "Pattern Hatching".
It is not a good idea for programmers to modify Relaxer-generated classes so as to embed their source codes. When the RELAX module is later revised, Java classes have to be generated again, and thus embedded programs will be lost.
Inheritance provide a nice solution: programmers creates subclasses of Relaxer-generated classes and write their own programs as methods of these subclasses.
In other words, even if the class generated by Relaxer is modified, programmers can often use its subclasses without any changes and can further use new features of the re-generated class.
Since an XML document is inherently hierarchical, classes generated by Relaxer naturally form hierarchical structures.
The design pattern "composite" (shown in "Design Patterns") is a mechanism for handling nodes in tree structures in an unified manner.
C:\tmp>relaxer -composite sample.rlx
Classes generated by the composite option is shown in figure[Example of composite]. Menubar
,Menu
and Item
implements
a common interface IRNode
. Access to superior or subordinate nodes can be implemented by providing codes required by this interface.
The design pattern "Visitor" (shown in "Design Patterns") is extremely useful for applications that traverse tree structures.
C:\tmp>relaxer -visitor sample.rlx
Classes generated with the visitor option is shown in figure[Example of visitor].
On top of classes generated with the composite mechanism, three classes, namely IRVisitable
, IRVisitor
and RVisitorBase
, are created as well. Moreover, although it is not shown this figure, VRVisitor
is created as a utility class for visitor operations.
List list[IRVisitor.java] shows IRVisitor
interface
, which is generated as a visitor interface. Automatic generation of such visitor interfaces is very helpful to programmers, since visitor interfaces are mandatory and routine.
Relaxer generates not only IRVisitor
but also some other programs automatically. For each class in the tree sturture, Relaxer generates two methods, namely "enter" and "leave", (declared by IRVisitable
), which are used by visitors. Furthermore, Relaxer generates a class URVisitor
and its traversal functions, namely "traverseBreadth" and "traverseDepth".
/** * @version menu.rlx 1.0 (Sun Jun 11 12:58:24 JST 2000) * @author Relaxer 0.9.2b (by ASAMI@Yokohama) */ public interface IRVisitor { /** * Visits this node for enter behavior. * * @param visitor */ void enter(Menubar visitor); /** * Visits this node for leave behavior. * * @param visitor */ void leave(Menubar visitor); /** * Visits this node for enter behavior. * * @param visitor */ void enter(Menu visitor); /** * Visits this node for leave behavior. * * @param visitor */ void leave(Menu visitor); /** * Visits this node for enter behavior. * * @param visitor */ void enter(Item visitor); /** * Visits this node for leave behavior. * * @param visitor */ void leave(Item visitor); /** * Visits this node for enter behavior. * * @param visitor */ void enter(RString visitor); /** * Visits this node for leave behavior. * * @param visitor */ void leave(RString visitor); }
A concrete example of visitor functions will be shown in the section "document oriented application".