Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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.builder.xml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.ErrorListener;
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.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.apache.camel.Exchange;
import org.apache.camel.ExpectedBodyTypeException;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.RuntimeTransformException;
import org.apache.camel.TypeConverter;
import org.apache.camel.converter.jaxp.StAX2SAXSource;
import org.apache.camel.converter.jaxp.XmlConverter;
import org.apache.camel.support.SynchronizationAdapter;
import org.apache.camel.util.ExchangeHelper;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.IOHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.camel.util.ObjectHelper.notNull;
/**
* Creates a Processor
* which performs an XSLT transformation of the IN message body.
*
* Will by default output the result as a String. You can chose which kind of output
* you want using the outputXXX methods.
*
* @version
*/
public class XsltBuilder implements Processor {
private static final Logger LOG = LoggerFactory.getLogger(XsltBuilder.class);
private Map parameters = new HashMap();
private XmlConverter converter = new XmlConverter();
private Templates template;
private volatile BlockingQueue transformers;
private ResultHandlerFactory resultHandlerFactory = new StringResultHandlerFactory();
private boolean failOnNullBody = true;
private URIResolver uriResolver;
private boolean deleteOutputFile;
private ErrorListener errorListener;
private boolean allowStAX = true;
private EntityResolver entityResolver;
public XsltBuilder() {
}
public XsltBuilder(Templates templates) {
this.template = templates;
}
@Override
public String toString() {
return "XSLT[" + template + "]";
}
public void process(Exchange exchange) throws Exception {
notNull(getTemplate(), "template");
if (isDeleteOutputFile()) {
// add on completion so we can delete the file when the Exchange is done
String fileName = ExchangeHelper.getMandatoryHeader(exchange, Exchange.XSLT_FILE_NAME, String.class);
exchange.addOnCompletion(new XsltBuilderOnCompletion(fileName));
}
Transformer transformer = getTransformer();
configureTransformer(transformer, exchange);
ResultHandler resultHandler = resultHandlerFactory.createResult(exchange);
Result result = resultHandler.getResult();
// let's copy the headers before we invoke the transform in case they modify them
Message out = exchange.getOut();
out.copyFrom(exchange.getIn());
// the underlying input stream, which we need to close to avoid locking files or other resources
InputStream is = null;
try {
Source source;
// only convert to input stream if really needed
if (isInputStreamNeeded(exchange)) {
is = exchange.getIn().getBody(InputStream.class);
source = getSource(exchange, is);
} else {
Object body = exchange.getIn().getBody();
source = getSource(exchange, body);
}
if (source instanceof StAXSource) {
// Always convert StAXSource to SAXSource.
// * Xalan and Saxon-B don't support StAXSource.
// * The JDK default implementation (XSLTC) doesn't handle CDATA events
// (see com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX).
// * Saxon-HE/PE/EE seem to support StAXSource, but don't advertise this
// officially (via TransformerFactory.getFeature(StAXSource.FEATURE))
source = new StAX2SAXSource(((StAXSource) source).getXMLStreamReader());
}
LOG.trace("Using {} as source", source);
transformer.transform(source, result);
LOG.trace("Transform complete with result {}", result);
resultHandler.setBody(out);
} finally {
releaseTransformer(transformer);
// IOHelper can handle if is is null
IOHelper.close(is);
}
}
// Builder methods
// -------------------------------------------------------------------------
/**
* Creates an XSLT processor using the given templates instance
*/
public static XsltBuilder xslt(Templates templates) {
return new XsltBuilder(templates);
}
/**
* Creates an XSLT processor using the given XSLT source
*/
public static XsltBuilder xslt(Source xslt) throws TransformerConfigurationException {
notNull(xslt, "xslt");
XsltBuilder answer = new XsltBuilder();
answer.setTransformerSource(xslt);
return answer;
}
/**
* Creates an XSLT processor using the given XSLT source
*/
public static XsltBuilder xslt(File xslt) throws TransformerConfigurationException {
notNull(xslt, "xslt");
return xslt(new StreamSource(xslt));
}
/**
* Creates an XSLT processor using the given XSLT source
*/
public static XsltBuilder xslt(URL xslt) throws TransformerConfigurationException, IOException {
notNull(xslt, "xslt");
return xslt(xslt.openStream());
}
/**
* Creates an XSLT processor using the given XSLT source
*/
public static XsltBuilder xslt(InputStream xslt) throws TransformerConfigurationException, IOException {
notNull(xslt, "xslt");
return xslt(new StreamSource(xslt));
}
/**
* Sets the output as being a byte[]
*/
public XsltBuilder outputBytes() {
setResultHandlerFactory(new StreamResultHandlerFactory());
return this;
}
/**
* Sets the output as being a String
*/
public XsltBuilder outputString() {
setResultHandlerFactory(new StringResultHandlerFactory());
return this;
}
/**
* Sets the output as being a DOM
*/
public XsltBuilder outputDOM() {
setResultHandlerFactory(new DomResultHandlerFactory());
return this;
}
/**
* Sets the output as being a File where the filename
* must be provided in the {@link Exchange#XSLT_FILE_NAME} header.
*/
public XsltBuilder outputFile() {
setResultHandlerFactory(new FileResultHandlerFactory());
return this;
}
/**
* Should the output file be deleted when the {@link Exchange} is done.
*
* This option should only be used if you use {@link #outputFile()} as well.
*/
public XsltBuilder deleteOutputFile() {
this.deleteOutputFile = true;
return this;
}
public XsltBuilder parameter(String name, Object value) {
parameters.put(name, value);
return this;
}
/**
* Sets a custom URI resolver to be used
*/
public XsltBuilder uriResolver(URIResolver uriResolver) {
setUriResolver(uriResolver);
return this;
}
/**
* Enables to allow using StAX.
*
* When enabled StAX is preferred as the first choice as {@link Source}.
*/
public XsltBuilder allowStAX() {
setAllowStAX(true);
return this;
}
/**
* Used for caching {@link Transformer}s.
*
* By default no caching is in use.
*
* @param numberToCache the maximum number of transformers to cache
*/
public XsltBuilder transformerCacheSize(int numberToCache) {
if (numberToCache > 0) {
transformers = new ArrayBlockingQueue(numberToCache);
} else {
transformers = null;
}
return this;
}
/**
* Uses a custom {@link javax.xml.transform.ErrorListener}.
*/
public XsltBuilder errorListener(ErrorListener errorListener) {
setErrorListener(errorListener);
return this;
}
// Properties
// -------------------------------------------------------------------------
public Map getParameters() {
return parameters;
}
public void setParameters(Map parameters) {
this.parameters = parameters;
}
public void setTemplate(Templates template) {
this.template = template;
if (transformers != null) {
transformers.clear();
}
}
public Templates getTemplate() {
return template;
}
public boolean isFailOnNullBody() {
return failOnNullBody;
}
public void setFailOnNullBody(boolean failOnNullBody) {
this.failOnNullBody = failOnNullBody;
}
public ResultHandlerFactory getResultHandlerFactory() {
return resultHandlerFactory;
}
public void setResultHandlerFactory(ResultHandlerFactory resultHandlerFactory) {
this.resultHandlerFactory = resultHandlerFactory;
}
public boolean isAllowStAX() {
return allowStAX;
}
public void setAllowStAX(boolean allowStAX) {
this.allowStAX = allowStAX;
}
/**
* Sets the XSLT transformer from a Source
*
* @param source the source
* @throws TransformerConfigurationException is thrown if creating a XSLT transformer failed.
*/
public void setTransformerSource(Source source) throws TransformerConfigurationException {
TransformerFactory factory = converter.getTransformerFactory();
if (errorListener != null) {
factory.setErrorListener(errorListener);
} else {
// use a logger error listener so users can see from the logs what the error may be
factory.setErrorListener(new XsltErrorListener());
}
if (getUriResolver() != null) {
factory.setURIResolver(getUriResolver());
}
// Check that the call to newTemplates() returns a valid template instance.
// In case of an xslt parse error, it will return null and we should stop the
// deployment and raise an exception as the route will not be setup properly.
Templates templates = factory.newTemplates(source);
if (templates != null) {
setTemplate(templates);
} else {
throw new TransformerConfigurationException("Error creating XSLT template. "
+ "This is most likely be caused by a XML parse error. "
+ "Please verify your XSLT file configured.");
}
}
/**
* Sets the XSLT transformer from a File
*/
public void setTransformerFile(File xslt) throws TransformerConfigurationException {
setTransformerSource(new StreamSource(xslt));
}
/**
* Sets the XSLT transformer from a URL
*/
public void setTransformerURL(URL url) throws TransformerConfigurationException, IOException {
notNull(url, "url");
setTransformerInputStream(url.openStream());
}
/**
* Sets the XSLT transformer from the given input stream
*/
public void setTransformerInputStream(InputStream in) throws TransformerConfigurationException, IOException {
notNull(in, "InputStream");
setTransformerSource(new StreamSource(in));
}
public XmlConverter getConverter() {
return converter;
}
public void setConverter(XmlConverter converter) {
this.converter = converter;
}
public URIResolver getUriResolver() {
return uriResolver;
}
public void setUriResolver(URIResolver uriResolver) {
this.uriResolver = uriResolver;
}
public void setEntityResolver(EntityResolver entityResolver) {
this.entityResolver = entityResolver;
}
public boolean isDeleteOutputFile() {
return deleteOutputFile;
}
public void setDeleteOutputFile(boolean deleteOutputFile) {
this.deleteOutputFile = deleteOutputFile;
}
public ErrorListener getErrorListener() {
return errorListener;
}
public void setErrorListener(ErrorListener errorListener) {
this.errorListener = errorListener;
}
// Implementation methods
// -------------------------------------------------------------------------
private void releaseTransformer(Transformer transformer) {
if (transformers != null) {
transformer.reset();
transformers.offer(transformer);
}
}
private Transformer getTransformer() throws Exception {
Transformer t = null;
if (transformers != null) {
t = transformers.poll();
}
if (t == null) {
t = createTransformer();
}
return t;
}
protected Transformer createTransformer() throws Exception {
return getTemplate().newTransformer();
}
/**
* Checks whether we need an {@link InputStream} to access the message body.
*
* Depending on the content in the message body, we may not need to convert
* to {@link InputStream}.
*
* @param exchange the current exchange
* @return true to convert to {@link InputStream} beforehand converting to {@link Source} afterwards.
*/
protected boolean isInputStreamNeeded(Exchange exchange) {
Object body = exchange.getIn().getBody();
if (body == null) {
return false;
}
if (body instanceof InputStream) {
return true;
} else if (body instanceof Source) {
return false;
} else if (body instanceof String) {
return false;
} else if (body instanceof byte[]) {
return false;
} else if (body instanceof Node) {
return false;
} else if (exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass()) != null) {
//there is a direct and hopefully optimized converter to Source
return false;
}
// yes an input stream is needed
return true;
}
/**
* Converts the inbound body to a {@link Source}, if the body is not already a {@link Source}.
*
* This implementation will prefer to source in the following order:
*
*
StAX - If StAX is allowed
*
SAX - SAX as 2nd choice
*
Stream - Stream as 3rd choice
*
DOM - DOM as 4th choice
*
*/
protected Source getSource(Exchange exchange, Object body) {
// body may already be a source
if (body instanceof Source) {
return (Source) body;
}
Source source = null;
if (body != null) {
if (isAllowStAX()) {
// try StAX if enabled
source = exchange.getContext().getTypeConverter().tryConvertTo(StAXSource.class, exchange, body);
}
if (source == null) {
// then try SAX
source = exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, exchange, body);
tryAddEntityResolver((SAXSource)source);
}
if (source == null) {
// then try stream
source = exchange.getContext().getTypeConverter().tryConvertTo(StreamSource.class, exchange, body);
}
if (source == null) {
// and fallback to DOM
source = exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, exchange, body);
}
// as the TypeConverterRegistry will look up source the converter differently if the type converter is loaded different
// now we just put the call of source converter at last
if (source == null) {
TypeConverter tc = exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass());
if (tc != null) {
source = tc.convertTo(Source.class, exchange, body);
}
}
}
if (source == null) {
if (isFailOnNullBody()) {
throw new ExpectedBodyTypeException(exchange, Source.class);
} else {
try {
source = converter.toDOMSource(converter.createDocument());
} catch (ParserConfigurationException e) {
throw new RuntimeTransformException(e);
}
}
}
return source;
}
private void tryAddEntityResolver(SAXSource source) {
//expecting source to have not null XMLReader
if (this.entityResolver != null && source != null) {
source.getXMLReader().setEntityResolver(this.entityResolver);
}
}
/**
* Configures the transformer with exchange specific parameters
*/
protected void configureTransformer(Transformer transformer, Exchange exchange) throws Exception {
if (uriResolver == null) {
uriResolver = new XsltUriResolver(exchange.getContext(), null);
}
transformer.setURIResolver(uriResolver);
if (errorListener == null) {
// set our error listener so we can capture errors and report them back on the exchange
transformer.setErrorListener(new DefaultTransformErrorHandler(exchange));
} else {
// use custom error listener
transformer.setErrorListener(errorListener);
}
transformer.clearParameters();
addParameters(transformer, exchange.getProperties());
addParameters(transformer, exchange.getIn().getHeaders());
addParameters(transformer, getParameters());
transformer.setParameter("exchange", exchange);
transformer.setParameter("in", exchange.getIn());
transformer.setParameter("out", exchange.getOut());
}
protected void addParameters(Transformer transformer, Map map) {
Set> propertyEntries = map.entrySet();
for (Map.Entry entry : propertyEntries) {
String key = entry.getKey();
Object value = entry.getValue();
if (value != null) {
LOG.trace("Transformer set parameter {} -> {}", key, value);
transformer.setParameter(key, value);
}
}
}
private static final class XsltBuilderOnCompletion extends SynchronizationAdapter {
private final String fileName;
private XsltBuilderOnCompletion(String fileName) {
this.fileName = fileName;
}
@Override
public void onDone(Exchange exchange) {
FileUtil.deleteFile(new File(fileName));
}
@Override
public String toString() {
return "XsltBuilderOnCompletion";
}
}
}