Introduction

Previously I described my use of Flazr, and open-source streaming client, to test my media server. And I mentioned that I wanted to test the server’s capabilities to achieve better scalability by distributing requests across satellite servers. When media server receives a request for content it chooses a satellite and then emits a redirection response in this style:

<smil>
    <head>
        <meta base="rtmp://hostX/app/" />
    </head>
    <body>
        <video src="djna01/someContent.mp4" />
    </body>
</smil>

This is SMIL format, albeit a very small subset of what SMIL can be used for – using full SMIL capabilities you can in effect build a complete animated presentation. That’s rather like having a PowerPoint for the Web.

Anyway my client then needs to understand this response and open up the stream on

rtmp://hostX/app/djna01/someContent.mp4

So in this article I’ll explain how I used JAX/B to parse the SMIL XML.

Why JAX/B

When faced with something as simple as that SMIL example it’s very tempting to use a few regular expressions (regexp) to extract the data we need. We could probably get something working quite quickly. However in the general case XML complexity defeats regexp capability (see discussions such as this) and most of the time I need to deal with non-trivial XML. So as I haven’t previously explored using the JAX/B APIs for parsing XML, now’s the chance!

It transpires that, using the Rational Application Developer tooling,  it actually took about 20 minutes to write the JAX/B-based code. I doubt whether I could have got the regexp right as quickly.

Using JAX/B

My starting point was a sample XML file as shown above. I created a simple Java project and then took the following steps:

  1. Generated an XSD
  2. From the XSD generated annotated Java classes
  3. Wrote the few required lines of code to call the JAX/B API.

Generating the XSD

I have the sample XML file in my project, I

rightClick->Generate->Xml Schema

and selected the defaults offered. The result was a schema

  <xsd:element name="head">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="meta"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="body">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="video"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="meta">
    <xsd:complexType>
      <xsd:attribute name="base" type="xsd:string"/>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="video">
    <xsd:complexType>
      <xsd:attribute name="src" type="xsd:string"/>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="smil">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="head"/>
        <xsd:element ref="body"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

There are various options I could have selected to get finer control over the XSD. Alternatively I could have written the XSD by hand, or in more complex cases the service provider would have already have published the XSD.

 

Generating Java Classes

I then need a set of Java Classes corresponding to the XSD, these classes using JAX/B annotations to control mapping between Java and XML. Again, I could write these by hand, but a simple set of cannotated classes can be generated very easily, select the XSD and

rightClick->Generate->Java

This brings up the XSD to Java wizard. On the first page select

JAX/B Schema to Java Bean

and select Next, then on the next page specify a package name such as  org.djna.smil.data and click Finish. The result is a suitable set of classes

image 

Here’s part of the generated Head.java class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "meta"
})
@XmlRootElement(name = "head")
public class Head {

    @XmlElement(required = true)
    protected Meta meta;

I won’t here elaborate on the meanings of the JAX/B annotations, but it’s pretty clear that we’ve got a class which maps to this portion of the SMIL

<head>
        <meta base="rtmp://hostX/app/" />
</head>

and the other classes are annotated similarly. So after a few mouse clicks we now have a set of classes which correspond to the SMIL file. All that remains is the code to use those classes.

The JAX/B invocation code

In my case I have the URL of the redirection service, which returns the SMIL document to be parsed. So I can write this code

public Smil exampleGet(String url)
        throws JAXBException, MalformedURLException{
        JAXBContext jc
           = JAXBContext.newInstance("org.djna.smil.data");
        Unmarshaller u = jc.createUnmarshaller();

        Smil theSmil = (Smil)u.unmarshal( new URL(url) );

        return theSmil;
    }

So I have initialsed the JAXBContent with the name of the package where my Beans were generated.

    JAXBContext.newInstance("org.djna.smil.data");

and then use that context to create an Unmarshaller. The unmarshaller will accept a URL parameter and parses the response.

And that’s it; four lines of code and the XML is parsed.

Conclusion

I have to admit that when I decided to use JAX/B rather than a simple regexp I thought I might have been making things unduly complex. I was surprised when all the above “just worked”. In fact when my application ran I spent a few minutes trying to find out where it had broken before realising that in fact it had worked seamlessly.