001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.component.spring.ws;
018    
019    import java.net.URI;
020    import java.net.URISyntaxException;
021    import java.util.Map;
022    import javax.xml.transform.TransformerFactory;
023    
024    import org.apache.camel.CamelContext;
025    import org.apache.camel.Endpoint;
026    import org.apache.camel.RuntimeCamelException;
027    import org.apache.camel.component.spring.ws.bean.CamelEndpointDispatcher;
028    import org.apache.camel.component.spring.ws.bean.CamelEndpointMapping;
029    import org.apache.camel.component.spring.ws.type.EndpointMappingKey;
030    import org.apache.camel.component.spring.ws.type.EndpointMappingType;
031    import org.apache.camel.converter.jaxp.XmlConverter;
032    import org.apache.camel.impl.DefaultComponent;
033    import org.apache.camel.util.CamelContextHelper;
034    import org.apache.camel.util.UnsafeUriCharactersEncoder;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    import org.springframework.ws.WebServiceMessageFactory;
038    import org.springframework.ws.client.core.WebServiceTemplate;
039    import org.springframework.ws.transport.WebServiceMessageSender;
040    import org.springframework.xml.xpath.XPathExpression;
041    import org.springframework.xml.xpath.XPathExpressionFactory;
042    
043    /**
044     * Apache Camel component for working with Spring Web Services (a.k.a Spring-WS).
045     */
046    public class SpringWebserviceComponent extends DefaultComponent {
047        private static final Logger LOG = LoggerFactory.getLogger(SpringWebserviceComponent.class);
048    
049        public SpringWebserviceComponent() {
050            super();
051        }
052    
053        public SpringWebserviceComponent(CamelContext context) {
054            super(context);
055        }
056    
057        @Override
058        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
059            SpringWebserviceConfiguration configuration = new SpringWebserviceConfiguration();
060            addConsumerConfiguration(remaining, parameters, configuration);
061            addProducerConfiguration(remaining, parameters, configuration);
062            addXmlConverterToConfiguration(parameters, configuration);
063            setProperties(configuration, parameters);
064            return new SpringWebserviceEndpoint(this, configuration);
065        }
066    
067        private void addConsumerConfiguration(String remaining, Map<String, Object> parameters,
068                                              SpringWebserviceConfiguration configuration) {
069            EndpointMappingType type = EndpointMappingType.getTypeFromUriPrefix(remaining);
070            if (type != null) {
071                LOG.debug("Building Spring Web Services consumer of type " + type);
072                String lookupKey = getLookupKey(remaining, type);
073                if (EndpointMappingType.BEANNAME.equals(type)) {
074                    addEndpointDispatcherToConfiguration(configuration, lookupKey);
075                } else {
076                    addEndpointMappingToConfiguration(parameters, configuration);
077                }
078                if (EndpointMappingType.XPATHRESULT.equals(type)) {
079                    XPathExpression expression = getXPathExpressionFromParameters(parameters);
080                    configuration.setEndpointMappingKey(new EndpointMappingKey(type, lookupKey, expression));
081                } else {
082                    configuration.setEndpointMappingKey(new EndpointMappingKey(type, lookupKey, null));
083                }
084            }
085        }
086    
087        private void addProducerConfiguration(String remaining, Map<String, Object> parameters,
088                                              SpringWebserviceConfiguration configuration) throws URISyntaxException {
089            if (configuration.getEndpointMapping() == null && configuration.getEndpointDispatcher() == null) {
090                LOG.debug("Building Spring Web Services producer");
091                URI webServiceEndpointUri = new URI(UnsafeUriCharactersEncoder.encode(remaining));
092    
093                // Obtain a WebServiceTemplate from the registry when specified by
094                // an option on the component, else create a new template with
095                // Spring-WS defaults
096                WebServiceTemplate webServiceTemplate = resolveAndRemoveReferenceParameter(parameters,
097                        "webServiceTemplate", WebServiceTemplate.class, new WebServiceTemplate());
098                WebServiceMessageSender messageSender = resolveAndRemoveReferenceParameter(parameters,
099                        "messageSender", WebServiceMessageSender.class, null);
100                WebServiceMessageFactory messageFactory = resolveAndRemoveReferenceParameter(parameters,
101                        "messageFactory", WebServiceMessageFactory.class, null);
102    
103                if (webServiceTemplate.getDefaultUri() == null) {
104                    webServiceTemplate.setDefaultUri(webServiceEndpointUri.toString());
105                }
106                if (messageSender != null) {
107                    webServiceTemplate.setMessageSender(messageSender);
108                }
109                if (messageFactory != null) {
110                    webServiceTemplate.setMessageFactory(messageFactory);
111                }
112                configuration.setWebServiceTemplate(webServiceTemplate);
113            }
114        }
115    
116        private String getLookupKey(String remaining, EndpointMappingType type) {
117            String lookupKey = remaining.substring(type.getPrefix().length());
118            return lookupKey.startsWith("//") ? lookupKey.substring(2) : lookupKey;
119        }
120    
121        private XPathExpression getXPathExpressionFromParameters(Map<String, Object> parameters) {
122            String xpathExpression = getAndRemoveParameter(parameters, "expression", String.class);
123            if (xpathExpression == null) {
124                throw new RuntimeCamelException("Expression parameter is required when using XPath endpoint mapping");
125            }
126            XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpathExpression);
127            return expression;
128        }
129    
130        private void addEndpointMappingToConfiguration(Map<String, Object> parameters,
131                                                       SpringWebserviceConfiguration configuration) {
132            // Obtain generic CamelEndpointMapping from registry
133            CamelEndpointMapping endpointMapping = resolveAndRemoveReferenceParameter(parameters, "endpointMapping", CamelEndpointMapping.class, null);
134            if (endpointMapping == null && configuration.getEndpointDispatcher() == null) {
135                throw new IllegalArgumentException("No CamelEndpointMapping found in Spring ApplicationContext."
136                        + " This bean is required for Spring-WS consumer support (unless the 'spring-ws:beanname:' URI scheme is used)");
137            }
138            configuration.setEndpointMapping(endpointMapping);
139        }
140    
141        private void addEndpointDispatcherToConfiguration(SpringWebserviceConfiguration configuration, String lookupKey) {
142            // Obtain CamelEndpointDispatcher with the given name from registry
143            CamelEndpointDispatcher endpoint = CamelContextHelper.mandatoryLookup(getCamelContext(), lookupKey, CamelEndpointDispatcher.class);
144            configuration.setEndpointDispatcher(endpoint);
145        }
146    
147        private void addXmlConverterToConfiguration(Map<String, Object> parameters, SpringWebserviceConfiguration configuration) {
148            XmlConverter xmlConverter = new XmlConverter();
149            TransformerFactory transformerFactory = resolveAndRemoveReferenceParameter(parameters, "transformerFactory", TransformerFactory.class, null);
150            if (transformerFactory != null) {
151                xmlConverter.setTransformerFactory(transformerFactory);
152            }
153            configuration.setXmlConverter(xmlConverter);
154        }
155    }