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.servicemix.http.endpoints;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021
022 import javax.jbi.management.DeploymentException;
023 import javax.jbi.servicedesc.ServiceEndpoint;
024 import javax.wsdl.Definition;
025 import javax.wsdl.Port;
026 import javax.wsdl.Service;
027 import javax.wsdl.WSDLException;
028 import javax.wsdl.extensions.soap.SOAPAddress;
029 import javax.wsdl.extensions.soap12.SOAP12Address;
030 import javax.xml.namespace.QName;
031
032 import org.w3c.dom.Element;
033
034 import org.apache.servicemix.common.DefaultComponent;
035 import org.apache.servicemix.common.ServiceUnit;
036 import org.apache.servicemix.soap.api.Policy;
037 import org.apache.servicemix.soap.util.DomUtil;
038 import org.apache.servicemix.soap.wsdl.BindingFactory;
039 import org.apache.servicemix.soap.wsdl.WSDLUtils;
040 import org.apache.servicemix.soap.wsdl.validator.WSIBPValidator;
041 import org.apache.woden.WSDLFactory;
042 import org.apache.woden.WSDLReader;
043 import org.apache.woden.types.NCName;
044 import org.apache.woden.wsdl20.Description;
045 import org.apache.woden.wsdl20.Endpoint;
046 import org.apache.woden.wsdl20.xml.DescriptionElement;
047 import org.springframework.core.io.Resource;
048 import org.xml.sax.InputSource;
049
050 /**
051 * @author gnodet
052 * @since 3.2
053 * @org.apache.xbean.XBean element="soap-consumer" description=
054 * "an HTTP consumer endpoint that is optimized to work with SOAP messages"
055 */
056 public class HttpSoapConsumerEndpoint extends HttpConsumerEndpoint {
057
058 private Resource wsdl;
059 private boolean useJbiWrapper = true;
060 private boolean validateWsdl = true;
061 private Policy[] policies;
062
063 public HttpSoapConsumerEndpoint() {
064 super();
065 }
066
067 public HttpSoapConsumerEndpoint(DefaultComponent component, ServiceEndpoint endpoint) {
068 super(component, endpoint);
069 }
070
071 public HttpSoapConsumerEndpoint(ServiceUnit serviceUnit, QName service, String endpoint) {
072 super(serviceUnit, service, endpoint);
073 }
074
075 public Resource getWsdl() {
076 return wsdl;
077 }
078
079 /**
080 * Specifies the WSDL document defining the messages sent by the endpoint.
081 *
082 * @param wsdl a <code>Resource</code> object that points to the WSDL document
083 * @org.apache.xbean.Property description="the URL of the WSDL document defining the endpoint's messages"
084 */
085 public void setWsdl(Resource wsdl) {
086 this.wsdl = wsdl;
087 }
088
089 public boolean isValidateWsdl() {
090 return validateWsdl;
091 }
092
093 /**
094 * Specifies in the WSDL is validated against the WS-I basic profile.
095 *
096 * @param validateWsdl <code>true</code> if WSDL is to be validated
097 * @org.apache.xbean.Property description="Specifies if the WSDL is checked for WSI-BP compliance. Default is <code>true</code>."
098 */
099 public void setValidateWsdl(boolean validateWsdl) {
100 this.validateWsdl = validateWsdl;
101 }
102
103 public boolean isUseJbiWrapper() {
104 return useJbiWrapper;
105 }
106
107 /**
108 * Specifies if the SOAP messages are wrapped in a JBI wrapper.
109 *
110 * @param useJbiWrapper <code>true</code> if the SOAP messages are wrapped
111 * @org.apache.xbean.Property description= "Specifies if the JBI wrapper is sent in the body of the message. Default is
112 * <code>true</code>."
113 */
114 public void setUseJbiWrapper(boolean useJbiWrapper) {
115 this.useJbiWrapper = useJbiWrapper;
116 }
117
118 public Policy[] getPolicies() {
119 return policies;
120 }
121
122 /**
123 * Specifies a list of interceptors that will process messages for the endpoint.
124 *
125 * @param policies an array of <code>Policy</code> objects
126 * @org.apache.xbean.Property description="a list of interceptors that will process messages"
127 */
128 public void setPolicies(Policy[] policies) {
129 this.policies = policies;
130 }
131
132 @Override
133 public void validate() throws DeploymentException {
134 if (wsdl == null) {
135 throw new DeploymentException("wsdl property must be set");
136 }
137 HttpSoapConsumerMarshaler marshaler;
138 if (getMarshaler() instanceof HttpSoapConsumerMarshaler) {
139 marshaler = (HttpSoapConsumerMarshaler)getMarshaler();
140 } else if (getMarshaler() == null) {
141 marshaler = new HttpSoapConsumerMarshaler();
142 } else {
143 throw new DeploymentException("The configured marshaler must inherit HttpSoapConsumerMarshaler");
144 }
145 try {
146 description = DomUtil.parse(wsdl.getInputStream());
147 Element elem = description.getDocumentElement();
148 if (WSDLUtils.WSDL1_NAMESPACE.equals(elem.getNamespaceURI())) {
149 validateWsdl1(marshaler);
150 } else if (WSDLUtils.WSDL2_NAMESPACE.equals(elem.getNamespaceURI())) {
151 validateWsdl2(marshaler);
152 } else {
153 throw new DeploymentException("Unrecognized wsdl namespace: " + elem.getNamespaceURI());
154 }
155 marshaler.setUseJbiWrapper(useJbiWrapper);
156 marshaler.setPolicies(policies);
157 setMarshaler(marshaler);
158 } catch (DeploymentException e) {
159 throw e;
160 } catch (Exception e) {
161 throw new DeploymentException("Unable to read WSDL from: " + wsdl, e);
162 }
163 if (getTargetService() == null && getTargetInterface() == null && getTargetUri() == null) {
164 setTargetService(getService());
165 setTargetEndpoint(getEndpoint());
166 }
167 super.validate();
168 }
169
170 protected void loadStaticResources() {
171 addResource(MAIN_WSDL, description);
172 }
173
174 protected void validateWsdl1(HttpSoapConsumerMarshaler marshaler) throws Exception {
175 InputStream is = wsdl.getInputStream();
176 try {
177 InputSource inputSource = new InputSource(is);
178 inputSource.setSystemId(wsdl.getURL().toString());
179 Definition def = WSDLUtils.createWSDL11Reader().readWSDL(wsdl.getURL().toString(), inputSource);
180 if (validateWsdl) {
181 WSIBPValidator validator = new WSIBPValidator(def);
182 if (!validator.isValid()) {
183 throw new DeploymentException("WSDL is not WS-I BP compliant: " + validator.getErrors());
184 }
185 }
186 Service svc;
187 if (getService() != null) {
188 svc = def.getService(getService());
189 if (svc == null) {
190 throw new DeploymentException("Could not find service '" + getService() + "' in wsdl");
191 }
192 } else if (def.getServices().size() == 1) {
193 svc = (Service)def.getServices().values().iterator().next();
194 setService(svc.getQName());
195 } else {
196 throw new DeploymentException(
197 "If service is not set, the WSDL must contain a single service definition");
198 }
199 Port port;
200 if (getEndpoint() != null) {
201 port = svc.getPort(getEndpoint());
202 if (port == null) {
203 throw new DeploymentException("Cound not find port '" + getEndpoint()
204 + "' in wsdl for service '" + getService() + "'");
205 }
206 } else if (svc.getPorts().size() == 1) {
207 port = (Port)svc.getPorts().values().iterator().next();
208 setEndpoint(port.getName());
209 } else {
210 throw new DeploymentException("If endpoint is not set, the WSDL service '" + getService()
211 + "' must contain a single port definition");
212 }
213 SOAPAddress soapAddress = WSDLUtils.getExtension(port, SOAPAddress.class);
214 if (soapAddress != null) {
215 soapAddress.setLocationURI(getLocationURI());
216 } else {
217 SOAP12Address soap12Address = WSDLUtils.getExtension(port, SOAP12Address.class);
218 if (soap12Address != null) {
219 soap12Address.setLocationURI(getLocationURI());
220 }
221 }
222 description = WSDLUtils.getWSDL11Factory().newWSDLWriter().getDocument(def);
223 marshaler.setBinding(BindingFactory.createBinding(port));
224 } finally {
225 is.close();
226 }
227 }
228
229 protected void validateWsdl2(HttpSoapConsumerMarshaler marshaler) throws Exception {
230 new Wsdl2Validator().validate(marshaler);
231 }
232
233 /**
234 * Use an inner class to avoid having a strong dependency on Woden if not needed
235 */
236 protected class Wsdl2Validator {
237 public void validate(HttpSoapConsumerMarshaler marshaler) throws Exception {
238 WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
239 DescriptionElement descElement = reader.readWSDL(wsdl.getURL().toString());
240 Description desc = descElement.toComponent();
241 org.apache.woden.wsdl20.Service svc;
242 if (getService() != null) {
243 svc = desc.getService(getService());
244 if (svc == null) {
245 throw new DeploymentException("Could not find service '" + getService() + "' in wsdl");
246 }
247 } else if (desc.getServices().length == 1) {
248 svc = desc.getServices()[0];
249 setService(svc.getName());
250 } else {
251 throw new DeploymentException(
252 "If service is not set, the WSDL must contain a single service definition");
253 }
254 Endpoint endpoint;
255 if (getEndpoint() != null) {
256 endpoint = svc.getEndpoint(new NCName(getEndpoint()));
257 if (endpoint == null) {
258 throw new DeploymentException("Cound not find endpoint '" + getEndpoint()
259 + "' in wsdl for service '" + getService() + "'");
260 }
261 } else if (svc.getEndpoints().length == 1) {
262 endpoint = svc.getEndpoints()[0];
263 setEndpoint(endpoint.getName().toString());
264 } else {
265 throw new DeploymentException("If endpoint is not set, the WSDL service '" + getService()
266 + "' must contain a single port definition");
267 }
268 marshaler.setBinding(BindingFactory.createBinding(endpoint));
269 }
270 }
271
272 }