KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55 package org.jboss.axis.wsdl.symbolTable;
56
57 import org.jboss.axis.Constants;
58 import org.jboss.axis.utils.JavaUtils;
59 import org.w3c.dom.NamedNodeMap JavaDoc;
60 import org.w3c.dom.Node JavaDoc;
61
62 import javax.xml.namespace.QName JavaDoc;
63 import javax.xml.rpc.holders.BooleanHolder JavaDoc;
64 import java.util.HashMap JavaDoc;
65 import java.util.HashSet JavaDoc;
66 import java.util.Iterator JavaDoc;
67 import java.util.Map JavaDoc;
68 import java.util.Vector JavaDoc;
69
70 /**
71  * This class contains static utility methods for the emitter.
72  *
73  * @author Rich Scheuerle (scheu@us.ibm.com)
74  * @author Tom Jordahl (tomj@macromedia.com)
75  */

76 public class Utils
77 {
78    /**
79     * cache of namespaces -> maps of localNames -> QNames
80     */

81    static final Map JavaDoc nsmap = new HashMap JavaDoc();
82
83    /**
84     * Find or create a QName with the specified namespace/localName.
85     *
86     * @param namespace
87     * @param localName
88     */

89    static QName JavaDoc findQName(String JavaDoc namespace, String JavaDoc localName)
90    {
91       QName JavaDoc qname = null;
92
93       // get the inner map, using the namespace as a key
94
Map JavaDoc ln2qn = (Map JavaDoc)nsmap.get(namespace);
95       if (null == ln2qn)
96       { // cache miss
97
ln2qn = new HashMap JavaDoc();
98          nsmap.put(namespace, ln2qn);
99
100          qname = new QName JavaDoc(namespace, localName);
101          ln2qn.put(localName, qname);
102       }
103       else
104       { // cache hit
105
qname = (QName JavaDoc)ln2qn.get(localName);
106          if (null == qname)
107          { // cache miss
108
qname = new QName JavaDoc(namespace, localName);
109             ln2qn.put(localName, qname);
110          }
111          else
112          {
113             // cache hit
114
}
115       }
116       return qname;
117    }
118
119    /**
120     * getNillableQName returns the QName to use if the nillable=true
121     * attribute is used.
122     * For example, in JAX-RPC:
123     * The QName "xsd:int" maps to a java int.
124     * However if an element with a type="xsd:int" also has the
125     * "nillable=true" attribute, the type should be an Integer (not an int).
126     * So in these circumstances, this routine is called with xsd:int to
127     * get a suitable qname (soapenc:int) which maps to Integer.
128     *
129     * @param qName QName
130     */

131    public static QName JavaDoc getNillableQName(QName JavaDoc qName)
132    {
133       QName JavaDoc rc = qName;
134       if (Constants.isSchemaXSD(rc.getNamespaceURI()))
135       {
136          String JavaDoc localName = rc.getLocalPart();
137          if (localName.equals("int") ||
138                  localName.equals("long") ||
139                  localName.equals("short") ||
140                  localName.equals("float") ||
141                  localName.equals("double") ||
142                  localName.equals("boolean") ||
143                  localName.equals("byte"))
144          {
145             rc = findQName(Constants.URI_DEFAULT_SOAP_ENC,
146                     qName.getLocalPart());
147          }
148          else if (localName.equals("base64Binary"))
149          {
150             rc = findQName(Constants.URI_DEFAULT_SOAP_ENC, "base64");
151          }
152          else if (localName.equals("hexBinary"))
153          {
154             rc = findQName(Constants.URI_DEFAULT_SCHEMA_XSD, "hexBinary");
155          }
156       }
157       return rc;
158    }
159
160    /**
161     * Given a node, return the value of the given attribute.
162     * If the attribute does not exist, searching continues through ancestor nodes until found.
163     * This method is useful for finding attributes that pertain to a group of contained
164     * nodes (i.e. xlmns, xmlns:tns, targetNamespace, name)
165     */

166    public static String JavaDoc getScopedAttribute(Node JavaDoc node, String JavaDoc attr)
167    {
168       if (node == null)
169       {
170          return null;
171       }
172
173       if (node.getAttributes() == null)
174          return getScopedAttribute(node.getParentNode(), attr);
175
176       Node JavaDoc attrNode = node.getAttributes().getNamedItem(attr);
177       if (attrNode != null)
178       {
179          return attrNode.getNodeValue();
180       }
181       else
182       {
183          return getScopedAttribute(node.getParentNode(), attr);
184       }
185    }
186
187    /**
188     * Given a node, return the value of the given attribute.
189     * Returns null if the attribute is not found
190     */

191    public static String JavaDoc getAttribute(Node JavaDoc node, String JavaDoc attr)
192    {
193       if (node == null || node.getAttributes() == null)
194       {
195          return null;
196       }
197
198       Node JavaDoc attrNode = node.getAttributes().getNamedItem(attr);
199       if (attrNode != null)
200       {
201          return attrNode.getNodeValue();
202       }
203       else
204       {
205          return null;
206       }
207    }
208
209    /**
210     * Given a node, return the attributes that have the specified local name.
211     * Returns null if the attribute is not found
212     */

213    public static Vector JavaDoc getAttributesWithLocalName(Node JavaDoc node, String JavaDoc localName)
214    {
215       Vector JavaDoc v = new Vector JavaDoc();
216       if (node == null)
217       {
218          return v;
219       }
220
221       NamedNodeMap JavaDoc map = node.getAttributes();
222       if (map != null)
223       {
224          for (int i = 0; i < map.getLength(); i++)
225          {
226             Node JavaDoc attrNode = map.item(i);
227             if (attrNode != null &&
228                     attrNode.getLocalName().equals(localName))
229             {
230                v.add(attrNode);
231             }
232          }
233       }
234       return v;
235    }
236
237    /**
238     * An xml element may have a name.
239     * For example &lt.element name="foo" type="b:bar"&gt.
240     * has the name "element". This routine gets the full QName of the element.
241     */

242    public static QName JavaDoc getNodeQName(Node JavaDoc node)
243    {
244       if (node == null)
245       {
246          return null;
247       }
248
249       String JavaDoc localName = node.getLocalName();
250       if (localName == null)
251       {
252          return null;
253       }
254       String JavaDoc namespace = node.getNamespaceURI();
255
256       return (findQName(namespace, localName));
257    }
258
259    /**
260     * XML nodes may have a name attribute.
261     * For example &lt.element name="foo" type="b:bar"&gt.
262     * has the name attribute value "foo". This routine gets the QName of the name attribute value.
263     */

264    public static QName JavaDoc getNodeNameQName(Node JavaDoc node)
265    {
266       if (node == null)
267       {
268          return null;
269       }
270       String JavaDoc localName = null;
271       String JavaDoc namespace = null;
272
273       // First try to get the name directly
274
localName = getAttribute(node, "name");
275
276       // If this fails and the node has a ref, use the ref name.
277
if (localName == null)
278       {
279          QName JavaDoc ref = getTypeQNameFromAttr(node, "ref");
280          if (ref != null)
281          {
282             localName = ref.getLocalPart();
283             namespace = ref.getNamespaceURI();
284          }
285       }
286
287       // This routine may be called for complexType elements. In some cases,
288
// the complexType may be anonymous, which is why the getScopedAttribute
289
// method is used.
290
if (localName == null)
291       {
292          localName = "";
293          Node JavaDoc search = node.getParentNode();
294          while (search != null)
295          {
296             QName JavaDoc kind = getNodeQName(search);
297             if (kind.getLocalPart().equals("schema"))
298             {
299                search = null;
300             }
301             else if (kind.getLocalPart().equals("element") ||
302                     kind.getLocalPart().equals("attribute"))
303             {
304                localName = SymbolTable.ANON_TOKEN +
305                        getNodeNameQName(search).getLocalPart();
306                search = search.getParentNode();
307             }
308             else if (kind.getLocalPart().equals("complexType") ||
309                     kind.getLocalPart().equals("simpleType"))
310             {
311                localName = getNodeNameQName(search).getLocalPart() + localName;
312                search = null;
313             }
314             else
315             {
316                search = search.getParentNode();
317             }
318          }
319       }
320       if (localName == null)
321          return null;
322
323       // Build and return the QName
324
if (namespace == null)
325       {
326          namespace = getScopedAttribute(node, "targetNamespace");
327       }
328       return (findQName(namespace, localName));
329    }
330
331    /**
332     * An XML element or attribute node has several ways of
333     * identifying the type of the element or attribute:
334     * - use the type attribute to reference a complexType/simpleType
335     * - use the ref attribute to reference another element
336     * - use of an anonymous type (i.e. a nested type underneath itself)
337     * - a wsdl:part can use the element attribute.
338     * - an extension can use the base attribute.
339     * <p/>
340     * This routine returns a QName representing this "type".
341     * The forElement value is also returned to indicate whether the
342     * QName represents an element (i.e. obtained using the ref attribute)
343     * or a type.
344     * <p/>
345     * Other attributes affect the QName that is returned.
346     * If the "minOccurs" and "maxOccurs" are set such that the
347     * type is a collection of "types", then an artificial qname is
348     * returned to represent the collection.
349     *
350     * @param node of the reference
351     * @param forElement output parameter is set to true if QName is for an element
352     * (i.e. ref= or element= attribute was used).
353     * @param ignoreMaxOccurs indicates whether minOccurs/maxOccurs affects the QName
354     * @return QName representing the type of this element
355     */

356    public static QName JavaDoc getTypeQName(Node JavaDoc node, BooleanHolder JavaDoc forElement, boolean ignoreMaxOccurs)
357    {
358       if (node == null) return null;
359       forElement.value = false; // Assume QName returned is for a type
360

361       // Try getting the QName of the type attribute.
362
// Note this also retrieves the type if an anonymous type is used.
363
QName JavaDoc qName = getTypeQNameFromAttr(node, "type");
364
365       // If not successful, try using the ref attribute.
366
if (qName == null)
367       {
368          forElement.value = true;
369          qName = getTypeQNameFromAttr(node, "ref");
370       }
371
372       // If the node has "type"/"ref" and "maxOccurs" then the type is really
373
// a collection. There is no qname in the wsdl which we can use to represent
374
// the collection, so we need to invent one.
375
// The local part of the qname is changed to <local>[minOccurs, maxOccurs]
376
// The namespace uri is changed to the targetNamespace of this node
377
if (!ignoreMaxOccurs)
378       {
379          if (qName != null)
380          {
381             String JavaDoc maxOccursValue = getAttribute(node, "maxOccurs");
382             String JavaDoc minOccursValue = getAttribute(node, "minOccurs");
383             if (maxOccursValue == null)
384             {
385                maxOccursValue = "1";
386             }
387             if (minOccursValue == null)
388             {
389                minOccursValue = "1";
390             }
391             if (minOccursValue.equals("0") && maxOccursValue.equals("1"))
392             {
393                // If we have a minoccurs="0"/maxoccurs="1", this is just
394
// like a nillable single value, so treat it as such.
395
qName = getNillableQName(qName);
396             }
397             else if (!maxOccursValue.equals("1") || !minOccursValue.equals("1"))
398             {
399                String JavaDoc localPart = qName.getLocalPart();
400                localPart += "[" + maxOccursValue + "]";
401                qName = findQName(qName.getNamespaceURI(), localPart);
402             }
403          }
404       }
405
406       // A WSDL Part uses the element attribute instead of the ref attribute
407
if (qName == null)
408       {
409          forElement.value = true;
410          qName = getTypeQNameFromAttr(node, "element");
411       }
412
413       // "base" references a "type"
414
if (qName == null)
415       {
416          forElement.value = false;
417          qName = getTypeQNameFromAttr(node, "base");
418       }
419       return qName;
420    }
421
422    /**
423     * Gets the QName of the type of the node via the specified attribute
424     * name.
425     * <p/>
426     * If "type", the QName represented by the type attribute's value is
427     * returned. If the type attribute is not set, the anonymous type
428     * or anyType is returned if no other type information is available.
429     * Note that the QName returned in these cases is affected by
430     * the presence of the nillable attribute.
431     * <p/>
432     * If "ref", the QName represented by the ref attribute's value is
433     * returned.
434     * <p/>
435     * If "base" or "element", the QName represented by the base/element
436     * attribute's value is returned.
437     *
438     * @param node in the dom
439     * @param typeAttrName (type, base, element, ref)
440     */

441    private static QName JavaDoc getTypeQNameFromAttr(Node JavaDoc node, String JavaDoc typeAttrName)
442    {
443       if (node == null)
444       {
445          return null;
446       }
447       // Get the raw prefixed value
448
String JavaDoc prefixedName = getAttribute(node, typeAttrName);
449
450       // If "type" was specified but there is no type attribute,
451
// check for an anonymous type. If no anonymous type
452
// then the type is anyType.
453
if (prefixedName == null &&
454               typeAttrName.equals("type"))
455       {
456          if (getAttribute(node, "ref") == null &&
457                  getAttribute(node, "base") == null &&
458                  getAttribute(node, "element") == null)
459          {
460
461             // Try getting the anonymous qname
462
QName JavaDoc anonQName = SchemaUtils.getElementAnonQName(node);
463             if (anonQName == null)
464             {
465                anonQName = SchemaUtils.getAttributeAnonQName(node);
466             }
467             if (anonQName != null)
468             {
469                return anonQName;
470             }
471
472             // Try returning anyType
473
QName JavaDoc nodeName = getNodeQName(node);
474             if (nodeName != null &&
475                     Constants.isSchemaXSD(nodeName.getNamespaceURI()) &&
476                     (nodeName.getLocalPart().equals("element") ||
477                     nodeName.getLocalPart().equals("attribute")))
478             {
479                return Constants.XSD_ANYTYPE;
480             }
481          }
482       }
483
484       // Return null if not found
485
if (prefixedName == null)
486       {
487          return null;
488       }
489       // Change the prefixed name into a full qname
490
QName JavaDoc qName = getQNameFromPrefixedName(node, prefixedName);
491
492       // An alternate qname is returned if nillable
493
if (typeAttrName.equals("type"))
494       {
495          if (JavaUtils.isTrueExplicitly(getAttribute(node, "nillable")))
496          {
497             qName = getNillableQName(qName);
498          }
499       }
500       return qName;
501    }
502
503    /**
504     * Convert a prefixed name into a qname
505     */

506    public static QName JavaDoc getQNameFromPrefixedName(Node JavaDoc node, String JavaDoc prefixedName)
507    {
508
509       String JavaDoc localName = prefixedName.substring(prefixedName.lastIndexOf(":") + 1);
510       String JavaDoc namespace = null;
511       // Associate the namespace prefix with a namespace
512
if (prefixedName.length() == localName.length())
513       {
514          namespace = getScopedAttribute(node, "xmlns"); // Get namespace for unqualified reference
515
}
516       else
517       {
518          namespace = getScopedAttribute(node, "xmlns:" + prefixedName.substring(0, prefixedName.lastIndexOf(":")));
519       }
520       return (findQName(namespace, localName));
521    }
522
523    /**
524     * This method returns a set of all types that are derived
525     * from this type via an extension of a complexType
526     */

527    public static HashSet JavaDoc getDerivedTypes(TypeEntry type, SymbolTable symbolTable)
528    {
529       HashSet JavaDoc types = new HashSet JavaDoc();
530       if (type != null && type.getNode() != null)
531       {
532          getDerivedTypes(type, types, symbolTable);
533       }
534       else if (Constants.isSchemaXSD(type.getQName().getNamespaceURI()) &&
535               (type.getQName().getLocalPart().equals("anyType") ||
536               type.getQName().getLocalPart().equals("any")))
537       {
538          // All types are derived from anyType
539
types.addAll(symbolTable.getTypeIndex().values());
540       }
541       return types;
542    } // getNestedTypes
543

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

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

579    public static HashSet JavaDoc getNestedTypes(TypeEntry type, SymbolTable symbolTable,
580                                         boolean derivedFlag)
581    {
582       HashSet JavaDoc types = new HashSet JavaDoc();
583       getNestedTypes(type, types, symbolTable, derivedFlag);
584       return types;
585    } // getNestedTypes
586

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

684
685       // Process extended types
686
TypeEntry extendType = SchemaUtils.getComplexElementExtensionBase(node, symbolTable);
687       if (extendType != null)
688       {
689          if (!types.contains(extendType))
690          {
691             types.add(extendType);
692             getNestedTypes(extendType, types, symbolTable, derivedFlag);
693          }
694       }
695
696       /* Array component processing should be automatically handled by the
697          reference processing above.
698       // Process array components
699       QName componentQName = SchemaUtils.getArrayComponentQName(node, new IntHolder(0));
700       TypeEntry componentType = symbolTable.getType(componentQName);
701       if (componentType == null) {
702           componentType = symbolTable.getElement(componentQName);
703       }
704       if (componentType != null) {
705           if (!types.contains(componentType)) {
706               types.add(componentType);
707               getNestedTypes(componentType, types, symbolTable, derivedFlag);
708           }
709       }
710       */

711
712    } // getNestedTypes
713

714    /**
715     * Generate an XML prefixed attribute value with a corresponding xmlns
716     * declaration for the prefix. If there is no namespace,
717     * don't prefix the name or emit the xmlns attribute.
718     * <p/>
719     * Caller should provide the enclosing quotes.
720     * <p/>
721     * Usage: println("name=\"" + genXMLQNameString(qname, "foo") + "\""
722     */

723    public static String JavaDoc genQNameAttributeString(QName JavaDoc qname, String JavaDoc prefix)
724    {
725       if (qname.getNamespaceURI() == null || qname.getNamespaceURI().equals(""))
726          return qname.getLocalPart();
727
728       return prefix + ":" + qname.getLocalPart() + "\" xmlns:" + prefix +
729               "=\"" + qname.getNamespaceURI();
730    }
731
732 }
733
734
Popular Tags