KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jbpm > bpel > service > soap > SoapEndpointCaller


1 package org.jbpm.bpel.service.soap;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Collection JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.List JavaDoc;
7 import java.util.Map JavaDoc;
8
9 import javax.wsdl.Binding;
10 import javax.wsdl.BindingFault;
11 import javax.wsdl.BindingInput;
12 import javax.wsdl.BindingOperation;
13 import javax.wsdl.BindingOutput;
14 import javax.wsdl.Message;
15 import javax.wsdl.Operation;
16 import javax.wsdl.Part;
17 import javax.wsdl.extensions.soap.SOAPBinding;
18 import javax.wsdl.extensions.soap.SOAPFault;
19 import javax.wsdl.extensions.soap.SOAPOperation;
20 import javax.xml.namespace.QName JavaDoc;
21 import javax.xml.soap.Detail JavaDoc;
22 import javax.xml.soap.MessageFactory JavaDoc;
23 import javax.xml.soap.Name JavaDoc;
24 import javax.xml.soap.SOAPConnection JavaDoc;
25 import javax.xml.soap.SOAPConnectionFactory JavaDoc;
26 import javax.xml.soap.SOAPElement JavaDoc;
27 import javax.xml.soap.SOAPEnvelope JavaDoc;
28 import javax.xml.soap.SOAPException JavaDoc;
29 import javax.xml.soap.SOAPMessage JavaDoc;
30 import javax.xml.soap.SOAPPart JavaDoc;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.w3c.dom.Document JavaDoc;
35 import org.w3c.dom.Element JavaDoc;
36
37 import org.jbpm.bpel.data.def.MessageTypeInfo;
38 import org.jbpm.bpel.data.exe.MessageVariableInstance;
39 import org.jbpm.bpel.exe.Fault;
40 import org.jbpm.bpel.wsdl.util.WsdlUtil;
41 import org.jbpm.bpel.xml.util.NodeUtil;
42
43 import com.ibm.wsdl.extensions.soap.SOAPConstants;
44 import com.ibm.wsdl.util.xml.DOMUtils;
45
46 /**
47  * @author Alejandro Guízar
48  * @version $Revision: 1.3 $ $Date: 2005/06/23 02:25:47 $
49  */

50 public class SoapEndpointCaller {
51   
52   private String JavaDoc address;
53   private Binding binding;
54   
55   private static final Log log = LogFactory.getLog(SoapEndpointCaller.class);
56   
57   public String JavaDoc getAddress() {
58     return address;
59   }
60   
61   public void setAddress(String JavaDoc address) {
62     this.address = address;
63   }
64   
65   public Binding getBinding() {
66     return binding;
67   }
68   
69   public void setBinding(Binding binding) {
70     SOAPBinding soapBinding = (SOAPBinding) WsdlUtil.getExtension(
71         binding.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BINDING);
72     // exclude non-soap bindings
73
if (soapBinding == null) {
74       throw new IllegalArgumentException JavaDoc("non-soap bindings not supported");
75     }
76     // exclude non-http transport protocols
77
String JavaDoc transport = soapBinding.getTransportURI();
78     if (!SoapBindConstants.HTTP_TRANSPORT_URI.equals(transport)) {
79       throw new IllegalArgumentException JavaDoc("non-http transport protocols not supported");
80     }
81     this.binding = binding;
82   }
83   
84   /** {@inheritDoc} */
85   public Element JavaDoc call(String JavaDoc operation, Element JavaDoc inputData) {
86     BindingOperation bindOperation = binding.getBindingOperation(operation, null, null);
87     try {
88       SOAPMessage JavaDoc soapOutput = callImpl(bindOperation, inputData);
89       // prepare output message
90
SOAPEnvelope JavaDoc envelope = soapOutput.getSOAPPart().getEnvelope();
91       if (envelope.getBody().hasFault()) {
92         throw readFault(bindOperation, envelope);
93       }
94       return readOutputData(bindOperation, envelope);
95     }
96     catch (SOAPException JavaDoc e) {
97       log.error(e);
98       throw new RuntimeException JavaDoc("failed to call soap endpoint: " + address, e);
99     }
100   }
101   
102   public void callOneWay(String JavaDoc operation, Element JavaDoc inputData) {
103     BindingOperation bindOperation = binding.getBindingOperation(operation, null, null);
104     try {
105       callImpl(bindOperation, inputData);
106     }
107     catch (SOAPException JavaDoc e) {
108       log.error(e);
109       throw new RuntimeException JavaDoc("failed to call soap endpoint: " + address, e);
110     }
111   }
112   
113   protected SOAPMessage JavaDoc callImpl(BindingOperation bindOperation, Element JavaDoc inputData) throws SOAPException JavaDoc {
114     SOAPConnection JavaDoc soapConnection = null;
115     try {
116       // prepare input message
117
SOAPMessage JavaDoc soapInput = writeInputMessage(bindOperation, inputData);
118       // call endpoint
119
SOAPConnectionFactory JavaDoc connectionFactory = SOAPConnectionFactory.newInstance();
120       soapConnection = connectionFactory.createConnection();
121       return soapConnection.call(soapInput, address);
122     }
123     finally {
124       if (soapConnection != null) {
125         try {
126           soapConnection.close();
127         }
128         catch (SOAPException JavaDoc e) {
129           log.warn("coult not close soap connection", e);
130         }
131       }
132     }
133   }
134
135   protected SOAPMessage JavaDoc writeInputMessage(BindingOperation bindOperation, Element JavaDoc inputData) throws SOAPException JavaDoc {
136     // create soap message
137
MessageFactory JavaDoc messageFactory = MessageFactory.newInstance();
138     SOAPMessage JavaDoc soapMessage = messageFactory.createMessage();
139     SOAPPart JavaDoc soapPart = soapMessage.getSOAPPart();
140     // obtain info on the operation as a whole
141
SOAPOperation soapOperation = (SOAPOperation) WsdlUtil.getExtension(
142         bindOperation.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_OPERATION);
143     // set the value of the SOAPAction HTTP header
144
String JavaDoc action = soapOperation.getSoapActionURI();
145     soapPart.setMimeHeader(SoapBindConstants.SOAP_ACTION_HEADER, action);
146     // determine whether the operation is rpc-oriented or document-oriented
147
String JavaDoc style = soapOperation.getStyle();
148     if (style == null) {
149       // default to the value specified in the soap:binding element
150
SOAPBinding soapBinding = (SOAPBinding) WsdlUtil.getExtension(
151           binding.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BINDING);
152       style = soapBinding.getStyle();
153       if (style == null) {
154         // if the soap:binding element does not specify a style, 'document' is assumed
155
style = SoapBindConstants.DOCUMENT_STYLE;
156       }
157     }
158     SOAPEnvelope JavaDoc envelope = soapPart.getEnvelope();
159     // write body element
160
if (SoapBindConstants.DOCUMENT_STYLE.equals(style)) {
161       writeDocumentBody(bindOperation, inputData, envelope);
162     }
163     else {
164       writeRpcBody(bindOperation, inputData, envelope);
165     }
166     return soapMessage;
167   }
168   
169   protected void writeRpcBody(BindingOperation bindOperation, Element JavaDoc inputData, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
170     // obtain info on how message parts appear inside the body element
171
BindingInput bindInput = bindOperation.getBindingInput();
172     javax.wsdl.extensions.soap.SOAPBody soapBody = (javax.wsdl.extensions.soap.SOAPBody) WsdlUtil.getExtension(
173         bindInput.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BODY);
174     // exclude the use of encodings
175
if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) {
176       throw new RuntimeException JavaDoc("encoded use not supported");
177     }
178     // obtain the definitions of parts which appear inside the body, in parameter order
179
List JavaDoc partNames = soapBody.getParts();
180     Operation operation = bindOperation.getOperation();
181     List JavaDoc parameterOrder = operation.getParameterOrdering();
182     if (parameterOrder != null) {
183       if (partNames != null) {
184         // retain only parts specified by soap:body keeping the parameter order
185
parameterOrder = new ArrayList JavaDoc(parameterOrder);
186         parameterOrder.retainAll(partNames);
187       }
188       partNames = parameterOrder;
189     }
190     Message message = operation.getInput().getMessage();
191     // the message filters out parts that it does not define
192
Collection JavaDoc parts = getParts(message, partNames);
193     // create operation wrapper
194
Name JavaDoc operationName = envelope.createName(bindOperation.getName(), null, soapBody.getNamespaceURI());
195     SOAPElement JavaDoc operationElem = envelope.getBody().addBodyElement(operationName);
196     // fill in part values
197
Iterator JavaDoc partIt = parts.iterator();
198     while (partIt.hasNext()) {
199       Part part = (Part) partIt.next();
200       String JavaDoc partName = part.getName();
201       // create part accessor under operation wrapper
202
SOAPElement JavaDoc operPartAccessor = operationElem.addChildElement(partName);
203       // get part accessor from input message data
204
Element JavaDoc inputPartAccessor = NodeUtil.getElement(inputData, partName);
205       // copy input part to operation part
206
NodeUtil.copy(operPartAccessor, inputPartAccessor);
207     }
208   }
209   
210   protected void writeDocumentBody(BindingOperation bindOperation, Element JavaDoc inputData, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
211     // obtain info on how message parts appear inside the body element
212
BindingInput bindInput = bindOperation.getBindingInput();
213     javax.wsdl.extensions.soap.SOAPBody soapBody = (javax.wsdl.extensions.soap.SOAPBody) WsdlUtil.getExtension(
214         bindInput.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BODY);
215     // exclude the use of encodings
216
if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) {
217       throw new RuntimeException JavaDoc("encoded use not supported");
218     }
219     // obtain the definitions of parts which appear inside the body
220
Message message = bindOperation.getOperation().getInput().getMessage();
221     Collection JavaDoc parts = getParts(message, soapBody.getParts());
222     // fill in part values
223
Iterator JavaDoc partIt = parts.iterator();
224     switch (parts.size()) {
225     case 0:
226       break;
227     case 1: {
228       Part part = (Part) partIt.next();
229       if (part.getTypeName() != null) {
230         // a schema type defines the content of the body
231
NodeUtil.copy(envelope.getBody(), NodeUtil.getElement(inputData, part.getName()));
232       }
233       else {
234         writeDocumentPart(part, inputData, envelope);
235       }
236       break;
237     }
238     default:
239       while (partIt.hasNext()) {
240         Part part = (Part) partIt.next();
241         writeDocumentPart(part, inputData, envelope);
242       }
243     }
244   }
245
246   private static void writeDocumentPart(Part part, Element JavaDoc inputData, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
247     QName JavaDoc elementName = part.getElementName();
248     if (elementName == null) {
249       throw new RuntimeException JavaDoc("only one part may be specified if a " +
250           "type defines the contents of the body for document style");
251     }
252     String JavaDoc namespaceUri = elementName.getNamespaceURI();
253     String JavaDoc localName = elementName.getLocalPart();
254     // get part element from input message
255
Element JavaDoc inputPartAccessor = NodeUtil.getElement(inputData, part.getName());
256     Element JavaDoc inputPartElem = NodeUtil.getElement(inputPartAccessor, namespaceUri, localName);
257     // create part element directly under soap body
258
Name JavaDoc bodyPartName = envelope.createName(localName, inputPartElem.getPrefix(), namespaceUri);
259     SOAPElement JavaDoc bodyPartElem = envelope.getBody().addBodyElement(bodyPartName);
260     NodeUtil.copy(bodyPartElem, inputPartElem);
261   }
262
263   private static Collection JavaDoc getParts(Message message, List JavaDoc partNames) {
264     return partNames != null ? message.getOrderedParts(partNames) : message.getParts().values();
265   }
266   
267   protected Element JavaDoc readOutputData(BindingOperation bindOperation, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
268     // obtain info on the operation as a whole
269
SOAPOperation soapOperation = (SOAPOperation) WsdlUtil.getExtension(
270         bindOperation.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_OPERATION);
271     // determine whether the operation is rpc-oriented or document-oriented
272
String JavaDoc style = soapOperation.getStyle();
273     if (style == null) {
274       // default to the value specified in the soap:binding element
275
SOAPBinding soapBinding = (SOAPBinding) WsdlUtil.getExtension(
276           binding.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BINDING);
277       style = soapBinding.getStyle();
278       if (style == null) {
279         // if the soap:binding element does not specify a style, 'document' is assumed
280
style = SoapBindConstants.DOCUMENT_STYLE;
281       }
282     }
283     // read body element
284
Element JavaDoc outputData;
285     if (SoapBindConstants.DOCUMENT_STYLE.equals(style)) {
286       outputData = readDocumentBody(bindOperation, envelope);
287     }
288     else {
289       outputData = readRpcBody(bindOperation, envelope);
290     }
291     return outputData;
292   }
293
294   protected Element JavaDoc readRpcBody(BindingOperation bindOperation, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
295     // obtain info on how message parts appear inside the body element
296
BindingOutput bindOutput = bindOperation.getBindingOutput();
297     javax.wsdl.extensions.soap.SOAPBody soapBody = (javax.wsdl.extensions.soap.SOAPBody) WsdlUtil.getExtension(
298         bindOutput.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BODY);
299     // exclude the use of encodings
300
if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) {
301       throw new RuntimeException JavaDoc("encoded use not supported");
302     }
303     // obtain the definitions of parts which appear inside the body
304
Message message = bindOperation.getOperation().getInput().getMessage();
305     Collection JavaDoc parts = getParts(message, soapBody.getParts());
306     // get the operation wrapper
307
Element JavaDoc operationElem = DOMUtils.getFirstChildElement(envelope.getBody());
308     // create the output message instance
309
Element JavaDoc outputData = MessageVariableInstance.createMessageElement();
310     Document JavaDoc elemFactory = outputData.getOwnerDocument();
311     // fill in part values
312
Iterator JavaDoc partIt = parts.iterator();
313     while (partIt.hasNext()) {
314       Part part = (Part) partIt.next();
315       String JavaDoc partName = part.getName();
316       // get part accessor from operation wrapper
317
Element JavaDoc operPartAccessor = NodeUtil.getElement(operationElem, partName);
318       // create part accessor under output data
319
Element JavaDoc outputPartAccessor = elemFactory.createElementNS(null, partName);
320       outputData.appendChild(outputPartAccessor);
321       // copy operation part to output part
322
NodeUtil.copy(outputPartAccessor, operPartAccessor);
323     }
324     return outputData;
325   }
326
327   protected Element JavaDoc readDocumentBody(BindingOperation bindOperation, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
328     // obtain info on how message parts appear inside the body element
329
BindingOutput bindOutput = bindOperation.getBindingOutput();
330     javax.wsdl.extensions.soap.SOAPBody soapBody = (javax.wsdl.extensions.soap.SOAPBody) WsdlUtil.getExtension(
331         bindOutput.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BODY);
332     // exclude the use of encodings
333
if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) {
334       throw new RuntimeException JavaDoc("encoded use not supported");
335     }
336     // obtain the definitions of parts which appear inside the body
337
Message message = bindOperation.getOperation().getInput().getMessage();
338     Collection JavaDoc parts = getParts(message, soapBody.getParts());
339     // create the output message data
340
Element JavaDoc outputData = MessageVariableInstance.createMessageElement();
341     Document JavaDoc outputDocument = outputData.getOwnerDocument();
342     // fill in part values
343
Iterator JavaDoc partIt = parts.iterator();
344     switch (parts.size()) {
345     case 0:
346       break;
347     case 1: {
348       Part part = (Part) partIt.next();
349       /* the contents of a composite body can be defined using a type; in this usage,
350        * only one part may be specified */

351       if (part.getTypeName() != null) {
352         // create part accessor under output message data
353
Element JavaDoc targetAccessor = outputDocument.createElementNS(null, part.getName());
354         outputData.appendChild(targetAccessor);
355         // copy body to output part directly
356
NodeUtil.copy(targetAccessor, envelope.getBody());
357       }
358       else {
359         readDocumentPart(part, outputData, envelope);
360       }
361       break;
362     }
363     default:
364       while (partIt.hasNext()) {
365         Part part = (Part) partIt.next();
366         readDocumentPart(part, outputData, envelope);
367       }
368     }
369     return outputData;
370   }
371
372   private static void readDocumentPart(Part part, Element JavaDoc outputData, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
373     // get element definition
374
QName JavaDoc elementName = part.getElementName();
375     if (elementName == null) {
376       throw new RuntimeException JavaDoc("only one part may be specified if a " +
377           "type defines the contents of the body for document style");
378     }
379     // get part element from soap body
380
Element JavaDoc bodyPartElem = NodeUtil.getElement(envelope.getBody(),
381         elementName.getNamespaceURI(), elementName.getLocalPart());
382     // create part accessor/element under output data
383
Element JavaDoc outputPartElem = createPartElement(outputData, part.getName(), elementName);
384     // copy body part to output part
385
NodeUtil.copy(outputPartElem, bodyPartElem);
386   }
387
388   private static Element JavaDoc createPartElement(Element JavaDoc output, String JavaDoc partName, QName JavaDoc elementName) {
389     // create part accessor
390
Element JavaDoc partAccessor = output.getOwnerDocument().createElementNS(null, partName);
391     output.appendChild(partAccessor);
392     // create part element with the given name under accessor
393
Element JavaDoc partElem = partAccessor.getOwnerDocument().createElementNS(
394         elementName.getNamespaceURI(), elementName.getLocalPart());
395     partAccessor.appendChild(partElem);
396     return partElem;
397   }
398   
399   protected Fault readFault(BindingOperation bindOperation, SOAPEnvelope JavaDoc envelope) throws SOAPException JavaDoc {
400     Detail JavaDoc detail = envelope.getBody().getFault().getDetail();
401     /* look for a fault whose message contains a single part defined by an element
402      * where that element appears in the contents of the soap fault detail */

403     Iterator JavaDoc faultIt = bindOperation.getOperation().getFaults().values().iterator();
404     while (faultIt.hasNext()) {
405       javax.wsdl.Fault fault = (javax.wsdl.Fault) faultIt.next();
406       // part definition
407
Message message = fault.getMessage();
408       Map JavaDoc parts = message.getParts();
409       if (parts.size() != 1) {
410         throw new RuntimeException JavaDoc("fault message must have a single part");
411       }
412       Part part = (Part) parts.values().iterator().next();
413       QName JavaDoc elementName = part.getElementName();
414       if (elementName == null) {
415         throw new RuntimeException JavaDoc("the part of a fault message must reference an element");
416       }
417       // locate the element referenced by the part under the soap detail element
418
Element JavaDoc detailPartElem = NodeUtil.getElement(detail, elementName.getNamespaceURI(), elementName.getLocalPart());
419       if (detailPartElem != null) {
420         // obtain info on the contents of the soap detail element
421
BindingFault bindFault = bindOperation.getBindingFault(fault.getName());
422         SOAPFault soapFault = (SOAPFault) WsdlUtil.getExtension(bindFault.getExtensibilityElements(),
423             SOAPConstants.Q_ELEM_SOAP_FAULT);
424         // exclude the use of encodings
425
if (SoapBindConstants.ENCODED_USE.equals(soapFault.getUse())) {
426           throw new RuntimeException JavaDoc("encoded use not supported");
427         }
428         // fill in part value
429
Element JavaDoc faultData = MessageVariableInstance.createMessageElement();
430         // create part accessor/element under fault data
431
Element JavaDoc faultPartElem = createPartElement(faultData, part.getName(), elementName);
432         // copy detail part to fault data part
433
NodeUtil.copy(faultPartElem, detailPartElem);
434         /* a WSDL fault is identified in BPEL by a qualified name formed by the target namespace of the
435          * corresponding portType and the fault name */

436         QName JavaDoc faultName = new QName JavaDoc(binding.getPortType().getQName().getNamespaceURI(), fault.getName());
437         return new Fault(faultName, faultData, new MessageTypeInfo(message));
438       }
439     }
440     throw new RuntimeException JavaDoc("no fault matches the contents of the soap detail element: " + detail);
441   }
442 }
443
Popular Tags