ServingXML: Extending

How to Extend the ServingXML Mark-Up Vocabulary


Record Readers, Writers, and Filters
Record Readers
Record Writers
Record Filters
XML Serializers
Assembler
SaxSinkFactory
Serializer
components.xml

ServingXML works as an "inversion of control" container for assembling components and making them work together to process records and XML. New elements may be added by implementing the contracts in the extension API's. See Serving XML: Inversion of Control Container for an overview.

Record Readers, Writers, and Filters

This section provides templates for custom record reader, filter, and writer elements that can be used in ServingXML resources scripts, as illustrated below.


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

  <sx:service id="countries">
    <sx:recordStream>
      <sx:recordReader ref="myFileReader"/>
      <myns:myRecordFilter myAttribute="xxx"/>
      <myns:myRecordWriter myAttribute="xxx"/>
      <sx:discardHandler>
        <sx:log message="{$sx:message}"/>
      </sx:discardHandler>
    </sx:recordStream>      
  </sx:service>

  <sx:flatFileReader id="myFileReader">
    <sx:flatFile ref="countriesFile"/>
  </sx:flatFileReader>

</sx:resources>  

Record Readers

Assembler


package mypackage;

import com.servingxml.app.ParameterDescriptor;
import com.servingxml.components.recordio.RecordReaderFactory;
import com.servingxml.components.recordio.RecordReaderFactoryPrefilter;
import com.servingxml.util.ServingXmlException;

public class MyRecordReaderFactoryAssembler {
  private ParameterDescriptor[] parameterDescriptors = ParameterDescriptor.EMPTY_ARRAY;
  private String myAttribute = "myDefault";

  public void setMyAttribute(String myAttribute) {
    this.myAttribute = myAttribute;
  }

  public void injectComponent(ParameterDescriptor[] parameterDescriptors) {
    this.parameterDescriptors = parameterDescriptors;
  }

  public RecordReaderFactory assemble(ConfigurationContext context) {
    RecordReaderFactory readerFactory = new MyRecordReaderFactory(/* args */);
    if (parameterDescriptors.length > 0) {
      readerFactory = new RecordReaderFactoryPrefilter(readerFactory,parameterDescriptors);
    }

    return readerFactory;
  }
}  

RecordReaderFactory


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordReaderFactory;
import com.servingxml.components.recordio.RecordReader;
import com.servingxml.util.record.Record;
import com.servingxml.util.ServingXmlException;

public class MyReaderFactory extends AbstractRecordReaderFactory
implements RecordReaderFactory  {     

  public MyReaderFactory(/* args */) {
  }
  
  protected RecordReader createRecordReader(ServiceContext context, Flow flow) {

    RecordReader recordReader = new MyRecordReader(/* args */);
    return recordReader;
  }
}

RecordReader


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordReader;
import com.servingxml.components.recordio.RecordReader;
import com.servingxml.util.record.Record;
import com.servingxml.util.ServingXmlException;

public class MyReaderReader extends AbstractRecordReader
implements RecordReader  {

  //  Per pipeline execution state

  public MyReaderReader(/* args */) {
  }

  public void readRecords(final ServiceContext context, final Flow flow) {
    try {
      startRecordStream(context, flow);
      //  For each record
      {
        RecordBuilder recordBuilder = new RecordBuilder();
        //  Build record
        Record newRecord = recordBuilder.toRecord();                                                                                         
        Flow newFlow = flow.replaceRecord(context, newRecord, ++lineNumber);
        try {
          writeRecord(context, newFlow);
        } catch (ServingXmlException e) {
          super.discardRecord(context, newFlow, e);
        }
      }
      endRecordStream(context, flow);
    } finally {
      close();
    }
  }
}

components.xml


<ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                xmlns:sx="http://www.servingxml.com/core">
                xmlns:myns="myurl">
               
  <ioc:serviceComponent name="myns:myRecordReader" base="sx:recordReader"
                assemblerClass="mypackage.MyRecordReaderFactoryAssembler"/>
  ...
                  
</ioc:components>                

Record Writers

Assembler


package mypackage;

import com.servingxml.app.ParameterDescriptor;
import com.servingxml.components.recordio.RecordWriterFactory;
import com.servingxml.components.recordio.RecordWriterFactoryPrefilter;
import com.servingxml.util.ServingXmlException;

public class MyRecordWriterFactoryAssembler {
  private ParameterDescriptor[] parameterDescriptors = ParameterDescriptor.EMPTY_ARRAY;
  private String myAttribute = "myDefault";

  public void setMyAttribute(String myAttribute) {
    this.myAttribute = myAttribute;
  }

  public void injectComponent(ParameterDescriptor[] parameterDescriptors) {
    this.parameterDescriptors = parameterDescriptors;
  }

  public RecordWriterFactory assemble(ConfigurationContext context)  {

    RecordWriterFactory recordWriterFactory = new MyRecordWriterFactory(/* args */);
    if (parameterDescriptors.length > 0) {
      recordWriterFactory = new RecordWriterFactoryPrefilter(recordWriterFactory,parameterDescriptors);
    }
    return recordWriterFactory;
  }
}  

RecordWriterFactory


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordWriterFactory;
import com.servingxml.components.recordio.RecordWriter;
import com.servingxml.util.record.Record;
import com.servingxml.util.ServingXmlException;

public class MyRecordWriterFactory extends AbstractRecordWriterFactory
implements RecordWriterFactory {     

  public MyRecordWriterFactory(/* args */) {
  }

  public RecordWriter createRecordWriter(ServiceContext context, Flow flow) 
   {
    RecordWriter recordWriter = new MyRecordWriter();
    return recordWriter;
  }
}

RecordWriter


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordWriter;
import com.servingxml.components.recordio.RecordWriter;
import com.servingxml.util.record.Record;
import com.servingxml.util.ServingXmlException;

public class MyRecordWriter extends AbstractRecordWriter 
implements RecordWriter {

  //  Per pipeline execution state

  public MyRecordWriter(/* args */) {
  }

  public void startRecordStream(ServiceContext context, Flow flow)  {
    //  Set up state
  }

  public void writeRecord(ServiceContext context, Flow flow) {

    Record record = flow.getRecord();

    //  Write the record 
  }  

  public void endRecordStream(ServiceContext context, Flow flow) {
    //  Tear down state
  }

  public void close()  {
  // Close all remaining open resources.  The framework will call close() 
  // even if there is a fault, so close() may be called even if startRecordStream() 
  // has not been called,  or in the successful case, after resources have already 
  // been disposed of in endRecordStream().
  }
}

components.xml


<ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                xmlns:sx="http://www.servingxml.com/core"
                xmlns:myns="myurl">
               
  <ioc:serviceComponent name="myns:myRecordWriter" base="sx:recordWriter"
                assemblerClass="mypackage.MyRecordWriterFactoryAssembler"/>
  ...
                  
</ioc:components>                

Record Filters

Assembler


package mypackage;

import com.servingxml.app.ParameterDescriptor;
import com.servingxml.components.recordio.RecordFilterAppender;
import com.servingxml.components.recordio.RecordFilterAppenderPrefilter;
import com.servingxml.util.ServingXmlException;

public class MyRecordFilterAppenderAssembler {
  private ParameterDescriptor[] parameterDescriptors = ParameterDescriptor.EMPTY_ARRAY;
  private String myAttribute = "myDefault";

  public void setMyAttribute(String myAttribute) {
    this.myAttribute = myAttribute;
  }

  public void injectComponent(ParameterDescriptor[] parameterDescriptors) {
    this.parameterDescriptors = parameterDescriptors;
  }

  public RecordFilterAppender assemble(ConfigurationContext context) {
    RecordFilterAppender recordFilterAppender = new MyRecordFilterAppender(/* args */);
    if (parameterDescriptors.length > 0) {
      recordFilterAppender = new RecordFilterAppenderPrefilter(recordFilterAppender,parameterDescriptors);
    }
    return recordFilterAppender;
  }
}

RecordFilterAppender


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordFilterAppender;
import com.servingxml.components.recordio.RecordFilterAppender;
import com.servingxml.components.recordio.RecordPipeline;
import com.servingxml.util.record.Record;
import com.servingxml.util.ServingXmlException;

public class MyRecordFilterAppender extends AbstractRecordFilterAppender    
implements RecordFilterAppender {

  public MyRecordFilterAppender(/* args */) {
  }

  public void appendToRecordPipeline(ServiceContext context, Flow flow, RecordPipeline pipeline) {
    RecordFilter filter = new MyRecordFilter();
    pipeline.addRecordFilter(filter);
  }
}

RecordFilter


package mypackage;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.components.recordio.AbstractRecordFilter;
import com.servingxml.util.RecordBuilder;
import com.servingxml.util.ServingXmlException;

public class MyRecordFilter extends AbstractRecordFilter
implements RecordFilter  {

  //  Per pipeline execution state

  public MyRecordFilter(/* args */) {
  }

  public void startRecordStream(ServiceContext context, Flow flow) {
    //  Acquire resources (input streams, SQL connections, etc.)
    super.startRecordStream(context, flow);
  }

  public void writeRecord(ServiceContext context, Flow flow) {

    try {                                       
      Record record = flow.getRecord();

      RecordBuilder recordBuilder = new RecordBuilder(record);
      //  Modify record
      Record newRecord = recordBuilder.toRecord();                                                                                         
      Flow newFlow = flow.replaceRecord(context, newRecord);

      super.writeRecord(context, newFlow);
    } catch (Exception e) {
      ServingXmlException reason = new ServingXmlException(e.getMessage(), e);
      super.discardRecord(context, flow, reason);
    }
  }  

  public void endRecordStream(ServiceContext context, Flow flow) {
    //  Finish up
    super.endRecordStream(context, flow);
  }
  
  public void close()  {
    // Close all remaining open resources.  The framework will call close() 
    // even if there is a fault, so close() may be called even if startRecordStream() 
    // has not been called,  or in the successful case, after resources have already 
    // been disposed of in endRecordStream().
  }
}

components.xml


<ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                xmlns:sx="http://www.servingxml.com/core">
                xmlns:myns="myurl">
               
  <ioc:serviceComponent name="myns:myRecordFilter" base="sx:recordFilter"
                assemblerClass="mypackage.MyRecordFilterFactoryAssembler"/>
  ...
                  
</ioc:components>                

XML Serializers

This section provides templates for custom serializer elements that can be used in ServingXML resources scripts.

Assembler


package mypackage;

import com.servingxml.app.ParameterDescriptor;
import com.servingxml.components.property.OutputProperty;
import com.servingxml.app.xmlpipeline.SerializerFactory;
import com.servingxml.app.xmlpipeline.SerializerFactoryPrefilter;
import com.servingxml.ioc.components.ConfigurationContext;
import com.servingxml.util.ServingXmlException;

public class MySerializerFactoryAssembler {
  private ParameterDescriptor[] parameterDescriptors = ParameterDescriptor.EMPTY_ARRAY;
  private OutputProperty[] outputProperties = new OutputProperty[0];

  public void injectComponent(ParameterDescriptor[] parameterDescriptors) {
    this.parameterDescriptors = parameterDescriptors;
  }

  public void injectComponent(OutputProperty[] outputProperties) {
    this.outputProperties = outputProperties;      
  }

  public SaxSinkFactory assemble(ConfigurationContext context)  {

    SaxSinkFactory saxSinkFactory = new MySerializerFactory(outputProperties);
    if (parameterDescriptors.length > 0) {
      saxSinkFactory = new SerializerFactoryPrefilter(saxSinkFactory, parameterDescriptors); 
    }

    return saxSinkFactory;
  }
}

SaxSinkFactory


package mypackage;

import java.util.Properties;
import org.xml.sax.ContentHandler;

import com.servingxml.app.Flow;
import com.servingxml.app.ServiceContext;
import com.servingxml.io.saxsink.SaxSink;
import com.servingxml.app.xmlpipeline.SerializerFactory;
import com.servingxml.util.ServingXmlException;

public class MySerializerFactory implements SaxSinkFactory {

  public MySerializerFactory(/* args */) {
  }

  public Serializer createSerializer(ServiceContext context, Flow flow, Properties outputProperties) {

    ContentHandler handler = new MyContentHandler(/* args */);                    
    Serializer serializer = new MySerializer(handler, /* other args */);
    return serializer;
  }                        
}

Serializer


package mypackage;

import org.xml.sax.ContentHandler;

import com.servingxml.io.saxsink.SaxSink;

public class MySerializer implements SaxSink {
  private final ContentHandler handler;

  public MySerializer(ContentHandler handler, /* other args */) {
    this.handler = handler;
  }

  public ContentHandler getContentHandler() {
    return handler;
  }

  public void setOutputProperties(Properties outputProperties) {
    //  Called by the framework to set output properties on the SAX sink
  }

  public void close() {
    //  Close output streams
  }
}

components.xml


<ioc:components xmlns:ioc="http://www.servingxml.com/ioc"
                xmlns:sx="http://www.servingxml.com/core">
                xmlns:myns="myurl">
               
  <ioc:serviceComponent name="myns:mySerializer" base="sx:saxSink"
                assemblerClass="mypackage.MySerializerFactoryAssembler"/>
  ...
                  
</ioc:components>