[jboss-svn-commits] JBL Code SVN: r32099 - labs/jbossesb/workspace/johan.kumps/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Mar 15 15:45:14 EDT 2010


Author: johan.kumps
Date: 2010-03-15 15:45:14 -0400 (Mon, 15 Mar 2010)
New Revision: 32099

Added:
   labs/jbossesb/workspace/johan.kumps/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/OntologyAction.java
Log:
Initial version

Added: labs/jbossesb/workspace/johan.kumps/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/OntologyAction.java
===================================================================
--- labs/jbossesb/workspace/johan.kumps/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/OntologyAction.java	                        (rev 0)
+++ labs/jbossesb/workspace/johan.kumps/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/OntologyAction.java	2010-03-15 19:45:14 UTC (rev 32099)
@@ -0,0 +1,396 @@
+/*
+ * JBoss, Home of Professional Open Source Copyright 2009, Red Hat Middleware
+ * LLC, and individual contributors by the @authors tag. See the copyright.txt
+ * in the distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * 
+ * This software is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this software; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
+ * site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.actions.transformation.xslt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.log4j.Logger;
+import org.jboss.internal.soa.esb.assertion.AssertArgument;
+import org.jboss.internal.soa.esb.util.StreamUtils;
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.actions.transformation.xslt.ResultFactory.ResultType;
+import org.jboss.soa.esb.actions.transformation.xslt.TransformerFactoryConfig.Builder;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.listeners.message.MessageDeliverException;
+import org.jboss.soa.esb.message.Message;
+import org.w3c.dom.Document;
+
+/**
+ * ESB Action that performs lifting tranformation of a message payload towards
+ * the ontology.
+ * <p/>
+ * Example configuration:
+ * 
+ * <pre>
+ * @code
+ * <action name="lifting-transform" class="org.jboss.soa.esb.actions.transformation.ontology.LiftingAction">
+ *    <property name="failOnWarning" value="true"/>
+ *    <property name="resultType" value="STRING"/>
+ * </action>
+ * }
+ * 
+ * <pre>
+ * 
+ * <h3>Configuration Properties</h3>
+ * <lu>
+ *    
+ *  <li><i>resultType</i>:
+ *  This property controls the output result of the transformation.
+ *  The following values are currently available:
+ *  {@link ResultType.STRING} - will produce a string.
+ *  {@link ResultType.BYTES} - will produce a byte[].
+ *  {@link ResultType.DOM} - will produce a {@link DOMResult}.
+ *  {@link ResultType.SAX} - will produce a {@link SAXResult}.
+ *  </li>
+ *  If the above does not suite your needs then you have the option of specifying both the
+ *  Source and Result by creating {@link SourceResult} object instance. This is a simple
+ *  object that holds both a {@link Source} and a {@link Result}. 
+ *  You need to create this object prior to calling this action and the type of {@link Result}
+ *  returned will be the type that was used to create the {@link SourceResult}.
+ *  
+ *  <li><i>failOnWarning</i>:
+ *  If true will cause a transformation warning to cause an exception to be thrown.
+ *  If false the failure will be logged. Default is true if not specified.</li>
+ *  
+ *  <li><i>uriResolver</i>:
+ *  Fully qualified class name of a class that implements {@link URIResolver}.
+ *  This will be set on the tranformation factory. Optional</li>
+ *  
+ *  <li><i>factory.feature.*</i>:
+ *  Factory features that will be set for the tranformation factory. Optional.
+ *  The feature name, which are fully qualified URIs will should be specified
+ *  after the 'factory.feature.' prefix. For example:
+ *  factory.feature.http://javax.xml.XMLConstants/feature/secure-processing</li>
+ *  
+ *  <li><i>factory.attribute.*</i>:
+ *  Factory attributes that will be set for the tranformation factory. Optional.
+ *  The attribute name should be specified after the 'factory.attribute.' prefix. 
+ *  For example:
+ *  factory.attribute.someVendorAttributename</li>
+ * </lu>
+ * 
+ * @author <a href="mailto:johan.kumps at telenet.be">Johan Kumps</a>
+ * @since 4.8
+ */
+public class OntologyAction extends XsltAction {
+
+	/*
+	 * The Logging instance for this class.
+	 */
+	private static Logger log = Logger.getLogger(OntologyAction.class);
+
+	/*
+	 * A Hashtable representing a Templates instance cache
+	 */
+	private static Hashtable<String, Templates> templateCache = new Hashtable<String, Templates>();
+
+	/*
+	 * The name of the attribute in the XML message containing the lifting
+	 * schema mapping location.
+	 */
+	private static final String LIFTING_SCHEMA_MAPPING = "liftingSchemaMapping";
+
+	/*
+	 * The XPath expression to use to extract the lifting schema attribute
+	 */
+	private static XPathExpression XPATH_GETTING_LIFTING_SCHEMA_MAPPING = null;
+
+	/*
+	 * The name of the attribute in the XML message containing the lowering
+	 * schema mapping location.
+	 */
+	private static final String LOWERING_SCHEMA_MAPPING = "loweringSchemaMapping";
+
+	/*
+	 * The XPath expression to use to extract the lowering schema attribute
+	 */
+	private static XPathExpression XPATH_GETTING_LOWERING_SCHEMA_MAPPING = null;
+
+	/*
+	 * Message given when an error occurs during the XPath initialisation
+	 */
+	private static final String ERROR_INTIALISING_XPATH = "An error occured while initialising the XPath expressions.";
+
+	/*
+	 * Message given when neighter the lifting nor the lowering schema mapping
+	 * attribute was found
+	 */
+	private static final String NO_ONTOLOGY_MAPPING_SCHEMA = "No ontology mapping schema linked to the incoming message.";
+
+	/*
+	 * Message given when both the lifting and the lowering schema mapping
+	 * attribute was found
+	 */
+	private static final String BOTH_ONTOLOGY_MAPPING_SCHEMAS = "Both ontology mapping schemas linked to the incoming message.";
+
+	/*
+	 * Factory used to create an new XSL template instance
+	 */
+	private TransformerFactory factory;
+
+	/**
+	 * Constructor that parses the passed-in {@link ConfigTree} for mandatory
+	 * attributes and sets the fields of this instance.
+	 * 
+	 * @param config
+	 *            The {@link ConfigTree} instance.
+	 * 
+	 * @throws ConfigurationException
+	 *             if a mandatory attribute has not been set (currently none).
+	 */
+	public OntologyAction(final ConfigTree config)
+			throws ConfigurationException {
+		super(config);
+	}
+
+	/**
+	 * Initialise the {@link TransformerFactory} and XPath expressions used to
+	 * evaluate the messages.
+	 * 
+	 * @throws ActionLifecycleException
+	 *             if the {@link TransformerFactory} could not be created.
+	 * 
+	 */
+	@Override
+	public void initialise() throws ActionLifecycleException {
+		try {
+			this.factory = TransformerFactory.newInstance();
+			addFeatures(transformerConfig.getFeatures(), factory);
+			addAttributes(transformerConfig.getAttributes(), factory);
+			setResolver(transformerConfig.getUriResolver(), factory);
+			setErrorListener(new TransformerListener(failOnWarning), factory);
+
+			XPathFactory xPathFactory = XPathFactory.newInstance();
+			XPath xpath = xPathFactory.newXPath();
+
+			XPATH_GETTING_LIFTING_SCHEMA_MAPPING = xpath.compile("//@"
+					+ LIFTING_SCHEMA_MAPPING);
+
+			XPATH_GETTING_LOWERING_SCHEMA_MAPPING = xpath.compile("//@"
+					+ LOWERING_SCHEMA_MAPPING);
+
+		} catch (final TransformerConfigurationException e) {
+			throw new ActionLifecycleException(e.getMessage(), e);
+		} catch (XPathExpressionException e) {
+			throw new ActionLifecycleException(ERROR_INTIALISING_XPATH, e);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.jboss.soa.esb.actions.ActionPipelineProcessor#process(org.jboss.soa
+	 * .esb.message.Message)
+	 */
+	@Override
+	public Message process(Message message) throws ActionProcessingException {
+		AssertArgument.isNotNull(message, "message");
+		Object payload;
+		try {
+			payload = payloadProxy.getPayload(message);
+
+			final Source source;
+			final Result result;
+			// If the payload is of SourceResult that use its source and result.
+			if (payload instanceof SourceResult) {
+				final SourceResult sourceResult = (SourceResult) payload;
+				source = sourceResult.getSource();
+				result = sourceResult.getResult();
+			} else {
+				source = SourceFactory.getInstance().createSource(payload);
+				result = ResultFactory.getInstance().createResult(
+						transformerConfig.getResultType());
+			}
+
+			Document document = DocumentFactory.getInstance().createDocument(
+					payload);
+
+			String liftingSchemaMapping = (String) XPATH_GETTING_LIFTING_SCHEMA_MAPPING
+					.evaluate(document, XPathConstants.STRING);
+			String loweringSchemaMapping = (String) XPATH_GETTING_LOWERING_SCHEMA_MAPPING
+					.evaluate(document, XPathConstants.STRING);
+
+			// If both a lifting and a lowering schema mapping are provided for
+			// the same element, we cannot handle the message
+			if (!isEmpty(liftingSchemaMapping)
+					&& !isEmpty(loweringSchemaMapping)) {
+				throw new ActionProcessingException(
+						BOTH_ONTOLOGY_MAPPING_SCHEMAS);
+			}
+
+			String ontologyMappingSchema = null;
+
+			if (!isEmpty(liftingSchemaMapping)) {
+				// We are acting as a lifting action
+				if (OntologyAction.log.isDebugEnabled()) {
+					OntologyAction.log
+							.debug("Acting as a lifting action for message "
+									+ message.getHeader().getCall()
+											.getMessageID());
+				}
+				ontologyMappingSchema = liftingSchemaMapping;
+			} else {
+				if (!isEmpty(loweringSchemaMapping)) {
+					// We are acting as a lowering action
+					if (OntologyAction.log.isDebugEnabled()) {
+						OntologyAction.log
+								.debug("Acting as a lowering action for message "
+										+ message.getHeader().getCall()
+												.getMessageID());
+					}
+					ontologyMappingSchema = loweringSchemaMapping;
+				}
+			}
+			if (ontologyMappingSchema != null) {
+				final Templates xslTemplate = this
+						.getTemplate(ontologyMappingSchema);
+				final Transformer transformer = xslTemplate.newTransformer();
+				// Perform the transformation.
+				transformer.transform(source, result);
+
+				// Get the result and set on the message object
+				final Object object = ResultFactory.getInstance()
+						.extractResult(result,
+								transformerConfig.getResultType());
+				payloadProxy.setPayload(message, object);
+				return message;
+			} else {
+				// LIFTING_SCHEMA_MAPPING nor LOWERING_SCHEMA_MAPPING attribute
+				// was found in the message payload
+				throw new ActionProcessingException(NO_ONTOLOGY_MAPPING_SCHEMA);
+			}
+
+		} catch (TransformerConfigurationException e) {
+			throw new ActionProcessingException(e);
+		} catch (ActionLifecycleException e) {
+			throw new ActionProcessingException(e);
+		} catch (TransformerException e) {
+			throw new ActionProcessingException(e);
+		} catch (MessageDeliverException e) {
+            throw new ActionProcessingException(e.getMessage(), e);
+        } catch (Exception e) {
+			throw new ActionProcessingException(e);
+		}
+	}
+
+	@Override
+	public String toString() {
+		return String.format("%s failOnWarning=%b, features=%s, attributes=%s",
+				getClass().getSimpleName(), failOnWarning, transformerConfig
+						.getFeatures(), transformerConfig.getAttributes());
+	}
+
+	/**
+	 * Parses the passed-in ESB {@link ConfigTree} and populates a
+	 * {@link TransformerFactoryConfig}.
+	 * 
+	 * @param config
+	 *            The ESB {@link ConfigTree}.
+	 * @return {@link TransformerFactoryConfig}.
+	 * @throws ConfigurationException
+	 */
+	protected TransformerFactoryConfig createConfig(final ConfigTree config)
+			throws ConfigurationException {
+		final Builder builder = new TransformerFactoryConfig.Builder();
+		extractFeatures(config, builder);
+		extractAttributes(config, builder);
+		createUrlResolver(config, builder);
+		builder.resultType(ResultFactory.ResultType.valueOf(config
+				.getRequiredAttribute("resultType")));
+		return builder.build();
+	}
+
+	/**
+	 * Method implementing a Templates cache. When the Templates object with the
+	 * corresponding ontologyMappingSchema key is not found in the cache, a new
+	 * instance is created and added to the cache.
+	 * 
+	 * @param ontologyMappingSchema
+	 *            the key used in the cache
+	 * @return the Templates object from the cache.
+	 * @throws TransformerConfigurationException
+	 * @throws ActionLifecycleException
+	 */
+	private Templates getTemplate(String ontologyMappingSchema)
+			throws TransformerConfigurationException, ActionLifecycleException {
+		if (!OntologyAction.templateCache.containsKey(ontologyMappingSchema)) {
+			OntologyAction.templateCache.put(ontologyMappingSchema, this
+					.createTemplate(ontologyMappingSchema));
+		}
+		return OntologyAction.templateCache.get(ontologyMappingSchema);
+	}
+
+	/**
+	 * 
+	 * @param templateFile
+	 * @return
+	 * @throws ActionLifecycleException
+	 * @throws TransformerConfigurationException
+	 */
+	private Templates createTemplate(final String templateFile)
+			throws ActionLifecycleException, TransformerConfigurationException {
+		InputStream stream = null;
+		try {
+			stream = StreamUtils.getResource(templateFile);
+			return factory.newTemplates(new StreamSource(stream));
+		} catch (final ConfigurationException e) {
+			throw new ActionLifecycleException(e.getMessage(), e);
+		} finally {
+			if (stream != null) {
+				try {
+					stream.close();
+				} catch (final IOException ignore) {
+					log.error("Exception while closing stream", ignore);
+				}
+			}
+		}
+	}
+
+	private boolean isEmpty(String value) {
+		if (value == null) {
+			return true;
+		} else {
+			return value.equals("");
+		}
+	}
+}



More information about the jboss-svn-commits mailing list