AVX

Applications via XML

System Architecture Specification

Version:

1.1

Date:

11th January 2002

Compiled by:

Kevin Osborne

For:

sourceforge


Revision History / Version Control

Version:

Date:

Comments:

1.0

26th September 2001

Initial document creation

1.1

11th January 2002

Working draft release. Further implementation details still to be documented.

Applications via XML - Theory

Premise: The concept behind the 'Applications via XML' architecture is to allow applications to become more flexible in the way they go about performing their duties. The essential idea is to avoid 'hard-coding' instructions into an applications' source code and to instead 'farm' the instructions out to XML.

Strategy: The premise above is split into three areas: UserInterface, Actions and Data, in a similar manner to the Model-View-Controller (MVC) architecture used throughout the Java programming language.

For each area, an XML Schema is developed with the aim of being able to encapsulate the operations and state associated with that area. A matching set of class libraries is then developed to represent the XML in as transparent a manner as possible.

The goal is to be able to have 100% of the application logic, data and functionality specified in XML and to simply create 'holder' classes created via the XML Schema framework associated with a particular area.

In this way the 'core' set of class libraries should require very little ongoing maintenance programming as all changes can be implemented via a new set of XML instance documents that define the changed behaviour of the updated application.

Also, components can be added 'on-the-fly' simply by reading an alternate XML file to the one originally specified and replacing the old components in the application. This is especially useful for user interfaces where custom designs can be implemented in XML and loaded at random. As there is no 'hard' code present in the application source code, these 'custom' interfaces can be composed of entirely different components from the original.

Design: A class object hierarchy is developed for each section of the library allocated to a particular application functionality area (UserInterface, Actions or Data).

The implementation of the 'holders' for the UserInterface and Actions sections are relatively static as they have a limited set of components to be dealt with. These include menus, buttons and graphical controls for the UserInterface, and method calls, execution sequences and object creation/retrieval for Actions.

The Data section will change fairly heavily from implementation to implementation. The responsibility is on the Data classes to provide their own inspectors/modifiers, constraint operations, event response methods etc. In this way the XML defined UserInterface components can call Action components in response to user events. These then call Data operations that are appropriate to the user event that has occurred. These Data components would then call Action components to refresh the UserInterface components to reflect the changed state of the application dataset.

Obviously a large number user interface components would need to be specific to particular applications/datasets. As long as the component 'fits' inside the user interface holders (which are designed to accommodate all possible components) then there is no problem. The data is loaded via XML, an appropriate graphical component is populated with the data via an XML linkage call, and any actions on the graphical component are messaged back and forth to the data via an XML defined action instruction set.

To stress the point, where possible data classes should also be packaged with their own graphical component classes. The idea is that the data 'knows how to display itself'. The data and associated user interface classes would have action-based methods that are invoked via XML defined method calls. This technique involves less XML generation as it would be reasonable to allow 'hard-coding' on application logic to occur in data classes, which naturally have the constraints of various data types and also the relationship between various data objects and the 'real-world' entities they reflect.

The linkages between the three sections are defined via XML as is the majority (hopefully) of the content of each object in the user-to-data chain. If a component in the sequence is to be updated at a later date the XML linkages can be modified to bypass the old component and to include the new.

Implementation: The first step is to write XML Schemas that define all possible options in state and operation for each of the application functionality areas.

These Schemas should be extensible, standards compliant and should have the aim of being able to define 100% of the application instructions and data that would normally have to be 'hard-coded' into the source code.

There are a number of common code components that can be extracted out of this architecture and developed as a core API. The first is the XML parsing code, and its ability to instantiate and populate arbitrary object data structures with XML defined data. The second is 'management' code which co-ordinates instantiation, access and messaging between the three areas. The third is common event components shared by all three areas, but especially between Actions and the UserInterface.

Finally, for all code components that are specific to a particular application, the matching class hierarchy must be developed and XML instance documents written, using the above schemas, to reference these classes.

These application specific classes can then be bundled with the core application framework code and XML documents that instruct the core API to load and manipulate the application specific components in the manner desired.

Applications via XML - Practice

Below is the specification of the architecture outlined above, as implemented in a set of Java class libraries.

XML Parsing

The parsing of XML instance documents occurs via the ObjectMapper class. In its most basic form this class takes an XML schema, an instance document and an object that will have the XML encountered data objects appended to it.

Please note that the schema is not required to be a valid schema for the XML instance document; ObjectMapper is a parser, not a validator, it simply identifies elements as defined by a schema and attempts to instantiate them.

ObjectMapper maps the elements outlined in the schema via the SchemaMapper class. The contents of the schema are encountered by referencing a static MappedObject schema definition object defined by SchemaMapper.

The MappedObject class defines the name, type and hierarchy of elements to be searched for. For an XML schema document itself this MappedObject is fixed by the constraints of the W3C XML Schema Recommendation definition available at <http://www.w3.org/TR/xmlschema-0/>. A schema can only contain a fixed element/attribute set (eg complexType, choice, element, import etc) and that element set is defined in SchemaMapper.

SchemaMapper then behaves similarly to ObjectMapper by using the static MappedObject schema definition as above with the XML schema itself as the equivalent of an XML instance document, and the SchemaMapper object itself as the object which will have the result object appended to it. In this case a further MappedObject is generated which mimics the content of the XML schema file.

ObjectMapper then uses the MappedObject that represents the schema to parse the XML instance file. This is achieved via the SaxMapper class (which is also used by SchemaMapper). SaxMapper is a derived class that extends a SAX DefaultHandler. Its purpose it to raise events whenever XML elements are encountered.

SaxMapper will track elements defined in the MappedObject and ignore those that are not expected. In this way only certain sections of the document can be loaded; simply define a schema that only includes the elements desired.

SaxMapper uses an open source SAX2 (Simple API for XML Parsing) parser implementation of the Java API for XML Parsing (JAXP) specification called Crimson, available from <http://xml.apache.org/>. Crimson is used for three reasons: it's small (~200KB), it has low resource usage and it's free. It also mimics the usage pattern of the heavyweight Xerces (address as above) XML validator/parser (~1.2MB) meaning that the code used for parsing will work seamlessly for both parsers (and for any other parsers which implement JAXP, which is a core API of JDK1.3. Note that Crimson is bundled with JDK1.4).

The usage of a SAX parser over a Document Object Model (DOM) parser is a firstly a question of resource usage. The DOM is an in-memory object model that can become very unwieldy for large XML documents. In fact most DOM parsers use SAX internally. SAX simply starts at the beginning of the document and works to the end, raising events for every XML element encountered. Secondly, the traversal of the resulting DOM tree would be required; this would have to be hard-coded, and would not allow the on-the-fly hierarchies required by the different open-ended application object systems we wish to allow via this architecture.

The core requirement of this architecture is exemplified by the 'add' method in ObjectMapper. This method does all the 'work' as far as XML to Java parsing in concerned. The main parent object passed to ObjectMapper must have a public 'add{root_element}' method, where {root_element} is the name of the XML instance document's root element. ObjectMapper will instantiate a Java object corresponding to the root element and then pass it as a parameter to the above method call. In this way you have access to the sum total of the content you have loaded via XML.

Notice the line 'instantiate a Java object corresponding to the root element'. This in fact happens for each and every XML element defined by the MappedObject that is encountered by ObjectMapper in it's travels through the XML document. When ObjectMapper encounters an element, it will attempt to instantiate it as a Java object via reflection. Any attributes in the element will be used as arguments for the constructor parameters.

There are a number of ways ObjectMapper can approach the identification of the Java class that maps to a given XML element:

Firstly it can treat the XML element as all it needs; it will call Class.forName({element}). For this to work, {element} needs to be the fully qualified class name, eg com.foo.FooBar. As long as that class is on the classpath, and the constructor parameters match, it will be instantiated. Its not the most elegant of XML element naming systems, but it works.

Secondly, the XML schema can define a 'type' for the element encountered. Again this must be a fully qualified class name:

<xsd:element name="foo" type="com.foo.Foobar"/>

In this case a 'foo' element will be instantiated as a 'com.foo.FooBar' object.

Thirdly, a package name can be passed to ObjectMapper. This will automatically be pre-pended to all elements encountered that do not have a 'type' declaration before construction is attempted. Eg call ObjectMapper with packageName = "com.foo."; when a <Foo> element (that had no type declaration in the schema) is located, 'com.foo.Foo' will be constructed. Note that the trailing period is required for passed package name strings.

Lastly, element names can be capitalized in conjunction with package names. In this case a <fooBar> (notice the lower case f) would become a com.foo.FooBar object.

As each subsequent element is instantiated, it is not appended to the main object passed to ObjectMapper; this only occurs for the root element, and any siblings it may have (for documents with multiple root elements). The first nested element inside the root element will be appended (via an add{element_name} call) to the object previously created to represent the root element, and so on for all nested elements within the XML document element tree. In this way the main object is not required to have 'add' methods for every element in the XML document and also the all-important object hierarchy in adhered to. Note that an object is not appended to its parent object until it is a leaf element; i.e. all it's sub-elements have been appended to it, or it had no sub-elements to begin with.

For elements that enclose text strings, a special convention is required. eg. For the XML

<person>

<name> John Doe </name>

</person>

The following must be present in the Java code

1. The class representing 'person' must have an add{name_class} (eg. from the example above: Person.addName(Name name))

2. 'name_class' as in 1 above will be the class representing the 'name' element above. This class must have a method of exactly the same signature as above; i.e add{name_class} (eg. name.addName (String name)).

In this way any text elements interspersed with XML sub-elements below a given tag will be recognised by the parser and added to the current node via an 'add' method of the same name as the current class which takes a text string as its only parameter. Note that only text 'String' objects are supported.

Management Code

The main management class in this Java implementation of Applications via XML is ApplicationManager. This is the central focus point of the entire system, and to use AVX either the loadApplication() or registerApplication() methods must be invoked before any other AVX class method calls.

loadApplication takes an application name and an application object as it's two parameters. The name has '.log' appended to it to create the application log file (it has no other use; it is still required for applets, even though they must report to the console). The application object is very important; this should be the main extended JApplet/JFrame calling class.

For further detail please refer to the relevant class documentation.

Appendices

Appendix I - Required Properties

The AVX package requires a number of files and directory structures being present in the applications' home directory, the first of which being the 'application.properties' file in the application root directory. This properties file is expected to have name=value for the following entries, listed with their purpose:

Application.properties - required entries

NOTE: All properties files should be specified minus their extension, which must be '.properties'.

Property Name

Example

Purpose

UserInterface.Directory

UserInterface.Directory=userinterface

Defines the directory relative to the application root where user interface data is to be found

UserInterface.Preference

UserInterface.Preference=custom_userinterface

The name of the currently preferred user interface properties file. Both this file and the preference file must be specified relative to the directory as set above.

UserIn terface.Default

UserInterface.Default=default_userinterface

The default user interface properties file which will be loaded if the preference file is not set or fails to load successfully.

Actions.Directory

Actions.Directory=actions

Defines the directory relative to the application root where application action data is to be found

Actions.Preference

Actions.Preference= custom _actions

The name of the currently preferred application actions properties file. Both this file and the preference file must be specified relative to the directory as set above.

Actions.Default

Actions.Default=default_actions

The default application actions properties file which will be loaded if the preference file is not set or fails to load successfully.

Data.Directory

Data.Directory=data

Defines the directory relative to the application root where application data properties files are to be found

Data.Preference

Data.Preference= custom_data

The name of the currently preferred application data properties file. Both this file and the preference file must be specified relative to the directory as set above.

Data.Default

Data.Default=default_data

The default application data properties file which will be loaded if the preference file is not set or fails to load successfully.

The next three properties files as specified above are required to have the following values:

User Interface Properties file - required entries

NOTE: Refer to the related class documentation for complete explanations of these properties.

Property Name

Example

Purpose

UserInterface.Name

UserInterface.Name=Hello World Applet

The name of the application, to be displayed in the application title bar

UserInterface.SourceDirectory

UserInterface.SourceDirectory=default

The directory relative to this properties file where the AVX XML documents and programming language specific compiled code modules will be located.

UserInterface.XML

UserInterface.XML=app_userinterface.xml

The XML Document where the details of the user interface have been specified in Applications via XML format

UserInterface.XSD

UserInterface.XSD=avx_userinterface.xsd

The XML Schema that will be used to parse the user interface XML document to retrieve the interface data

UserInterface.Default

UserInterface.Default=com.package.application.ApplicationUserInterface

The main user interface compiled code module that implements the AVXUserInterface class.

UserInterface.ImageDirectory

UserInterface.ImageDirectory=userinterface/default/images

The directory relative to the user interface directory (not the source directory) where images used in the user interface will be located.

UserInterface.LookAndFeel

UserInterface.LookAndFeel=Native

The default user interface look and feel.

UserInterface.ThemepacksEnabled

UserInterface.ThemepacksEnabled=true

A true/false flag to enable/disable user interface themes

UserInterface.Theme

UserInterface.Theme=themepacks/modernthemepack.zip

The theme to be applied to the user interface.

Actions Properties file - required entries

NOTE: Refer to the related class documentation for complete explanations of these properties.

Property Name

Example

Purpose

UserInterface.SourceDirectory

UserInterface.SourceDirectory=default

The directory relative to this properties file where the AVX actions XML documents as below will be located.

Actions.XML

Actions.XML=app_actions.xml

The XML Document where the details of the applications' actions have been specified in Applications via XML format

Actions.XSD

Actions.XSD=avx_actions.xsd

The XML Schema that will be used to parse the actions XML document to retrieve the application action data

Actions Properties file - required entries

NOTE: Refer to the related class documentation for complete explanations of these properties.

Property Name

Example

Purpose

Data.SourceDirectory

Data.SourceDirectory=default

The directory relative to this properties file where the AVX actions XML documents as below will be located.

Data.XML

Data.XML=acacia.lpxk

The XML Document where the details of the applications' actions have been specified in Applications via XML format

Data.XSD

Data.XSD=new_nonamespace_phoenix_schema.xsd

The XML Schema that will be used to parse the actions XML document to retrieve the application action data

Data.Package

Data.Package=com.lucidcentral.common.framework

This property is optional, but can be used in conjunction with the XML files to provide a base classpath for data objects - please refer to the section 'XML Parsing' as above.

.