0001: /* *****************************************************************************
0002: * WSDLParser.java
0003: * ****************************************************************************/
0004:
0005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
0006: * Copyright 2001-2007 Laszlo Systems, Inc. All Rights Reserved. *
0007: * Use is subject to license terms. *
0008: * J_LZ_COPYRIGHT_END *********************************************************/
0009:
0010: package org.openlaszlo.remote.json.soap;
0011:
0012: import java.util.*;
0013: import java.io.*;
0014: import javax.xml.rpc.*;
0015: import javax.xml.parsers.*;
0016: import javax.xml.namespace.*;
0017: import org.w3c.dom.*;
0018: import org.xml.sax.*;
0019: import org.apache.axis.Constants;
0020: import org.apache.axis.utils.*;
0021: import org.apache.log4j.Logger;
0022:
0023: /**
0024: * WSDL parser to obtain a SOAP service object.
0025: */
0026: public class WSDLParser {
0027: private static Logger mLogger = Logger.getLogger(WSDLParser.class);
0028:
0029: public String mTargetNamespace;
0030: public String mNamespaceURI_WSDL;
0031: public String mNamespaceURI_WSDL_SOAP;
0032: public String mNamespaceURI_SOAP_ENC;
0033: public String mNamespaceURI_SCHEMA_XSD;
0034:
0035: public QName mQNameOperationInput;
0036: public QName mQNameOperationOutput;
0037:
0038: HashMap mComplexTypeMap = new HashMap();
0039:
0040: public static final String[] URIS_SOAP_HTTP = {
0041: Constants.URI_SOAP11_HTTP, Constants.URI_SOAP12_HTTP };
0042:
0043: /** Static document builder. */
0044: static DocumentBuilder mBuilder = null;
0045:
0046: /** WSDL root element. */
0047: Element mDefinitions = null;
0048:
0049: //------------------------------------------------------------
0050: // create namespace aware builder
0051: //------------------------------------------------------------
0052: {
0053: DocumentBuilderFactory factory = DocumentBuilderFactory
0054: .newInstance();
0055: factory.setNamespaceAware(true);
0056: try {
0057: mBuilder = factory.newDocumentBuilder();
0058: } catch (ParserConfigurationException e) {
0059: mLogger.error(
0060: /* (non-Javadoc)
0061: * @i18n.test
0062: * @org-mes="Can't create DocumentBuilder"
0063: */
0064: org.openlaszlo.i18n.LaszloMessages.getMessage(
0065: WSDLParser.class.getName(), "051018-68"));
0066: }
0067: }
0068:
0069: /**
0070: * Protected constructor. Entry point is static parse() method.
0071: */
0072: private WSDLParser() {
0073: }
0074:
0075: /**
0076: * Entry point method.
0077: *
0078: * @param wsdl WSDL URL
0079: * @param is
0080: * @param serviceName can be null.
0081: * @param servicePort can be null.
0082: * @return LZSOAPService object.
0083: * @exception WSDLException if there was a problem with the WSDL.
0084: * @exception ServiceException if there was a problem creating LZSOAPService.
0085: */
0086: static public LZSOAPService parse(String wsdl, InputSource is,
0087: String serviceName, String servicePort)
0088: throws WSDLException, ServiceException {
0089: WSDLParser parser = new WSDLParser();
0090: return parser.parseWSDL(wsdl, is, serviceName, servicePort);
0091: }
0092:
0093: /**
0094: * Entry point method. Same as calling parse(is, null, null).
0095: *
0096: * @param wsdl WSDL URL
0097: * @param is
0098: * @return LZSOAPService object.
0099: * @exception WSDLException if there was a problem with the WSDL.
0100: * @exception ServiceException if there was a problem creating LZSOAPService.
0101: */
0102: static public LZSOAPService parse(String wsdl, InputSource is)
0103: throws WSDLException, ServiceException {
0104: return parse(wsdl, is, null, null);
0105: }
0106:
0107: /**
0108: * Set namespaces:
0109: *
0110: * mNamespaceURI_WSDL, mNamespaceURI_WSDL_SOAP, mNamespaceURI_SCHEMA_XSD,
0111: * mQNameOperationInput, mQNameOperationOutput
0112: */
0113: void setNamespaces() {
0114: mTargetNamespace = mDefinitions.getAttribute("targetNamespace");
0115:
0116: NamedNodeMap attrs = mDefinitions.getAttributes();
0117: for (int i = 0; i < attrs.getLength(); i++) {
0118: String attr = ((Attr) attrs.item(i)).getValue();
0119: if (Constants.isWSDL(attr)) {
0120: mNamespaceURI_WSDL = attr;
0121: } else if (Constants.isSchemaXSD(attr)) {
0122: mNamespaceURI_SCHEMA_XSD = attr;
0123: } else if (Constants.isWSDLSOAP(attr)) {
0124: mNamespaceURI_WSDL_SOAP = attr;
0125: } else if (Constants.isSOAP_ENC(attr)) {
0126: mNamespaceURI_SOAP_ENC = attr;
0127: }
0128: }
0129:
0130: mQNameOperationInput = new QName(mNamespaceURI_WSDL, "input");
0131: mQNameOperationOutput = new QName(mNamespaceURI_WSDL, "output");
0132:
0133: if (mLogger.isDebugEnabled()) {
0134: mLogger.debug("WSDL: URI_WSDL " + mNamespaceURI_WSDL);
0135: mLogger.debug("WSDL: URI_SCHEMA_XSD "
0136: + mNamespaceURI_SCHEMA_XSD);
0137: mLogger.debug("WSDL: URI_WSDL_SOAP "
0138: + mNamespaceURI_WSDL_SOAP);
0139: mLogger.debug("WSDL: URI_SOAP_ENC "
0140: + mNamespaceURI_SOAP_ENC);
0141: mLogger.debug("WSDL: targetnamespace " + mTargetNamespace);
0142: }
0143: }
0144:
0145: /**
0146: * Parse WDSL file
0147: *
0148: * @param wsdl WSDL URL
0149: * @param is WSDL input source.
0150: * @param serviceName name of service. If null, use first service element encountered.
0151: * @param servicePort name of port. if null, use first SOAP port element
0152: * encountered..
0153: * @return LZSOAPService object.
0154: * @exception WSDLException if there was a problem with the WSDL.
0155: * @exception ServiceException if there was a problem creating LZSOAPService.
0156: */
0157: LZSOAPService parseWSDL(String wsdl, InputSource is,
0158: String serviceName, String servicePort)
0159: throws WSDLException, ServiceException {
0160:
0161: LZSOAPService soapService = null;
0162:
0163: try {
0164: mDefinitions = mBuilder.parse(is).getDocumentElement();
0165: } catch (IOException e) {
0166: throw new WSDLException("IOException: " + e.getMessage());
0167: } catch (SAXException e) {
0168: throw new WSDLException("SAXException: " + e.getMessage());
0169: }
0170:
0171: setNamespaces();
0172:
0173: SchemaParser sp = null;
0174: try {
0175: NodeList schemalist = getSchema();
0176: if (schemalist != null) {
0177: for (int i = 0; i < schemalist.getLength(); i++) {
0178: Element schema = (Element) schemalist.item(i);
0179: sp = new SchemaParser(this , schema);
0180: sp.parse(mComplexTypeMap);
0181: }
0182: }
0183: } catch (Exception e) {
0184: mLogger.warn("SchemaParser", e);
0185: }
0186:
0187: Element service;
0188: if (serviceName == null)
0189: service = LZSOAPUtils.getFirstElementByTagNameNS(
0190: mNamespaceURI_WSDL, mDefinitions, "service");
0191: else
0192: service = findServiceElement(serviceName);
0193:
0194: if (service == null) {
0195: if (serviceName != null)
0196: throw new WSDLException(
0197: /* (non-Javadoc)
0198: * @i18n.test
0199: * @org-mes="no service named " + p[0] + " was found."
0200: */
0201: org.openlaszlo.i18n.LaszloMessages.getMessage(
0202: WSDLParser.class.getName(), "051018-207",
0203: new Object[] { serviceName }));
0204: else
0205: throw new WSDLException(
0206: /* (non-Javadoc)
0207: * @i18n.test
0208: * @org-mes="no service was found"
0209: */
0210: org.openlaszlo.i18n.LaszloMessages.getMessage(
0211: WSDLParser.class.getName(), "051018-216"));
0212: }
0213:
0214: serviceName = service.getAttribute("name");
0215: if (serviceName.equals("")) {
0216: throw new WSDLException(
0217: /* (non-Javadoc)
0218: * @i18n.test
0219: * @org-mes="service has no name"
0220: */
0221: org.openlaszlo.i18n.LaszloMessages.getMessage(
0222: WSDLParser.class.getName(), "051018-229"));
0223: }
0224:
0225: NodeList portList = service.getElementsByTagNameNS(
0226: mNamespaceURI_WSDL, "port");
0227: int len = portList.getLength();
0228: if (len == 0)
0229: throw new WSDLException(
0230: /* (non-Javadoc)
0231: * @i18n.test
0232: * @org-mes="No SOAP ports found for service " + p[0]
0233: */
0234: org.openlaszlo.i18n.LaszloMessages.getMessage(
0235: WSDLParser.class.getName(), "051018-243",
0236: new Object[] { serviceName }));
0237:
0238: for (int i = 0; i < len; i++) {
0239: Element port = (Element) portList.item(i);
0240:
0241: String portName = port.getAttribute("name");
0242: if (portName == null) {
0243: mLogger.warn(
0244: /* (non-Javadoc)
0245: * @i18n.test
0246: * @org-mes="encountered port with no name"
0247: */
0248: org.openlaszlo.i18n.LaszloMessages.getMessage(
0249: WSDLParser.class.getName(), "051018-256"));
0250: continue;
0251: }
0252:
0253: if (servicePort != null && !servicePort.equals(portName)) {
0254: continue;
0255: }
0256:
0257: if (doesPortSupportSOAP(port)) {
0258:
0259: Element binding = getBindingElement(port);
0260: mLogger.debug("binding: " + binding);
0261:
0262: Element soapBinding = LZSOAPUtils
0263: .getFirstElementByTagNameNS(
0264: mNamespaceURI_WSDL_SOAP, binding,
0265: "binding");
0266:
0267: if (soapBinding == null) {
0268: throw new WSDLException(
0269: /* (non-Javadoc)
0270: * @i18n.test
0271: * @org-mes="no SOAP binding for port " + p[0]
0272: */
0273: org.openlaszlo.i18n.LaszloMessages.getMessage(
0274: WSDLParser.class.getName(), "051018-281",
0275: new Object[] { portName }));
0276: }
0277:
0278: // we only support SOAP over HTTP
0279: String transport = soapBinding
0280: .getAttribute("transport");
0281: if (!isSOAPHTTPTransport(transport)) {
0282: if (servicePort != null
0283: && servicePort.equals(portName)) {
0284: throw new WSDLException(
0285: /* (non-Javadoc)
0286: * @i18n.test
0287: * @org-mes="port " + p[0] + " does not have a valid SOAP transport"
0288: */
0289: org.openlaszlo.i18n.LaszloMessages.getMessage(
0290: WSDLParser.class.getName(),
0291: "051018-294",
0292: new Object[] { servicePort }));
0293: } else {
0294: continue;
0295: }
0296: }
0297:
0298: soapService = new LZSOAPService(wsdl, service
0299: .getAttribute("name"), portName,
0300: getEndpointAddress(port), transport,
0301: mTargetNamespace, mNamespaceURI_SCHEMA_XSD,
0302: mNamespaceURI_SOAP_ENC);
0303:
0304: String defaultStyle = soapBinding.getAttribute("style");
0305: if ("".equals(defaultStyle))
0306: defaultStyle = "document";
0307:
0308: parseOperations(soapService, binding, defaultStyle);
0309: break;
0310: } else if (servicePort != null
0311: && servicePort.equals(portName)) {
0312: throw new WSDLException(
0313: /* (non-Javadoc)
0314: * @i18n.test
0315: * @org-mes="port " + p[0] + " does not support SOAP"
0316: */
0317: org.openlaszlo.i18n.LaszloMessages.getMessage(
0318: WSDLParser.class.getName(), "051018-319",
0319: new Object[] { servicePort }));
0320: }
0321: }
0322:
0323: if (soapService == null) {
0324: throw new WSDLException(
0325: /* (non-Javadoc)
0326: * @i18n.test
0327: * @org-mes="could not find requested SOAP service " + "(service: " + p[0] + ", port: " + p[1] + ")"
0328: */
0329: org.openlaszlo.i18n.LaszloMessages.getMessage(
0330: WSDLParser.class.getName(), "051018-331",
0331: new Object[] { serviceName, servicePort }));
0332: }
0333:
0334: soapService.setSchemaComplexTypes(mComplexTypeMap);
0335:
0336: return soapService;
0337: }
0338:
0339: /**
0340: * Get the namespace for the schema.
0341: *
0342: * @return target namespace for schema.
0343: */
0344: NodeList getSchema() {
0345: return mDefinitions.getElementsByTagNameNS(
0346: mNamespaceURI_SCHEMA_XSD, "schema");
0347: }
0348:
0349: /**
0350: * Parse SOAP operations and add them to service object.
0351: *
0352: * @param service SOAP service object to add operations.
0353: * @param binding WSDL SOAP binding element.
0354: */
0355: void parseOperations(LZSOAPService service, Element binding,
0356: String defaultStyle) throws WSDLException {
0357:
0358: String bindingType = binding.getAttribute("type");
0359: if ("".equals(bindingType)) {
0360: throw new WSDLException(
0361: /* (non-Javadoc)
0362: * @i18n.test
0363: * @org-mes="binding does not have a type attribute"
0364: */
0365: org.openlaszlo.i18n.LaszloMessages.getMessage(
0366: WSDLParser.class.getName(), "051018-368"));
0367: }
0368: QName bindingTypeQName = XMLUtils.getQNameFromString(
0369: bindingType, binding);
0370:
0371: // binding maps to portType
0372: Element portType = findPortTypeElement(bindingTypeQName
0373: .getLocalPart());
0374: if (portType == null) {
0375: throw new WSDLException(
0376: /* (non-Javadoc)
0377: * @i18n.test
0378: * @org-mes="could not find portType named " + p[0]
0379: */
0380: org.openlaszlo.i18n.LaszloMessages.getMessage(
0381: WSDLParser.class.getName(), "051018-382",
0382: new Object[] { bindingTypeQName }));
0383: }
0384:
0385: // list of operations for portType
0386: NodeList portTypeOpList = portType.getElementsByTagNameNS(
0387: mNamespaceURI_WSDL, "operation");
0388: if (portTypeOpList.getLength() == 0) {
0389: throw new WSDLException(
0390: /* (non-Javadoc)
0391: * @i18n.test
0392: * @org-mes="portType named " + p[0] + " has no operations"
0393: */
0394: org.openlaszlo.i18n.LaszloMessages.getMessage(
0395: WSDLParser.class.getName(), "051018-396",
0396: new Object[] { bindingTypeQName.getLocalPart() }));
0397: }
0398:
0399: Map operationMap = new HashMap();
0400: service.setOperations(operationMap);
0401:
0402: NodeList list = binding.getElementsByTagNameNS(
0403: mNamespaceURI_WSDL, "operation");
0404: for (int i = 0; i < list.getLength(); i++) {
0405: Element operation = (Element) list.item(i);
0406: String opName = operation.getAttribute("name");
0407: if ("".equals(opName)) {
0408: mLogger.warn(
0409: /* (non-Javadoc)
0410: * @i18n.test
0411: * @org-mes="name not found for an operation element"
0412: */
0413: org.openlaszlo.i18n.LaszloMessages.getMessage(
0414: WSDLParser.class.getName(), "051018-414"));
0415: continue;
0416: }
0417:
0418: // From WSDL spec: For the HTTP protocol binding of SOAP,
0419: // [soapAction] is value required (it has no default value).
0420: //
0421: // <operation>
0422: // <soap:operation soapAction="..." style="[rpc|document]"? />
0423: // ...
0424: // </operation>
0425: Element soapOperation = LZSOAPUtils
0426: .getFirstElementByTagNameNS(
0427: mNamespaceURI_WSDL_SOAP, operation,
0428: "operation");
0429:
0430: String soapAction = null;
0431: if (isSOAPHTTPTransport(service.getTransport())) {
0432: Attr soapActionAttr = soapOperation
0433: .getAttributeNode("soapAction");
0434: if (soapActionAttr == null) {
0435: mLogger.warn(
0436: /* (non-Javadoc)
0437: * @i18n.test
0438: * @org-mes="required soapAction attribute not found for <soap:operation>"
0439: */
0440: org.openlaszlo.i18n.LaszloMessages.getMessage(
0441: WSDLParser.class.getName(), "051018-440"));
0442: continue;
0443: }
0444: soapAction = soapActionAttr.getValue();
0445: }
0446:
0447: String style = soapOperation.getAttribute("style");
0448: if ("".equals(style))
0449: style = defaultStyle;
0450:
0451: // get operation names for input and output parameters
0452: Element input = LZSOAPUtils.getFirstElementByTagNameNS(
0453: mNamespaceURI_WSDL, operation, "input");
0454: Element output = LZSOAPUtils.getFirstElementByTagNameNS(
0455: mNamespaceURI_WSDL, operation, "output");
0456: if (input == null || output == null) {
0457: mLogger.warn(
0458: /* (non-Javadoc)
0459: * @i18n.test
0460: * @org-mes="(0) WARNING: operation named " + p[0] + " is not a supported operation." + " Only request-response operations are supported."
0461: */
0462: org.openlaszlo.i18n.LaszloMessages.getMessage(
0463: WSDLParser.class.getName(), "051018-463",
0464: new Object[] { opName }));
0465: continue;
0466: }
0467:
0468: String inputName = input.getAttribute("name");
0469: String outputName = output.getAttribute("name");
0470:
0471: Element portTypeOp = findPortTypeOperationElement(
0472: portTypeOpList, opName, inputName, outputName);
0473: if (portTypeOp == null) {
0474: mLogger.warn(
0475: /* (non-Javadoc)
0476: * @i18n.test
0477: * @org-mes="could not find portType operation named " + p[0]
0478: */
0479: org.openlaszlo.i18n.LaszloMessages.getMessage(
0480: WSDLParser.class.getName(), "051018-481",
0481: new Object[] { opName }));
0482: continue;
0483: }
0484:
0485: // We only support request-response type operations
0486: if (!isRequestResponseOperation(portTypeOp)) {
0487: mLogger.warn(
0488: /* (non-Javadoc)
0489: * @i18n.test
0490: * @org-mes="(1) WARNING: portType operation named " + p[0] + " is not a supported operation." + " Only request-response operations are supported."
0491: */
0492: org.openlaszlo.i18n.LaszloMessages.getMessage(
0493: WSDLParser.class.getName(), "051018-494",
0494: new Object[] { opName }));
0495: continue;
0496: }
0497:
0498: LZSOAPMessage inputBody;
0499: LZSOAPMessage outputBody;
0500: try {
0501: inputBody = getMessage(operation, portTypeOp, "input",
0502: "Request");
0503: outputBody = getMessage(operation, portTypeOp,
0504: "output", "Response");
0505: } catch (WSDLException e) {
0506: mLogger.warn(e.getMessage());
0507: continue;
0508: }
0509:
0510: LZSOAPOperation op = new LZSOAPOperation(opName);
0511: op.setSoapAction(soapAction);
0512: op.setStyle(style);
0513: op.setInputMessage(inputBody);
0514: op.setOutputMessage(outputBody);
0515: op.setMangledName(opName + "_" + inputBody.getName() + "_"
0516: + outputBody.getName());
0517: op
0518: .setIsDocumentLiteralWrapped(isDocumentLiteralWrapped(op));
0519:
0520: if (operationMap.containsKey(op.getMangledName())) {
0521: mLogger.warn(
0522: /* (non-Javadoc)
0523: * @i18n.test
0524: * @org-mes="(0) operation " + p[0] + " is not unique"
0525: */
0526: org.openlaszlo.i18n.LaszloMessages.getMessage(
0527: WSDLParser.class.getName(), "051018-524",
0528: new Object[] { op.getMangledName() }));
0529: continue;
0530: }
0531:
0532: // if already exists, we have overloaded method
0533: if (operationMap.containsKey(op.getName())) {
0534:
0535: // make sure previous operation wouldn't mangle to the same
0536: // mangled name as the current one
0537: LZSOAPOperation prevOp = (LZSOAPOperation) operationMap
0538: .get(op.getName());
0539: if (prevOp.getMangledName().equals(op.getMangledName())) {
0540: mLogger.warn(
0541: /* (non-Javadoc)
0542: * @i18n.test
0543: * @org-mes="(1) operation " + p[0] + " is not unique"
0544: */
0545: org.openlaszlo.i18n.LaszloMessages.getMessage(
0546: WSDLParser.class.getName(), "051018-542",
0547: new Object[] { op.getMangledName() }));
0548: continue;
0549: }
0550:
0551: operationMap.put(op.getMangledName(), op);
0552:
0553: } else {
0554: operationMap.put(op.getName(), op);
0555: }
0556:
0557: }
0558: }
0559:
0560: /**
0561: * Check to see if operation is a document/literal wrapped operation.
0562: *
0563: * @param op check to see if operation is document/literal wrapped.
0564: * @return true if it's a document/literal wrapped operation, else false.
0565: */
0566: boolean isDocumentLiteralWrapped(LZSOAPOperation op) {
0567:
0568: // make sure it's document literal
0569: if (!op.getStyle().equals("document")) {
0570: return false;
0571: }
0572:
0573: LZSOAPMessage inputMesg = op.getInputMessage();
0574: if (!inputMesg.getUse().equals("literal")) {
0575: return false;
0576: }
0577:
0578: // only one part can exist
0579: List parts = inputMesg.getParts();
0580: if (parts == null || parts.size() != 1) {
0581: return false;
0582: }
0583:
0584: // element has to exist
0585: LZSOAPPart part = (LZSOAPPart) parts.get(0);
0586: String eName = part.getElement();
0587: if (eName == null) {
0588: return false;
0589: }
0590:
0591: // maybe I should be getting qname from schema element?
0592: QName eQName = XMLUtils.getQNameFromString(eName, mDefinitions);
0593: Element element = findSchemaElement(eQName.getLocalPart());
0594: if (element == null) {
0595: return false;
0596: }
0597:
0598: // name of element has to match name of operation
0599: String name = element.getAttribute("name");
0600: if (!name.equals(op.getName())) {
0601: return false;
0602: }
0603:
0604: // there can't be attributes on this element
0605: NodeList attrList = element.getElementsByTagNameNS(
0606: mNamespaceURI_SCHEMA_XSD, "attribute");
0607: if (attrList.getLength() != 0) {
0608: return false;
0609: }
0610:
0611: return true;
0612: }
0613:
0614: /**
0615: * Find service element.
0616: *
0617: * @param name name of service element to find.
0618: * @return found service element, else null.
0619: */
0620: Element findServiceElement(String name) {
0621: return findElementByName(mNamespaceURI_WSDL, mDefinitions,
0622: "service", name);
0623: }
0624:
0625: /**
0626: * Find schema element.
0627: *
0628: * @param name name of schema element to find.
0629: * @return found schema element, else null.
0630: */
0631: Element findSchemaElement(String name) {
0632: return findElementByName(mNamespaceURI_SCHEMA_XSD,
0633: mDefinitions, "element", name);
0634: }
0635:
0636: /**
0637: * Find message element.
0638: *
0639: * @param name name of message to find.
0640: * @return found message element, else null.
0641: */
0642: Element findMessageElement(String name) {
0643: return findElementByName(mNamespaceURI_WSDL, mDefinitions,
0644: "message", name);
0645: }
0646:
0647: /**
0648: * Find portType element.
0649: *
0650: * @param name name of portType element to find.
0651: * @return matched portType element or null, if none found.
0652: */
0653: Element findPortTypeElement(String name) {
0654: return findElementByName(mNamespaceURI_WSDL, mDefinitions,
0655: "portType", name);
0656: }
0657:
0658: /**
0659: * Find a particular portType operation element based on name.
0660: *
0661: * @param portTypeOpList node list of portType operations.
0662: * @param opname operation name to find.
0663: * @param input name of input parameter
0664: * @param output name of output parameter
0665: * @return portType operation element if found, else null.
0666: */
0667: Element findPortTypeOperationElement(NodeList portTypeOpList,
0668: String opname, String input, String output) {
0669: for (int i = 0; i < portTypeOpList.getLength(); i++) {
0670: Element e = (Element) portTypeOpList.item(i);
0671: if (opname.equals(e.getAttribute("name"))) {
0672: // get operation names for input and output parameters
0673: Element _input = LZSOAPUtils
0674: .getFirstElementByTagNameNS(mNamespaceURI_WSDL,
0675: e, "input");
0676: Element _output = LZSOAPUtils
0677: .getFirstElementByTagNameNS(mNamespaceURI_WSDL,
0678: e, "output");
0679: if (_input != null && _output != null
0680: && input.equals(_input.getAttribute("name"))
0681: && output.equals(_output.getAttribute("name"))) {
0682: if (mLogger.isDebugEnabled()) {
0683: mLogger.debug(
0684: /* (non-Javadoc)
0685: * @i18n.test
0686: * @org-mes="found port type operation for " + p[0]
0687: */
0688: org.openlaszlo.i18n.LaszloMessages.getMessage(
0689: WSDLParser.class.getName(),
0690: "051018-684", new Object[] { opname }));
0691: }
0692: return e;
0693: }
0694: }
0695: }
0696: return null;
0697: }
0698:
0699: /**
0700: * Find element by name attribute.
0701: *
0702: * @param ns namespace.
0703: * @param owner owner element.
0704: * @param tag tag to search on.
0705: * @param name name to match.
0706: * @return found element.
0707: */
0708: Element findElementByName(String ns, Element owner, String tag,
0709: String name) {
0710: NodeList list = owner.getElementsByTagNameNS(ns, tag);
0711: return findElementByName(list, name);
0712: }
0713:
0714: /**
0715: * Find element by name attribute.
0716: *
0717: * @param list node list.
0718: * @param name name value to match.
0719: * @return found element.
0720: */
0721: Element findElementByName(NodeList list, String name) {
0722: for (int i = 0; i < list.getLength(); i++) {
0723: Element e = (Element) list.item(i);
0724: if (name.equals(e.getAttribute("name")))
0725: return e;
0726: }
0727: return null;
0728: }
0729:
0730: /**
0731: * Parse message for input, output from portType operation.
0732: *
0733: * @param bindOp operation element in binding
0734: * @param portTypeOp operation element in portType.
0735: * @param tag one of input, output.
0736: * @param appendName string to append to create implicit operation type name
0737: * if element has not explicitly declared it.
0738: * @return a soap message object.
0739: */
0740: LZSOAPMessage getMessage(Element bindOp, Element portTypeOp,
0741: String tag, String appendName) throws WSDLException {
0742:
0743: Element opType = LZSOAPUtils.getFirstElementByTagNameNS(
0744: mNamespaceURI_WSDL, portTypeOp, tag);
0745: String opName = portTypeOp.getAttribute("name");
0746:
0747: String name = opType.getAttribute("name");
0748: if (name.equals("")) {
0749: name = opName + appendName;
0750: }
0751:
0752: LZSOAPMessage message = new LZSOAPMessage(name, tag);
0753:
0754: Element bindTag = LZSOAPUtils.getFirstElementByTagNameNS(
0755: mNamespaceURI_WSDL, bindOp, tag);
0756: if (bindTag == null) {
0757: throw new WSDLException(
0758: /* (non-Javadoc)
0759: * @i18n.test
0760: * @org-mes="could not find " + p[0] + " element for bind operation " + p[1]
0761: */
0762: org.openlaszlo.i18n.LaszloMessages.getMessage(
0763: WSDLParser.class.getName(), "051018-760",
0764: new Object[] { tag, opName }));
0765: }
0766:
0767: // only parse <soap:body> element for now
0768: Element soapBody = LZSOAPUtils.getFirstElementByTagNameNS(
0769: mNamespaceURI_WSDL_SOAP, bindTag, "body");
0770:
0771: String use = soapBody.getAttribute("use");
0772: if (use.equals("")) {
0773: throw new WSDLException(
0774: /* (non-Javadoc)
0775: * @i18n.test
0776: * @org-mes="Attribute use is not defined for " + p[0] + " <soap:body> in operation " + p[1]
0777: */
0778: org.openlaszlo.i18n.LaszloMessages.getMessage(
0779: WSDLParser.class.getName(), "051018-776",
0780: new Object[] { tag, opName }));
0781: }
0782: message.setUse(use);
0783:
0784: String parts = soapBody.getAttribute("parts");
0785: if (!parts.equals("")) {
0786: message.setPartNames(getPartSet(parts));
0787: }
0788:
0789: String mesgName = opType.getAttribute("message");
0790: QName mesgQName = XMLUtils.getQNameFromString(mesgName, opType);
0791: Element mesgElement = findMessageElement(mesgQName
0792: .getLocalPart());
0793: if (mesgElement == null) {
0794: throw new WSDLException(
0795: /* (non-Javadoc)
0796: * @i18n.test
0797: * @org-mes="could not find message element named " + p[0]
0798: */
0799: org.openlaszlo.i18n.LaszloMessages.getMessage(
0800: WSDLParser.class.getName(), "051018-795",
0801: new Object[] { mesgQName.getLocalPart() }));
0802: }
0803:
0804: bindMessage(message, mesgElement, tag);
0805:
0806: return message;
0807: }
0808:
0809: /**
0810: * @param soapMessage
0811: * @param mesgElement
0812: * @param tag one of input or output
0813: */
0814: void bindMessage(LZSOAPMessage soapMessage, Element mesgElement,
0815: String tag) throws WSDLException {
0816:
0817: List parts = new Vector();
0818: Set partNames = soapMessage.getPartNames();
0819:
0820: // go through mesgElement and add part information to soapMessage
0821: NodeList list = mesgElement.getElementsByTagNameNS(
0822: mNamespaceURI_WSDL, "part");
0823: for (int i = 0; i < list.getLength(); i++) {
0824: Element part = (Element) list.item(i);
0825: Attr nameAttr = part.getAttributeNode("name");
0826: if (nameAttr == null) {
0827: throw new WSDLException(
0828: /* (non-Javadoc)
0829: * @i18n.test
0830: * @org-mes="part for message named " + p[0] + " does not have required name attribute"
0831: */
0832: org.openlaszlo.i18n.LaszloMessages
0833: .getMessage(WSDLParser.class.getName(),
0834: "051018-828",
0835: new Object[] { mesgElement
0836: .getAttribute("name") }));
0837: }
0838: String name = nameAttr.getValue();
0839:
0840: // only set part if message should contain it
0841: if (partNames != null && !partNames.contains(name))
0842: continue;
0843:
0844: LZSOAPPart p = new LZSOAPPart(name);
0845:
0846: ParameterMode mode;
0847: if (tag.equals("output")) {
0848: mode = ParameterMode.OUT;
0849: } else {
0850: mode = ParameterMode.IN;
0851: }
0852: p.setParameterMode(mode);
0853:
0854: Attr elementAttr = part.getAttributeNode("element");
0855: Attr typeAttr = part.getAttributeNode("type");
0856:
0857: if (elementAttr != null) {
0858: p.setElement(elementAttr.getValue());
0859: }
0860:
0861: if (typeAttr != null) {
0862: QName qname = XMLUtils.getQNameFromString(typeAttr
0863: .getValue(), part);
0864:
0865: // If it's an array, refer to type definition of the array.
0866: ComplexType ct = (ComplexType) mComplexTypeMap
0867: .get(qname);
0868: if (ct == null) {
0869: String ns = qname.getNamespaceURI();
0870: if (Constants.isSchemaXSD(ns)
0871: || Constants.isSOAP_ENC(ns)) {
0872: ct = new ComplexType(qname);
0873: mComplexTypeMap.put(qname, ct);
0874: } else {
0875: throw new WSDLException(
0876: /* (non-Javadoc)
0877: * @i18n.test
0878: * @org-mes="could not find type for " + p[0]
0879: */
0880: org.openlaszlo.i18n.LaszloMessages.getMessage(
0881: WSDLParser.class.getName(),
0882: "051018-871", new Object[] { qname }));
0883: }
0884: }
0885: p.setType(ct);
0886: }
0887:
0888: parts.add(p);
0889: }
0890:
0891: soapMessage.setParts(parts);
0892: }
0893:
0894: /**
0895: * Get list of message parts.
0896: *
0897: * @param nmtokens name tokens.
0898: * @return set part names.
0899: */
0900: Set getPartSet(String nmtokens) {
0901: Set set = null;
0902: StringTokenizer st = new StringTokenizer(nmtokens);
0903: while (st.hasMoreTokens()) {
0904: if (set == null)
0905: set = new HashSet();
0906: set.add(st.nextToken());
0907: }
0908: return set;
0909: }
0910:
0911: /**
0912: * Check to see if portType operation is request-response operation, since
0913: * we currently have no way of supporting one-way, solicit-response,
0914: * notification operations.
0915: *
0916: * @param op port Type operation element.
0917: */
0918: boolean isRequestResponseOperation(Element op) {
0919: Node n = op.getFirstChild();
0920: while (n != null
0921: && (n.getNodeType() != Node.ELEMENT_NODE || n
0922: .getNodeName().equals("documentation"))) {
0923: n = n.getNextSibling();
0924: }
0925:
0926: // make sure we're comparing w/o prefix but with the right namespace
0927: QName input = XMLUtils.getQNameFromString(n.getNodeName(), op);
0928: input = new QName(n.getNamespaceURI(), input.getLocalPart());
0929: if (n == null || !input.equals(mQNameOperationInput))
0930: return false;
0931:
0932: n = n.getNextSibling();
0933: while (n != null && n.getNodeType() != Node.ELEMENT_NODE) {
0934: n = n.getNextSibling();
0935: }
0936: QName output = XMLUtils.getQNameFromString(n.getNodeName(), op);
0937: output = new QName(n.getNamespaceURI(), output.getLocalPart());
0938: if (n == null || !output.equals(mQNameOperationOutput))
0939: return false;
0940:
0941: return true;
0942: }
0943:
0944: /**
0945: * Check to see if SOAP transport for binding is supported. Support only
0946: * HTTP for now.
0947: *
0948: * @param transport transport string.
0949: * @return true if SOAP transport is supported, else false.
0950: */
0951: boolean isSOAPHTTPTransport(String transport) {
0952: if (transport == null)
0953: return false;
0954:
0955: for (int i = 0; i < URIS_SOAP_HTTP.length; i++) {
0956: if (URIS_SOAP_HTTP[i].equals(transport)) {
0957: return true;
0958: }
0959: }
0960: return false;
0961: }
0962:
0963: /**
0964: * Get the <soap:address .../> location attribute.
0965: *
0966: * @param port port element to get endpoint address from.
0967: * @return endpoint address string.
0968: */
0969: String getEndpointAddress(Element port) {
0970: Element soapAddress = LZSOAPUtils.getFirstElementByTagNameNS(
0971: mNamespaceURI_WSDL_SOAP, port, "address");
0972: String name = port.getAttribute("name");
0973: return soapAddress.getAttribute("location");
0974: }
0975:
0976: /**
0977: * Get binding element specified by the port's binding attribute.
0978: *
0979: * @param port port element to get binding.
0980: * @return binding element.
0981: */
0982: Element getBindingElement(Element port) {
0983: QName bindingQName = XMLUtils.getQNameFromString(port
0984: .getAttribute("binding"), port);
0985: return getElementByAttributeNS(mNamespaceURI_WSDL, "binding",
0986: "name", bindingQName);
0987: }
0988:
0989: /**
0990: * Get an element based on its attribute name.
0991: *
0992: * @param ns namespace.
0993: * @param elementName name of element to search.
0994: * @param attrName name of attribute to match.
0995: * @param attrValue value of attribute to match.
0996: * @return element or null, if none found with elementName.
0997: */
0998: Element getElementByAttributeNS(String ns, String elementName,
0999: String attrName, QName attrValue) {
1000: NodeList list = mDefinitions.getElementsByTagNameNS(ns,
1001: elementName);
1002:
1003: int length = list.getLength();
1004: if (length == 0)
1005: return null;
1006:
1007: for (int i = 0; i < length; i++) {
1008: Element element = (Element) list.item(i);
1009: String searchAttr = element.getAttribute(attrName);
1010: if (searchAttr.equals(attrValue.getLocalPart())) {
1011: return element;
1012: }
1013: }
1014:
1015: return null;
1016: }
1017:
1018: /**
1019: * Check to see if port supports SOAP.
1020: *
1021: * @param port port to check SOAP support.
1022: * @return true if port supports SOAP, else false.
1023: */
1024: boolean doesPortSupportSOAP(Element port) {
1025: return LZSOAPUtils.getFirstElementByTagNameNS(
1026: mNamespaceURI_WSDL_SOAP, port, "address") != null;
1027: }
1028:
1029: static public void main(String[] args) {
1030:
1031: if (1 < args.length && args.length > 3) {
1032: System.err
1033: .println("Usage: WSDLParser <wsdl> [<service> <port>]");
1034: return;
1035: }
1036:
1037: String service = null;
1038: String port = null;
1039:
1040: if (args.length == 2 || args.length == 3)
1041: service = args[1];
1042: if (args.length == 3)
1043: port = args[2];
1044:
1045: StringBuffer sb = new StringBuffer();
1046: try {
1047: InputSource is = new InputSource(new FileReader(args[0]));
1048: WSDLParser.parse(args[0], is, service, port).toXML(sb);
1049: System.out.println(sb);
1050: } catch (IOException e) {
1051: e.printStackTrace();
1052: } catch (ServiceException e) {
1053: System.err.println("ERROR: " + e.getMessage());
1054: } catch (WSDLException e) {
1055: System.err.println("ERROR: " + e.getMessage());
1056: }
1057: }
1058: }
|