INT-1812 namespace parser for xsl transformer now sets always use source and result factories if result factory or type is specified

This commit is contained in:
Jonas Partner
2011-03-08 17:29:26 +00:00
parent 3a1bd0fdcd
commit 653c61e8d1
8 changed files with 580 additions and 389 deletions

View File

@@ -61,6 +61,10 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser {
builder.addConstructorArgReference(xslTemplates);
}
XmlNamespaceUtils.configureResultFactory(builder, resultType, resultFactory);
boolean resultFactorySpecified = StringUtils.hasText(resultFactory) || StringUtils.hasText(resultType);
if(resultFactorySpecified){
builder.addPropertyValue("alwaysUseResultFactory", true);
}
if (StringUtils.hasText(resultTransformer)) {
builder.addConstructorArgReference(resultTransformer);
}
@@ -88,7 +92,9 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser {
}
builder.addPropertyValue("xslParameterMappings", xslParameterMappings);
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "source-factory");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "source-factory");
}
}

View File

@@ -70,188 +70,225 @@ import org.w3c.dom.Document;
* payload and the {@link Result} to pass into the transformer. An instance of
* {@link ResultTransformer} can also be provided to convert the Result prior to
* returning.
*
*
* @author Jonas Partner
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class XsltPayloadTransformer extends AbstractTransformer {
private final Log logger = LogFactory.getLog(this.getClass());
private final Log logger = LogFactory.getLog(this.getClass());
private final Templates templates;
private final Templates templates;
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
private Map<String, Expression> xslParameterMappings;
private Map<String, Expression> xslParameterMappings;
private final ResultTransformer resultTransformer;
private final ResultTransformer resultTransformer;
private volatile SourceFactory sourceFactory = new DomSourceFactory();
private volatile SourceFactory sourceFactory = new DomSourceFactory();
private volatile ResultFactory resultFactory = new DomResultFactory();
private volatile ResultFactory resultFactory = new DomResultFactory();
private volatile boolean alwaysUseSourceResultFactories = false;
private volatile boolean alwaysUseSourceFactory = false;
private volatile String[] xsltParamHeaders;
private volatile boolean alwaysUseResultFactory = false;
private volatile String[] xsltParamHeaders;
public XsltPayloadTransformer(Templates templates) throws ParserConfigurationException {
this(templates, null);
}
public XsltPayloadTransformer(Templates templates) throws ParserConfigurationException {
this(templates, null);
}
public XsltPayloadTransformer(Resource xslResource) throws Exception {
this(TransformerFactory.newInstance().newTemplates(createStreamSourceOnResource(xslResource)), null);
}
public XsltPayloadTransformer(Resource xslResource) throws Exception {
this(TransformerFactory.newInstance().newTemplates(createStreamSourceOnResource(xslResource)), null);
}
public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer) throws Exception {
this(TransformerFactory.newInstance().newTemplates(createStreamSourceOnResource(xslResource)), resultTransformer);
}
public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer) throws Exception {
this(TransformerFactory.newInstance().newTemplates(createStreamSourceOnResource(xslResource)), resultTransformer);
}
public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) throws ParserConfigurationException {
this.templates = templates;
this.resultTransformer = resultTransformer;
this.evaluationContext.addPropertyAccessor(new MapAccessor());
}
public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) throws ParserConfigurationException {
this.templates = templates;
this.resultTransformer = resultTransformer;
this.evaluationContext.addPropertyAccessor(new MapAccessor());
}
/**
* Sets the SourceFactory.
*/
public void setSourceFactory(SourceFactory sourceFactory) {
Assert.notNull(sourceFactory, "SourceFactory must not be null");
this.sourceFactory = sourceFactory;
}
/**
* Sets the SourceFactory.
*/
public void setSourceFactory(SourceFactory sourceFactory) {
Assert.notNull(sourceFactory, "SourceFactory must not be null");
this.sourceFactory = sourceFactory;
}
/**
* Sets the ResultFactory
*/
public void setResultFactory(ResultFactory resultFactory) {
Assert.notNull(sourceFactory, "ResultFactory must not be null");
this.resultFactory = resultFactory;
}
/**
* Specifies whether {@link ResultFactory} and {@link SourceFactory} should always
* be used, even for directly supported payloads such as {@link String} and {@link Document}.
*/
public void setAlwaysUseSourceResultFactories(boolean alwaysUseSourceResultFactories) {
this.alwaysUseSourceResultFactories = alwaysUseSourceResultFactories;
}
public void setXslParameterMappings(Map<String, Expression> xslParameterMappings) {
this.xslParameterMappings = xslParameterMappings;
}
public void setXsltParamHeaders(String[] xsltParamHeaders) {
this.xsltParamHeaders = xsltParamHeaders;
}
public String getComponentType() {
return "xml:xslt-transformer";
}
@Override
protected Object doTransform(Message<?> message) throws Exception {
Transformer transformer = buildTransformer(message);
Object payload = message.getPayload();
Object transformedPayload = null;
if (this.alwaysUseSourceResultFactories) {
transformedPayload = transformUsingFactories(payload, transformer);
}
else if (payload instanceof String) {
transformedPayload = transformString((String) payload, transformer);
}
else if (payload instanceof Document) {
transformedPayload = transformDocument((Document) payload, transformer);
}
else if (payload instanceof Source) {
transformedPayload = transformSource((Source) payload, payload, transformer);
}
else {
// fall back to trying factories
transformedPayload = transformUsingFactories(payload, transformer);
}
return transformedPayload;
}
private Object transformUsingFactories(Object payload, Transformer transformer) throws TransformerException {
Source source = this.sourceFactory.createSource(payload);
return transformSource(source, payload, transformer);
}
private Object transformSource(Source source, Object payload, Transformer transformer) throws TransformerException {
Result result = this.resultFactory.createResult(payload);
transformer.transform(source, result);
if (this.resultTransformer != null) {
return this.resultTransformer.transformResult(result);
}
return result;
}
private String transformString(String stringPayload, Transformer transformer) throws TransformerException {
StringResult result = new StringResult();
transformer.transform(new StringSource(stringPayload), result);
return result.toString();
}
private Document transformDocument(Document documentPayload, Transformer transformer) throws TransformerException {
DOMSource source = new DOMSource(documentPayload);
Result result = this.resultFactory.createResult(documentPayload);
if (!DOMResult.class.isAssignableFrom(result.getClass())) {
throw new MessagingException(
"Document to Document conversion requires a DOMResult-producing ResultFactory implementation.");
}
DOMResult domResult = (DOMResult) result;
transformer.transform(source, domResult);
return (Document) domResult.getNode();
}
private Transformer buildTransformer(Message<?> message) throws TransformerException {
//process individual mappings
Transformer transformer = this.templates.newTransformer();
if (this.xslParameterMappings != null){
for (String parameterName: this.xslParameterMappings.keySet()) {
Expression expression = this.xslParameterMappings.get(parameterName);
try {
Object value = expression.getValue(this.evaluationContext, message);
transformer.setParameter(parameterName, value);
}
catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("Evaluation of header expression '" + expression.getExpressionString() +
"' failed. The XSLT parameter '" + parameterName + "' will be skipped.");
}
}
}
}
// process xslt-parameter-headers
MessageHeaders headers = message.getHeaders();
if (!ObjectUtils.isEmpty(this.xsltParamHeaders)) {
for (String headerName : headers.keySet()) {
if (PatternMatchUtils.simpleMatch(this.xsltParamHeaders, headerName)) {
transformer.setParameter(headerName, headers.get(headerName));
}
}
}
return transformer;
}
/**
* Sets the ResultFactory
*/
public void setResultFactory(ResultFactory resultFactory) {
Assert.notNull(sourceFactory, "ResultFactory must not be null");
this.resultFactory = resultFactory;
}
/**
* Compensate for the fact that a Resource <i>may</i> not be a File or even
* addressable through a URI. If it is, we want the created StreamSource to
* read other resources relative to the provided one. If it isn't, it loads
* from the default path.
*/
private static StreamSource createStreamSourceOnResource(Resource xslResource) throws IOException {
try {
String systemId = xslResource.getURI().toString();
return new StreamSource(xslResource.getInputStream(), systemId);
}
catch (IOException e) {
return new StreamSource(xslResource.getInputStream());
}
}
/**
* User source factory even for directly supported payloads
*
* @return
*/
public void setAlwaysUseSourceFactory(boolean alwaysUseSourceFactory) {
this.alwaysUseSourceFactory = alwaysUseSourceFactory;
}
/**
* Always use result factory even for directly supported payload types
*
* @param alwaysUseResultFactory
*/
public void setAlwaysUseResultFactory(boolean alwaysUseResultFactory) {
this.alwaysUseResultFactory = alwaysUseResultFactory;
}
public void setXslParameterMappings(Map<String, Expression> xslParameterMappings) {
this.xslParameterMappings = xslParameterMappings;
}
public void setXsltParamHeaders(String[] xsltParamHeaders) {
this.xsltParamHeaders = xsltParamHeaders;
}
public String getComponentType() {
return "xml:xslt-transformer";
}
@Override
protected Object doTransform(Message<?> message) throws Exception {
Transformer transformer = buildTransformer(message);
Object payload;
if (this.alwaysUseSourceFactory) {
payload = sourceFactory.createSource(message.getPayload());
} else {
payload = message.getPayload();
}
Object transformedPayload = null;
if (this.alwaysUseResultFactory) {
transformedPayload = transformUsingResultFactory(payload, transformer);
} else if (payload instanceof String) {
transformedPayload = transformString((String) payload, transformer);
} else if (payload instanceof Document) {
transformedPayload = transformDocument((Document) payload, transformer);
} else if (payload instanceof Source) {
transformedPayload = transformSource((Source) payload, payload, transformer);
} else {
// fall back to trying factories
transformedPayload = transformUsingResultFactory(payload, transformer);
}
return transformedPayload;
}
private Object transformUsingResultFactory(Object payload, Transformer transformer) throws TransformerException {
Source source;
if (this.alwaysUseSourceFactory) {
source = this.sourceFactory.createSource(payload);
} else if (payload instanceof String) {
source = new StringSource((String) payload);
} else if (payload instanceof Document) {
source = new DOMSource((Document) payload);
} else if (payload instanceof Source) {
source = (Source) payload;
} else {
source = this.sourceFactory.createSource(payload);
}
return transformSource(source, payload, transformer);
}
private Object transformSource(Source source, Object payload, Transformer transformer) throws TransformerException {
Result result = this.resultFactory.createResult(payload);
transformer.transform(source, result);
if (this.resultTransformer != null) {
return this.resultTransformer.transformResult(result);
}
return result;
}
private String transformString(String stringPayload, Transformer transformer) throws TransformerException {
StringResult result = new StringResult();
Source source;
if (this.alwaysUseSourceFactory) {
source = this.sourceFactory.createSource(stringPayload);
} else {
source = new StringSource(stringPayload);
}
transformer.transform(source, result);
return result.toString();
}
private Document transformDocument(Document documentPayload, Transformer transformer) throws TransformerException {
Source source;
if (this.alwaysUseSourceFactory) {
source = this.sourceFactory.createSource(documentPayload);
} else {
source = new DOMSource(documentPayload);
}
Result result = this.resultFactory.createResult(documentPayload);
if (!DOMResult.class.isAssignableFrom(result.getClass())) {
throw new MessagingException(
"Document to Document conversion requires a DOMResult-producing ResultFactory implementation.");
}
DOMResult domResult = (DOMResult) result;
transformer.transform(source, domResult);
return (Document) domResult.getNode();
}
private Transformer buildTransformer(Message<?> message) throws TransformerException {
//process individual mappings
Transformer transformer = this.templates.newTransformer();
if (this.xslParameterMappings != null) {
for (String parameterName : this.xslParameterMappings.keySet()) {
Expression expression = this.xslParameterMappings.get(parameterName);
try {
Object value = expression.getValue(this.evaluationContext, message);
transformer.setParameter(parameterName, value);
} catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("Evaluation of header expression '" + expression.getExpressionString() +
"' failed. The XSLT parameter '" + parameterName + "' will be skipped.");
}
}
}
}
// process xslt-parameter-headers
MessageHeaders headers = message.getHeaders();
if (!ObjectUtils.isEmpty(this.xsltParamHeaders)) {
for (String headerName : headers.keySet()) {
if (PatternMatchUtils.simpleMatch(this.xsltParamHeaders, headerName)) {
transformer.setParameter(headerName, headers.get(headerName));
}
}
}
return transformer;
}
/**
* Compensate for the fact that a Resource <i>may</i> not be a File or even
* addressable through a URI. If it is, we want the created StreamSource to
* read other resources relative to the provided one. If it isn't, it loads
* from the default path.
*/
private static StreamSource createStreamSourceOnResource(Resource xslResource) throws IOException {
try {
String systemId = xslResource.getURI().toString();
return new StreamSource(xslResource.getInputStream(), systemId);
} catch (IOException e) {
return new StreamSource(xslResource.getInputStream());
}
}
}