001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019: package de.schlund.pfixcore.webservice.jaxws.generate;
020:
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030: import java.util.regex.Matcher;
031: import java.util.regex.Pattern;
032:
033: import javax.wsdl.Binding;
034: import javax.wsdl.BindingOperation;
035: import javax.wsdl.Definition;
036: import javax.wsdl.Input;
037: import javax.wsdl.Message;
038: import javax.wsdl.Operation;
039: import javax.wsdl.Output;
040: import javax.wsdl.Part;
041: import javax.wsdl.Port;
042: import javax.wsdl.Service;
043: import javax.wsdl.Types;
044: import javax.wsdl.extensions.ExtensibilityElement;
045: import javax.wsdl.extensions.schema.Schema;
046: import javax.wsdl.extensions.schema.SchemaImport;
047: import javax.wsdl.extensions.soap.SOAPAddress;
048: import javax.wsdl.factory.WSDLFactory;
049: import javax.wsdl.xml.WSDLReader;
050: import javax.xml.namespace.QName;
051:
052: import org.w3c.dom.Element;
053: import org.w3c.dom.NamedNodeMap;
054: import org.w3c.dom.Node;
055: import org.w3c.dom.NodeList;
056: import org.xml.sax.InputSource;
057:
058: import com.ibm.wsdl.util.xml.DOMUtils;
059:
060: import de.schlund.pfixcore.webservice.Constants;
061: import de.schlund.pfixcore.webservice.jsgen.JsBlock;
062: import de.schlund.pfixcore.webservice.jsgen.JsClass;
063: import de.schlund.pfixcore.webservice.jsgen.JsMethod;
064: import de.schlund.pfixcore.webservice.jsgen.JsParam;
065: import de.schlund.pfixcore.webservice.jsgen.JsStatement;
066:
067: /**
068: * This class generates a Javascript stub file from a WSDL description.
069: *
070: * @author mleidig@schlund.de
071: */
072: public class Wsdl2Js {
073:
074: private final static Pattern PREFIXPATTERN = Pattern
075: .compile("(\\w+):(\\w+)");
076: private final static String XMLNS_SCHEMA = "http://www.w3.org/2001/XMLSchema";
077: private final static String XMLNS_JAXB_ARRAY = "http://jaxb.dev.java.net/array";
078:
079: private File outputFile;
080: private File inputFile;
081:
082: private Map<QName, Element> schemaComplexTypes;
083: private Map<QName, QName> schemaElementsToTypes;
084:
085: private HashMap<QName, String> typeInfoMap;
086: private ArrayList<String> typeInfoList;
087: private ArrayList<String> popInfoList;
088:
089: /**
090: * Set WSDL input file
091: */
092: public void setInputFile(File inputFile) {
093: this .inputFile = inputFile;
094: }
095:
096: /**
097: * Set Javascript output file
098: */
099: public void setOutputFile(File outputFile) {
100: this .outputFile = outputFile;
101: }
102:
103: /**
104: * Generate Javascript stub file from WSDL file
105: */
106: public void generate() throws Wsdl2JsException, IOException {
107: if (inputFile == null)
108: throw new Wsdl2JsException("No WSDL input file specified");
109: if (outputFile == null)
110: throw new Wsdl2JsException("No JS output file specified");
111: if (!inputFile.exists())
112: throw new Wsdl2JsException("WSDL input file doesn't exist");
113: Definition def = null;
114: try {
115: WSDLFactory wf = WSDLFactory.newInstance();
116: WSDLReader wr = wf.newWSDLReader();
117: wr.setFeature("javax.wsdl.verbose", false);
118: wr.setFeature("javax.wsdl.importDocuments", true);
119: InputSource inSrc = new InputSource(new FileInputStream(
120: inputFile));
121: def = wr.readWSDL(inputFile.getParentFile().toURI()
122: .toString(), inSrc);
123: } catch (Exception x) {
124: throw new Wsdl2JsException("Error reading WSDL from: "
125: + inputFile.getAbsolutePath(), x);
126: }
127: typeInfoMap = new HashMap<QName, String>();
128: popInfoList = new ArrayList<String>();
129: typeInfoList = new ArrayList<String>();
130: readSchema(def.getTypes());
131: Iterator<?> srvIt = def.getServices().values().iterator();
132: if (srvIt.hasNext()) {
133: Service service = (Service) srvIt.next();
134: Iterator<?> prtIt = service.getPorts().values().iterator();
135: if (prtIt.hasNext()) {
136: Port port = (Port) prtIt.next();
137: String stubClass = Constants.STUBGEN_DEFAULT_JSNAMESPACE
138: + service.getQName().getLocalPart();
139: JsParam[] constParams = new JsParam[] { new JsParam(
140: "cbObj") };
141: JsClass jsClass = new JsClass(stubClass, "SOAP_Stub",
142: constParams);
143: JsBlock block = jsClass.getConstructorBody();
144: block
145: .addStatement(new JsStatement(
146: "this._cbObj=cbObj"));
147: block.addStatement(new JsStatement("this._setURL(\""
148: + getAddressLocation(port) + "\")"));
149: Binding binding = port.getBinding();
150: Iterator<?> bopIt = binding.getBindingOperations()
151: .iterator();
152: while (bopIt.hasNext()) {
153: BindingOperation bop = (BindingOperation) bopIt
154: .next();
155: Operation op = bop.getOperation();
156: try {
157: JsMethod jsMethod = new JsMethod(jsClass, op
158: .getName());
159: JsBlock jsBlock = jsMethod.getBody();
160: jsBlock.addStatement(new JsStatement(
161: "var call=this._createCall()"));
162: jsBlock
163: .addStatement(new JsStatement(
164: "call.setTargetNamespace(this._targetNamespace)"));
165: jsBlock.addStatement(new JsStatement(
166: "call.setOperationName(\""
167: + jsMethod.getName() + "\")"));
168: //get input params
169: Input input = op.getInput();
170: Message inputMsg = input.getMessage();
171: Part inputPart = inputMsg.getPart("parameters");
172: if (inputPart != null) {
173: QName typeName = schemaElementsToTypes
174: .get(inputPart.getElementName());
175: Element typeElem = schemaComplexTypes
176: .get(typeName);
177: Element[] children = getSchemaChildren(typeElem);
178: if (children.length > 1
179: || (children.length == 1 && !children[0]
180: .getLocalName().equals(
181: "sequence")))
182: throw new Wsdl2JsException(
183: "Expected only single sequence child element for complexType: "
184: + typeName);
185: children = getSchemaChildren(children[0]);
186: for (int paraNo = 0; paraNo < children.length; paraNo++) {
187: if (!children[paraNo].getLocalName()
188: .equals("element"))
189: throw new Wsdl2JsException(
190: "Expected only element children within sequence of complexType: "
191: + typeName);
192: String name = children[paraNo]
193: .getAttribute("name");
194: JsParam jsParam = new JsParam(name);
195: jsMethod.addParam(jsParam);
196: String info = createTypeInfo(children[paraNo]);
197: jsBlock.addStatement(new JsStatement(
198: "call.addParameter(\"" + name
199: + "\"," + info + ")"));
200: }
201: }
202: jsBlock.addStatement(new JsStatement(
203: "this._extractCallback(call,arguments,"
204: + jsMethod.getParams().length
205: + ")"));
206: //get return param
207: Output output = op.getOutput();
208: Message outputMsg = output.getMessage();
209: Part outputPart = outputMsg
210: .getPart("parameters");
211: if (outputPart != null) {
212: QName typeName = schemaElementsToTypes
213: .get(outputPart.getElementName());
214: Element typeElem = schemaComplexTypes
215: .get(typeName);
216: Element[] children = getSchemaChildren(typeElem);
217: if (children.length > 1
218: || (children.length == 1 && !children[0]
219: .getLocalName().equals(
220: "sequence")))
221: throw new Wsdl2JsException(
222: "Expected only single sequence child element for complexType: "
223: + typeName);
224: children = getSchemaChildren(children[0]);
225: if (children.length > 1)
226: throw new Wsdl2JsException(
227: "Expected only one or none return parameters");
228: if (children.length == 1) {
229: String info = createTypeInfo(children[0]);
230: jsBlock.addStatement(new JsStatement(
231: "call.setReturnType(" + info
232: + ")"));
233: }
234: }
235: jsBlock
236: .addStatement(new JsStatement(
237: "return call.invoke("
238: + jsMethod
239: .getParamList()
240: + ")"));
241: jsClass.addMethod(jsMethod);
242: } catch (Wsdl2JsTypeException x) {
243: System.out.println("WARNING: Skip method '"
244: + op.getName() + "' as signature "
245: + "contains unsupported type '"
246: + x.getTypeName() + "'.");
247: }
248: }
249: block.addStatement(new JsStatement(
250: "this._targetNamespace=\""
251: + def.getTargetNamespace() + "\""));
252: for (int i = 0; i < typeInfoList.size(); i++) {
253: block.addStatement(new JsStatement(
254: "this._typeInfos[" + i + "]="
255: + (String) typeInfoList.get(i)));
256: }
257: for (int i = 0; i < popInfoList.size(); i++) {
258: block.addStatement(new JsStatement(
259: (String) popInfoList.get(i)));
260: }
261: jsClass.printCode(new FileOutputStream(outputFile));
262: }
263: }
264: }
265:
266: /**
267: * Get endpoint location URI from WSDL port
268: */
269: private String getAddressLocation(Port port)
270: throws Wsdl2JsException {
271: Iterator<?> it = port.getExtensibilityElements().iterator();
272: while (it.hasNext()) {
273: ExtensibilityElement elem = (ExtensibilityElement) it
274: .next();
275: if (elem instanceof SOAPAddress) {
276: SOAPAddress adr = (SOAPAddress) elem;
277: return adr.getLocationURI();
278: }
279: }
280: throw new Wsdl2JsException(
281: "No soap address binding found for port " + port);
282: }
283:
284: /**
285: * Create type description JS code for the the given schema element
286: */
287: private String createTypeInfo(Element element)
288: throws Wsdl2JsException {
289: if (!(element.getNamespaceURI().equals(XMLNS_SCHEMA) && element
290: .getLocalName().equals("element")))
291: throw new IllegalArgumentException(
292: "Expected element declaration as argument");
293: if (isElementArray(element)) {
294: ArrayInfo arrayInfo = getArrayInfoFromElement(element);
295: QName compType = arrayInfo.arrayType;
296: int dim = arrayInfo.arrayDim;
297: String name = compType.getLocalPart();
298: for (int i = 0; i < dim; i++)
299: name += "Array";
300: String nsuri = compType.getNamespaceURI();
301: if (compType.getNamespaceURI().equals(XMLNS_SCHEMA))
302: nsuri = XMLNS_JAXB_ARRAY;
303: QName arrType = new QName(nsuri, name);
304: String ret = typeInfoMap.get(arrType);
305: if (ret == null) {
306: int ind = typeInfoList.size();
307: String info = "\"\"";
308: typeInfoList.add(info);
309: ret = "this._typeInfos[" + ind + "]";
310: typeInfoMap.put(arrType, ret);
311: String ainf = createJsTypeInfo(arrayInfo.arrayType);
312: String pop = ret + ".populate(" + ainf + ","
313: + arrayInfo.arrayDim + ")";
314: popInfoList.add(pop);
315: String qn = createJsQName(arrType);
316: info = "new SOAP_ArrayInfo(" + qn + ")";
317: typeInfoList.set(ind, info);
318: }
319: return ret;
320: } else {
321:
322: String type = element.getAttribute("type");
323: QName qname = getQName(type, element);
324:
325: return createJsTypeInfo(qname);
326: }
327: }
328:
329: /**
330: * Create type description JS code for the the given schema type
331: */
332: private String createJsTypeInfo(QName type) throws Wsdl2JsException {
333: String ret = typeInfoMap.get(type);
334: if (ret == null) {
335: int ind = typeInfoList.size();
336: ret = "this._typeInfos[" + ind + "]";
337: typeInfoMap.put(type, ret);
338: String info = "\"\"";
339: typeInfoList.add(info);
340: if (type.getNamespaceURI().equals(Constants.XMLNS_XSD)) {
341: info = "new SOAP_TypeInfo(" + createJsQName(type) + ")";
342: } else if (type.getLocalPart().equals("hashMap")) {
343: throw new Wsdl2JsTypeException(type);
344: } else {
345: Element ctypeElem = (Element) schemaComplexTypes
346: .get(type);
347: if (ctypeElem != null) {
348: if (isComplexTypeArray(ctypeElem)) {
349: String qn = createJsQName(type);
350: ArrayInfo arrayInfo = getArrayInfoFromComplexType(ctypeElem);
351: String ainf = createJsTypeInfo(arrayInfo.arrayType);
352: String pop = ret + ".populate(" + ainf + ","
353: + arrayInfo.arrayDim + ")";
354: popInfoList.add(pop);
355: info = "new SOAP_ArrayInfo(" + qn + ")";
356: } else {
357: info = "new SOAP_BeanInfo("
358: + createJsQName(type) + ")";
359: String pop = ret + ".populate(new Array(";
360: String memberList = getMemberInfos(ctypeElem);
361: pop += memberList;
362: pop += "))";
363: popInfoList.add(pop);
364: }
365: } else
366: throw new Wsdl2JsException("Type '" + type
367: + "' not found within WSDL types section."
368: + " ->" + type.getNamespaceURI());
369: }
370: typeInfoList.set(ind, info);
371: }
372: return ret;
373: }
374:
375: /**
376: * Create QName instance JS code (using JS constant for schema namespace)
377: */
378: private String createJsQName(QName name) {
379: String nsuri = "";
380: if (name.getNamespaceURI().equals(Constants.XMLNS_XSD))
381: nsuri = "XML_NS_XSD";
382: else
383: nsuri = "\"" + name.getNamespaceURI() + "\"";
384: return "new XML_QName(" + nsuri + ",\"" + name.getLocalPart()
385: + "\")";
386: }
387:
388: /**
389: * Stores top-level schema elements and complexTypes in maps (for all imported schemas)
390: */
391: private void readSchema(Types wsdlTypes) throws Wsdl2JsException {
392: schemaComplexTypes = new HashMap<QName, Element>();
393: schemaElementsToTypes = new HashMap<QName, QName>();
394: if (wsdlTypes != null) {
395: List<?> schemaList = wsdlTypes.getExtensibilityElements();
396: Iterator<?> schemaIt = schemaList.iterator();
397: while (schemaIt.hasNext()) {
398: ExtensibilityElement extElem = (ExtensibilityElement) schemaIt
399: .next();
400: if (extElem instanceof Schema) {
401: Schema schema = (Schema) extElem;
402: readSchema(schema);
403: }
404: }
405: }
406: }
407:
408: /**
409: * Stores top-level schema elements and complexTypes in maps (for a single schema)
410: */
411: private void readSchema(Schema schema) throws Wsdl2JsException {
412: // Process imported schemas
413: Map<?, ?> imports = schema.getImports();
414: Iterator<?> impIt = imports.keySet().iterator();
415: while (impIt.hasNext()) {
416: String targetNS = (String) impIt.next();
417: List<?> list = (List<?>) imports.get(targetNS);
418: Iterator<?> listIt = list.iterator();
419: while (listIt.hasNext()) {
420: Object obj = listIt.next();
421: if (obj instanceof SchemaImport) {
422: SchemaImport schemaImp = (SchemaImport) obj;
423: Schema refSchema = schemaImp.getReferencedSchema();
424: readSchema(refSchema);
425: }
426: }
427: }
428: // Process schema type definitions
429: NodeList nodes = schema.getElement().getChildNodes();
430: for (int i = 0; i < nodes.getLength(); i++) {
431: Node node = nodes.item(i);
432: if (node.getNodeType() == Node.ELEMENT_NODE
433: && node.getNamespaceURI().equals(
434: Constants.XMLNS_XSD)) {
435: if (node.getLocalName().equals("complexType")) {
436: Element typeElem = (Element) node;
437: String name = typeElem.getAttribute("name");
438: String targetNS = schema.getElement().getAttribute(
439: "targetNamespace");
440: QName qname = new QName(targetNS, name);
441: schemaComplexTypes.put(qname, typeElem);
442: } else if (node.getLocalName().equals("element")) {
443: Element elemElem = (Element) node;
444: String name = elemElem.getAttribute("name");
445: String targetNS = schema.getElement().getAttribute(
446: "targetNamespace");
447: String type = elemElem.getAttribute("type");
448: Matcher matcher = PREFIXPATTERN.matcher(type);
449: if (!matcher.matches())
450: throw new Wsdl2JsException(
451: "Element type value isn't prefixed: "
452: + type);
453: String prefix = matcher.group(1);
454: String localName = matcher.group(2);
455: String nsuri = DOMUtils.getNamespaceURIFromPrefix(
456: elemElem, prefix);
457: if (nsuri == null)
458: throw new Wsdl2JsException(
459: "No namespace declaration found for prefix: "
460: + prefix);
461: QName elemQName = new QName(targetNS, name);
462: QName typeQName = new QName(nsuri, localName);
463: schemaElementsToTypes.put(elemQName, typeQName);
464: }
465: }
466: }
467: }
468:
469: /**
470: * Check if complexType declaration represents an array
471: */
472: private boolean isComplexTypeArray(Element complexType) {
473: if (!(complexType.getNamespaceURI().equals(XMLNS_SCHEMA) && complexType
474: .getLocalName().equals("complexType")))
475: throw new IllegalArgumentException(
476: "Expected complex type declaration element as argument");
477: Element[] elems = getSchemaChildren(complexType);
478: if (elems.length == 1
479: && elems[0].getLocalName().equals("sequence")) {
480: elems = getSchemaChildren(elems[0]);
481: if (elems.length == 1
482: && elems[0].getLocalName().equals("element")) {
483: String min = elems[0].getAttribute("minOccurs");
484: String max = elems[0].getAttribute("maxOccurs");
485: if (min != null && max != null && min.equals("0")
486: && max.equals("unbounded"))
487: return true;
488: }
489: }
490: return false;
491: }
492:
493: /**
494: * Check if element declaration represents an array
495: */
496: private boolean isElementArray(Element element) {
497: if (!(element.getNamespaceURI().equals(XMLNS_SCHEMA) && element
498: .getLocalName().equals("element")))
499: throw new IllegalArgumentException(
500: "Expected element declaration as argument");
501: String min = element.getAttribute("minOccurs");
502: String max = element.getAttribute("maxOccurs");
503: if (min != null && max != null && min.equals("0")
504: && max.equals("unbounded"))
505: return true;
506: return false;
507: }
508:
509: /**
510: * Extract array information from complexType
511: */
512: private ArrayInfo getArrayInfoFromComplexType(Element complexType)
513: throws Wsdl2JsException {
514: if (!(complexType.getNamespaceURI().equals(XMLNS_SCHEMA) && complexType
515: .getLocalName().equals("complexType")))
516: throw new IllegalArgumentException(
517: "Expected complex type declaration element as argument");
518: Element[] elems = getSchemaChildren(complexType);
519: if (elems.length == 1
520: && elems[0].getLocalName().equals("sequence")) {
521: elems = getSchemaChildren(elems[0]);
522: if (elems.length == 1
523: && elems[0].getLocalName().equals("element")) {
524: if (isElementArray(elems[0])) {
525: return getArrayInfoFromElement(elems[0]);
526: }
527: }
528: }
529: throw new IllegalArgumentException(
530: "Expected complex type declaration representing an array");
531: }
532:
533: /**
534: * Extract array information from element
535: */
536: private ArrayInfo getArrayInfoFromElement(Element element)
537: throws Wsdl2JsException {
538: if (!(element.getNamespaceURI().equals(XMLNS_SCHEMA) && element
539: .getLocalName().equals("element")))
540: throw new IllegalArgumentException(
541: "Expected element declaration as argument");
542: if (!isElementArray(element))
543: throw new IllegalArgumentException(
544: "Expected element declaration representing an array");
545: String compType = element.getAttribute("type");
546: Matcher mat = PREFIXPATTERN.matcher(compType);
547: if (!mat.matches())
548: throw new Wsdl2JsException(
549: "Expected prefixed element array component type: "
550: + compType);
551: String compPrefix = mat.group(1);
552: String compLocalName = mat.group(2);
553: String compNSUri = DOMUtils.getNamespaceURIFromPrefix(element,
554: compPrefix);
555: QName compQName = new QName(compNSUri, compLocalName);
556: Element complexType = (Element) schemaComplexTypes
557: .get(compQName);
558: if (complexType != null) {
559: if (isComplexTypeArray(complexType)) {
560: ArrayInfo compInfo = getArrayInfoFromComplexType(complexType);
561: ArrayInfo info = new ArrayInfo(compInfo.arrayType,
562: compInfo.arrayDim + 1);
563: return info;
564: } else
565: return new ArrayInfo(compQName, 1);
566: } else
567: return new ArrayInfo(compQName, 1);
568: }
569:
570: /**
571: * Create type description JS code for a bean using its complexType definition
572: */
573: private String getMemberInfos(Element complexType)
574: throws Wsdl2JsException {
575: if (!(complexType.getNamespaceURI().equals(XMLNS_SCHEMA) && complexType
576: .getLocalName().equals("complexType")))
577: throw new IllegalArgumentException(
578: "Expected complex type declaration element as argument: "
579: + getXMLString(complexType));
580: Element modelElem = getFirstSchemaChild(complexType);
581: if (modelElem != null) {
582: if (modelElem.getLocalName().equals("sequence")) {
583: return getSequenceMemberInfos(modelElem);
584: } else if (modelElem.getLocalName()
585: .equals("complexContent")) {
586: Element extElem = getFirstSchemaChild(modelElem);
587: if (extElem != null
588: && extElem.getLocalName().equals("extension")) {
589: String base = extElem.getAttribute("base");
590: QName qname = getQName(base, extElem);
591: Element baseElem = (Element) schemaComplexTypes
592: .get(qname);
593: String baseInfos = getMemberInfos(baseElem);
594: Element seqElem = getFirstSchemaChild(extElem);
595: if (seqElem != null
596: && seqElem.getLocalName()
597: .equals("sequence")) {
598: String infos = getSequenceMemberInfos(seqElem);
599: if (infos.length() > 0
600: && baseInfos.length() > 0) {
601: infos = infos + "," + baseInfos;
602: } else {
603: infos = infos + baseInfos;
604: }
605: return infos;
606: } else
607: throw new Wsdl2JsException(
608: "Illegal 'extension' content: "
609: + complexType
610: .getAttribute("name"));
611: } else
612: throw new Wsdl2JsException(
613: "Illegal 'complexContent': "
614: + complexType.getAttribute("name"));
615: } else
616: throw new Wsdl2JsException("Illegal content model: "
617: + complexType.getAttribute("name"));
618: } else
619: throw new Wsdl2JsException(
620: "XML Schema child expected below complex type: "
621: + getXMLString(complexType));
622: }
623:
624: /**
625: * Create type description JS code for a bean using its sequence definition
626: */
627: private String getSequenceMemberInfos(Element sequence)
628: throws Wsdl2JsException {
629: if (!(sequence.getNamespaceURI().equals(XMLNS_SCHEMA) && sequence
630: .getLocalName().equals("sequence")))
631: throw new IllegalArgumentException(
632: "Expected sequence declaration element as argument");
633: String memberList = "";
634: Element[] elems = getSchemaChildren(sequence);
635: for (int i = 0; i < elems.length; i++) {
636: Element elem = elems[i];
637: if (elem.getLocalName().equals("element")) {
638: String name = elem.getAttribute("name");
639: String typeInfo = createTypeInfo(elem);
640: memberList += "\"" + name + "\"," + typeInfo;
641: if (i < elems.length - 1)
642: memberList += ",";
643: }
644: }
645: return memberList;
646: }
647:
648: /**
649: * Create a QName object from a prefixed value (the passed element is used for namespace resolution)
650: */
651: private QName getQName(String value, Element element)
652: throws Wsdl2JsException {
653: Matcher matcher = PREFIXPATTERN.matcher(value);
654: if (!matcher.matches())
655: throw new Wsdl2JsException("Value isn't prefixed: " + value);
656: String prefix = matcher.group(1);
657: String localName = matcher.group(2);
658: String nsuri = DOMUtils.getNamespaceURIFromPrefix(element,
659: prefix);
660: return new QName(nsuri, localName);
661: }
662:
663: /**
664: * Return the first schema child element
665: */
666: private Element getFirstSchemaChild(Element parent) {
667: NodeList nl = parent.getChildNodes();
668: for (int i = 0; i < nl.getLength(); i++) {
669: Node n = nl.item(i);
670: if (n.getNodeType() == Node.ELEMENT_NODE
671: && n.getNamespaceURI().equals(Constants.XMLNS_XSD)) {
672: return (Element) n;
673: }
674: }
675: return null;
676: }
677:
678: /**
679: * Return an array of all schema child elements
680: */
681: private Element[] getSchemaChildren(Element parent) {
682: List<Element> al = new ArrayList<Element>();
683: NodeList nl = parent.getChildNodes();
684: for (int i = 0; i < nl.getLength(); i++) {
685: Node n = nl.item(i);
686: if (n.getNodeType() == Node.ELEMENT_NODE
687: && n.getNamespaceURI().equals(Constants.XMLNS_XSD)) {
688: al.add((Element) n);
689: }
690: }
691: Element[] elems = new Element[al.size()];
692: al.toArray(elems);
693: return elems;
694: }
695:
696: /**
697: * Create string representation of the XML element
698: */
699: private String getXMLString(Element element) {
700: StringBuilder sb = new StringBuilder();
701: getXMLString(element, sb);
702: return sb.toString();
703: }
704:
705: /**
706: * Create string representation of the XML element by walking down the DOM tree
707: */
708: private void getXMLString(Element element, StringBuilder sb) {
709: sb.append("<");
710: sb.append(element.getLocalName());
711: NamedNodeMap attrs = element.getAttributes();
712: for (int i = 0; i < attrs.getLength(); i++) {
713: Node node = attrs.item(i);
714: sb.append(" ");
715: sb.append(node.getNodeName());
716: sb.append("=\"");
717: sb.append(node.getNodeValue());
718: sb.append("\"");
719: }
720: if (element.hasChildNodes()) {
721: sb.append(">");
722: NodeList nodes = element.getChildNodes();
723: for (int i = 0; i < nodes.getLength(); i++) {
724: if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
725: Element child = (Element) nodes.item(i);
726: getXMLString(child, sb);
727: }
728: }
729: sb.append("</");
730: sb.append(element.getLocalName());
731: sb.append(">");
732: } else {
733: sb.append("/>");
734: }
735: }
736:
737: /**
738: * Helper class for storing information while traversing array schema definitions
739: */
740: class ArrayInfo {
741:
742: QName arrayType;
743: int arrayDim;
744:
745: ArrayInfo(QName arrayType, int arrayDim) {
746: this.arrayType = arrayType;
747: this.arrayDim = arrayDim;
748: }
749:
750: }
751:
752: }
|