ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Using PASX
Pages: 1, 2, 3

PASX uses XML for configuration because it is much more expressive than a simple list of properties. To illustrate how XML is better for this task, consider the first example, which would look something like this in the markup defined by PASX:



<List>
  <String>ns.foo.com</String>
  <String>ns.bar.com</String>
  <String>ns.acme.com</String>
</List>

While this is more verbose, it is much more elegant. And because some Lists can be ordered, the order in which the elements appear in the XML determines the order of the final data structure. With a properties file that ends up being a Properties object, the name must indicate the element index, because a Properties object is a simple derivation of Hashtable.

The second properties example would look like this in XML:

<List name="name-servers">
  <String>ns.foo.com</String>
  <String>ns.bar.com</String>
  <String>ns.acme.com</String>
</List>
<List name="web-servers">
  <String>www.foo.com</String>
  <String>www.bar.com</String>
  <String>www.acme.com</String>
</List>

And remember the challenge given? Make one of the elements in the list into a sub-list, and make one of the lists into a map structure where the name of each element may contain an underscore. Here is that example:

<List name="name-servers">
  <String>ns.foo.com<String>
  <List>
    <String>ns1.bar.com</String>
    <String>ns2.bar.com</String>
  </List>
  <String>ns.acme.com</String>
</List>
<Map name="web-servers">
  <String name="most_visited">www.foo.com<String>
  <String name="most_bytes">www.bar.com</String>
</Map>

In PASX, components (a class or tightly-integrated set of classes) are Java Beans that implement the PASXService interface. They are defined by the <Service> tag in XML, and this tag is used to name the individual instances of a component. The XML to give instance "A" the list of name servers and instance "B" the list of web servers would look like this:

<Service name="A" class="my.InternetHost">
	  <List name="hosts">
    <String>ns.foo.com</String>
    <String<ns.bar.com</String>
    <String<ns.acme.com</String>
  </List>
</Service>
<Service name="B" class="my.InternetHost">
  <List name="hosts">
    <String>web.foo.com</String>
    <String>web.bar.com</String>
    <String>web.acme.com</String>
  </List>
</Service>

PASX defines a set of standard XML tags for declaring properties of type List, Map, Integer, String, Boolean, etc. However, a PASXService class may also use XML tags of its own through the miracles of Namespaces and XML Schemas. The use of an XML Schema allows the component author to define his own tags and allows the parser to validate both the tags defined by PASX and the tags defined by the component author. The following example schema defines a <Server> tag, which must have hostName and portNumber attributes. The <Server> tag must appear as the child of the <Cluster> tag at least once, but as many times as are needed. And the <Cluster> tag must appear as the child of the <ServerFarm> tag at least once, but as many times as are needed.

<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2000/10/XMLSchema"
  xmlns:pce="http://pasx.org/PASX/CUSTOM-EXAMPLE"
  targetNamespace="http://pasx.org/PASX/CUSTOM-EXAMPLE"
  elementFormDefault="qualified" >

  <annotation>
    <documentation>
    A custom schema example to be using with PASX (PCE)
    </documentation>
  </annotation>

  <element name="Server">
    <complexType content="empty">
      <attribute
        name="hostName" 
        use="required" 
        type="string"/>
      <attribute
        name="portNumber"
        use="required" 
        type="positiveInteger"/>
    </complexType>
  </element>

  <element name="Cluster">
    <complexType>
      <sequence>
        <element
          ref="pce:Server"
          minOccurs="1" 
          maxOccurs="unbounded"/>
      </sequence>
      <attribute
        name="name" 
        use="required" 
        type="string"/>
    </complexType>
  </element>

  <element name="ServerFarm">
    <complexType>
      <sequence>
        <element
          ref="pce:Cluster" 
          minOccurs="1" 
          maxOccurs="unbounded"/>
      </sequence>
      <attribute
        name="name"
        use="required" 
        type="string"/>
    </complexType>
  </element>

  <element name="PCE">
    <complexType>
      <sequence>
        <element
          ref="pce:ServerFarm"
          minOccurs="1" 
          maxOccurs="unbounded"/>
      </sequence>
    </complexType>
  </element>

</schema>

The details about constructing an XML Schema document (XSD) are beyond the scope of this article. What is important to understand is that the author of a PASXService component can use a set of custom tags. What is even better is that the author need not write any validation code to ensure the XML is valid and not just well-formed; this is done by the parser. The following declaration of a <Service> tag uses the schema from above.

<Service 
  class="org.pasx.examples.CustomConfigExample"
  name="examples.customConfigExample" >

  <pce:PCE 
    xmlns="http://pasx.org/PASX/CUSTOM-EXAMPLE"
    xmlns:pce="http://pasx.org/PASX/CUSTOM-EXAMPLE"
    xsi:schemaLocation="http://pasx.org/PASX/CUSTOM-
EXAMPLE /org/pasx/examples/custom-example.xsd" >

    <ServerFarm name="farm0">
      <Cluster name="cluster0">
        <Server 
          hostName="app0.foo.com" 
          portNumber="8080" />
        <Server 
          hostName="app1.foo.com" 
          portNumber="8080" />
      </Cluster>
      <Cluster name="cluster1">
        <Server
          hostName="app2.foo.com"
          portNumber="8080" />
        <Server 
          hostName="app3.foo.com" 
          portNumber="8080" />
      </Cluster>
    </ServerFarm>
    <ServerFarm name="farm1">
      <Cluster name="cluster0">
        <Server 
          hostName="app4.foo.com" 
          portNumber="8080" />
        <Server 
          hostName="app5.foo.com" 
          portNumber="8080" />
      </Cluster>
      <Cluster name="cluster1">
        <Server 
          hostName="app6.foo.com" 
          portNumber="8080" />
        <Server 
          hostName="app7.foo.com" 
          portNumber="8080" />
      </Cluster>
    </ServerFarm>

  </pce:PCE>

</Service>

How a PASXService class uses the XML handed to it is really up to the author of the class. When it is time for the class to be configured, it is handed the XML element declaring it (<Service>) via the configure method. This method has the following signature:

public void configure(org.jdom.Element config,
                      Context context,
                      ServiceManager caller)

Notice that the Element parameter is a reference to a JDOM Element, not a DOM Element. JDOM is a more natural fit with Java than DOM, but if you need a DOM version, there are methods in the JDOM package to convert them. When using custom elements, the class author must use the JDOM API to traverse the parsed XML. However, because an XML Schema was employed, the class author only needs to concentrate on using the information in the JDOM data structures, and need not write any code to verify that the data structures are valid (i.e. the <Cluster> element only contains <Server> elements).

Pages: 1, 2, 3

Next Pagearrow