KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > wsdl > symbolTable > SchemaUtils


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.axis.wsdl.symbolTable;
17
18 import org.apache.axis.Constants;
19 import org.apache.axis.AxisProperties;
20 import org.apache.axis.utils.JavaUtils;
21 import org.w3c.dom.DOMException JavaDoc;
22 import org.w3c.dom.Element JavaDoc;
23 import org.w3c.dom.Node JavaDoc;
24 import org.w3c.dom.NodeList JavaDoc;
25
26 import javax.xml.namespace.QName JavaDoc;
27 import javax.xml.rpc.holders.BooleanHolder JavaDoc;
28 import javax.xml.rpc.holders.IntHolder JavaDoc;
29 import javax.xml.rpc.holders.BooleanHolder JavaDoc;
30 import javax.xml.rpc.holders.QNameHolder JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Set JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import java.util.Vector JavaDoc;
36
37 /**
38  * This class contains static utility methods specifically for schema type queries.
39  *
40  * @author Rich Scheuerle (scheu@us.ibm.com)
41  */

42 public class SchemaUtils {
43
44     /** Field VALUE_QNAME */
45     static final QName JavaDoc VALUE_QNAME = Utils.findQName("", "_value");
46
47     /**
48      * This method checks mixed=true attribute is set either on
49      * complexType or complexContent element.
50      */

51     public static boolean isMixed(Node JavaDoc node) {
52         // Expecting a schema complexType
53
if (isXSDNode(node, "complexType")) {
54             String JavaDoc mixed = ((Element)node).getAttribute("mixed");
55             if (mixed != null && mixed.length() > 0) {
56                 return ("true".equalsIgnoreCase(mixed) ||
57                         "1".equals(mixed));
58             }
59             // Under the complexType there could be complexContent with
60
// mixed="true"
61
NodeList JavaDoc children = node.getChildNodes();
62
63             for (int j = 0; j < children.getLength(); j++) {
64                 Node JavaDoc kid = children.item(j);
65                 if (isXSDNode(kid, "complexContent")) {
66                     mixed = ((Element)kid).getAttribute("mixed");
67                     return ("true".equalsIgnoreCase(mixed) ||
68                             "1".equals(mixed));
69                 }
70             }
71         }
72         return false;
73     }
74
75     public static Node JavaDoc getUnionNode(Node JavaDoc node) {
76         // Expecting a schema complexType
77
if (isXSDNode(node, "simpleType")) {
78             // Under the simpleType there could be union
79
NodeList JavaDoc children = node.getChildNodes();
80             for (int j = 0; j < children.getLength(); j++) {
81                 Node JavaDoc kid = children.item(j);
82                 if (isXSDNode(kid, "union")) {
83                     return kid;
84                 }
85             }
86         }
87         return null;
88     }
89
90     public static Node JavaDoc getListNode(Node JavaDoc node) {
91         // Expecting a schema simpleType
92
if (isXSDNode(node, "simpleType")) {
93             // Under the simpleType there could be list
94
NodeList JavaDoc children = node.getChildNodes();
95             for (int j = 0; j < children.getLength(); j++) {
96                 Node JavaDoc kid = children.item(j);
97                 if (isXSDNode(kid, "list")) {
98                     return kid;
99                 }
100             }
101         }
102         return null;
103     }
104
105     public static boolean isSimpleTypeWithUnion(Node JavaDoc node) {
106         return (getUnionNode(node) != null);
107     }
108
109   /**
110    * This method checks out if the given node satisfies the 3rd condition
111    * of the "wrapper" style:
112    * such an element (a wrapper) must be of a complex type defined using the
113    * xsd:sequence compositor and containing only elements declarations.
114    * (excerpt from JAX-RPC spec 1.1 Maintenanace Review 2 Chapter 6 Section 4.1.)
115    *
116    * @param node
117    * @return
118    */

119   public static boolean isWrappedType(Node JavaDoc node) {
120
121     if (node == null) {
122       return false;
123     }
124
125     // If the node kind is an element, dive into it.
126
if (isXSDNode(node, "element")) {
127       NodeList JavaDoc children = node.getChildNodes();
128       boolean hasComplexType = false;
129       for (int j = 0; j < children.getLength(); j++) {
130         Node JavaDoc kid = children.item(j);
131         if (isXSDNode(kid, "complexType")) {
132           node = kid;
133           hasComplexType = true;
134           break;
135         }
136       }
137       if (!hasComplexType) {
138         return false;
139       }
140     }
141
142     // Expecting a schema complexType
143
if (isXSDNode(node, "complexType")) {
144       // Under the complexType there could be complexContent/simpleContent
145
// and extension elements if this is a derived type.
146
// A wrapper element must be complex-typed.
147

148       NodeList JavaDoc children = node.getChildNodes();
149
150       for (int j = 0; j < children.getLength(); j++) {
151         Node JavaDoc kid = children.item(j);
152
153         if (isXSDNode(kid, "complexContent")) {
154           return false;
155         } else if (isXSDNode(kid, "simpleContent")) {
156           return false;
157         }
158       }
159
160       // Under the complexType there may be choice, sequence, group and/or all nodes.
161
// (There may be other #text nodes, which we will ignore).
162
// The complex type of a wrapper element must have only sequence
163
// and again element declarations in the sequence.
164
children = node.getChildNodes();
165       int len = children.getLength();
166       for (int j = 0; j < len; j++) {
167           Node JavaDoc kid = children.item(j);
168           String JavaDoc localName = kid.getLocalName();
169           if (localName != null &&
170               Constants.isSchemaXSD(kid.getNamespaceURI())) {
171               if (localName.equals("sequence")) {
172                   Node JavaDoc sequenceNode = kid;
173                   NodeList JavaDoc sequenceChildren = sequenceNode.getChildNodes();
174                   int sequenceLen = sequenceChildren.getLength();
175                   for (int k = 0; k < sequenceLen; k++) {
176                       Node JavaDoc sequenceKid = sequenceChildren.item(k);
177                       String JavaDoc sequenceLocalName = sequenceKid.getLocalName();
178                       if (sequenceLocalName != null &&
179                           Constants.isSchemaXSD(sequenceKid.getNamespaceURI())) {
180                           // allow choice with element children
181
if (sequenceLocalName.equals("choice")) {
182                               Node JavaDoc choiceNode = sequenceKid;
183                               NodeList JavaDoc choiceChildren = choiceNode.getChildNodes();
184                               int choiceLen = choiceChildren.getLength();
185                               for (int l = 0; l < choiceLen; l++) {
186                                   Node JavaDoc choiceKid = choiceChildren.item(l);
187                                   String JavaDoc choiceLocalName = choiceKid.getLocalName();
188                                   if (choiceLocalName != null &&
189                                       Constants.isSchemaXSD(choiceKid.getNamespaceURI())) {
190                                       if (!choiceLocalName.equals("element")) {
191                                           return false;
192                                       }
193                                   }
194                               }
195                           }
196                           else
197                           if (!sequenceLocalName.equals("element")) {
198                               return false;
199                           }
200                       }
201                   }
202                   return true;
203               } else {
204                   return false;
205               }
206           }
207       }
208     }
209     // allows void type
210
return true;
211   }
212
213     /**
214      * If the specified node represents a supported JAX-RPC complexType or
215      * simpleType, a Vector is returned which contains ElementDecls for the
216      * child element names.
217      * If the element is a simpleType, an ElementDecls is built representing
218      * the restricted type with the special name "value".
219      * If the element is a complexType which has simpleContent, an ElementDecl
220      * is built representing the extended type with the special name "value".
221      * This method does not return attribute names and types
222      * (use the getContainedAttributeTypes)
223      * If the specified node is not a supported
224      * JAX-RPC complexType/simpleType/element null is returned.
225      *
226      * @param node
227      * @param symbolTable
228      * @return
229      */

230     public static Vector JavaDoc getContainedElementDeclarations(Node JavaDoc node,
231                                                          SymbolTable symbolTable) {
232
233         if (node == null) {
234             return null;
235         }
236
237         // If the node kind is an element, dive into it.
238
if (isXSDNode(node, "element")) {
239             NodeList JavaDoc children = node.getChildNodes();
240
241             for (int j = 0; j < children.getLength(); j++) {
242                 Node JavaDoc kid = children.item(j);
243
244                 if (isXSDNode(kid, "complexType")) {
245                     node = kid;
246
247                     break;
248                 }
249             }
250         }
251
252         // Expecting a schema complexType or simpleType
253
if (isXSDNode(node, "complexType")) {
254
255             // Under the complexType there could be complexContent/simpleContent
256
// and extension elements if this is a derived type. Skip over these.
257
NodeList JavaDoc children = node.getChildNodes();
258             Node JavaDoc complexContent = null;
259             Node JavaDoc simpleContent = null;
260             Node JavaDoc extension = null;
261
262             for (int j = 0; j < children.getLength(); j++) {
263                 Node JavaDoc kid = children.item(j);
264
265                 if (isXSDNode(kid, "complexContent")) {
266                     complexContent = kid;
267
268                     break; // REMIND: should this be here or on either branch?
269
} else if (isXSDNode(kid, "simpleContent")) {
270                     simpleContent = kid;
271                 }
272             }
273
274             if (complexContent != null) {
275                 children = complexContent.getChildNodes();
276
277                 for (int j = 0;
278                      (j < children.getLength()) && (extension == null);
279                      j++) {
280                     Node JavaDoc kid = children.item(j);
281
282                     if (isXSDNode(kid, "extension")
283                             || isXSDNode(kid, "restriction")) {
284                         extension = kid;
285                     }
286                 }
287             }
288
289             if (simpleContent != null) {
290                 children = simpleContent.getChildNodes();
291
292                 int len = children.getLength();
293                 for (int j = 0;
294                      (j < len) && (extension == null);
295                      j++) {
296                     Node JavaDoc kid = children.item(j);
297                     String JavaDoc localName = kid.getLocalName();
298
299                     if ((localName != null)
300                         && (localName.equals("extension") || localName.equals("restriction"))
301                         && Constants.isSchemaXSD(kid.getNamespaceURI())) {
302
303                         // get the type of the extension/restriction from the "base" attribute
304
QName JavaDoc extendsOrRestrictsType =
305                                 Utils.getTypeQName(children.item(j),
306                                         new BooleanHolder JavaDoc(), false);
307
308                         // Return an element declaration with a fixed name
309
// ("value") and the correct type.
310
Vector JavaDoc v = new Vector JavaDoc();
311                         ElementDecl elem = new ElementDecl(symbolTable.getTypeEntry(extendsOrRestrictsType, false), VALUE_QNAME);
312                         v.add(elem);
313
314                         return v;
315                     }
316                 }
317             }
318
319             if (extension != null) {
320                 node = extension; // Skip over complexContent and extension
321
}
322
323             // Under the complexType there may be choice, sequence, group and/or all nodes.
324
// (There may be other #text nodes, which we will ignore).
325
children = node.getChildNodes();
326
327             Vector JavaDoc v = new Vector JavaDoc();
328             int len = children.getLength();
329             for (int j = 0; j < len; j++) {
330                 Node JavaDoc kid = children.item(j);
331                 String JavaDoc localName = kid.getLocalName();
332                 if (localName != null &&
333                     Constants.isSchemaXSD(kid.getNamespaceURI())) {
334                     if (localName.equals("sequence")) {
335                         v.addAll(processSequenceNode(kid, symbolTable));
336                     } else if (localName.equals("all")) {
337                         v.addAll(processAllNode(kid, symbolTable));
338                     } else if (localName.equals("choice")) {
339                         v.addAll(processChoiceNode(kid, symbolTable));
340                     } else if (localName.equals("group")) {
341                         v.addAll(processGroupNode(kid, symbolTable));
342                     }
343                 }
344             }
345
346             return v;
347         } else if (isXSDNode(node, "group")) {
348             /*
349             * Does this else clause make any sense anymore if
350             * we're treating refs to xs:groups like a macro inclusion
351             * into the referencing type?
352             * Maybe this else clause should never be possible?
353             *
354             NodeList children = node.getChildNodes();
355             Vector v = new Vector();
356             int len = children.getLength();
357             for (int j = 0; j < len; j++) {
358                 Node kid = children.item(j);
359                 String localName = kid.getLocalName();
360                 if (localName != null &&
361                     Constants.isSchemaXSD(kid.getNamespaceURI())) {
362                     if (localName.equals("sequence")) {
363                         v.addAll(processSequenceNode(kid, symbolTable));
364                     } else if (localName.equals("all")) {
365                         v.addAll(processAllNode(kid, symbolTable));
366                     } else if (localName.equals("choice")) {
367                         v.addAll(processChoiceNode(kid, symbolTable));
368                     }
369                 }
370             }
371             return v;
372             */

373                 return null;
374         } else {
375
376             // This may be a simpleType, return the type with the name "value"
377
QName JavaDoc[] simpleQName = getContainedSimpleTypes(node);
378
379             if (simpleQName != null) {
380                 Vector JavaDoc v = null;
381
382                 for (int i = 0; i < simpleQName.length; i++) {
383
384                     Type simpleType = symbolTable.getType(simpleQName[i]);
385
386                     if (simpleType != null) {
387                         if (v == null) {
388                             v = new Vector JavaDoc();
389                         }
390
391                         QName JavaDoc qname = null;
392                         if (simpleQName.length > 1) {
393                             qname = new QName JavaDoc("", simpleQName[i].getLocalPart() + "Value");
394                         } else {
395                             qname = new QName JavaDoc("", "value");
396                         }
397
398                         v.add(new ElementDecl(simpleType, qname));
399                     }
400                 }
401
402                 return v;
403             }
404         }
405
406         return null;
407     }
408
409     /**
410      * Invoked by getContainedElementDeclarations to get the child element types
411      * and child element names underneath a Choice Node
412      *
413      * @param choiceNode
414      * @param symbolTable
415      * @return
416      */

417     private static Vector JavaDoc processChoiceNode(Node JavaDoc choiceNode,
418                                             SymbolTable symbolTable) {
419
420         Vector JavaDoc v = new Vector JavaDoc();
421         NodeList JavaDoc children = choiceNode.getChildNodes();
422         int len = children.getLength();
423         for (int j = 0; j < len; j++) {
424             Node JavaDoc kid = children.item(j);
425             String JavaDoc localName = kid.getLocalName();
426             if (localName != null &&
427                 Constants.isSchemaXSD(kid.getNamespaceURI())) {
428                 if (localName.equals("choice")) {
429                     v.addAll(processChoiceNode(kid, symbolTable));
430                 } else if (localName.equals("sequence")) {
431                     v.addAll(processSequenceNode(kid, symbolTable));
432                 } else if (localName.equals("group")) {
433                     v.addAll(processGroupNode(kid, symbolTable));
434                 } else if (localName.equals("element")) {
435                     ElementDecl elem = processChildElementNode(kid,
436                                                                symbolTable);
437
438                     if (elem != null) {
439                         // XXX: forces minOccurs="0" so that a null choice
440
// element can be serialized ok.
441
elem.setMinOccursIs0(true);
442
443                         v.add(elem);
444                     }
445                 } else if (localName.equals("any")) {
446                     // Represent this as an element named any of type any type.
447
// This will cause it to be serialized with the element
448
// serializer.
449
Type type = symbolTable.getType(Constants.XSD_ANY);
450                     ElementDecl elem = new ElementDecl(type,
451                             Utils.findQName("",
452                                     "any"));
453
454                     elem.setAnyElement(true);
455                     v.add(elem);
456                 }
457             }
458         }
459
460         return v;
461     }
462
463     /**
464      * Returns named child node.
465      *
466      * @param parentNode Parent node.
467      * @param name Element name of child node to return.
468      */

469     private static Node JavaDoc getChildByName(Node JavaDoc parentNode, String JavaDoc name) throws DOMException JavaDoc {
470         if (parentNode == null) return null;
471         NodeList JavaDoc children = parentNode.getChildNodes();
472         if (children != null) {
473             for (int i = 0; i < children.getLength(); i++) {
474                 Node JavaDoc child = children.item(i);
475                 if (child != null) {
476                     if (child.getNodeName() != null && name.equals(child.getNodeName())) {
477                         return child;
478                     }
479                 }
480             }
481         }
482         return null;
483     }
484
485     /**
486      * Returns all textual nodes of a subnode defined by a parent node
487      * and a path of element names to that subnode.
488      *
489      * @param root Parent node.
490      * @param path Path of element names to text of interest, delimited by "/".
491      */

492     public static String JavaDoc getTextByPath(Node JavaDoc root, String JavaDoc path) throws DOMException JavaDoc {
493         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(path, "/");
494         Node JavaDoc node = root;
495         while (st.hasMoreTokens()) {
496             String JavaDoc elementName = st.nextToken();
497             Node JavaDoc child = getChildByName(node, elementName);
498             if (child == null)
499                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, "could not find " + elementName);
500             node = child;
501         }
502
503         // should have found the node
504
String JavaDoc text = "";
505         NodeList JavaDoc children = node.getChildNodes();
506         if (children != null) {
507             for (int i = 0; i < children.getLength(); i++) {
508                 Node JavaDoc child = children.item(i);
509                 if (child != null) {
510                     if (child.getNodeName() != null
511                             && (child.getNodeName().equals("#text")
512                             || child.getNodeName().equals("#cdata-section"))) {
513                         text += child.getNodeValue();
514                     }
515                 }
516             }
517         }
518         return text;
519     }
520
521     /**
522      * Returns the complete text of the child xsd:annotation/xsd:documentation
523      * element from the provided node. Only the first annotation element and
524      * the first documentation element in the annotation element will be used.
525      *
526      * @param typeNode Parent node.
527      */

528     public static String JavaDoc getAnnotationDocumentation(Node JavaDoc typeNode) {
529         Node JavaDoc annotationNode = typeNode.getFirstChild();
530         while (annotationNode != null) {
531             if (isXSDNode(annotationNode, "annotation")) {
532                 break;
533             }
534             annotationNode = annotationNode.getNextSibling();
535         }
536         Node JavaDoc documentationNode;
537         if (annotationNode != null) {
538             documentationNode = annotationNode.getFirstChild();
539             while (documentationNode != null) {
540                 if (isXSDNode(documentationNode, "documentation")) {
541                     break;
542                 }
543                 documentationNode = documentationNode.getNextSibling();
544             }
545         } else {
546             documentationNode = null;
547         }
548
549         // should have found the node if it exists
550
String JavaDoc text = "";
551         if (documentationNode != null) {
552             NodeList JavaDoc children = documentationNode.getChildNodes();
553             if (children != null) {
554                 for (int i = 0; i < children.getLength(); i++) {
555                     Node JavaDoc child = children.item(i);
556                     if (child != null) {
557                         if (child.getNodeName() != null
558                                 && (child.getNodeName().equals("#text")
559                                 || child.getNodeName().equals("#cdata-section"))) {
560                             text += child.getNodeValue();
561                         }
562                     }
563                 }
564             }
565         }
566         return text;
567     }
568
569     /**
570      * Invoked by getContainedElementDeclarations to get the child element types
571      * and child element names underneath a Sequence Node
572      *
573      * @param sequenceNode
574      * @param symbolTable
575      * @return
576      */

577     private static Vector JavaDoc processSequenceNode(Node JavaDoc sequenceNode,
578                                               SymbolTable symbolTable) {
579
580         Vector JavaDoc v = new Vector JavaDoc();
581         NodeList JavaDoc children = sequenceNode.getChildNodes();
582         int len = children.getLength();
583         for (int j = 0; j < len; j++) {
584             Node JavaDoc kid = children.item(j);
585             String JavaDoc localName = kid.getLocalName();
586
587             if (localName != null &&
588                 Constants.isSchemaXSD(kid.getNamespaceURI())) {
589                 if (localName.equals("choice")) {
590                     v.addAll(processChoiceNode(kid, symbolTable));
591                 } else if (localName.equals("sequence")) {
592                     v.addAll(processSequenceNode(kid, symbolTable));
593                 } else if (localName.equals("group")) {
594                     v.addAll(processGroupNode(kid, symbolTable));
595                 } else if (localName.equals("any")) {
596                     // Represent this as an element named any of type any type.
597
// This will cause it to be serialized with the element
598
// serializer.
599
Type type = symbolTable.getType(Constants.XSD_ANY);
600                     ElementDecl elem = new ElementDecl(type,
601                             Utils.findQName("",
602                                     "any"));
603
604                     elem.setAnyElement(true);
605                     v.add(elem);
606                 } else if (localName.equals("element")) {
607                     ElementDecl elem = processChildElementNode(kid,
608                                                                symbolTable);
609
610                     if (elem != null) {
611                         v.add(elem);
612                     }
613                 }
614             }
615         }
616
617         return v;
618     }
619
620     /**
621      * Invoked by getContainedElementDeclarations to get the child element types
622      * and child element names underneath a group node. If a ref attribute is
623      * specified, only the referenced group element is returned.
624      *
625      * @param groupNode
626      * @param symbolTable
627      * @return
628      */

629     private static Vector JavaDoc processGroupNode(Node JavaDoc groupNode,
630                                            SymbolTable symbolTable) {
631
632         Vector JavaDoc v = new Vector JavaDoc();
633         if (groupNode.getAttributes().getNamedItem("ref") == null) {
634             NodeList JavaDoc children = groupNode.getChildNodes();
635             int len = children.getLength();
636             for (int j = 0; j < len; j++) {
637                 Node JavaDoc kid = children.item(j);
638                 String JavaDoc localName = kid.getLocalName();
639                 if (localName != null &&
640                     Constants.isSchemaXSD(kid.getNamespaceURI())) {
641                     if (localName.equals("choice")) {
642                         v.addAll(processChoiceNode(kid, symbolTable));
643                     } else if (localName.equals("sequence")) {
644                         v.addAll(processSequenceNode(kid, symbolTable));
645                     } else if (localName.equals("all")) {
646                         v.addAll(processAllNode(kid, symbolTable));
647                     }
648                 }
649             }
650         } else {
651             QName JavaDoc nodeName = Utils.getNodeNameQName(groupNode);
652             QName JavaDoc nodeType = Utils.getTypeQName(groupNode, new BooleanHolder JavaDoc(), false);
653             // The value of the second argument is 'false' since global model group
654
// definitions are always represented by objects whose type is
655
// assignment compatible with 'org.apache.axis.wsdl.symbolTable.Type'.
656
Type type = (Type) symbolTable.getTypeEntry(nodeType, false);
657
658             if (type != null && type.getNode() != null) {
659                 //v.add(new ElementDecl(type, nodeName));
660
Node JavaDoc node = type.getNode();
661                 NodeList JavaDoc children = node.getChildNodes();
662                 for (int j = 0; j < children.getLength(); j++) {
663                     QName JavaDoc subNodeKind = Utils.getNodeQName(children.item(j));
664                     if ((subNodeKind != null)
665                         && Constants.isSchemaXSD(
666                             subNodeKind.getNamespaceURI())) {
667                    &nb