Defining a dynamic class in XML

The XML file may be loaded at the beginning of the program or at a later stage. In the same way as you can load a model from a file, you can also load the corresponding data from a file. You will find an example of a model and the corresponding data defined in the same file in Adding business objects from JavaBeans.
The example below shows how to describe the dynamic classes Event and Alarm in XML format. These classes will be created when the XML file is loaded.
The Event class has the ID attribute of type string . The Alarm class is a subclass of the Event class that has two attributes, PerceivedSeverity , of type String , and Acknowledged , a Boolean attribute that defaults to false . The Alarm class inherits the ID attribute from the Event class. For details, see Inheritance.

How to define dynamic classes in XML

<classes xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation = "ilog/cpl/schema/model.xsd">
<classes>
  <class>
    <name>Event</name>
    <attribute>
      <name>ID</name>
      <javaClass>java.lang.String</javaClass>
    </attribute>
  </class>  
  <class>
    <name>Alarm</name>
    <superClass>Event</superClass>
    <attribute>
      <name>PerceivedSeverity</name>
      <javaClass>java.lang.String</javaClass>
    </attribute>
    <attribute>
      <name>Acknowledged</name>
      <javaClass>java.lang.Boolean</javaClass>
      <defaultValue>false</defaultValue>
    </attribute>
  </class>
</classes>
The following table describes the elements that you can use to define your business model in XML format. You can also find a description of this format in the XML schema file model.xsd.
Elements in an XML business model
XML element
Attributes
Default
Description
<classes>
None
 
Delimits classes definition. This element is required. The file containing classes should necessarily start and end with this element. This element can be used inside data (see Elements in an XML data file ). This element contains <class> elements.
<class>
None
 
Contains a class definition. The class definition contains a name and possibly a <superClass> element and some <attribute> elements.
<superClass>
None
 
Contains the name of the superclass.
<name>
None
 
Contains the name of the class or of the attribute being defined.
<attribute>
None
 
Defines an attribute in the current <class>. The attribute contains a <name>, a <javaClass>, and optionally a <defaultValue>.
<javaClass>
None
 
Contains the name of the Java™ class of the attribute (for example java.lang.String ).
<defaultValue>
   
Contains the default value of an attribute.
 
javaClass
The Java class of the attribute.
Sometimes the Java class of the default value is not the Java class of the attribute (for example, if the Java class of the attribute is abstract). This attribute allows you to specify the Java class of the default value.
 
null
false
If the default value is to be null, you can set this optional attribute to true .

Inheritance

The dynamic classes created from an XML file can inherit from existing classes, in the same way as the dynamic classes that you can create using the Java API, which are either classes created from JavaBean™ classes or custom IlpClass implementations retrieved by the static GetIlpClass() method.
The order in which classes are defined within the element <classes> has no impact when loading classes that have inheritance relationships. In other words, you can define a class before a superclass within the same <classes> element.

Attribute types

The JViews TGO schema for defining an XML business model provides a <javaClass> element that lets you assign an abstract class or interface type to an attribute (for example java.lang.Number ) and provide a default value.

How to assign an abstract class or interface type and default value to an attribute

<attribute>
  <name>number</name>
  <javaClass>java.lang.Number</javaClass>
  <defaultValue javaClass="java.lang.Integer">100</defaultValue>
</attribute>
You may want to specify that an attribute has a null default value. Sometimes it is difficult to distinguish between a null value and an empty value. For example, if you have an attribute of type String , its default value will be "".

How to specify a null default value for an attribute

<attribute>
  <name>emptyString</name>
  <javaClass>java.lang.String</javaClass>
  <defaultValue />
</attribute>
Therefore, there is another XML attribute for default values to specify that the default value is null:
<attribute>
  <name>nullString</name>
  <javaClass>java.lang.String</javaClass>
  <defaultValue null="true" />
</attribute>

Type conversion

The types assigned to attributes of dynamic classes defined in an XML file should be recognized by the XML parser in order to load data contained in these classes.
Since attribute types may be complex, JViews TGO supports both simple attribute types, which can be read from a single string, and complex attribute types which can be composed of several XML tags.
For converting simple types, the XML parser uses the type converter service of the current application context (see Type converter). It executes the type conversion by calling the methods createJavaInstance and createStringValue . These methods support all the types defined in java.lang , plus extra ones such as:
  • Dates (instances of java.util.Date ). The following format is supported:
    "yyyy'-'MM'-'dd'T'HH':'mm':'ss"
  • Colors (instances of java.awt.Color ). Regular HTML formats are supported; for example:
    "RED" or "#NNNNNN"
  • Fonts (instances of java.awt.Font ). To know the formats that are supported, see the java.awt.Font.decode method.
  • Enumerated values (instances of ilog.util.IlEnum ).
You can extend the number of types supported by the default type converter by creating specific property editors or by subclassing the type converter.

Complex types

The interface IlpSAXSerializable supports complex types. This interface lets you read an instance from a SAX XmlReader and write it as a SAX event to a SAX ContentHandler . To be recognized, this interface should be implemented by a class named <className>SAXInfo ; or, if you are using the default type converter implementation ( IlpDefaultTypeConverter), you can register the value handler so that it is automatically taken into account by the XML parser, using the method IlpDefaultTypeConverter. setAttributeValueHandler.
Most of the JViews TGO classes that can be used as attribute types have a corresponding SAXInfo class. For example, the IlpPoint class in the ilog.cpl.graphic package comes with the IlpPointSAXInfo class. When an IlpPoint is to be read, the default type converter checks whether there is a corresponding IlpSAXSerializable instance. If not, it will try to load the IlpPointSAXInfo class. If it succeeds, this class will be returned as the IlpSAXSerializable interface of the IlpPoint class.
As an example, here is the code of the class IlpPointSAXInfo .

How to use the IlpSAXSerializable interface with complex types

/**
 * Returns a SAX handler capable of reading the attribute.
 * To avoid an instance of a SAX handler being used simultaneously 
 * by two concurrent threads, this method should either return a new 
 * instance of a SAX handler each time it is called or take advantage of 
 * the java.lang.ThreadLocal class to return a different 
 * instance for each thread.
 * @return A SAX event handler.
 */
  public IlpSAXAttributeValueHandler getSAXHandler() {
    return new IlpSAXPointHandler();
  }

  public static class IlpSAXPointHandler extends IlpSAXAttributeValueHandler {
  protected float x;
  protected float y;
  /**
   * Indicates the beginning of an element.
   * By default, this method only clears the content of the element.
   */
  public void startElement(String namespaceURI,
                           String localName,
                           String qName,
                           Attributes atts) throws SAXException {
    if (localName.equals(finalTag)) {
      x = y = 0.0f;
    }
    super.startElement(namespaceURI,localName,qName,atts);
  }

  /**
   * Notifies the end of an element.
   * When this method is called for the "attribute" element,
   * the <CODE>getAttributeValue</CODE> method is called, the object 
   * is modified accordingly, and parsing continues.
   */
  public void endElement(String namespaceURI,
                         String localName,
                         String qName) throws SAXException {
    if (localName.equals("x")) {
      x = Float.parseFloat(getContent());
    }

    if (localName.equals("y")) {
      y = Float.parseFloat(getContent());
    }

    super.endElement(namespaceURI,localName,qName);
  }

  /**
   * Is called at the end of the "attribute" element.
   */
  protected Object getAttributeValue() {
    Object value = new IlpPoint(x,y);
    return value;
  }

  }

  /**
  * Writes the <CODE>value</CODE> to a SAX ContentHandler.
  * The method translates the object as SAX ContentHandler method calls.
  * @param value The object to write.
  * @param typeConverter The type converter that may be needed to translate
  * values to strings.
  * @param outputHandler The SAX ContentHandler used by this method.
  * @see ilog.cpl.util.IlpTypeConverter#createStringValue(Object,IlpKey)
  */
  public void output(Object value,
    IlpTypeConverter typeConverter,
    ContentHandler outputHandler)
    throws SAXException {
    IlpPoint point = (IlpPoint)value;
    String valueStr = String.valueOf(point.x);
    outputHandler.startElement("","x","x",IlpSAXSerializable.EMPTY_ATTRS);
    outputHandler.characters(valueStr.toCharArray(),0,valueStr.length());
    outputHandler.endElement("","x","x");
    valueStr = String.valueOf(point.y);
    outputHandler.startElement("","y","y",IlpSAXSerializable.EMPTY_ATTRS);
    outputHandler.characters(valueStr.toCharArray(),0,valueStr.length());
    outputHandler.endElement("","y","y");
  }
}