# Serving XML: Inversion of Control Container

### Daniel Parker

This is the fourth of four articles describing the ServingXML pipeline language.

- ServingXML: Pipeline Language
- ServingXML: Flat Files
- ServingXML: Inversion of Control Container

This article looks at `ServingXML` as an "inversion of control" (IoC) container that allows us to assemble components from a variety of projects - the Apache FOP project, the Sun MSV project and others - and make them work together to process records and XML. The term "inversion" conveys the idea that the `ServingXML` container does not instantiate components directly, but rather supports an extensible component assembler module that allows user defined components to be injected into the container.

## Configuration and Service Components

The `ServingXML` container supports two types of components:

- configuration components
- service components

The difference between the two is in how they are identified.

- Configuration components are identified by object type and scope within an XML document.
- Service components are identified by object type and instance name.

In Java code, we can see the difference in how we look up component instances in the IoC container. This is how we look up a configuration component, passing only an object type to the lookup method:

      XsltConfiguration config = (XsltConfiguration)resources.lookupConfigurationComponent(JaxpConfiguration.class);

This is how we look up a service component, passing both an object type and an instance name to the lookup method:

      Service service = (Service)resources.lookupServiceComponent(Service.class, "books");

The example below shows a resources script that declares some configuration and service components, in particular, the `sx:xsltConfiguration` configuration component and the `sx:service` service component named "books".

    <sx:resources xmlns:sx="http://www.servingxml.com/core">

      <!-- A configuration component -->
      <sx:xsltConfiguration>
        <sx:systemProperty name="javax.xml.transform.TransformerFactory"
                           value="com.icl.saxon.TransformerFactoryImpl"/>
        <sx:outputProperty name="indent" value="no"/>
        <sx:outputProperty name="{http://icl.com/saxon}omit-meta-tag" value="yes"/>
      </sx:xsltConfiguration>

      <!-- A service component -->
      <sx:service id="books">
        <sx:serialize>
          <sx:transform>
            <sx:content ref="style1"/>
          </sx:transform>
        </sx:serialize>
      </sx:service>

      <sx:xslt id="style1"><sx:urlSource url="styles/catalog.xsl"/></sx:xslt>
      <sx:xslt id="style2"><sx:urlSource url="styles/brochure.xsl"/></sx:xslt>

       ...

The components declared in a resources script are assembled by the IoC container, using assemblers that are defined in a components file. The assemblers for the components shown above are defined as follows.

    <ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                   xmlns:sx="http://www.servingxml.com/core">

      <!--  Configuration Components -->
      <ioc:configurationComponent name="sx:xsltConfiguration"
        assemblerClass="com.servingxml.components.xsltconfig.XsltConfigurationAssembler"/>

      <!--  Abstract Components -->
      <ioc:abstractComponent name="sx:content"
        interface="com.servingxml.app.xmlpipeline.Content"/>
      <ioc:abstractComponent name="sx:stringable"
        interface="com.servingxml.components.string.StringFactory"/>
      <ioc:abstractComponent name="sx:task"
        interface="com.servingxml.components.task.Task"/>

      <!--  Service Components -->
      <ioc:serviceComponent name="sx:outputProperty"
        assemblerClass="com.servingxml.components.property.OutputPropertyFactoryAssembler"/>
      <ioc:serviceComponent name="sx:serialize" base="sx:task sx:stringable"
        assemblerClass="com.servingxml.components.transform.SerializedContentAssembler"/>
      <ioc:serviceComponent name="sx:xslt" base="sx:content"
        assemblerClass="com.servingxml.components.xslt.XsltFilterFactoryAssembler"/>
      <ioc:serviceComponent name="sx:systemProperty"
        assemblerClass="com.servingxml.components.property.SystemPropertyAssembler"/>
      <ioc:serviceComponent name="sx:transform"
        interface="com.servingxml.app.xmlpipeline.XmlPipelineFactory"
        assemblerClass="com.servingxml.components.transform.TransformedContentAssembler"/>

      ...

The code fragment below shows the `injectComponent` methods on the serialize assembler that receive configuration and service component instances. It is the IoC container's responsibility to call these methods.

    public class SerializedContentAssembler ...

      public void injectComponent(XsltConfiguration jaxpConfig) {
        this.jaxpConfig = jaxpConfig;
      }

      public void injectComponent(XmlFilterAppender pipelineFactory) {
        this.pipelineFactory = pipelineFactory;
      }

Each assembler has a method `assemble` that the IoC container, after it calls the `injectXXX` methods, calls to instantiate the component.

    public class SerializedContentAssembler ...

      public Task assemble(ConfigurationContext context)
       { ...

        //  Instantiate and return task using the configuration and service
        //  component instances injected into the component.

## Creating a Custom Service Component

### Creating an Extension Package

The ServingXML distribution includes a template extension package `servingxmlx` under the `extensions` directory. In the `servingxmlx` directory you will find the following files and directories.

- build.properties - This is where the extension jar file is named.
- build.xml - Ant build file (called by the main build.)
- build - Empty directory.
- lib - Put your extension specific jar files here.
- samples - Samples go here.
- src/java/servingxmlx - Component source code goes here.
- src/resources/components.xml - Register your extension components here.

You can place any extension to the system in the `servingxmlx` package. Alternatively, you can create a custom package name, using the `servingxmlx` package as a template, and place your extension in your own package. If you create a custom package name, you will also need to go to the root directory of the `servingxml` download and add an entry to the `build-extensions.xml` file.

The components supplied by an extension are registered in the extension's `components.xml` file. This file is included in the component's jar file. An entry in the jar's manifest named "ServingXML-Components" tells the `ServingXML` implementation where to find the components.

To build your package and make it part of the `ServingXML` distribution

- Edit the root-level `build-extensions.xml` file to include your extension in the main build.
- Build the distribution from the command line in the root directory of the servingxml download.

### Creating a Custom FTP Sink Component

In the example below, we show a resources script that transforms a document with a style sheet and writes the result to the local file `output.xml`.

    <sx:resources xmlns:sx="http://www.servingxml.com/core">

      <sx:service id="myService">
        <sx:transform>
          <sx:document><sx:urlSource url="document.xml"/></sx:document>
          <sx:xslt><sx:urlSource url="style.xsl"/></sx:xslt>
          <sx:xsltSerializer>
            <sx:fileSink file="output.xml"/>
          </sx:xsltSerializer>
        </sx:transform>
      </sx:service>

    </sx:resources>

Now, suppose that instead of writing the output to a local file, we want to send it to a remote host using our favourite third party FTP tool. In particular, we want to define a new element, say `ftpSink`, that we can use anywhere in a resources script where an element of the `sx:streamSink` family is currently allowed. We want to write something like this.

    <sx:resources xmlns:sx="http://www.servingxml.com/core"
                  xmlns:sxx="servingxmlx"> ...

      <sx:service id="service">
        <sx:serialize>
          <sx:xsltSerializer>
            <sxx:ftpSink remoteFile="output.xml">
              <sxx:ftpClient host="xxx" user="xxx" password="xxx"/>
            </sxx:ftpSink>
          <sx:xsltSerializer>

Note that we've put our proposed new elements `ftpSink` and `ftpClient` in a separate namespace, to distinguish them from the built-in `ServingXML` elements.

We'll start by examining the framework `components.xml` file, which is where the `sx:fileSink` element is registered. We see that it has an assembler class that creates `StreamSinkFactory` instances.

    <ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                   xmlns:sx="http://www.servingxml.com/core"> ...

      <ioc:abstractComponent name="sx:streamSink"
        interface="com.servingxml.components.streamsink.StreamSinkFactory"/>

      <ioc:serviceComponent name="sx:fileSink" base="sx:streamSink"
        assemblerClass="com.servingxml.components.streamsink.file.FileSinkFactoryAssembler"/>

The `StreamSinkFactory` interface is defined as follows.

    public interface StreamSinkFactory {
      StreamSink createStreamSink(ServiceContext context,  Flow flow)
      ;
    }

    public interface StreamSink {

      OutputStream openStream() throws IOException;

      void closeStream(OutputStream os) throws IOException;
    }

We'll need `StreamSinkFactory` and `StreamSink` implementations. Ultimatelty, the framework will call `openStream` on a `StreamSink` object, and we'll want the content that is written to the output stream to be sent to a file on a remote host. There are different ways of implementing this, for example, we could stream the content to the remote file as it is written, or alternatively we could stream it to a local file, and then send the local file to the remote host when the framework calls `closeStream`.

We'll need to register our new elements with the `ServingXML` container, which we'll do by adding some entries to the local `components.xml` file for the `servingxmlx` extension.

    <ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                   xmlns:sx="http://www.servingxml.com/core"
                   xmlns:sxx="servingxmlx">...

      <ioc:serviceComponent name="sxx:ftpSink" base="sx:streamSink"
        assemblerClass="servingxmlx.components.streamsink.edtftpj.FtpSinkFactoryAssembler"/>

      <ioc:serviceComponent name="sxx:ftpClient"
        interface="servingxmlx.components.streamsink.FtpClient"
        assemblerClass="servingxmlx.components.connect.edtftpj.FtpClientAssembler"/>

We need an assembler class for building a `StreamSinkFactory`.

    public class FtpSinkFactoryAssembler ...

      public StreamSinkFactory assemble(ConfigurationContext context)
       {

        return new FtpSinkFactory(ftpClient,remoteFile);
      }
    }

We define setter methods to allow the `ServingXML` container to inject the attribute values of the `edt:ftpSink` element into the builder object.

    public class FtpSinkFactoryAssembler ...

      public void setRemoteFile(String remoteFile) {
        this.remoteFile = remoteFile;
      }

We define an `injectComponent` method to allow the `ServingXML` container to inject an `FtpClient` object into the builder object.

    public class FtpSinkFactoryAssembler ...

      public void injectComponent(FtpClient ftpClient) {
        this.ftpClient = ftpClient;
      }

We need another builder for the ftpClient. This builder class only requires setter methods.

    public class FtpClientAssembler ...

      private int port = 21;

      public void setHost(String host) {
        this.host = host;
      }

      public void setPort(int port) {
        this.port = port;
      }

      public void setUser(String user) {
        this.user = user;
      }

      public void setPassword(String password) {
        this.password = password;
      }

      public FtpClient assemble(ConfigurationContext context)
       {

        return new FtpClient(host,port,user,password);
      }
    }

We can now rewite the resources script as proposed above, or alternatively, we can rewirte it using references like this.

    <sx:resources xmlns:sx="http://www.servingxml.com/core"
                  xmlns:sxx="servingxmlx">

      <sxx:ftpClient name="myFtpClient" host="xxx" user="xxx" password="xxx"/>

      <sx:service id="service">
        <sx:serialize>
          <sx:xsltSerializer>
            <sx:streamSink ref="myFtpSink"/>
          </sx:xsltSerializer>
          <sx:transform>
            <sx:document><sx:urlSource url="document.xml"/></sx:document>
            <sx:xslt><sx:urlSource url="style.xsl"/></sx:xslt>
          </sx:transform>
        </sx:serialize>
      </sx:service>

      <sxx:ftpSink name="myFtpSink" remoteFile="output.xml">
        <sxx:ftpClient ref="myFtpClient"/>
      </sxx:ftpSink>

    </sx:resources>

Note that the `ServingXML` container is responsible for resolving dependencies, so we don't need to worry about the precise order of the `sxx:ftpSink` and `sxx:ftpClient` elements, or references to them, in the script.

If we wanted to access the objects we've just defined in Java code, we could do so as follows.

    Name myFtpClient = new QualifiedName("myFtpClient");
    Name myFtpSink = new QualifiedName("myFtpSink");

    IocContainer resources = appContext.getResources();

    FtpClient ftpClient = (FtpClient)resources.lookupResource(FtpClient.class,myFtpClient);

    StreamSinkFactory streamSinkFactory = (StreamSinkFactory)resources.lookupResource(
        StreamSinkFactory.class,myFtpSink);