KickJava   Java API By Example, From Geeks To Geeks.

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


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.utils.XMLUtils;
20 import org.w3c.dom.NamedNodeMap JavaDoc;
21 import org.w3c.dom.Node JavaDoc;
22
23 import javax.xml.namespace.QName JavaDoc;
24 import javax.xml.rpc.holders.BooleanHolder JavaDoc;
25 import java.util.*;
26
27 /**
28  * This class contains static utility methods for the emitter.
29  *
30  * @author Rich Scheuerle (scheu@us.ibm.com)
31  * @author Tom Jordahl (tomj@macromedia.com)
32  */

33 public class Utils {
34
35     /** cache of namespaces -> maps of localNames -> QNames */
36     static final Map JavaDoc nsmap = new HashMap();
37
38     /**
39      * Find or create a QName with the specified namespace/localName.
40      *
41      * @param namespace
42      * @param localName
43      * @return
44      */

45     static QName JavaDoc findQName(String JavaDoc namespace, String JavaDoc localName) {
46
47         QName JavaDoc qname = null;
48
49         // get the inner map, using the namespace as a key
50
Map JavaDoc ln2qn = (Map JavaDoc) nsmap.get(namespace);
51
52         if (null == ln2qn) { // cache miss
53
ln2qn = new HashMap();
54
55             nsmap.put(namespace, ln2qn);
56
57             qname = new QName JavaDoc(namespace, localName);
58
59             ln2qn.put(localName, qname);
60         } else { // cache hit
61
qname = (QName JavaDoc) ln2qn.get(localName);
62
63             if (null == qname) { // cache miss
64
qname = new QName JavaDoc(namespace, localName);
65
66                 ln2qn.put(localName, qname);
67             } else {
68
69                 // cache hit
70
}
71         }
72
73         return qname;
74     }
75
76     /**
77      * Given a node, return the value of the given attribute.
78      * If the attribute does not exist, searching continues through ancestor nodes until found.
79      * This method is useful for finding attributes that pertain to a group of contained
80      * nodes (i.e. xlmns, xmlns:tns, targetNamespace, name)
81      *
82      * @param node
83      * @param attr
84      * @return
85      */

86     public static String JavaDoc getScopedAttribute(Node JavaDoc node, String JavaDoc attr) {
87
88         if (node == null) {
89             return null;
90         }
91
92         if (node.getAttributes() == null) {
93             return getScopedAttribute(node.getParentNode(), attr);
94         }
95
96         Node JavaDoc attrNode = node.getAttributes().getNamedItem(attr);
97
98         if (attrNode != null) {
99             return attrNode.getNodeValue();
100         } else {
101             return getScopedAttribute(node.getParentNode(), attr);
102         }
103     }
104
105     /**
106      * Given a node, return the value of the given attribute.
107      * Returns null if the attribute is not found
108      *
109      * @param node
110      * @param attr
111      * @return
112      */

113     public static String JavaDoc getAttribute(Node JavaDoc node, String JavaDoc attr) {
114
115         if ((node == null) || (node.getAttributes() == null)) {
116             return null;
117         }
118
119         Node JavaDoc attrNode = node.getAttributes().getNamedItem(attr);
120
121         if (attrNode != null) {
122             return attrNode.getNodeValue();
123         } else {
124             return null;
125         }
126     }
127
128     /**
129      * Given a node, return the attributes that have the specified local name.
130      * Returns null if the attribute is not found
131      *
132      * @param node
133      * @param localName
134      * @return
135      */

136     public static Vector getAttributesWithLocalName(Node JavaDoc node,
137                                                     String JavaDoc localName) {
138
139         Vector v = new Vector();
140
141         if (node == null) {
142             return v;
143         }
144
145         NamedNodeMap JavaDoc map = node.getAttributes();
146
147         if (map != null) {
148             for (int i = 0; i < map.getLength(); i++) {
149                 Node JavaDoc attrNode = map.item(i);
150
151                 if ((attrNode != null)
152                         && attrNode.getLocalName().equals(localName)) {
153                     v.add(attrNode);
154                 }
155             }
156         }
157
158         return v;
159     }
160
161     /**
162      * An xml element may have a name.
163      * For example &lt.element name="foo" type="b:bar"&gt.
164      * has the name "element". This routine gets the full QName of the element.
165      *
166      * @param node
167      * @return
168      */

169     public static QName JavaDoc getNodeQName(Node JavaDoc node) {
170
171         if (node == null) {
172             return null;
173         }
174
175         String JavaDoc localName = node.getLocalName();
176
177         if (localName == null) {
178             return null;
179         }
180
181         String JavaDoc namespace = node.getNamespaceURI();
182
183         return (findQName(namespace, localName));
184     }
185
186     /**
187      * XML nodes may have a name attribute.
188      * For example &lt.element name="foo" type="b:bar"&gt.
189      * has the name attribute value "foo". This routine gets the QName of the name attribute value.
190      *
191      * @param node
192      * @return
193      */

194     public static QName JavaDoc getNodeNameQName(Node JavaDoc node) {
195
196         if (node == null) {
197             return null;
198         }
199
200         String JavaDoc localName = null;
201         String JavaDoc namespace = null;
202
203         // First try to get the name directly
204
localName = getAttribute(node, "name");
205
206         // If this fails and the node has a ref, use the ref name.
207
if (localName == null) {
208             QName JavaDoc ref = getTypeQNameFromAttr(node, "ref");
209
210             if (ref != null) {
211                 localName = ref.getLocalPart();
212                 namespace = ref.getNamespaceURI();
213             }
214         }
215
216         // This routine may be called for complexType elements. In some cases,
217
// the complexType may be anonymous, which is why the getScopedAttribute
218
// method is used.
219

220             Node JavaDoc search = node.getParentNode();
221
222             while (search != null) {
223                 String JavaDoc ln = search.getLocalName();
224
225                 if (ln.equals("schema")) {
226                     search = null;
227                 } else if (ln.equals("element")
228                         || ln.equals("attribute")) {
229                     localName = SymbolTable.ANON_TOKEN
230                             + getNodeNameQName(search).getLocalPart();
231                     search = null;
232                 } else if (ln.equals("complexType")
233                         || ln.equals("simpleType")) {
234                     localName = getNodeNameQName(search).getLocalPart()
235                             + SymbolTable.ANON_TOKEN + localName;
236                     search = null;
237                 } else {
238                     search = search.getParentNode();
239                 }
240             }
241
242         if (localName == null) {
243             return null;
244         }
245
246         // Build and return the QName
247
if (namespace == null) {
248             namespace = getScopedAttribute(node, "targetNamespace");
249         }
250
251         return (findQName(namespace, localName));
252     }
253
254     /**
255      * An XML element or attribute node has several ways of
256      * identifying the type of the element or attribute:
257      * - use the type attribute to reference a complexType/simpleType
258      * - use the ref attribute to reference another element, group or attributeGroup
259      * - use of an anonymous type (i.e. a nested type underneath itself)
260      * - a wsdl:part can use the element attribute.
261      * - an extension can use the base attribute.
262      * <p/>
263      * This routine returns a QName representing this "type".
264      * The forElement value is also returned to indicate whether the
265      * QName represents an element (i.e. obtained using the ref attribute)
266      * or a type.
267      * <p/>
268      * Other attributes affect the QName that is returned.
269      * If the "minOccurs" and "maxOccurs" are set such that the
270      * type is a collection of "types", then an artificial qname is
271      * returned to represent the collection.
272      *
273      * @param node of the reference
274      * @param forElement output parameter is set to true if QName is for an element
275      * (i.e. ref= or element= attribute was used).
276      * @param ignoreMaxOccurs indicates whether minOccurs/maxOccurs affects the QName
277      * @return QName representing the type of this element
278      */

279     public static QName JavaDoc getTypeQName(Node JavaDoc node, BooleanHolder JavaDoc forElement,
280                                      boolean ignoreMaxOccurs) {
281
282         if (node == null) {
283             return null;
284         }
285
286         forElement.value = false; // Assume QName returned is for a type
287

288         // Try getting the QName of the type attribute.
289
// Note this also retrieves the type if an anonymous type is used.
290
QName JavaDoc qName = getTypeQNameFromAttr(node, "type");
291
292         // If not successful, try using the ref attribute.
293
if (qName == null) {
294             String JavaDoc localName = node.getLocalName();
295
296             // bug 23145: support attributeGroup (Brook Richan)
297
// a ref can be for an element or attributeGroup
298
if ((localName != null)
299                 && !(localName.equals("attributeGroup") ||
300                         localName.equals("group") ||
301                         localName.equals("list"))) {
302                 forElement.value = true;
303             }
304
305             qName = getTypeQNameFromAttr(node, "ref");
306         }
307
308         // in case of a list get the itemType
309
if (qName == null) {
310             qName = getTypeQNameFromAttr(node, "itemType");
311         }
312
313         // If the node has "type"/"ref" and "maxOccurs" then the type is really
314
// a collection. There is no qname in the wsdl which we can use to represent
315
// the collection, so we need to invent one.
316
// The local part of the qname is changed to <local>[minOccurs, maxOccurs]
317
// The namespace uri is changed to the targetNamespace of this node
318
if (!ignoreMaxOccurs) {
319             if (qName != null) {
320                 String JavaDoc maxOccursValue = getAttribute(node, "maxOccurs");
321                 String JavaDoc minOccursValue = getAttribute(node, "minOccurs");
322
323                 if (maxOccursValue == null) {
324                     maxOccursValue = "1";
325                 }
326
327                 if (minOccursValue == null) {
328                     minOccursValue = "1";
329                 }
330
331                 if (minOccursValue.equals("0") && maxOccursValue.equals("1")) {
332
333                     // If we have a minoccurs="0"/maxoccurs="1", this is just
334
// like a nillable single value, so treat it as such.
335
// qName = getNillableQName(qName);
336
} else if (!maxOccursValue.equals("1")
337                         || !minOccursValue.equals("1")) {
338                     String JavaDoc localPart = qName.getLocalPart();
339                     String JavaDoc range = "[";
340                     if (!minOccursValue.equals("1")) {
341                         range += minOccursValue;
342                     }
343                     range += ",";
344                     if (!maxOccursValue.equals("1")) {
345                         range += maxOccursValue;
346                     }
347                     range += "]";
348                     localPart += range;
349                     qName = findQName(qName.getNamespaceURI(), localPart);
350                 }
351             }
352         }
353
354         // A WSDL Part uses the element attribute instead of the ref attribute
355
if (qName == null) {
356             forElement.value = true;
357             qName = getTypeQNameFromAttr(node, "element");
358         }
359
360         // "base" references a "type"
361
if (qName == null) {
362             forElement.value = false;
363             qName = getTypeQNameFromAttr(node, "base");
364         }
365
366         return qName;
367     }
368
369     /**
370      * Method getMemberTypeQNames
371      *
372      * @param node
373      * @return
374      */

375     public static QName JavaDoc[] getMemberTypeQNames(Node JavaDoc node) {
376
377         String JavaDoc attribute = getAttribute(node, "memberTypes");
378
379         if (attribute == null) {
380             return null;
381         }
382
383         StringTokenizer tokenizer = new StringTokenizer(attribute, " ");
384         QName JavaDoc[] memberTypes = new QName JavaDoc[tokenizer.countTokens()];
385
386         for (int i = 0; tokenizer.hasMoreElements(); i++) {
387             String JavaDoc element = (String JavaDoc) tokenizer.nextElement();
388
389             memberTypes[i] = XMLUtils.getFullQNameFromString(element, node);
390         }
391
392         return memberTypes;
393     }
394
395     /**
396      * Gets the QName of the type of the node via the specified attribute
397      * name.
398      * <p/>
399      * If "type", the QName represented by the type attribute's value is
400      * returned. If the type attribute is not set, the anonymous type
401      * or anyType is returned if no other type information is available.
402      * Note that the QName returned in these cases is affected by
403      * the presence of the nillable attribute.
404      * <p/>
405      * If "ref", the QName represented by the ref attribute's value is
406      * returned.
407      * <p/>
408      * If "base" or "element", the QName represented by the base/element
409      * attribute's value is returned.
410      *
411      * @param node in the dom
412      * @param typeAttrName (type, base, element, ref)
413      * @return
414      */

415     private static QName JavaDoc getTypeQNameFromAttr(Node JavaDoc node, String JavaDoc typeAttrName) {
416
417         if (node == null) {
418             return null;
419         }
420
421         // Get the raw prefixed value
422
String JavaDoc prefixedName = getAttribute(node, typeAttrName);
423
424         // If "type" was specified but there is no type attribute,
425
// check for an anonymous type. If no anonymous type
426
// then the type is anyType.
427
if ((prefixedName == null) && typeAttrName.equals("type")) {
428             if ((getAttribute(node, "ref") == null)
429                     && (getAttribute(node, "base") == null)
430                     && (getAttribute(node, "element") == null)) {
431
432                 // Try getting the anonymous qname
433
QName JavaDoc anonQName = SchemaUtils.getElementAnonQName(node);
434
435                 if (anonQName == null) {
436                     anonQName = SchemaUtils.getAttributeAnonQName(node);
437                 }
438
439                 if (anonQName != null) {
440                     return anonQName;
441                 }
442
443                 // Try returning anyType
444
String JavaDoc localName = node.getLocalName();
445                 
446                 if ((localName != null)
447                     && Constants.isSchemaXSD(node.getNamespaceURI())
448                     && (localName.equals("element") ||
449                         localName.equals("attribute"))) {
450                     return Constants.XSD_ANYTYPE;
451                 }
452             }
453         }
454
455         // Return null if not found
456
if (prefixedName == null) {
457             return null;
458         }
459
460         // Change the prefixed name into a full qname
461
QName JavaDoc qName = getQNameFromPrefixedName(node, prefixedName);
462
463         // An alternate qname is returned if nillable
464
// if (typeAttrName.equals("type")) {
465
// if (JavaUtils.isTrueExplicitly(getAttribute(node, "nillable"))) {
466
// qName = getNillableQName(qName);
467
// }
468
// }
469

470         return qName;
471     }
472
473     /**
474      * Convert a prefixed name into a qname
475      *
476      * @param node
477      * @param prefixedName
478      * @return
479      */

480     public static QName JavaDoc getQNameFromPrefixedName(Node JavaDoc node,
481                                                  String JavaDoc prefixedName) {
482
483         String JavaDoc localName = prefixedName.substring(prefixedName.lastIndexOf(":")
484                 + 1);
485         String JavaDoc namespace = null;
486
487         // Associate the namespace prefix with a namespace
488
if (prefixedName.length() == localName.length()) {
489             namespace = getScopedAttribute(
490                     node, "xmlns"); // Get namespace for unqualified reference
491
} else {
492             namespace = getScopedAttribute(node,
493                     "xmlns:"
494                     + prefixedName.substring(0,
495                             prefixedName.lastIndexOf(":")));
496         }
497
498         return (findQName(namespace, localName));
499     }
500
501     /**
502      * This method returns a set of all types that are derived
503      * from this type via an extension of a complexType
504      *
505      * @param type
506      * @param symbolTable
507      * @return
508      */

509     public static HashSet getDerivedTypes(TypeEntry type,
510                                           SymbolTable symbolTable) {
511
512         HashSet types = (HashSet)symbolTable.derivedTypes.get(type);
513
514         if (types != null) {
515             return types;
516         }
517
518         types = new HashSet();
519
520         symbolTable.derivedTypes.put(type, types);
521
522         if ((type != null) && (type.getNode() != null)) {
523             getDerivedTypes(type, types, symbolTable);
524         }
525         else if (type != null && Constants.isSchemaXSD(type.getQName().getNamespaceURI())
526                 && (type.getQName().getLocalPart().equals("anyType")
527                 || type.getQName().getLocalPart().equals("any"))) {
528
529             // All types are derived from anyType, except anonymous ones
530
final Collection typeValues = symbolTable.getTypeIndex().values();
531             for (Iterator it = typeValues.iterator(); it.hasNext();) {
532                 SymTabEntry e = (SymTabEntry) it.next();
533                 if (! e.getQName().getLocalPart().startsWith(SymbolTable.ANON_TOKEN))
534                     types.add(e);
535             }
536         }
537
538         return types;
539     } // getNestedTypes
540

541     /**
542      * Method getDerivedTypes
543      *
544      * @param type
545      * @param types
546      * @param symbolTable
547      */

548     private static void getDerivedTypes(TypeEntry type, HashSet types,
549                                         SymbolTable symbolTable) {
550
551         // If all types are in the set, return
552
if (types.size() == symbolTable.getTypeEntryCount()) {
553             return;
554         }
555
556         // Search the dictionary for derived types of type
557
for (Iterator it = symbolTable.getTypeIndex().values().iterator();
558              it.hasNext();) {
559             Type t = (Type) it.next();
560
561             if ((t instanceof DefinedType) && (t.getNode() != null)
562                     && !types.contains(t)
563                     && (((DefinedType) t).getComplexTypeExtensionBase(symbolTable)
564                     == type)) {
565                 types.add(t);
566                 getDerivedTypes(t, types, symbolTable);
567             }
568         }
569     } // getDerivedTypes
570

571     /**
572      * This method returns a set of all the nested types.
573      * Nested types are types declared within this TypeEntry (or descendents)
574      * plus any extended types and the extended type nested types
575      * The elements of the returned HashSet are Types.
576      *
577      * @param type is the type entry to consider
578      * @param symbolTable is the symbolTable
579      * @param derivedFlag should be set if all dependendent derived types should also be
580      * returned.
581      * @return
582      */

583     protected static HashSet getNestedTypes(TypeEntry type,
584                                          SymbolTable symbolTable,
585                                          boolean derivedFlag) {
586
587         HashSet types = new HashSet();
588
589         getNestedTypes(type, types, symbolTable, derivedFlag);
590
591         return types;
592     } // getNestedTypes
593

594     /**
595      * Method getNestedTypes
596      *
597      * @param type
598      * @param types
599      * @param symbolTable
600      * @param derivedFlag
601      */

602     private static void getNestedTypes(TypeEntry type, HashSet types,
603                                        SymbolTable symbolTable,
604                                        boolean derivedFlag) {
605
606         if (type == null) {
607             return;
608         }
609
610         // If all types are in the set, return
611
if (types.size() == symbolTable.getTypeEntryCount()) {
612             return;
613         }
614
615         // Process types derived from this type
616
if (derivedFlag) {
617             HashSet derivedTypes = getDerivedTypes(type, symbolTable);
618             Iterator it = derivedTypes.iterator();
619
620             while (it.hasNext()) {
621                 TypeEntry derivedType = (TypeEntry) it.next();
622
623                 if (!types.contains(derivedType)) {
624                     types.add(derivedType);
625                     getNestedTypes(derivedType, types, symbolTable,
626                             derivedFlag);
627                 }
628             }
629         }
630
631         // Continue only if the node exists
632
if (type.getNode() == null) {
633             return;
634         }
635
636         Node JavaDoc node = type.getNode();
637
638         // Process types declared in this type
639
Vector v = SchemaUtils.getContainedElementDeclarations(node,
640                 symbolTable);
641
642         if (v != null) {
643             for (int i = 0; i < v.size(); i++) {
644                 ElementDecl elem = (ElementDecl) v.get(i);
645
646                 if (!types.contains(elem.getType())) {
647                     types.add(elem.getType());
648                     getNestedTypes(elem.getType(), types, symbolTable,
649                             derivedFlag);
650                 }
651             }
652         }
653
654         // Process attributes declared in this type
655
v = SchemaUtils.getContainedAttributeTypes(node, symbolTable);
656
657         if (v != null) {
658             for (int i = 0; i < v.size(); i++) {
659                 ContainedAttribute attr = (ContainedAttribute) v.get(i);
660                 TypeEntry te = attr.getType();
661                 if (!types.contains(te)) {
662                     types.add(te);
663                     getNestedTypes(te, types, symbolTable, derivedFlag);
664                 }
665             }
666         }
667
668         // Process referenced types
669
if ((type.getRefType() != null) && !types.contains(type.getRefType())) {
670             types.add(type.getRefType());
671             getNestedTypes(type.getRefType(), types, symbolTable, derivedFlag);
672         }
673
674         /*
675          * Anonymous processing and should be automatically handled by the
676          * reference processing above
677          * // Get the anonymous type of the element
678          * QName anonQName = SchemaUtils.getElementAnonQName(node);
679          * if (anonQName != null) {
680          * TypeEntry anonType = symbolTable.getType(anonQName);
681          * if (anonType != null && !types.contains(anonType)) {
682          * types.add(anonType);
683          * }
684          * }
685          *
686          * // Get the anonymous type of an attribute
687          * anonQName = SchemaUtils.getAttributeAnonQName(node);
688          * if (anonQName != null) {
689          * TypeEntry anonType = symbolTable.getType(anonQName);
690          * if (anonType != null && !types.contains(anonType)) {
691          * types.add(anonType);
692          * }
693          * }
694          */

695
696         // Process extended types
697
TypeEntry extendType = SchemaUtils.getComplexElementExtensionBase(node,
698                 symbolTable);
699
700         if (extendType != null) {
701             if (!types.contains(extendType)) {
702                 types.add(extendType);
703                 getNestedTypes(extendType, types, symbolTable, derivedFlag);
704             }
705         }
706
707         /*
708          * Array component processing should be automatically handled by the
709          * reference processing above.
710          * // Process array components
711          * QName componentQName = SchemaUtils.getArrayComponentQName(node, new IntHolder(0));
712          * TypeEntry componentType = symbolTable.getType(componentQName);
713          * if (componentType == null) {
714          * componentType = symbolTable.getElement(componentQName);
715          * }
716          * if (componentType != null) {
717          * if (!types.contains(componentType)) {
718          * types.add(componentType);
719          * getNestedTypes(componentType, types, symbolTable, derivedFlag);
720          * }
721          * }
722          */

723     } // getNestedTypes
724

725     /**
726      * Generate an XML prefixed attribute value with a corresponding xmlns
727      * declaration for the prefix. If there is no namespace,
728      * don't prefix the name or emit the xmlns attribute.
729      * <p/>
730      * Caller should provide the enclosing quotes.
731      * <p/>
732      * Usage: println("name=\"" + genXMLQNameString(qname, "foo") + "\""
733      *
734      * @param qname
735      * @param prefix
736      * @return
737      */

738     public static String JavaDoc genQNameAttributeString(QName JavaDoc qname, String JavaDoc prefix) {
739
740         if ((qname.getNamespaceURI() == null)
741                 || qname.getNamespaceURI().equals("")) {
742             return qname.getLocalPart();
743         }
744
745         return prefix + ":" + qname.getLocalPart() + "\" xmlns:" + prefix
746                 + "=\"" + qname.getNamespaceURI();
747     }
748     
749     public static String JavaDoc genQNameAttributeStringWithLastLocalPart(QName JavaDoc qname, String JavaDoc prefix) {
750         String JavaDoc lastLocalPart = getLastLocalPart(qname.getLocalPart());
751         if ((qname.getNamespaceURI() == null)
752                 || qname.getNamespaceURI().equals("")) {
753             return lastLocalPart;
754         }
755
756         return prefix + ":" + lastLocalPart + "\" xmlns:" + prefix
757                 + "=\"" + qname.getNamespaceURI();
758     }
759
760     public static String JavaDoc getLastLocalPart(String JavaDoc localPart) {
761         int anonymousDelimitorIndex = localPart.lastIndexOf('>');
762         if (anonymousDelimitorIndex > -1 && anonymousDelimitorIndex < localPart.length()-1) {
763             localPart = localPart.substring(anonymousDelimitorIndex + 1);
764         }
765         return localPart;
766         
767     }
768 }
769
Popular Tags