Users interested in downloading the jar files, source code, or getting support should consult the Source Force project page.
The Offsprings Splitter uses Spring's Aspect Oriented Programming (AOP) capability to simply and transparently parallelize any operation which must iterate over a list, map or array of objects. Return types of Array, List, Map, void, and XML String/Stream are supported. Example methods to which splitter can be applied are provided below (these examples do not include all of the parameters and return types supported):
public List<Document> getDocListFromIdList(List<String> ids);
public Document[] getDocArrayFromIdArray(String[] ids);
public InputStream getInputStreamFromIdList(List<String> ids);
public String getXMLFromIdList(List<String> ids);
public void updateAccounts (List<Integer> ids);
Offspring Splitter is currently beta software, licensed under the Apache License, Version 2.0
The included example demonstrates the performance improvement provided by the splitter when obtaining 200 documents from a list of unique ids if processing each document introduces a latency of 200 milliseconds. As expected, spreading the processing between ten threads reduces total processing time by a factor 10:
Download and install the Spring Framework. Ensure the following jar files from this distribution are in your project's classpath:
| dist/spring.jar |
| lib/jakarta-commons/commons-logging.jar |
| lib/junit/junit-4.4.jar |
Download and unzip the latest Offsprings release. Add offsprings.jar to the project classpath and place defaultSplitterContext.xml within the project classpath.
Modify the project's Spring context file as follows:
Add a SplitterAdvice bean, for example:
<bean id="splitterAdviceDelayedService" parent="abstractSplitterAdvice"> <property name = "properties"> <map> <entry key="docPath" value="delayed_service/docs/doc" /> <entry key="metaPath" value="delayed_service/meta_info" /> <entry key="metaXSLTTemplate" value="meta.xsl" /> </map> </property> </bean>
Using parent="abstractSplitterAdvice" means that the splitter will use the default parameters defined in defaultSplitterContext.xml. If the default parameters are not suitable, simply declare and use (as parent) a SplitterAdvice bean in the project context with the appropriate parameters.
The optional "properties" property only applies to Advice which wraps methods that return XML. If omitted, the default behavior is to concatenate the elements within the root element. The entries above indicate that each call to the method will return XML with the following structure:
<delayed_service> <meta_info> <-- Information about the document (e.g. doc count) goes here --> </meta_info> <docs> <doc> <-- Content goes here --> </doc> <doc> <-- Content goes here --> </doc> <-- etc... --> </docs> </delayed_service>
Behind the scenes, the Splitter will break one method call into several (which are run in paralell) and then combine the several XML documents into one. The transform meta.xsl will then be used to combine the various "meta_info" sections into one.
Declare the bean you wish to parallelize. For example:
<bean id="delayedServiceImpl" class="net.sourceforge.offsprings.examples.DelayedServiceImpl" />
Wrap that bean using a ProxyFactoryBean. For example:
<bean id="delayedService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>net.sourceforge.offsprings.examples.DelayedService</value> </property> <property name="interceptorNames"> <list> <value>splitterAdvisorDelayedService</value> </list> </property> <property name="target"> <ref bean="delayedServiceImpl"/> </bean>
See example.xml for a complete example context file.
Obtain the wrapped bean from a SplitterFactory. For example:
String[] contextFiles = {"classpath:net/sourceforge/offsprings/examples/config/exampleContext.xml",
"classpath:net/sourceforge/offsprings/splitter/config/defaultSplitterContext.xml"};
SplitterFactory factory = SplitterFactory.getInstance(contextFiles, "splitterFactory");
DelayedService service = (DelayedService)factory.getBean("delayedService");
Method invocations on the DelayedService interface of the service object will now be transparently split, run in parallel, and reassembled.
Splitter can easily be extended to support additional parameter or return types. If you produce an extension of general interest, please consider joining and submitting your changes on the offsprings-developers list.
Write a class which implements the interface IdsIterator<IDS> (generally this will be a descendent of IdsIteratorBaseImpl<IDS>). This class implements the process of splitting the parameter objects into batches. Note that the method nextBatch() must be synchronized. The method public Class<?>[] getApplicableClasses() should return an array containing the classes to which the new idsIterator will apply (descendents to these classes will work automatically and do not need to be listed separately). For descendents of IdsIteratorBaseImpl<IDS>), the method protected int sizeFromIds (Object ids) should return the number of items in the container ids.
Add a bean declaration for this implementation class to the project's Spring context file, for example:
<bean id="idsIteratorArray" class="net.sourceforge.offsprings.splitter.impl.IdsIteratorArrayImpl" singleton = "false" />
Add a value to the "idsIterators" property of the splitterFactory in the defaultSplitterContext.xml file referencing the newly created bean. For example
<value>idsIteratorArray</value>
Write a class which implements the interface BarrierResult (generally this will be a descendent of BarrierBaseImpl). This class implements the process of merging the various batches. The method public Class<?>[] getApplicableClasses() should return an array containing the classes to which the new idsIterator will apply (descendents to these classes will work automatically and do not need to be listed separately).
Add a bean declaration for this implementation class to the project's Spring context file, for example:
<bean id="barrierArray" class="net.sourceforge.offsprings.splitter.impl.BarrierArrayImpl" singleton = "false" />
Add a value to the "barriers" property of the splitterFactory in the defaultSplitterContext.xml file referencing the newly created bean. For example
<value>barrierArray</value>