1 4 5 9 10 package org.openlaszlo.remote.soap; 11 12 import java.util.*; 13 import java.io.*; 14 import javax.xml.rpc.*; 15 import javax.xml.parsers.*; 16 import javax.xml.namespace.*; 17 import org.w3c.dom.*; 18 import org.xml.sax.*; 19 import org.apache.axis.Constants; 20 import org.apache.axis.utils.*; 21 import org.apache.log4j.Logger; 22 23 24 27 public class WSDLParser 28 { 29 private static Logger mLogger = Logger.getLogger(WSDLParser.class); 30 31 public String mTargetNamespace; 32 public String mNamespaceURI_WSDL; 33 public String mNamespaceURI_WSDL_SOAP; 34 public String mNamespaceURI_SOAP_ENC; 35 public String mNamespaceURI_SCHEMA_XSD; 36 37 public QName mQNameOperationInput; 38 public QName mQNameOperationOutput; 39 40 HashMap mComplexTypeMap = new HashMap(); 41 42 43 public static final String [] URIS_SOAP_HTTP = { 44 Constants.URI_SOAP11_HTTP, 45 Constants.URI_SOAP12_HTTP 46 }; 47 48 49 static DocumentBuilder mBuilder = null; 50 51 52 Element mDefinitions = null; 53 54 { 58 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 59 factory.setNamespaceAware(true); 60 try { 61 mBuilder = factory.newDocumentBuilder(); 62 } catch (ParserConfigurationException e) { 63 mLogger.error("Can't create DocumentBuilder"); 64 } 65 } 66 67 68 71 private WSDLParser() { } 72 73 74 85 static public LZSOAPService parse(String wsdl, InputSource is, String serviceName, 86 String servicePort) 87 throws WSDLException, ServiceException { 88 WSDLParser parser = new WSDLParser(); 89 return parser.parseWSDL(wsdl, is, serviceName, servicePort); 90 } 91 92 101 static public LZSOAPService parse(String wsdl, InputSource is) 102 throws WSDLException, ServiceException { 103 return parse(wsdl, is, null, null); 104 } 105 106 107 113 void setNamespaces() { 114 mTargetNamespace = mDefinitions.getAttribute("targetNamespace"); 115 116 NamedNodeMap attrs = mDefinitions.getAttributes(); 117 for (int i=0; i < attrs.getLength(); i++) { 118 String attr = ((Attr)attrs.item(i)).getValue(); 119 if (Constants.isWSDL(attr)) { 120 mNamespaceURI_WSDL = attr; 121 } else if (Constants.isSchemaXSD(attr)) { 122 mNamespaceURI_SCHEMA_XSD = attr; 123 } else if (Constants.isWSDLSOAP(attr)) { 124 mNamespaceURI_WSDL_SOAP = attr; 125 } else if (Constants.isSOAP_ENC(attr)) { 126 mNamespaceURI_SOAP_ENC = attr; 127 } 128 } 129 130 mQNameOperationInput = new QName(mNamespaceURI_WSDL, "input"); 131 mQNameOperationOutput = new QName(mNamespaceURI_WSDL, "output"); 132 133 if (mLogger.isDebugEnabled()) { 134 mLogger.debug("WSDL: URI_WSDL " + mNamespaceURI_WSDL); 135 mLogger.debug("WSDL: URI_SCHEMA_XSD " + mNamespaceURI_SCHEMA_XSD); 136 mLogger.debug("WSDL: URI_WSDL_SOAP " + mNamespaceURI_WSDL_SOAP); 137 mLogger.debug("WSDL: URI_SOAP_ENC " + mNamespaceURI_SOAP_ENC); 138 mLogger.debug("WSDL: targetnamespace " + mTargetNamespace); 139 } 140 } 141 142 143 155 LZSOAPService parseWSDL(String wsdl, InputSource is, String serviceName, 156 String servicePort) 157 throws WSDLException, ServiceException { 158 159 LZSOAPService soapService = null; 160 161 try { 162 mDefinitions = mBuilder.parse(is).getDocumentElement(); 163 } catch (IOException e) { 164 throw new WSDLException("IOException: " + e.getMessage()); 165 } catch (SAXException e) { 166 throw new WSDLException("SAXException: " + e.getMessage()); 167 } 168 169 setNamespaces(); 170 171 SchemaParser sp = null; 172 try { 173 NodeList schemalist = getSchema(); 174 if (schemalist != null) { 175 for (int i=0; i < schemalist.getLength(); i++) { 176 Element schema = (Element)schemalist.item(i); 177 sp = new SchemaParser(this, schema); 178 sp.parse(mComplexTypeMap); 179 } 180 } 181 } catch (Exception e) { 182 mLogger.warn("SchemaParser", e); 183 } 184 185 Element service; 186 if (serviceName == null) 187 service = 188 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL, 189 mDefinitions, "service"); 190 else 191 service = findServiceElement(serviceName); 192 193 if (service == null) { 194 if (serviceName != null) 195 throw new WSDLException("no service named " + serviceName + 196 " was found."); 197 else 198 throw new WSDLException("no service was found"); 199 } 200 201 202 serviceName = service.getAttribute("name"); 203 if (serviceName.equals("")) { 204 throw new WSDLException("service has no name"); 205 } 206 207 208 NodeList portList = service.getElementsByTagNameNS(mNamespaceURI_WSDL, "port"); 209 int len = portList.getLength(); 210 if (len == 0) 211 throw new WSDLException("No SOAP ports found for service " + 212 serviceName); 213 214 for (int i=0; i < len; i++) { 215 Element port = (Element)portList.item(i); 216 217 String portName = port.getAttribute("name"); 218 if ( portName == null ) { 219 mLogger.warn("encountered port with no name"); 220 continue; 221 } 222 223 if (servicePort != null && ! servicePort.equals(portName)) { 224 continue; 225 } 226 227 if (doesPortSupportSOAP(port)) { 228 229 Element binding = getBindingElement(port); 230 mLogger.debug("binding: " + binding); 231 232 Element soapBinding = 233 LZSOAPUtils.getFirstElementByTagNameNS 234 (mNamespaceURI_WSDL_SOAP, binding, "binding"); 235 236 if (soapBinding == null) { 237 throw new WSDLException("no SOAP binding for port " + 238 portName); 239 } 240 241 String transport = soapBinding.getAttribute("transport"); 243 if ( ! isSOAPHTTPTransport(transport) ) { 244 if ( servicePort != null && servicePort.equals(portName)) { 245 throw new WSDLException("port " + servicePort + 246 " does not have a valid SOAP transport"); 247 } else { 248 continue; 249 } 250 } 251 252 soapService = new LZSOAPService(wsdl, service.getAttribute("name"), 253 portName, getEndpointAddress(port), 254 transport, mTargetNamespace, 255 mNamespaceURI_SCHEMA_XSD, 256 mNamespaceURI_SOAP_ENC); 257 258 String defaultStyle = soapBinding.getAttribute("style"); 259 if ( "".equals(defaultStyle) ) defaultStyle = "document"; 260 261 parseOperations(soapService, binding, defaultStyle); 262 break; 263 } else if (servicePort != null && servicePort.equals(portName)) { 264 throw new WSDLException("port " + servicePort + 265 " does not support SOAP"); 266 } 267 } 268 269 if (soapService == null) { 270 throw new WSDLException("could not find requested SOAP service " 271 + "(service: " + serviceName 272 + ", port: " + servicePort 273 + ")"); 274 } 275 276 soapService.setSchemaComplexTypes(mComplexTypeMap); 277 278 return soapService; 279 } 280 281 282 287 NodeList getSchema() { 288 return mDefinitions.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, 289 "schema"); 290 } 291 292 298 void parseOperations(LZSOAPService service, Element binding, 299 String defaultStyle) throws WSDLException { 300 301 String bindingType = binding.getAttribute("type"); 302 if ("".equals(bindingType)) { 303 throw new WSDLException("binding does not have a type attribute"); 304 } 305 QName bindingTypeQName = XMLUtils.getQNameFromString(bindingType, binding); 306 307 Element portType = findPortTypeElement(bindingTypeQName.getLocalPart()); 309 if (portType == null) { 310 throw new WSDLException("could not find portType named " + 311 bindingTypeQName); 312 } 313 314 NodeList portTypeOpList = 316 portType.getElementsByTagNameNS(mNamespaceURI_WSDL, "operation"); 317 if (portTypeOpList.getLength() == 0) { 318 throw new WSDLException("portType named " + 319 bindingTypeQName.getLocalPart() + 320 " has no operations"); 321 } 322 323 Map operationMap = new HashMap(); 324 service.setOperations(operationMap); 325 326 NodeList list = binding.getElementsByTagNameNS(mNamespaceURI_WSDL, "operation"); 327 for (int i=0; i < list.getLength(); i++) { 328 Element operation = (Element)list.item(i); 329 String opName = operation.getAttribute("name"); 330 if ( "".equals(opName) ) { 331 mLogger.warn("name not found for an operation element"); 332 continue; 333 } 334 335 Element soapOperation = 343 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL_SOAP, 344 operation, "operation"); 345 346 String soapAction = null; 347 if (isSOAPHTTPTransport(service.getTransport())) { 348 Attr soapActionAttr = soapOperation.getAttributeNode("soapAction"); 349 if ( soapActionAttr == null ) { 350 mLogger.warn("required soapAction attribute not found for <soap:operation>"); 351 continue; 352 } 353 soapAction = soapActionAttr.getValue(); 354 } 355 356 String style = soapOperation.getAttribute("style"); 357 if ( "".equals(style) ) 358 style = defaultStyle; 359 360 Element portTypeOp = findPortTypeOperationElement(portTypeOpList, opName); 361 if (portTypeOp == null) { 362 mLogger.warn("could not find portType operation named " + opName); 363 continue; 364 } 365 366 if (! isRequestResponseOperation(portTypeOp)) { 368 mLogger.warn("WARNING: portType operation named " + opName + 369 " is not a supported operation." + 370 " Only request-response operations are supported."); 371 continue; 372 } 373 374 LZSOAPMessage inputBody; 375 LZSOAPMessage outputBody; 376 try { 377 inputBody = getMessage(operation, portTypeOp, "input", "Request"); 378 outputBody = getMessage(operation, portTypeOp, "output", "Response"); 379 } catch (WSDLException e) { 380 mLogger.warn(e.getMessage()); 381 continue; 382 } 383 384 LZSOAPOperation op = new LZSOAPOperation(opName); 385 op.setSoapAction(soapAction); 386 op.setStyle(style); 387 op.setInputMessage(inputBody); 388 op.setOutputMessage(outputBody); 389 op.setMangledName(opName + "_" + inputBody.getName() + "_" + outputBody.getName()); 390 op.setIsDocumentLiteralWrapped(isDocumentLiteralWrapped(op)); 391 392 if (operationMap.containsKey(op.getMangledName())) { 393 mLogger.warn("operation named " + op.getMangledName() + " is not unique"); 394 continue; 395 } 396 397 if (operationMap.containsKey(op.getName())) { 399 400 LZSOAPOperation prevOp = (LZSOAPOperation)operationMap.get(op.getName()); 403 if ( prevOp.getMangledName().equals(op.getMangledName()) ) { 404 mLogger.warn("operation named" + op.getMangledName() + 405 " is not unique"); 406 continue; 407 } 408 409 operationMap.put(op.getMangledName(), op); 410 411 } else { 412 operationMap.put(op.getName(), op); 413 } 414 415 } 416 } 417 418 419 425 boolean isDocumentLiteralWrapped(LZSOAPOperation op) { 426 427 if (! op.getStyle().equals("document")) { 429 return false; 430 } 431 432 LZSOAPMessage inputMesg = op.getInputMessage(); 433 if (! inputMesg.getUse().equals("literal")) { 434 return false; 435 } 436 437 List parts = inputMesg.getParts(); 439 if (parts == null || parts.size() != 1) { 440 return false; 441 } 442 443 LZSOAPPart part = (LZSOAPPart)parts.get(0); 445 String eName = part.getElement(); 446 if ( eName == null ) { 447 return false; 448 } 449 450 QName eQName = XMLUtils.getQNameFromString(eName, mDefinitions); 452 Element element = findSchemaElement(eQName.getLocalPart()); 453 if (element == null) { 454 return false; 455 } 456 457 String name = element.getAttribute("name"); 459 if (! name.equals(op.getName())) { 460 return false; 461 } 462 463 NodeList attrList = 465 element.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, 466 "attribute"); 467 if (attrList.getLength() != 0) { 468 return false; 469 } 470 471 return true; 472 } 473 474 480 Element findServiceElement(String name) { 481 return findElementByName(mNamespaceURI_WSDL, mDefinitions, 482 "service", name); 483 } 484 485 486 492 Element findSchemaElement(String name) { 493 return findElementByName(mNamespaceURI_SCHEMA_XSD, mDefinitions, 494 "element", name); 495 } 496 497 503 Element findMessageElement(String name) { 504 return findElementByName(mNamespaceURI_WSDL, mDefinitions, "message", name); 505 } 506 507 513 Element findPortTypeElement(String name) { 514 return findElementByName(mNamespaceURI_WSDL, mDefinitions, "portType", name); 515 } 516 517 524 Element findPortTypeOperationElement(NodeList portTypeOpList, String name) { 525 return findElementByName(portTypeOpList, name); 526 } 527 528 537 Element findElementByName(String ns, Element owner, String tag, String name) { 538 NodeList list = owner.getElementsByTagNameNS(ns, tag); 539 return findElementByName(list, name); 540 } 541 542 549 Element findElementByName(NodeList list, String name) { 550 for (int i=0; i < list.getLength(); i++) { 551 Element e = (Element)list.item(i); 552 if ( name.equals(e.getAttribute("name")) ) 553 return e; 554 } 555 return null; 556 } 557 558 568 LZSOAPMessage getMessage(Element bindOp, Element portTypeOp, 569 String tag, String appendName) 570 throws WSDLException { 571 572 Element opType = 573 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL, 574 portTypeOp, tag); 575 String opName = portTypeOp.getAttribute("name"); 576 577 String name = opType.getAttribute("name"); 578 if (name.equals("")) { 579 name = opName + appendName; 580 } 581 582 LZSOAPMessage message = new LZSOAPMessage(name, tag); 583 584 Element bindTag = 585 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL, 586 bindOp, tag); 587 if (bindTag == null) { 588 throw new WSDLException("could not find " + tag + 589 " element for bind operation " + opName); 590 } 591 592 Element soapBody = 594 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL_SOAP, 595 bindTag, "body"); 596 597 String use = soapBody.getAttribute("use"); 598 if (use.equals("")) { 599 throw new WSDLException("Attribute use is not defined for " + tag + 600 " <soap:body> in operation " + opName); 601 } 602 message.setUse(use); 603 604 String parts = soapBody.getAttribute("parts"); 605 if (! parts.equals("")) { 606 message.setPartNames(getPartSet(parts)); 607 } 608 609 String mesgName = opType.getAttribute("message"); 610 QName mesgQName = XMLUtils.getQNameFromString(mesgName, opType); 611 Element mesgElement = findMessageElement(mesgQName.getLocalPart()); 612 if (mesgElement == null) { 613 throw new WSDLException("could not find message element named " + 614 mesgQName.getLocalPart()); 615 } 616 617 618 bindMessage(message, mesgElement, tag); 619 620 return message; 621 } 622 623 624 629 void bindMessage(LZSOAPMessage soapMessage, Element mesgElement, String tag) 630 throws WSDLException { 631 632 List parts = new Vector(); 633 Set partNames = soapMessage.getPartNames(); 634 635 NodeList list = mesgElement.getElementsByTagNameNS(mNamespaceURI_WSDL, "part"); 637 for (int i=0; i < list.getLength(); i++) { 638 Element part = (Element)list.item(i); 639 Attr nameAttr = part.getAttributeNode("name"); 640 if (nameAttr == null) { 641 throw new WSDLException("part for message named " + 642 mesgElement.getAttribute("name") + 643 " does not have required name attribute"); 644 } 645 String name = nameAttr.getValue(); 646 647 if (partNames != null && ! partNames.contains(name)) continue; 649 650 LZSOAPPart p = new LZSOAPPart(name); 651 652 ParameterMode mode; 653 if (tag.equals("output")) { 654 mode = ParameterMode.OUT; 655 } else { 656 mode = ParameterMode.IN; 657 } 658 p.setParameterMode(mode); 659 660 Attr elementAttr = part.getAttributeNode("element"); 661 Attr typeAttr = part.getAttributeNode("type"); 662 663 if (elementAttr != null) { 664 p.setElement(elementAttr.getValue()); 665 } 666 667 if (typeAttr != null) { 668 QName qname = XMLUtils.getQNameFromString(typeAttr.getValue(), 669 part); 670 671 ComplexType ct = (ComplexType)mComplexTypeMap.get(qname); 673 if (ct == null) { 674 if (Constants.isSchemaXSD(qname.getNamespaceURI()) ) { 675 ct = new ComplexType(qname); 676 mComplexTypeMap.put(qname, ct); 677 } else { 678 throw new WSDLException("could not find type for " + qname); 679 } 680 } 681 p.setType(ct); 682 } 683 684 parts.add(p); 685 } 686 687 soapMessage.setParts(parts); 688 } 689 690 691 697 Set getPartSet(String nmtokens) { 698 Set set = null; 699 StringTokenizer st = new StringTokenizer(nmtokens); 700 while (st.hasMoreTokens()) { 701 if (set == null) set = new HashSet(); 702 set.add(st.nextToken()); 703 } 704 return set; 705 } 706 707 708 715 boolean isRequestResponseOperation(Element op) { 716 Node n = op.getFirstChild(); 717 while (n != null && 718 ( n.getNodeType() != Node.ELEMENT_NODE || 719 n.getNodeName().equals("documentation")) ) { 720 n = n.getNextSibling(); 721 } 722 723 QName input = XMLUtils.getQNameFromString(n.getNodeName(), op); 725 input = new QName(n.getNamespaceURI(), input.getLocalPart()); 726 if (n == null || ! input.equals(mQNameOperationInput)) 727 return false; 728 729 n = n.getNextSibling(); 730 while (n != null && 731 n.getNodeType() != Node.ELEMENT_NODE) { 732 n = n.getNextSibling(); 733 } 734 QName output = XMLUtils.getQNameFromString(n.getNodeName(), op); 735 output = new QName(n.getNamespaceURI(), output.getLocalPart()); 736 if (n == null || ! output.equals(mQNameOperationOutput)) 737 return false; 738 739 return true; 740 } 741 742 743 750 boolean isSOAPHTTPTransport(String transport) { 751 if (transport == null) 752 return false; 753 754 for (int i=0; i<URIS_SOAP_HTTP.length; i++) { 755 if (URIS_SOAP_HTTP[i].equals(transport)) { 756 return true; 757 } 758 } 759 return false; 760 } 761 762 768 String getEndpointAddress(Element port) { 769 Element soapAddress = 770 LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL_SOAP, 771 mDefinitions, "address"); 772 String name = port.getAttribute("name"); 773 return soapAddress.getAttribute("location"); 774 } 775 776 782 Element getBindingElement(Element port) { 783 QName bindingQName = 784 XMLUtils.getQNameFromString(port.getAttribute("binding"), port); 785 return getElementByAttributeNS(mNamespaceURI_WSDL, "binding", "name", 786 bindingQName); 787 } 788 789 790 799 Element getElementByAttributeNS(String ns, String elementName, 800 String attrName, QName attrValue) { 801 NodeList list = mDefinitions.getElementsByTagNameNS(ns, elementName); 802 803 int length = list.getLength(); 804 if (length == 0) return null; 805 806 for (int i=0; i < length; i++) { 807 Element element = (Element)list.item(i); 808 String searchAttr = element.getAttribute(attrName); 809 if (searchAttr.equals(attrValue.getLocalPart())) { 810 return element; 811 } 812 } 813 814 return null; 815 } 816 817 818 824 boolean doesPortSupportSOAP(Element port) { 825 return LZSOAPUtils.getFirstElementByTagNameNS(mNamespaceURI_WSDL_SOAP, 826 port, "address") != null; 827 } 828 829 static public void main(String [] args) { 830 831 if (1 < args.length && args.length > 3) { 832 System.err.println("Usage: WSDLParser <wsdl> [<service> <port>]"); 833 return; 834 } 835 836 String service = null; 837 String port = null; 838 839 if (args.length == 2 || args.length == 3) service = args[1]; 840 if (args.length == 3) port = args[2]; 841 842 StringBuffer sb = new StringBuffer (); 843 try { 844 InputSource is = new InputSource(new FileReader(args[0])); 845 WSDLParser.parse(args[0], is, service, port).toXML(sb); 846 System.out.println(sb); 847 } catch (IOException e) { 848 e.printStackTrace(); 849 } catch (ServiceException e) { 850 System.err.println("ERROR: " + e.getMessage()); 851 } catch (WSDLException e) { 852 System.err.println("ERROR: " + e.getMessage()); 853 } 854 } 855 } 856 | Popular Tags |