This commit is contained in:
Oleg Zhurakousky
2010-08-27 14:26:50 +00:00
parent 2e1ba3efc0
commit 12a82618c3
11 changed files with 312 additions and 297 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,18 +16,25 @@
package org.springframework.integration.xml.config;
import org.w3c.dom.Element;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractTransformerParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* @author Jonas Partner
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class XsltPayloadTransformerParser extends AbstractTransformerParser {
@@ -43,6 +50,7 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser {
String resultTransformer = element.getAttribute("result-transformer");
String resultFactory = element.getAttribute("result-factory");
String resultType = element.getAttribute("result-type");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "xslt-param-headers");
Assert.isTrue(StringUtils.hasText(xslResource) ^ StringUtils.hasText(xslTemplates),
"Exactly one of 'xsl-resource' or 'xsl-templates' is required.");
if (StringUtils.hasText(xslResource)) {
@@ -55,7 +63,33 @@ public class XsltPayloadTransformerParser extends AbstractTransformerParser {
if (StringUtils.hasText(resultTransformer)) {
builder.addConstructorArgReference(resultTransformer);
}
List<Element> xslParameterElements = DomUtils.getChildElementsByTagName(element, "xslt-param");
if (!CollectionUtils.isEmpty(xslParameterElements)) {
Map<String, Object> xslParameterMappings = new ManagedMap<String, Object>();
for (Element xslParameterElement : xslParameterElements) {
String name = xslParameterElement.getAttribute("name");
String expression = xslParameterElement.getAttribute("expression");
String value = xslParameterElement.getAttribute("value");
Assert.isTrue(StringUtils.hasText(expression) ^ StringUtils.hasText(value),
"Exactly one of 'expression' or 'value' is required.");
RootBeanDefinition expressionDef = null;
if (StringUtils.hasText(value)){
expressionDef = new RootBeanDefinition("org.springframework.expression.common.LiteralExpression");
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(value);
} else if (StringUtils.hasText(expression)){
expressionDef = new RootBeanDefinition("org.springframework.integration.config.ExpressionFactoryBean");
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(expression);
}
if (expressionDef != null) {
xslParameterMappings.put(name, expressionDef);
}
}
builder.addPropertyValue("xslParameterMappings", xslParameterMappings);
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "source-factory");
}
}

View File

@@ -1,79 +0,0 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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.springframework.integration.xml.transformer;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Transformer;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
/**
* {@link TransformerConfigurer} instance which looks for headers and uses them
* to configure the provided {@link Transformer} instance. For example a header
* named 'xslt_parameter_X' will cause the transformer to be configured with a
* property named 'X' with the value of the header. A property named
* 'xslt_output_property_X' will cause an output property on the transformer to be
* set with this header's value.
*
* @author Jonas Partner
*/
public class DefaultTransformerConfigurer implements TransformerConfigurer {
public void configureTransformer(Message<?> message, Transformer transformer) {
Map<String,Object> parameters = extractParameterHeaders(message.getHeaders());
for (String paramName: parameters.keySet()) {
transformer.setParameter(paramName, parameters.get(paramName));
}
Map<String, String> outputProperties = extractOutputPropertyHeaders(message.getHeaders());
for (String outputPropertyName : outputProperties.keySet()) {
transformer.setOutputProperty(outputPropertyName, outputProperties.get(outputPropertyName));
}
}
protected Map<String, String> extractOutputPropertyHeaders(MessageHeaders headers) {
Map<String, String> parameters = new HashMap<String, String>();
int prefixStringLength = XsltHeaders.OUTPUT_PROPERTY.length();
for (String key : headers.keySet()) {
if (key.startsWith(XsltHeaders.OUTPUT_PROPERTY)) {
Object headerValue = headers.get(key);
if (!(headerValue instanceof String)) {
throw new IllegalArgumentException(
"XSLT Transformer only supports String output properties received header of type "
+ headerValue.getClass().getName()
+ " for header named " + key);
}
parameters.put(key.substring(prefixStringLength), (String) headerValue);
}
}
return parameters;
}
protected Map<String, Object> extractParameterHeaders(MessageHeaders headers) {
Map<String, Object> parameters = new HashMap<String, Object>();
int prefixStringLength = XsltHeaders.PARAMETER.length();
for (String key : headers.keySet()) {
if (key.startsWith(XsltHeaders.PARAMETER)) {
parameters.put(key.substring(prefixStringLength), headers.get(key));
}
}
return parameters;
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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.springframework.integration.xml.transformer;
import javax.xml.transform.Transformer;
import org.springframework.integration.Message;
/**
* Allows customization of the transformer based on the received message prior to transformation.
*
* @author Jonas Partner
*/
public interface TransformerConfigurer {
/**
* Callback method called by XSLT transformer implementations after transformer is created.
*/
public void configureTransformer(Message<?> message, Transformer transformer);
}

View File

@@ -16,6 +16,10 @@
package org.springframework.integration.xml.transformer;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -27,10 +31,16 @@ import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.io.Resource;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.MessagingException;
import org.springframework.integration.transformer.AbstractTransformer;
import org.springframework.integration.xml.result.DomResultFactory;
@@ -40,8 +50,7 @@ import org.springframework.integration.xml.source.SourceFactory;
import org.springframework.util.Assert;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import java.io.IOException;
import org.w3c.dom.Document;
/**
* Thread safe XSLT transformer implementation which returns a transformed
@@ -65,10 +74,16 @@ import java.io.IOException;
*
* @author Jonas Partner
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class XsltPayloadTransformer extends AbstractTransformer {
private final Log logger = LogFactory.getLog(this.getClass());
private final Map<String, Expression> expressionCache = new HashMap<String, Expression>();
private final Templates templates;
private final StandardEvaluationContext context = new StandardEvaluationContext();
private ExpressionParser spelParser = new SpelExpressionParser();
private Map<String, Expression> xslParameterMappings;
private final ResultTransformer resultTransformer;
@@ -78,8 +93,7 @@ public class XsltPayloadTransformer extends AbstractTransformer {
private volatile boolean alwaysUseSourceResultFactories = false;
private volatile TransformerConfigurer transformerConfigurer = new DefaultTransformerConfigurer();
private String[] xsltParamHeaders;
public XsltPayloadTransformer(Templates templates) throws ParserConfigurationException {
this(templates, null);
@@ -195,12 +209,70 @@ public class XsltPayloadTransformer extends AbstractTransformer {
return (Document) domResult.getNode();
}
@SuppressWarnings("unchecked")
protected Transformer buildTransformer(Message<?> message) throws TransformerException {
Transformer transformer = this.templates.newTransformer();
if (this.transformerConfigurer != null) {
this.transformerConfigurer.configureTransformer(message, transformer);
context.setRootObject(message);
context.addPropertyAccessor(new MapAccessor());
if (xslParameterMappings != null){
for (String parameterName: xslParameterMappings.keySet()) {
Expression expression = xslParameterMappings.get(parameterName);
Object value = null;
try {
value = expression.getValue(context);
transformer.setParameter(parameterName, value);
} catch (Exception e) {
logger.warn("Header expression '" + expression.getExpressionString() + "' can not resolve within current message and will not be mapped to XSLT parameter");
}
}
}
MessageHeaders headers = message.getHeaders();
if (xsltParamHeaders != null){
for (String headerPattern : xsltParamHeaders) {
if (headerPattern.contains("*")){
Expression expression = expressionCache.get(headerPattern);
Map<String, Object> filteredHeaders = null;
if (expression == null){
if (headerPattern.startsWith("*")){
headerPattern = headerPattern.replace("*", "");
expression = spelParser.parseExpression("headers.?[key.endsWith('" + headerPattern + "')]");
} else if (headerPattern.endsWith("*")){
headerPattern = headerPattern.replace("*", "");
expression = spelParser.parseExpression("headers.?[key.startsWith('" + headerPattern + "')]");
} else {
throw new IllegalArgumentException("Can not match the following header name pattern '" + headerPattern + "'");
}
expressionCache.put(headerPattern, expression);
}
filteredHeaders = (Map<String, Object>)expression.getValue(context);
for (String headerName : filteredHeaders.keySet()) {
transformer.setParameter(headerName, filteredHeaders.get(headerName));
}
} else {
Object value = headers.get(headerPattern);
if (value != null){
transformer.setParameter(headerPattern, headers.get(headerPattern));
} else{
logger.warn("Header with the name '" + headerPattern + "' is not present in the current message and will not be mapped to XSLT parameter");
}
}
}
}
return transformer;
}
public Map<String, Expression> getXslParameterMappings() {
return xslParameterMappings;
}
public void setXslParameterMappings(Map<String, Expression> xslParameterMappings) {
this.xslParameterMappings = xslParameterMappings;
}
public String[] getXsltParamHeaders() {
return xsltParamHeaders;
}
public void setXsltParamHeaders(String[] xsltParamHeaders) {
this.xsltParamHeaders = xsltParamHeaders;
}
}

View File

@@ -107,6 +107,10 @@
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="inputOutputEndpoint">
<xsd:sequence>
<xsd:element name="xslt-param" type="paramType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="xslt-param-headers" type="xsd:string" use="optional"/>
<xsd:attribute name="xsl-resource" type="xsd:string" use="optional"/>
<xsd:attribute name="xsl-templates" type="xsd:string" use="optional">
<xsd:annotation>
@@ -558,5 +562,11 @@
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="paramType">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="expression" type="xsd:string" use="optional"/>
<xsd:attribute name="value" type="xsd:string" use="optional"/>
</xsd:complexType>
</xsd:schema>