The File System Binding

Legacy systems often used asynchronous batch connectivity where files containing messages are placed in a directory that is polled. If a response is required, a reply directory where files are written is typically used. To facilitate this kind of integration, Fabric3 provides a file system binding, binding.file.

The streaming sample in the features section and BigBank application contains an example of using the file system binding.

Service Bindings 

Below is an example of how to configure the binding on a service:

<component name="GatewayComponent">
   <implementation.java class="..."/>
   <service name="GatewayService">
      <f3:binding.file location="in.queue" pattern=".*\.xml" error.location="error.queue" delay="120000"/>
   </service>
</component>

The above example configures the GatewayComponent to receive .xml files placed in the "in.queue" directory. The pattern attribute is a Regex expression which is used to match file names. The location attribute is used to specify a directory to poll. This directory is relative to the current runtime /data/inbox directory (if the directory is not present at runtime startup, it will be created). The error.location attribute specifies a directory to place files that encountered a processing error, for example, if the GatewayComponent raises an parsing exception due to an invalid format. The delay attribute is used to specify the number of milliseconds to wait between polling attempts.

A service bound to the file system binding must have one operation. The default signature takes an InputStream parameter, which can be used to read the contents of a file:

public interface GatewayService {

   public void process(InputStream stream) throws MessageException;

}

Note the use of an InputStream facilitates handling large messages as a streaming parser such as StAX can be used for processing without having to load the entire content into memory.

Also note that the GatewayService component can signal an invalid message by throwing an exception, in this case MessageException. If an exception is thrown, the file system binding will by default move the file to the error directory.

Service Adapter Components

Sometimes special processing may need to be performed prior to passing a file to the bound service. A special adapter component that implements the org.fabric3.binding.file.api.ServiceAdapter interface can be specified:

<component name="GatewayComponent">
   <implementation.java class="..."/>
   <service name="GatewayService">
      <f3:binding.file location="in.queue" 
                       pattern=".*\.xml" 
                       error.location="error.queue" 
                       adapter.component="GatewayAdapter"
                       delay="120000"/>
   </service>
</component>

<component name="GatewayAdapter">
   <implementation.java class="..."/>
</component>

A ServiceAdaptor receives callbacks and can perform tasks prior to reading a file, closing it or when an error is encountered. In addition, the ServiceAdaptor may pass additional parameters to the bound service. The following example shows how the GatewayService can be modified to receive the filename in addition to an input stream:

public interface GatewayService {

   public void process(InputStream stream) throws MessageException;

}

public class GatewayServiceAdapter implements ServiceAdapter {
   
    public Object[] beforeInvoke(File file) throws InvalidDataException {
        InputStream stream = null;
        try {
            stream = new FileInputStream(file);
            return new Object[]{file, stream};
        } catch (FileNotFoundException e) {
            IOHelper.close(stream);
            throw new InvalidDataException(e);
        }
    }

   // ...
}

In order to use the ServiceAdapter in an application, you must import the file system binding API package in the appropriate contribution manifest (sca-contribution.xml):

<import.java package="org.fabric3.binding.file.api" version="..."/>

Reference Bindings

A reference can be bound to the file system binding. This can be used to send messages or return responses to a client. Below is an example of how to configure the binding on a reference:

<component name="ResponseService">
   <implementation.java class="..."/>
   <reference name="destination">
      <f3:binding.file location="out.queue"/>
   </reference>
</component>

The above example will place response messages in the out.queue, which is a directory relative to the runtime /data/outbox directory.

The following shows the component configured above and how it writes a message using JAXB:

public class ResponseService ... {
    private JAXBContext context;

    @Reference
    protected FileDestination destination;

    public void send(Message message) throws SendException {
       Marshaller marshaller = context.createMarshaller();
       OutputStream stream = destination.openStream(message.getClientCorrelation() + ".xml");
       marshaller.marshal(message, stream);
       stream.close();
    }

The file binding destination is represented as an interface provided by the application:

public interface FileDestination {

    /**
     * Returns a stream that can be used to write to the response queue.
     *
     * @param key the data key
     * @return the stream
     * @throws ServiceRuntimeException if an error occurs writing the data
     */
    OutputStream openStream(String key) throws ServiceRuntimeException;

}

The interface must have one operation that takes a String parameter (used to create the file name for the message) and returns an OutputStream.

Reference Adapter Components

An adapter can also be configured for a reference bound to the file system binding. In this case, the adapter must implement org.fabric3.binding.file.api.ReferenceAdapter. The binding configuration is identical:

<component name="ResponseService">
   <implementation.java class="..."/>
   <reference name="destination">
      <f3:binding.file location="out.queue" adapter.component="ResponseReferenceAdapter"/>
   </reference>
</component>

<component name="ResponseReferenceAdapter">
!-- ... -->
</component>

In order to use the ReferenceAdapter in an application, you must import the file system binding API package in the appropriate contribution manifest (sca-contribution.xml):

<import.java package="org.fabric3.binding.file.api" version="..."/>

Configuring the Archive Strategy

By default, the file system binding delete a message file once it has been processed. If the message should instead be archived, this can be done by specifying the archive strategy and an archive directory on the binding configuration:

<component name="GatewayComponent">
   <implementation.java class="..."/>
   <service name="GatewayService">
      <f3:binding.file ... strategy="archive" archive.location="archive.directory"/>
   </service>
</component>

Cluster Setup

Often, the file system binding will be used in a cluster setup. When this is the case, the binding inbox and outbox must be mapped to shared filesystem directories (these could be on a SAN to provide high-availability and guaranteed message delivery). Also note that when deployed to a cluster, the file system binding creates file locks to avoid more than one instances simultaneously processing a file.