// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library.tools.mapping; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import openadk.library.ElementDef; import openadk.library.SIFElement; import openadk.library.SIFVersion; import openadk.library.ValueBuilder; import openadk.library.tools.xpath.SIFXPathContext; import org.apache.commons.jxpath.Variables; /** * Encapsulates context operation about a set of mappings that is being done * to handle a specific operation, such as processing a SIF Message.<p> * * Using MappingsContext is more efficient than repeatedly calling <code>Mappings.mapInbound<code> * or <code>Mappings.mapOutbound</code>. To get an instance of MappingsContext, call * {@link Mappings#selectInbound(ElementDef, SIFVersion, String, String)} or * {@link Mappings#selectOutbound(ElementDef, SIFVersion, String, String)} * * @author Andrew Elmhorst * */ public class MappingsContext { private SIFXPathContext fRootContext; private SIFVersion fSIFVersion; private ElementDef fElementDef; private MappingsDirection fDirection; private ValueBuilder fValueBuilder; private List<Mapping> fFieldMappings = new ArrayList<Mapping>(); private Mappings fMappings; private ObjectMapping fObjectMappings; /** * @param mappings * @param direction * @param version * @param elementType */ private MappingsContext( Mappings mappings, MappingsDirection direction, SIFVersion version, ElementDef elementType ) { fMappings = mappings; fDirection = direction; fSIFVersion = version; fElementDef = elementType; } /** * Creates a MappingsContext instance to handle a set of mappings operations using * the same parameters * @param m The mappings instance to use * @param direction The mappings direction * @param version The version of SIF to use for evaluating rule filters on field mappings * @param elementDef The ElementDef representing the object type being mapped * @return A new MappingsContext, initialized to map using the specified parameters */ public static MappingsContext create(Mappings m, MappingsDirection direction, SIFVersion version, ElementDef elementDef) { // Get the rules associated with the element type MappingsContext mc = new MappingsContext( m, direction, version, elementDef ); ObjectMapping om = m.getRules( elementDef.name(), true ); mc.addRules( om ); return mc; } private void addRules( ObjectMapping om ) { // Get the rules associated with the element type fObjectMappings = om; if( om != null ) { for( Mapping fm: om.getAllRulesList( true ) ){ // addRule( FieldMapping ) will automatically filter out // any rules that need to be filtered addRule( fm ); } } } private synchronized SIFXPathContext getXPathContext( SIFElement mappedElement, FieldAdaptor adaptor ) throws ADKMappingException { if( !mappedElement.getElementDef().name().equals( fElementDef.name() ) ){ throw new ADKMappingException( "Unable to use object for mapping. MappingsContext expected an object of type '" + fElementDef.name() + "' but was '" + mappedElement.getElementDef().name() + "'.", null ); } if( fRootContext == null ){ fRootContext = SIFXPathContext.newSIFContext( mappedElement, fSIFVersion ); if( adaptor instanceof Variables ){ fRootContext.setVariables( (Variables)adaptor ); } } return SIFXPathContext.newSIFContext( fRootContext, mappedElement ); } /** * Perform a mapping operation on the specified SIFElement. The mapping operation * will be either inbound or outbound, depending on whether this class was returned * from {@link Mappings#selectInbound(ElementDef, SIFVersion, String, String)} or * {@link Mappings#selectOutbound(ElementDef, SIFVersion, String, String)} * @param mappedElement The SIFElement to perform the mappings operation on * @param adaptor The FieldAdaptor to use for getting or setting data * @throws ADKMappingException */ public void map(SIFElement mappedElement, FieldAdaptor adaptor ) throws ADKMappingException { SIFXPathContext context = getXPathContext( mappedElement, adaptor ); if( getDirection() == MappingsDirection.INBOUND ){ fMappings.mapInbound( context, adaptor, mappedElement, fFieldMappings, fSIFVersion ); } else if (getDirection() == MappingsDirection.OUTBOUND ){ fMappings.mapOutbound( context, adaptor, mappedElement, fFieldMappings, fValueBuilder, fSIFVersion ); } } /** * Evaluates the filters defined for this FieldMapping. If any of the filters * evaluate to false, the FieldMapping is not added * * @param fieldMapping The FieldMapping to add * @return True if the FieldMapping was added. Otherwise false */ boolean addRule( Mapping mapping ) { MappingsFilter filt = mapping.getFilter(); // Filter out this rule? if( filt != null ) { if( !filt.evalDirection( getDirection() ) || !filt.evalVersion( fSIFVersion ) ) return false; } return fFieldMappings.add( mapping ); } /** * Gets the MappingsDirection being used for this Mappings Context * @return A MappingsDirection value (INBOUND or OUTBOUND) */ public MappingsDirection getDirection() { return fDirection; } /** * Sets the ValueBuilder instance to use for mapping operations. * @param functions A class implementing the ValueBuilder interface */ public void setValueBuilder( ValueBuilder functions ) { fValueBuilder = functions; } /** * Gets the ObjectMapping instance that this MappingsContext was initialized with * @return The ObjectMapping being used for this MappingsContext */ public ObjectMapping getObjectMappings() { return fObjectMappings; } /** * Returns an unmodifiable collection of the FieldMappings defined * in this mapping context * @return an unmodifiable collection of FieldMappings */ public Collection<Mapping> getFieldMappings(){ return Collections.unmodifiableCollection( fFieldMappings ); } /** * Returns the ElementDef that this MappingsContext is initialized to * map values for * @return The ElementDef that this MappingsContext is mapping data for */ public ElementDef getObjectDef(){ return fElementDef; } /** * Returns the Mappings object that this context is using to perform * Mapping operations. * @return a Mappings instance */ public Mappings getMappings() { return fMappings; } }