Spring – Engine / Processors pattern

This is a pattern that is very easy to configure and use in Spring. It allows you to map object or any arbitrary key in a map to a service that will process objects of any types.

The Engine delegates calls to each one of the configured processors. Although the example is very simple and shows no real functionality I have used this same pattern to create services that generate thumbnails, process images, extract text from files based on content types, etc…

Once the engine is configured you can smply call engine.process(object) and based on the configuration the engine will delegate to the right processor.

This same pattern with slight modifications can be reused to implement filters and chain of commands/responsibility.
You can base the keys on the map on any other attribute besides the class.

This tutorial is available for download with svn:
svn checkout http://raulrajatutorials.googlecode.com/svn/trunk/ raulrajatutorials-read-only
Comments in the code itself should be self-explanatory if you already have some java + spring experience.

And now to the point.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
       default-autowire="byName">
 
    <!-- A processor that know about Person objects -->
    <bean id="personProcessor" class="com.raulraja.processor.impl.PersonProcessorImpl"/>
 
    <!-- A processor that knows about Place objects -->
    <bean id="placeProcessor" class="com.raulraja.processor.impl.PlaceProcessorImpl"/>
 
    <!-- A configured processing engine that maps object types to their processors and delegates calls to each one of them -->
    <bean id="processingEngine" class="com.raulraja.processor.impl.DefaultProcessingEngineImpl">
        <property name="processors">
            <map>
                <entry key="com.raulraja.domain.Person" value-ref="personProcessor"/>
                <entry key="com.raulraja.domain.Place" value-ref="placeProcessor"/>
            </map>
        </property>
    </bean>
 
    <!--
        This handler is actually not required but used for demonstrating the tutorial by invoking
        http://localhost:port/tutorialName
    -->
    <bean id="serviceInvokerHandler" class="com.raulraja.util.handler.impl.ServiceInvokerHandlerImpl" autowire="autodetect" />
 
</beans>

ProcessingEngine.java

package com.raulraja.processor;
 
/**
 * A processing engine that you can feed objects to and processes them
 */
public interface ProcessingEngine<Target> {
 
	/**
	 * Processes something
	 * @param target the target object to be processed
	 */
	void process(Target target);
 
}

DefaultProcessingEngineImpl.java

 
package com.raulraja.processor.impl;
 
import com.raulraja.processor.ProcessingEngine;
import com.raulraja.processor.Processor;
import org.apache.log4j.Logger;
 
import java.util.Map;
 
/**
 * Default impl of the processing engine based on a spring configured service.
 * Delegates processing calls to the right processor
 */
public class DefaultProcessingEngineImpl<Target> implements ProcessingEngine<Target> {
 
	private final static Logger log = Logger.getLogger(DefaultProcessingEngineImpl.class);
 
	/**
	 * A map of processor that maps object types to a processor that know how to process it
	 */
	private Map<Class<Target>, Processor<Target>> processors;
 
	public void setProcessors(Map<Class<Target>, Processor<Target>> processors) {
		this.processors = processors;
	}
 
	/**
	 * Processes something
	 *
	 * @param target the target object to be processed
	 */
	public void process(Target target) {
		log.debug("started processing " + target);
		Processor<Target> processor = processors.get(target.getClass());
		if (processor != null) {
			processor.process(target);
		} else {
			log.debug("processor not found for " + target);		
		}
		log.debug("finished processing " + target);
	}
}

Processor.java

package com.raulraja.processor;
 
/**
 * A service that know how to process a type of object
 */
public interface Processor<Target> {
 
	/**
	 * Processes something
	 * @param target the target object to be processed
	 */
	void process(Target target);
 
}

PersonProcessorImpl.java

package com.raulraja.processor.impl;
 
import com.raulraja.domain.Person;
import com.raulraja.processor.Processor;
import org.apache.log4j.Logger;
 
/**
 * Demonstrates how a Person can be processed
 */
public class PersonProcessorImpl implements Processor<Person> {
 
	private final static Logger log = Logger.getLogger(PersonProcessorImpl.class);
 
	/**
	 * Processes something
	 *
	 * @param person the target object to be processed
	 */
	public void process(Person person) {
   		log.debug(person + " something is being done to a person object");
	}
}

PlaceProcessorImpl.java

package com.raulraja.processor.impl;
 
import com.raulraja.domain.Place;
import com.raulraja.processor.Processor;
import org.apache.log4j.Logger;
 
/**
 * Demonstrates how a Person can be processed
 */
public class PlaceProcessorImpl implements Processor<Place> {
 
	private final static Logger log = Logger.getLogger(PlaceProcessorImpl.class);
 
	/**
	 * Processes something
	 *
	 * @param place the target object to be processed
	 */
	public void process(Place place) {
   		log.debug(place + " something is being done to a place object");
	}
}

Person.java

package com.raulraja.domain;
 
/**
 * Represents a person
 */
public class Person {
}

Place.java

package com.raulraja.domain;
 
/**
 * Represents a place
 */
public class Place {
}

ServiceInvokerHandlerImpl.java

package com.raulraja.util.handler.impl;
 
import com.raulraja.processor.ProcessingEngine;
import com.raulraja.domain.Person;
import com.raulraja.domain.Place;
import org.springframework.web.HttpRequestHandler;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
/**
 * Frontend entry point for the demo
 */
public class ServiceInvokerHandlerImpl implements HttpRequestHandler {
 
	/**
	 * The engine that processes object types
	 */
	private ProcessingEngine<Object> processingEngine;
 
	/**
	 * sets the engine that processes object types
	 * @param processingEngine the engine
	 */
	public void setProcessingEngine(ProcessingEngine<Object> processingEngine) {
		this.processingEngine = processingEngine;
	}
 
	/**
	 * Process the given request, generating a response.
	 *
	 * @param request  current HTTP request
	 * @param response current HTTP response
	 * @throws javax.servlet.ServletException in case of general errors
	 * @throws java.io.IOException			in case of I/O errors
	 */
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Person person = new Person();
		Place place = new Place();
		processingEngine.process(person);
		processingEngine.process(place);
	}
}

Output

07/01 08:53:59 DEBUG com.raulraja.processor.impl.DefaultProcessingEngineImpl – started processing com.raulraja.domain.Person@53fb687a
07/01 08:53:59 DEBUG com.raulraja.processor.impl.PersonProcessorImpl – com.raulraja.domain.Person@53fb687a something is being done to a person object
07/01 08:53:59 DEBUG com.raulraja.processor.impl.DefaultProcessingEngineImpl – finished processing com.raulraja.domain.Person@53fb687a
07/01 08:53:59 DEBUG com.raulraja.processor.impl.DefaultProcessingEngineImpl – started processing com.raulraja.domain.Place@a427a0b
07/01 08:53:59 DEBUG com.raulraja.processor.impl.PlaceProcessorImpl – com.raulraja.domain.Place@a427a0b something is being done to a place object
07/01 08:53:59 DEBUG com.raulraja.processor.impl.DefaultProcessingEngineImpl – finished processing com.raulraja.domain.Place@a427a0b

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • LinkedIn
  • MySpace
  • RSS
  • TwitThis
  • email
  • FriendFeed
  • PDF
  • Slashdot

This post is tagged , ,

don't '

One Response

  1. [...] This tutorial also uses the Engine / Processor pattern as explained here. [...]

Leave a Reply

Comments may be held for moderation, please do not repost. I reserve the right to remove any inappropriate or off-topic comments. If you plan on sharing helpful code, please pass it through Postable first. Want other to know who you are? Register a Gravatar.





Sponsored Links

Categories

Pages

mousetrap bar muppets music relocate server share 1965 peace prize recipiant ai wo koete focus macro for warlock 12 steps of 12 step program duchess restaurant in norwalk ct nubian heritage harlem ferry from kos to lesvos american famaly ins approach meeting discuss forward opportunity 2008 topps update highlights yankees bern north carolina alcohol drug halfway houses phoenix az bartender 4 cindysthrows.com 1st global national conference girls yuri rimini coast icu and ethic girls basketball brethren christian high school codes to the legend of zelda association-office.com blood elf priest dry brushing cabinets free needlepoint slipper pattern aaacap.org gluten free sauces cast and crowns butternut squash ravioli chicago 1920 s style shutter hinges butterflies lake morton alabama malamute 1996 jaguar oil pan anita denise fuller 72 listening skills curved chain nose pliers kari byron pics mythbusters afghan and fruit of the spirit a sweet science fair project discourse markers activities for tefl fractal mac os x dexadine.com bass companion cassie cato partingwishes.com bittorrent free downloader mac apostles today boba fet and leia bonsai societies newsletters coupon code dvdxpress kiosk penguin wild tangent crack 12 step bible burroughs farms brighton michigan penske rental in chico california chocolate coconut truffles copy a locked file brick paving driveway efi smithsonian tours ball draining blowjobs aircraft latrine discharge educacion locke benjamin james loves born in tennessee east brunswick nj vo tech email contact adresses ministers in usa yogafamily.com aol always sunny in philadelphia 2020 automotive group az christmas teas at hotels game ideas for family reunions 2x 4 saddle rack florida radon training brinkmann charcoal smoker modification bali hindu hawks ridge duluth minn ace bowling ball bargains.com arizona motto ditat mongolian barbeque denver buy fujitsu scansnap color image scanner .22 stirling rifles blue spiny lizard ancient stone walls in oakland ca cherry tree leaf parasites elderberry shrubs piragis.com hbs and mpc provider dandy vom hause neubrand kg frontierairline.com box sash windows kent wee ride calgon catalytic carbon filters family homestay in kyoto church choir robes 3288 tranquility lane ao calculate multi range requirement beliefs of messianic judaism charlie bit me utube lakers apparel civil-war.com how to get harder erections tartanstore.net deux de coeur download sega saturn emulator defiance movie watching free child to cherish handprint ornament aftermarketsupport.com benjamin m curry saginaw mi cityofphoenix.gov anakin skywalker darth vader bios not acpi compliant big toe manipulation ac schnitzer facelift lip 92 silver eagle coach billy peterson csi abdomen fat getting large pagesvpp.com 108mbps gaming adapter removeable antenna air bake muffin maris carey touch my body bunting bearings ku nudesville.com 02 pt crusier touring edition manual craiglist fargo how may kkk members are there tilley.com caviar yamaha a life of faith dolls outrageous blondes foodsafeschools.org chesapeake general hosp youngsrvcenters.com globe weis folders online news pakistani channel aloe vera ears campgrounds by wildwood beach new jersey 138 highway closure fgcdirect9.com 6.5 crank sensor tomb-raider-anniversary.com alhambra california newspaper bobble fish days of elijah lyrics bk 2160 parts lloyd james wingate susannah cannon camera retailers honduras 2002 mustang gt spark plugs australian chemist ixsweb.com catholic monastery tennessee carpel tunnel syndrome in golfers electoral college federalist papers australian carp record el segundo stick n stein dodge dually big tires ankle fractures in pediatric patients 1975 toyota celica for sale 115th police academy cadets austin texas conspiracy theory robots downloading soul list of common transitional words dr horner in belleville il leech inside urethra artery inflamation cannondale adventure 800