org.apache.camel.util.toolbox.XsltAggregationStrategy Maven / Gradle / Ivy
Show all versions of camel-core Show documentation
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.util.toolbox;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import org.w3c.dom.Document;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.builder.xml.XsltBuilder;
import org.apache.camel.builder.xml.XsltUriResolver;
import org.apache.camel.component.xslt.XsltEndpoint;
import org.apache.camel.component.xslt.XsltOutput;
import org.apache.camel.processor.aggregate.AggregationStrategy;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The XSLT Aggregation Strategy enables you to use XSL stylesheets to aggregate messages.
*
* Since XSLT does not directly support providing multiple XML payloads as an input, this aggregator injects
* the new incoming XML document (newExchange) into the oldExchange as an exchange property of
* type {@link Document}. The old exchange therefore remains accessible as the root context.
* This exchange property can then be accessed from your XSLT by declaring an {@code } at the top
* of your stylesheet:
*
*
*
*
*
*
*
*
*
*
*
*
* The exchange property name defaults to new-exchange but can be
* changed through {@link #setPropertyName(String)}.
*
* Some code bits have been copied from the {@link org.apache.camel.component.xslt.XsltEndpoint}.
*
*/
public class XsltAggregationStrategy implements AggregationStrategy {
private static final Logger LOG = LoggerFactory.getLogger(XsltAggregationStrategy.class);
private static final String DEFAULT_PROPERTY_NAME = "new-exchange";
private volatile XsltBuilder xslt;
private volatile URIResolver uriResolver;
private String propertyName;
private String xslFile;
private String transformerFactoryClass;
private XsltOutput output = XsltOutput.string;
/**
* Constructor.
*
* @param xslFileLocation location of the XSL transformation
*/
public XsltAggregationStrategy(String xslFileLocation) {
this.xslFile = xslFileLocation;
}
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
// guard against unlikely NPE
if (newExchange == null) {
return oldExchange;
}
// in the first call to this aggregation, do not call the XSLT but instead store the
// incoming exchange
if (oldExchange == null) {
return newExchange;
}
try {
// initialize if this is the first call
if (xslt == null) {
initialize(oldExchange.getContext());
}
oldExchange.setProperty(propertyName, newExchange.getIn().getBody(Document.class));
xslt.process(oldExchange);
return oldExchange;
} catch (Throwable e) {
oldExchange.setException(e);
}
return oldExchange;
}
public void setOutput(XsltOutput output) {
this.output = output;
}
public void setXslt(XsltBuilder xslt) {
this.xslt = xslt;
}
public void setUriResolver(URIResolver uriResolver) {
this.uriResolver = uriResolver;
}
public void setTransformerFactoryClass(String transformerFactoryClass) {
this.transformerFactoryClass = transformerFactoryClass;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
protected void initialize(CamelContext context) throws Exception {
// set the default property name if not set
this.propertyName = ObjectHelper.isNotEmpty(propertyName) ? propertyName : DEFAULT_PROPERTY_NAME;
// initialize the XsltBuilder
this.xslt = context.getInjector().newInstance(XsltBuilder.class);
if (transformerFactoryClass != null) {
Class factoryClass = context.getClassResolver().resolveMandatoryClass(transformerFactoryClass,
XsltAggregationStrategy.class.getClassLoader());
TransformerFactory factory = (TransformerFactory) context.getInjector().newInstance(factoryClass);
xslt.getConverter().setTransformerFactory(factory);
}
if (uriResolver == null) {
uriResolver = new XsltUriResolver(context.getClassResolver(), xslFile);
}
xslt.setUriResolver(uriResolver);
xslt.setFailOnNullBody(true);
xslt.transformerCacheSize(0);
xslt.setAllowStAX(true);
configureOutput(xslt, output.name());
loadResource(xslFile);
}
protected void configureOutput(XsltBuilder xslt, String output) throws Exception {
if (ObjectHelper.isEmpty(output)) {
return;
}
if ("string".equalsIgnoreCase(output)) {
xslt.outputString();
} else if ("bytes".equalsIgnoreCase(output)) {
xslt.outputBytes();
} else if ("DOM".equalsIgnoreCase(output)) {
xslt.outputDOM();
} else if ("file".equalsIgnoreCase(output)) {
xslt.outputFile();
} else {
throw new IllegalArgumentException("Unknown output type: " + output);
}
}
/**
* Loads the resource.
*
* @param resourceUri the resource to load
* @throws TransformerException is thrown if error loading resource
* @throws IOException is thrown if error loading resource
*/
protected void loadResource(String resourceUri) throws TransformerException, IOException {
LOG.trace("{} loading schema resource: {}", this, resourceUri);
Source source = xslt.getUriResolver().resolve(resourceUri, null);
if (source == null) {
throw new IOException("Cannot load schema resource " + resourceUri);
} else {
xslt.setTransformerSource(source);
}
}
// --- fluent builders ---
public static XsltAggregationStrategy create(String xslFile) {
return new XsltAggregationStrategy(xslFile);
}
public XsltAggregationStrategy withPropertyName(String propertyName) {
setPropertyName(propertyName);
return this;
}
public XsltAggregationStrategy withOutput(XsltOutput output) {
setOutput(output);
return this;
}
public XsltAggregationStrategy withUriResolver(URIResolver resolver) {
setUriResolver(resolver);
return this;
}
public XsltAggregationStrategy withTransformerFactoryClass(String clazz) {
setTransformerFactoryClass(clazz);
return this;
}
public XsltAggregationStrategy withSaxon() {
setTransformerFactoryClass(XsltEndpoint.SAXON_TRANSFORMER_FACTORY_CLASS_NAME);
return this;
}
}