1 package org.jbpm.bpel.service.soap; 2 3 import java.util.ArrayList ; 4 import java.util.Collection ; 5 import java.util.Iterator ; 6 import java.util.List ; 7 import java.util.Map ; 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 ; 21 import javax.xml.soap.Detail ; 22 import javax.xml.soap.MessageFactory ; 23 import javax.xml.soap.Name ; 24 import javax.xml.soap.SOAPConnection ; 25 import javax.xml.soap.SOAPConnectionFactory ; 26 import javax.xml.soap.SOAPElement ; 27 import javax.xml.soap.SOAPEnvelope ; 28 import javax.xml.soap.SOAPException ; 29 import javax.xml.soap.SOAPMessage ; 30 import javax.xml.soap.SOAPPart ; 31 32 import org.apache.commons.logging.Log; 33 import org.apache.commons.logging.LogFactory; 34 import org.w3c.dom.Document ; 35 import org.w3c.dom.Element ; 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 50 public class SoapEndpointCaller { 51 52 private String address; 53 private Binding binding; 54 55 private static final Log log = LogFactory.getLog(SoapEndpointCaller.class); 56 57 public String getAddress() { 58 return address; 59 } 60 61 public void setAddress(String 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 if (soapBinding == null) { 74 throw new IllegalArgumentException ("non-soap bindings not supported"); 75 } 76 String transport = soapBinding.getTransportURI(); 78 if (!SoapBindConstants.HTTP_TRANSPORT_URI.equals(transport)) { 79 throw new IllegalArgumentException ("non-http transport protocols not supported"); 80 } 81 this.binding = binding; 82 } 83 84 85 public Element call(String operation, Element inputData) { 86 BindingOperation bindOperation = binding.getBindingOperation(operation, null, null); 87 try { 88 SOAPMessage soapOutput = callImpl(bindOperation, inputData); 89 SOAPEnvelope envelope = soapOutput.getSOAPPart().getEnvelope(); 91 if (envelope.getBody().hasFault()) { 92 throw readFault(bindOperation, envelope); 93 } 94 return readOutputData(bindOperation, envelope); 95 } 96 catch (SOAPException e) { 97 log.error(e); 98 throw new RuntimeException ("failed to call soap endpoint: " + address, e); 99 } 100 } 101 102 public void callOneWay(String operation, Element inputData) { 103 BindingOperation bindOperation = binding.getBindingOperation(operation, null, null); 104 try { 105 callImpl(bindOperation, inputData); 106 } 107 catch (SOAPException e) { 108 log.error(e); 109 throw new RuntimeException ("failed to call soap endpoint: " + address, e); 110 } 111 } 112 113 protected SOAPMessage callImpl(BindingOperation bindOperation, Element inputData) throws SOAPException { 114 SOAPConnection soapConnection = null; 115 try { 116 SOAPMessage soapInput = writeInputMessage(bindOperation, inputData); 118 SOAPConnectionFactory 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 e) { 129 log.warn("coult not close soap connection", e); 130 } 131 } 132 } 133 } 134 135 protected SOAPMessage writeInputMessage(BindingOperation bindOperation, Element inputData) throws SOAPException { 136 MessageFactory messageFactory = MessageFactory.newInstance(); 138 SOAPMessage soapMessage = messageFactory.createMessage(); 139 SOAPPart soapPart = soapMessage.getSOAPPart(); 140 SOAPOperation soapOperation = (SOAPOperation) WsdlUtil.getExtension( 142 bindOperation.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_OPERATION); 143 String action = soapOperation.getSoapActionURI(); 145 soapPart.setMimeHeader(SoapBindConstants.SOAP_ACTION_HEADER, action); 146 String style = soapOperation.getStyle(); 148 if (style == null) { 149 SOAPBinding soapBinding = (SOAPBinding) WsdlUtil.getExtension( 151 binding.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BINDING); 152 style = soapBinding.getStyle(); 153 if (style == null) { 154 style = SoapBindConstants.DOCUMENT_STYLE; 156 } 157 } 158 SOAPEnvelope envelope = soapPart.getEnvelope(); 159 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 inputData, SOAPEnvelope envelope) throws SOAPException { 170 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 if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) { 176 throw new RuntimeException ("encoded use not supported"); 177 } 178 List partNames = soapBody.getParts(); 180 Operation operation = bindOperation.getOperation(); 181 List parameterOrder = operation.getParameterOrdering(); 182 if (parameterOrder != null) { 183 if (partNames != null) { 184 parameterOrder = new ArrayList (parameterOrder); 186 parameterOrder.retainAll(partNames); 187 } 188 partNames = parameterOrder; 189 } 190 Message message = operation.getInput().getMessage(); 191 Collection parts = getParts(message, partNames); 193 Name operationName = envelope.createName(bindOperation.getName(), null, soapBody.getNamespaceURI()); 195 SOAPElement operationElem = envelope.getBody().addBodyElement(operationName); 196 Iterator partIt = parts.iterator(); 198 while (partIt.hasNext()) { 199 Part part = (Part) partIt.next(); 200 String partName = part.getName(); 201 SOAPElement operPartAccessor = operationElem.addChildElement(partName); 203 Element inputPartAccessor = NodeUtil.getElement(inputData, partName); 205 NodeUtil.copy(operPartAccessor, inputPartAccessor); 207 } 208 } 209 210 protected void writeDocumentBody(BindingOperation bindOperation, Element inputData, SOAPEnvelope envelope) throws SOAPException { 211 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 if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) { 217 throw new RuntimeException ("encoded use not supported"); 218 } 219 Message message = bindOperation.getOperation().getInput().getMessage(); 221 Collection parts = getParts(message, soapBody.getParts()); 222 Iterator 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 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 inputData, SOAPEnvelope envelope) throws SOAPException { 247 QName elementName = part.getElementName(); 248 if (elementName == null) { 249 throw new RuntimeException ("only one part may be specified if a " + 250 "type defines the contents of the body for document style"); 251 } 252 String namespaceUri = elementName.getNamespaceURI(); 253 String localName = elementName.getLocalPart(); 254 Element inputPartAccessor = NodeUtil.getElement(inputData, part.getName()); 256 Element inputPartElem = NodeUtil.getElement(inputPartAccessor, namespaceUri, localName); 257 Name bodyPartName = envelope.createName(localName, inputPartElem.getPrefix(), namespaceUri); 259 SOAPElement bodyPartElem = envelope.getBody().addBodyElement(bodyPartName); 260 NodeUtil.copy(bodyPartElem, inputPartElem); 261 } 262 263 private static Collection getParts(Message message, List partNames) { 264 return partNames != null ? message.getOrderedParts(partNames) : message.getParts().values(); 265 } 266 267 protected Element readOutputData(BindingOperation bindOperation, SOAPEnvelope envelope) throws SOAPException { 268 SOAPOperation soapOperation = (SOAPOperation) WsdlUtil.getExtension( 270 bindOperation.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_OPERATION); 271 String style = soapOperation.getStyle(); 273 if (style == null) { 274 SOAPBinding soapBinding = (SOAPBinding) WsdlUtil.getExtension( 276 binding.getExtensibilityElements(), SOAPConstants.Q_ELEM_SOAP_BINDING); 277 style = soapBinding.getStyle(); 278 if (style == null) { 279 style = SoapBindConstants.DOCUMENT_STYLE; 281 } 282 } 283 Element 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 readRpcBody(BindingOperation bindOperation, SOAPEnvelope envelope) throws SOAPException { 295 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 if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) { 301 throw new RuntimeException ("encoded use not supported"); 302 } 303 Message message = bindOperation.getOperation().getInput().getMessage(); 305 Collection parts = getParts(message, soapBody.getParts()); 306 Element operationElem = DOMUtils.getFirstChildElement(envelope.getBody()); 308 Element outputData = MessageVariableInstance.createMessageElement(); 310 Document elemFactory = outputData.getOwnerDocument(); 311 Iterator partIt = parts.iterator(); 313 while (partIt.hasNext()) { 314 Part part = (Part) partIt.next(); 315 String partName = part.getName(); 316 Element operPartAccessor = NodeUtil.getElement(operationElem, partName); 318 Element outputPartAccessor = elemFactory.createElementNS(null, partName); 320 outputData.appendChild(outputPartAccessor); 321 NodeUtil.copy(outputPartAccessor, operPartAccessor); 323 } 324 return outputData; 325 } 326 327 protected Element readDocumentBody(BindingOperation bindOperation, SOAPEnvelope envelope) throws SOAPException { 328 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 if (SoapBindConstants.ENCODED_USE.equals(soapBody.getUse())) { 334 throw new RuntimeException ("encoded use not supported"); 335 } 336 Message message = bindOperation.getOperation().getInput().getMessage(); 338 Collection parts = getParts(message, soapBody.getParts()); 339 Element outputData = MessageVariableInstance.createMessageElement(); 341 Document outputDocument = outputData.getOwnerDocument(); 342 Iterator partIt = parts.iterator(); 344 switch (parts.size()) { 345 case 0: 346 break; 347 case 1: { 348 Part part = (Part) partIt.next(); 349 351 if (part.getTypeName() != null) { 352 Element targetAccessor = outputDocument.createElementNS(null, part.getName()); 354 outputData.appendChild(targetAccessor); 355 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 outputData, SOAPEnvelope envelope) throws SOAPException { 373 QName elementName = part.getElementName(); 375 if (elementName == null) { 376 throw new RuntimeException ("only one part may be specified if a " + 377 "type defines the contents of the body for document style"); 378 } 379 Element bodyPartElem = NodeUtil.getElement(envelope.getBody(), 381 elementName.getNamespaceURI(), elementName.getLocalPart()); 382 Element outputPartElem = createPartElement(outputData, part.getName(), elementName); 384 NodeUtil.copy(outputPartElem, bodyPartElem); 386 } 387 388 private static Element createPartElement(Element output, String partName, QName elementName) { 389 Element partAccessor = output.getOwnerDocument().createElementNS(null, partName); 391 output.appendChild(partAccessor); 392 Element 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 envelope) throws SOAPException { 400 Detail detail = envelope.getBody().getFault().getDetail(); 401 403 Iterator faultIt = bindOperation.getOperation().getFaults().values().iterator(); 404 while (faultIt.hasNext()) { 405 javax.wsdl.Fault fault = (javax.wsdl.Fault) faultIt.next(); 406 Message message = fault.getMessage(); 408 Map parts = message.getParts(); 409 if (parts.size() != 1) { 410 throw new RuntimeException ("fault message must have a single part"); 411 } 412 Part part = (Part) parts.values().iterator().next(); 413 QName elementName = part.getElementName(); 414 if (elementName == null) { 415 throw new RuntimeException ("the part of a fault message must reference an element"); 416 } 417 Element detailPartElem = NodeUtil.getElement(detail, elementName.getNamespaceURI(), elementName.getLocalPart()); 419 if (detailPartElem != null) { 420 BindingFault bindFault = bindOperation.getBindingFault(fault.getName()); 422 SOAPFault soapFault = (SOAPFault) WsdlUtil.getExtension(bindFault.getExtensibilityElements(), 423 SOAPConstants.Q_ELEM_SOAP_FAULT); 424 if (SoapBindConstants.ENCODED_USE.equals(soapFault.getUse())) { 426 throw new RuntimeException ("encoded use not supported"); 427 } 428 Element faultData = MessageVariableInstance.createMessageElement(); 430 Element faultPartElem = createPartElement(faultData, part.getName(), elementName); 432 NodeUtil.copy(faultPartElem, detailPartElem); 434 436 QName faultName = new QName (binding.getPortType().getQName().getNamespaceURI(), fault.getName()); 437 return new Fault(faultName, faultData, new MessageTypeInfo(message)); 438 } 439 } 440 throw new RuntimeException ("no fault matches the contents of the soap detail element: " + detail); 441 } 442 } 443 | Popular Tags |