| /** |
| * 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.component.spring.ws.bean; |
| |
| import java.io.IOException; |
| import java.net.URISyntaxException; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import javax.xml.namespace.QName; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| |
| import org.w3c.dom.Node; |
| import org.xml.sax.SAXException; |
| |
| import org.apache.camel.RuntimeCamelException; |
| import org.apache.camel.component.spring.ws.type.EndpointMappingKey; |
| import org.apache.camel.component.spring.ws.type.EndpointMappingType; |
| import org.apache.camel.converter.jaxp.XmlConverter; |
| import org.springframework.beans.factory.InitializingBean; |
| import org.springframework.util.StringUtils; |
| import org.springframework.ws.context.MessageContext; |
| import org.springframework.ws.server.EndpointInterceptor; |
| import org.springframework.ws.server.EndpointInvocationChain; |
| import org.springframework.ws.server.EndpointMapping; |
| import org.springframework.ws.server.endpoint.MessageEndpoint; |
| import org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping; |
| import org.springframework.ws.server.endpoint.support.PayloadRootUtils; |
| import org.springframework.ws.soap.SoapMessage; |
| import org.springframework.ws.soap.server.SoapEndpointInvocationChain; |
| import org.springframework.ws.transport.WebServiceConnection; |
| import org.springframework.ws.transport.context.TransportContext; |
| import org.springframework.ws.transport.context.TransportContextHolder; |
| import org.springframework.xml.xpath.XPathExpression; |
| |
| /** |
| * Spring {@link EndpointMapping} for mapping messages to corresponding Camel endpoints. |
| * This class needs to be registered in the Spring <tt>ApplicationContext</tt> when |
| * consuming messages using any of the following URI schemes: |
| * <p/> |
| * <ul> |
| * <li><tt>spring-ws:rootqname:</tt><br/> |
| * Equivalent to endpoint mappings specified through {@link org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping} |
| * <p/> |
| * <li><tt>spring-ws:soapaction:</tt><br/> |
| * Equivalent to endpoint mappings specified through {@link org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping} |
| * <p/> |
| * <li><tt>spring-ws:uri:</tt><br/> |
| * Equivalent to endpoint mappings specified through {@link org.springframework.ws.server.endpoint.mapping.UriEndpointMapping} |
| * <p/> |
| * <li><tt>spring-ws:xpathresult:</tt><br/> |
| * Equivalent to endpoint mappings specified through {@link org.springframework.ws.server.endpoint.mapping.XPathPayloadEndpointMapping} |
| * </ul> |
| * |
| * @see org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping |
| * @see org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping |
| * @see org.springframework.ws.server.endpoint.mapping.UriEndpointMapping |
| * @see org.springframework.ws.server.endpoint.mapping.XPathPayloadEndpointMapping |
| * @see org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping |
| */ |
| public class CamelEndpointMapping extends AbstractEndpointMapping implements InitializingBean { |
| |
| private static final String DOUBLE_QUOTE = "\""; |
| private Map<EndpointMappingKey, MessageEndpoint> endpoints = new ConcurrentHashMap<EndpointMappingKey, MessageEndpoint>(); |
| private TransformerFactory transformerFactory; |
| private XmlConverter xmlConverter; |
| |
| @Override |
| protected Object getEndpointInternal(MessageContext messageContext) throws Exception { |
| for (EndpointMappingKey key : endpoints.keySet()) { |
| Object messageKey = null; |
| switch (key.getType()) { |
| case ROOT_QNAME: |
| messageKey = getRootQName(messageContext); |
| break; |
| case SOAP_ACTION: |
| messageKey = getSoapAction(messageContext); |
| break; |
| case XPATHRESULT: |
| messageKey = getXPathResult(messageContext, key.getExpression()); |
| break; |
| case URI: |
| messageKey = getUri(); |
| break; |
| default: |
| throw new RuntimeCamelException("Invalid mapping type specified. Supported types are: root QName, SOAP action, XPath expression and URI"); |
| } |
| if (messageKey != null && key.getLookupKey().equals(messageKey)) { |
| return endpoints.get(key); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| protected final EndpointInvocationChain createEndpointInvocationChain(MessageContext messageContext, Object endpoint, EndpointInterceptor[] interceptors) { |
| for (EndpointMappingKey key : endpoints.keySet()) { |
| if (EndpointMappingType.SOAP_ACTION.equals(key.getType())) { |
| Object messageKey = getSoapAction(messageContext); |
| if (messageKey != null && key.getLookupKey().equals(messageKey)) { |
| return new SoapEndpointInvocationChain(endpoint, interceptors); |
| // possibly add support for SOAP actors/roles and ultimate |
| // receiver in the future |
| } |
| } |
| } |
| return super.createEndpointInvocationChain(messageContext, endpoint, interceptors); |
| } |
| |
| private String getSoapAction(MessageContext messageContext) { |
| if (messageContext.getRequest() instanceof SoapMessage) { |
| SoapMessage request = (SoapMessage) messageContext.getRequest(); |
| String soapAction = request.getSoapAction(); |
| if (StringUtils.hasLength(soapAction) && soapAction.startsWith(DOUBLE_QUOTE) && soapAction.endsWith(DOUBLE_QUOTE)) { |
| return soapAction.substring(1, soapAction.length() - 1); |
| } |
| return soapAction; |
| } |
| return null; |
| } |
| |
| private String getUri() throws URISyntaxException { |
| TransportContext transportContext = TransportContextHolder.getTransportContext(); |
| if (transportContext != null) { |
| WebServiceConnection webServiceConnection = transportContext.getConnection(); |
| if (webServiceConnection != null) { |
| return webServiceConnection.getUri().toString(); |
| } |
| } |
| return null; |
| } |
| |
| private String getRootQName(MessageContext messageContext) throws TransformerException, XMLStreamException { |
| QName qName = PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), transformerFactory); |
| return qName != null ? qName.toString() : null; |
| } |
| |
| private String getXPathResult(MessageContext messageContext, XPathExpression expression) throws TransformerException, XMLStreamException, ParserConfigurationException, IOException, SAXException { |
| if (expression != null) { |
| Node domNode = xmlConverter.toDOMNode(messageContext.getRequest().getPayloadSource()); |
| if (domNode != null) { |
| return expression.evaluateAsString(domNode.getFirstChild()); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Used by Camel Spring Web Services endpoint to register consumers |
| * |
| * @param key unique consumer key |
| * @param endpoint consumer |
| */ |
| public void addConsumer(EndpointMappingKey key, MessageEndpoint endpoint) { |
| endpoints.put(key, endpoint); |
| } |
| |
| /** |
| * Used by Camel Spring Web Services endpoint to unregister consumers |
| * |
| * @param key unique consumer key |
| */ |
| public void removeConsumer(Object key) { |
| endpoints.remove(key); |
| } |
| |
| /** |
| * Gets the configured TransformerFactory |
| * |
| * @return instance of TransformerFactory |
| */ |
| public TransformerFactory getTransformerFactory() { |
| return transformerFactory; |
| } |
| |
| /** |
| * Optional setter to override default TransformerFactory |
| * |
| * @param transformerFactory non-default TransformerFactory |
| */ |
| public void setTransformerFactory(TransformerFactory transformerFactory) { |
| this.transformerFactory = transformerFactory; |
| } |
| |
| public void afterPropertiesSet() throws Exception { |
| xmlConverter = new XmlConverter(); |
| if (transformerFactory != null) { |
| xmlConverter.setTransformerFactory(transformerFactory); |
| } else { |
| transformerFactory = TransformerFactory.newInstance(); |
| } |
| } |
| } |