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.soap;
018
019 import java.net.URI;
020 import java.util.Collections;
021 import java.util.HashMap;
022 import java.util.Iterator;
023 import java.util.List;
024 import java.util.Map;
025
026 import javax.jbi.JBIException;
027 import javax.jbi.component.ComponentContext;
028 import javax.jbi.messaging.DeliveryChannel;
029 import javax.jbi.messaging.MessageExchange;
030 import javax.jbi.messaging.MessageExchangeFactory;
031 import javax.jbi.messaging.MessagingException;
032 import javax.jbi.messaging.NormalizedMessage;
033 import javax.jbi.servicedesc.ServiceEndpoint;
034 import javax.wsdl.Binding;
035 import javax.wsdl.Definition;
036 import javax.wsdl.Operation;
037 import javax.wsdl.Part;
038 import javax.wsdl.Port;
039 import javax.wsdl.PortType;
040 import javax.wsdl.Service;
041 import javax.wsdl.WSDLException;
042 import javax.wsdl.factory.WSDLFactory;
043 import javax.wsdl.xml.WSDLReader;
044 import javax.xml.namespace.QName;
045
046 import org.apache.commons.logging.Log;
047 import org.apache.commons.logging.LogFactory;
048 import org.apache.servicemix.common.JbiConstants;
049 import org.apache.servicemix.jbi.jaxp.W3CDOMStreamWriter;
050 import org.apache.servicemix.soap.marshalers.JBIMarshaler;
051 import org.apache.servicemix.soap.marshalers.SoapMarshaler;
052 import org.apache.servicemix.soap.marshalers.SoapMessage;
053 import org.apache.servicemix.soap.marshalers.SoapWriter;
054
055 import org.w3c.dom.Document;
056
057 import com.ibm.wsdl.Constants;
058
059 /**
060 * Helper class for working with soap endpoints
061 *
062 * @author Guillaume Nodet
063 * @version $Revision: 1.5 $
064 * @since 3.0
065 */
066 public class SoapHelper {
067
068 private static final Log logger = LogFactory.getLog(SoapHelper.class);
069
070 private SoapEndpoint endpoint;
071 private List policies;
072 private JBIMarshaler jbiMarshaler;
073 private SoapMarshaler soapMarshaler;
074 private Map definitions;
075 private Map operationNames;
076
077 public SoapHelper(SoapEndpoint endpoint) {
078 this.policies = endpoint.getPolicies();
079 if (this.policies == null) {
080 this.policies = Collections.EMPTY_LIST;
081 }
082 this.definitions = new HashMap();
083 this.operationNames = new HashMap();
084 this.jbiMarshaler = new JBIMarshaler();
085 this.endpoint = endpoint;
086 boolean requireDom = false;
087 for (Iterator iter = policies.iterator(); iter.hasNext();) {
088 Handler handler = (Handler) iter.next();
089 requireDom |= handler.requireDOM();
090 }
091 this.soapMarshaler = new SoapMarshaler(endpoint.isSoap(), requireDom);
092 if (endpoint.isSoap() && "1.1".equals(endpoint.getSoapVersion())) {
093 this.soapMarshaler.setSoapUri(SoapMarshaler.SOAP_11_URI);
094 }
095 }
096
097 public SoapMarshaler getSoapMarshaler() {
098 return this.soapMarshaler;
099 }
100
101 public JBIMarshaler getJBIMarshaler() {
102 return this.jbiMarshaler;
103 }
104
105 public MessageExchange onReceive(Context context) throws Exception {
106 if (policies != null) {
107 for (Iterator it = policies.iterator(); it.hasNext();) {
108 Handler policy = (Handler) it.next();
109 policy.onReceive(context);
110 }
111 }
112
113 // If WS-A has not set informations, use the default ones
114 if (context.getProperty(Context.SERVICE) == null && context.getProperty(Context.INTERFACE) == null) {
115 // If no target endpoint / service / interface is defined
116 // we assume we use the same informations has defined on the
117 // external endpoint
118 if (endpoint.getTargetInterfaceName() == null && endpoint.getTargetService() == null
119 && endpoint.getTargetEndpoint() == null) {
120 context.setProperty(Context.INTERFACE, endpoint.getInterfaceName());
121 context.setProperty(Context.SERVICE, endpoint.getService());
122 context.setProperty(Context.ENDPOINT, endpoint.getEndpoint());
123 } else {
124 context.setProperty(Context.INTERFACE, endpoint.getTargetInterfaceName());
125 context.setProperty(Context.SERVICE, endpoint.getTargetService());
126 context.setProperty(Context.ENDPOINT, endpoint.getTargetEndpoint());
127 }
128 }
129 Operation operation = findOperation(context);
130 if (context.getProperty(Context.OPERATION) == null) {
131 if (operation != null) {
132 // the operation QName must be retrieved from the map
133 // so that we can have the right namespace
134 context.setProperty(Context.OPERATION, operationNames.get(operation));
135 } else if (endpoint.getDefaultOperation() != null) {
136 context.setProperty(Context.OPERATION, endpoint.getDefaultOperation());
137 } else {
138 // By default, use name of body element (i.e., RPC-style)
139 QName bodyName = context.getInMessage().getBodyName();
140 context.setProperty(Context.OPERATION, bodyName);
141 }
142 }
143 URI mep = null;
144 if ( operation != null ) {
145 mep = getMep(operation);
146 }
147 if (mep == null) {
148 mep = endpoint.getDefaultMep();
149 }
150 MessageExchange exchange = createExchange(mep);
151 exchange.setService((QName) context.getProperty(Context.SERVICE));
152 exchange.setInterfaceName((QName) context.getProperty(Context.INTERFACE));
153 exchange.setOperation((QName) context.getProperty(Context.OPERATION));
154 if (context.getProperty(Context.ENDPOINT) != null) {
155 ComponentContext componentContext = endpoint.getServiceUnit().getComponent().getComponentContext();
156 QName serviceName = (QName) context.getProperty(Context.SERVICE);
157 String endpointName = (String) context.getProperty(Context.ENDPOINT);
158 ServiceEndpoint se = componentContext.getEndpoint(serviceName, endpointName);
159 if (se != null) {
160 exchange.setEndpoint(se);
161 }
162 }
163 NormalizedMessage inMessage = exchange.createMessage();
164 jbiMarshaler.toNMS(inMessage, context.getInMessage());
165 exchange.setMessage(inMessage, "in");
166 return exchange;
167 }
168
169 public SoapMessage onReply(Context context, NormalizedMessage outMsg) throws Exception {
170 SoapMessage out = new SoapMessage();
171 if (context.getInMessage() != null) {
172 out.setEnvelopeName(context.getInMessage().getEnvelopeName());
173 }
174 jbiMarshaler.fromNMS(out, outMsg);
175 context.setOutMessage(out);
176 if (policies != null) {
177 for (Iterator it = policies.iterator(); it.hasNext();) {
178 Handler policy = (Handler) it.next();
179 policy.onReply(context);
180 }
181 }
182 return out;
183 }
184
185 public SoapMessage onFault(Context context, SoapFault fault) throws Exception {
186 SoapMessage soapFault = new SoapMessage();
187 soapFault.setFault(fault);
188 if (context == null) {
189 context = new Context();
190 }
191 if (context.getInMessage() != null) {
192 soapFault.setEnvelopeName(context.getInMessage().getEnvelopeName());
193 }
194 context.setFaultMessage(soapFault);
195 if (policies != null) {
196 for (Iterator it = policies.iterator(); it.hasNext();) {
197 Handler policy = (Handler) it.next();
198 policy.onFault(context);
199 }
200 }
201 return soapFault;
202 }
203
204 public void onSend(Context context) throws Exception {
205 if (policies != null) {
206 for (Iterator it = policies.iterator(); it.hasNext();) {
207 Handler policy = (Handler) it.next();
208 if (policy.requireDOM()) {
209 SoapWriter writer = soapMarshaler.createWriter(context.getInMessage());
210 W3CDOMStreamWriter domWriter = new W3CDOMStreamWriter();
211 writer.writeSoapEnvelope(domWriter);
212 context.getInMessage().setDocument(domWriter.getDocument());
213 }
214 policy.onSend(context);
215 }
216 }
217 }
218
219 public void onAnswer(Context context) throws Exception {
220 if (policies != null) {
221 for (Iterator it = policies.iterator(); it.hasNext();) {
222 Handler policy = (Handler) it.next();
223 policy.onAnswer(context);
224 }
225 }
226 }
227
228 public Context createContext(SoapMessage message) {
229 Context context = createContext();
230 context.setInMessage(message);
231 return context;
232 }
233
234 public Context createContext() {
235 Context context = new Context();
236 context.setProperty(Context.AUTHENTICATION_SERVICE, endpoint.getAuthenticationService());
237 context.setProperty(Context.KEYSTORE_MANAGER, endpoint.getKeystoreManager());
238 return context;
239 }
240
241 protected MessageExchange createExchange(URI mep) throws MessagingException {
242 ComponentContext context = endpoint.getServiceUnit().getComponent().getComponentContext();
243 DeliveryChannel channel = context.getDeliveryChannel();
244 MessageExchangeFactory factory = channel.createExchangeFactory();
245 MessageExchange exchange = factory.createExchange(mep);
246 return exchange;
247 }
248
249 private URI getMep(Operation oper) {
250 URI mep = null;
251 if (oper != null) {
252 boolean output = oper.getOutput() != null && oper.getOutput().getMessage() != null
253 && oper.getOutput().getMessage().getParts().size() > 0;
254 boolean faults = oper.getFaults().size() > 0;
255 if (output) {
256 mep = JbiConstants.IN_OUT;
257 } else if (faults) {
258 mep = JbiConstants.ROBUST_IN_ONLY;
259 } else {
260 mep = JbiConstants.IN_ONLY;
261 }
262 }
263 return mep;
264 }
265
266 protected Operation findOperation(Context context) throws Exception {
267 QName interfaceName = (QName) context.getProperty(Context.INTERFACE);
268 QName serviceName = (QName) context.getProperty(Context.SERVICE);
269 String endpointName = (String) context.getProperty(Context.ENDPOINT);
270 ComponentContext componentContext = endpoint.getServiceUnit().getComponent().getComponentContext();
271 QName bodyName = context.getInMessage().getBodyName();
272
273 // Find target endpoint
274 ServiceEndpoint se = null;
275 if (serviceName != null && endpointName != null) {
276 se = componentContext.getEndpoint(serviceName, endpointName);
277 }
278 if (se == null && interfaceName != null) {
279 ServiceEndpoint[] ses = componentContext.getEndpoints(interfaceName);
280 if (ses != null && ses.length > 0) {
281 se = ses[0];
282 }
283 }
284
285 // Find WSDL description
286 Definition definition = null;
287 if (se != null) {
288 // Find endpoint description from the component context
289 definition = getDefinition(se);
290 }
291 if (definition == null) {
292 // Get this endpoint definition
293 definition = endpoint.getDefinition();
294 }
295
296 // Find operation matching
297 if (definition != null) {
298 if (interfaceName != null) {
299 PortType portType = definition.getPortType(interfaceName);
300 if (portType != null) {
301 return findOperationFor(portType, bodyName);
302 }
303 } else if (definition.getService(serviceName) != null) {
304 Service service = definition.getService(serviceName);
305 if (endpointName != null) {
306 Port port = service.getPort(endpointName);
307 if (port != null) {
308 Binding binding = port.getBinding();
309 if (binding != null) {
310 PortType portType = binding.getPortType();
311 if (portType != null) {
312 return findOperationFor(portType, bodyName);
313 }
314 }
315 }
316 } else if (service.getPorts().size() == 1) {
317 Port port = (Port) service.getPorts().values().iterator().next();
318 Binding binding = port.getBinding();
319 if (binding != null) {
320 PortType portType = binding.getPortType();
321 if (portType != null) {
322 return findOperationFor(portType, bodyName);
323 }
324 }
325 }
326 } else if (definition.getPortTypes().size() == 1) {
327 PortType portType = (PortType) definition.getPortTypes().values().iterator().next();
328 return findOperationFor(portType, bodyName);
329 }
330 }
331 return null;
332 }
333
334 protected Operation findOperationFor(PortType portType, QName bodyName) {
335 List list = portType.getOperations();
336 for (int i = 0; i < list.size(); i++) {
337 Operation operation = (Operation) list.get(i);
338 if (operation.getInput() != null && operation.getInput().getMessage() != null) {
339 Map parts = operation.getInput().getMessage().getParts();
340 Iterator iter = parts.values().iterator();
341 while (iter.hasNext()) {
342 Part part = (Part) iter.next();
343 QName elementName = part.getElementName();
344 if (elementName != null && elementName.equals(bodyName)) {
345 // found
346 operationNames.put(operation, new QName(portType.getQName().getNamespaceURI(), operation.getName()));
347 return operation;
348 }
349 }
350 }
351 }
352 return null;
353 }
354
355 protected Definition getDefinition(ServiceEndpoint se) throws WSDLException, JBIException {
356 Definition definition;
357 ComponentContext componentContext = endpoint.getServiceUnit().getComponent().getComponentContext();
358 String key = se.getServiceName() + se.getEndpointName();
359 synchronized (definitions) {
360 definition = (Definition) definitions.get(key);
361 if (definition == null) {
362 WSDLFactory factory = WSDLFactory.newInstance();
363 Document description = componentContext.getEndpointDescriptor(se);
364 if (description != null) {
365 // Parse WSDL
366 WSDLReader reader = factory.newWSDLReader();
367 reader.setFeature(Constants.FEATURE_VERBOSE, false);
368 try {
369 definition = reader.readWSDL(null, description);
370 definitions.put(key, definition);
371 } catch (WSDLException e) {
372 logger.info("Could not read wsdl from endpoint descriptor: " + e.getMessage());
373 if (logger.isDebugEnabled()) {
374 logger.debug("Could not read wsdl from endpoint descriptor", e);
375 }
376 }
377 }
378 }
379 }
380 return definition;
381 }
382
383 }