All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.module.xml.routing.XmlMessageSplitter Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
/*
 * $Id: XmlMessageSplitter.java 23724 2012-01-26 02:32:14Z dirk.olmes $
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.module.xml.routing;

import org.mule.api.MuleMessage;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.registry.RegistrationException;
import org.mule.config.i18n.CoreMessages;
import org.mule.module.xml.util.NamespaceManager;
import org.mule.routing.CorrelationMode;
import org.mule.routing.outbound.AbstractRoundRobinMessageSplitter;
import org.mule.util.ExceptionUtils;
import org.mule.util.IOUtils;
import org.mule.util.StringUtils;

import java.io.InputStream;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.DOMReader;
import org.dom4j.io.SAXReader;

/**
 * XmlMessageSplitter will split a DOM4J document into nodes
 * based on the "splitExpression" property. 

Optionally, you can specify a * namespaces property map that contain prefix/namespace mappings. * Mind if you have a default namespace declared you should map it to some namespace, * and reference it in the splitExpression property.

The splitter * can optionally validate against an XML schema. By default schema validation is * turned off.

You may reference an external schema from the classpath by using * the externalSchemaLocation property.

Note that each part * returned is actually returned as a new Document. */ public class XmlMessageSplitter extends AbstractRoundRobinMessageSplitter { // xml parser feature names for optional XSD validation public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema"; public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING = "http://apache.org/xml/features/validation/schema-full-checking"; // JAXP property for specifying external XSD location public static final String JAXP_PROPERTIES_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; // JAXP properties for specifying external XSD language (as required by newer // JAXP implementation) public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE = "http://www.w3.org/2001/XMLSchema"; protected volatile String splitExpression = ""; protected volatile Map namespaces; protected NamespaceManager namespaceManager; protected volatile boolean validateSchema; protected volatile String externalSchemaLocation = ""; public void setSplitExpression(String splitExpression) { this.splitExpression = StringUtils.trimToEmpty(splitExpression); } public void setNamespaces(Map namespaces) { this.namespaces = namespaces; } public Map getNamespaces() { return Collections.unmodifiableMap(namespaces); } public String getSplitExpression() { return splitExpression; } public boolean isValidateSchema() { return validateSchema; } public void setValidateSchema(boolean validateSchema) { this.validateSchema = validateSchema; } public String getExternalSchemaLocation() { return externalSchemaLocation; } /** * Set classpath location of the XSD to check against. If the resource cannot be * found, an exception will be thrown at runtime. * * @param externalSchemaLocation location of XSD */ public void setExternalSchemaLocation(String externalSchemaLocation) { this.externalSchemaLocation = externalSchemaLocation; } @Override public void initialise() throws InitialisationException { logger.warn("Deprecation warning: The XmlMessageSplitter router has been deprecating in Mule 2.2 in favour of using the router."); if (StringUtils.isBlank(splitExpression)) { throw new IllegalArgumentException(CoreMessages.objectIsNull("splitExpression").getMessage()); } try { namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class); if (namespaceManager != null) { if (namespaces == null) { namespaces = new HashMap(namespaceManager.getNamespaces()); } else { namespaces.putAll(namespaceManager.getNamespaces()); } } } catch (RegistrationException e) { throw new InitialisationException(CoreMessages.failedToLoad("NamespaceManager"), e, this); } super.initialise(); } /** * Template method can be used to split the message up before the getMessagePart * method is called . * * @param message the message being routed */ @Override protected List splitMessage(MuleMessage message) { if (logger.isDebugEnabled()) { if (splitExpression.length() == 0) { logger.warn("splitExpression is not specified, no processing will take place"); } else { logger.debug("splitExpression is " + splitExpression); } } Object src = message.getPayload(); try { if (src instanceof byte[]) { src = new String((byte[]) src); } Document dom4jDoc; if (src instanceof String) { String xml = (String) src; SAXReader reader = new SAXReader(); setDoSchemaValidation(reader, isValidateSchema()); dom4jDoc = reader.read(new StringReader(xml)); } else if (src instanceof org.dom4j.Document) { dom4jDoc = (org.dom4j.Document) src; } else if (src instanceof org.w3c.dom.Document) { DOMReader xmlReader = new DOMReader(); dom4jDoc = xmlReader.read((org.w3c.dom.Document)src); } else { throw new IllegalArgumentException(CoreMessages.objectNotOfCorrectType( src.getClass(), new Class[]{org.w3c.dom.Document.class, Document.class, String.class, byte[].class}).getMessage()); } XPath xpath = dom4jDoc.createXPath(splitExpression); if (namespaces != null) { xpath.setNamespaceURIs(namespaces); } List foundNodes = xpath.selectNodes(dom4jDoc); if (enableCorrelation != CorrelationMode.NEVER) { message.setCorrelationGroupSize(foundNodes.size()); } if (logger.isDebugEnabled()) { logger.debug("Split into " + foundNodes.size()); } List parts = new LinkedList(); // Rather than reparsing these when individual messages are // created, lets do it now // We can also avoid parsing the Xml again altogether for (Iterator iterator = foundNodes.iterator(); iterator.hasNext();) { Node node = (Node) iterator.next(); if (node instanceof Element) { // Can't do detach here just in case the source object // was a document. node = (Node) node.clone(); parts.add(DocumentHelper.createDocument((Element) node)); } else { logger.warn("Dcoument node: " + node.asXML() + " is not an element and thus is not a valid part"); } } return parts; } catch (Exception ex) { throw new IllegalArgumentException("Failed to initialise the payload: " + ExceptionUtils.getStackTrace(ex)); } } protected void setDoSchemaValidation(SAXReader reader, boolean validate) throws Exception { reader.setValidation(validate); reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA, validate); reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, true); // By default we're not validating against an XSD. If this is the case, // there's no need to continue here, so we bail. if (!validate) { return; } InputStream xsdAsStream = IOUtils.getResourceAsStream(getExternalSchemaLocation(), getClass()); if (xsdAsStream == null) { throw new IllegalArgumentException("Couldn't find schema at " + getExternalSchemaLocation()); } // Set schema language property (must be done before the schemaSource // is set) reader.setProperty(JAXP_PROPERTIES_SCHEMA_LANGUAGE, JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE); // Need this one to map schemaLocation to a physical location reader.setProperty(JAXP_PROPERTIES_SCHEMA_SOURCE, xsdAsStream); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy