You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by di...@apache.org on 2004/10/25 15:44:14 UTC

cvs commit: ws-axis/c/src/wsdl/org/apache/axis/wsdl/symbolTable CElementDecl.java CSchemaUtils.java ElementDecl.java SchemaUtils.java

dicka       2004/10/25 06:44:14

  Modified:    c/src/wsdl/org/apache/axis/wsdl/wsdl2ws WSDL2Ws.java
  Added:       c/src/wsdl/org/apache/axis/wsdl/symbolTable
                        CElementDecl.java CSchemaUtils.java
  Removed:     c/src/wsdl/org/apache/axis/wsdl/symbolTable ElementDecl.java
                        SchemaUtils.java
  Log:
  Resolve classpath ordering problem for WSDL2Ws tool.
  
  Submitted by: Adrian Dick
  
  Revision  Changes    Path
  1.42      +13 -12    ws-axis/c/src/wsdl/org/apache/axis/wsdl/wsdl2ws/WSDL2Ws.java
  
  Index: WSDL2Ws.java
  ===================================================================
  RCS file: /home/cvs/ws-axis/c/src/wsdl/org/apache/axis/wsdl/wsdl2ws/WSDL2Ws.java,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -r1.41 -r1.42
  --- WSDL2Ws.java	20 Oct 2004 13:33:18 -0000	1.41
  +++ WSDL2Ws.java	25 Oct 2004 13:44:13 -0000	1.42
  @@ -32,11 +32,12 @@
   
   import org.apache.axis.wsdl.gen.Parser;
   import org.apache.axis.wsdl.symbolTable.BindingEntry;
  +import org.apache.axis.wsdl.symbolTable.CElementDecl;
   import org.apache.axis.wsdl.symbolTable.CollectionType;
   import org.apache.axis.wsdl.symbolTable.Element;
   import org.apache.axis.wsdl.symbolTable.ElementDecl;
   import org.apache.axis.wsdl.symbolTable.PortTypeEntry;
  -import org.apache.axis.wsdl.symbolTable.SchemaUtils;
  +import org.apache.axis.wsdl.symbolTable.CSchemaUtils;
   import org.apache.axis.wsdl.symbolTable.ServiceEntry;
   import org.apache.axis.wsdl.symbolTable.SymTabEntry;
   import org.apache.axis.wsdl.symbolTable.SymbolTable;
  @@ -581,7 +582,7 @@
   		Vector restrictdata = null;
   		if(type.isSimpleType()){
   			//check for extended types
  -			TypeEntry base = SchemaUtils.getComplexElementExtensionBase(type.getNode(),symbolTable);
  +			TypeEntry base = CSchemaUtils.getComplexElementExtensionBase(type.getNode(),symbolTable);
   			if (base != null){
   				String localpart = type.getQName().getLocalPart()+ "_value";
   				QName typeName = new QName(type.getQName().getNamespaceURI(),localpart);
  @@ -598,7 +599,7 @@
   			}
   			// There can be attributes in this extended basic type
   			// Process the attributes
  -			Vector attributes = SchemaUtils.getContainedAttributeTypes(
  +			Vector attributes = CSchemaUtils.getContainedAttributeTypes(
   				type.getNode(), symbolTable);
   			if (attributes != null) {
   				for (int j=0; j<attributes.size(); j+=2) {
  @@ -614,13 +615,13 @@
   		}else{
   			//is this a SOAPEnc array type	
   			QName arrayType =
  -				SchemaUtils.getArrayComponentQName(node, new IntHolder(0),symbolTable);
  +				CSchemaUtils.getArrayComponentQName(node, new IntHolder(0),symbolTable);
   			if (arrayType != null) {
   				typedata.setTypeNameForElementName(new ElementInfo(new QName("item"),
   						createTypeInfo(arrayType,targetLanguage)));
   				typedata.setArray(true);
   			} else if (
  -				(arrayType = SchemaUtils.getCollectionComponentQName(node))
  +				(arrayType = CSchemaUtils.getCollectionComponentQName(node))
   					!= null) {
   				typedata.setTypeNameForElementName(new ElementInfo(new QName("item"),
   						createTypeInfo(arrayType,targetLanguage)));
  @@ -631,11 +632,11 @@
   				// get all extended types
   				Vector extendList = new Vector();
   				extendList.add(type);
  -				TypeEntry parent = SchemaUtils.getComplexElementExtensionBase(
  +				TypeEntry parent = CSchemaUtils.getComplexElementExtensionBase(
   														type.getNode(),symbolTable);
   				while(parent != null) {
   					extendList.add(parent);
  -					parent = SchemaUtils.getComplexElementExtensionBase(
  +					parent = CSchemaUtils.getComplexElementExtensionBase(
   												parent.getNode(),symbolTable);
   				}
   		
  @@ -658,7 +659,7 @@
   					//}
   					
   					// Process the attributes
  -					Vector attributes = SchemaUtils.getContainedAttributeTypes(
  +					Vector attributes = CSchemaUtils.getContainedAttributeTypes(
   						te.getNode(), symbolTable);
   					if (attributes != null) {
   						for (int j=0; j<attributes.size(); j+=2) {
  @@ -668,12 +669,12 @@
   						}
   					}
   					// Process the elements
  -					Vector elements = SchemaUtils.getContainedElementDeclarations(
  +					Vector elements = CSchemaUtils.getContainedElementDeclarations(
   											te.getNode(), symbolTable);
   					if (elements != null) {
   						for (int j=0; j<elements.size(); j++) {
   							ElementInfo eleinfo = null;
  -							ElementDecl elem = (ElementDecl)elements.get(j);
  +							CElementDecl elem = (CElementDecl)elements.get(j);
   							if (elem.getAnyElement()){
   							
   								Type anyType = new Type(CUtils.anyTypeQname, CUtils.anyTypeQname.getLocalPart(), true, targetLanguage);
  @@ -695,7 +696,7 @@
   									eleinfo = new ElementInfo(elem.getName(),createTypeInfo(typeName,targetLanguage));								
   								}
   							}
  -							eleinfo.setMinOccurs(elem.getMinOccrs());
  +							eleinfo.setMinOccurs(elem.getMinOccurs());
   							eleinfo.setMaxOccurs(elem.getMaxOccurs());
   							typedata.setTypeNameForElementName(eleinfo);
   						}			
  @@ -816,7 +817,7 @@
   		catch(NoSuchMethodError noSuchMethodError)
               {
               	// catch the no such method error that occurs when they have put this class after axis java 1.2
  -            	if(noSuchMethodError.getMessage().indexOf("org.apache.axis.wsdl.symbolTable.ElementDecl.getMinOccrs")>-1)
  +            	if(noSuchMethodError.getMessage().indexOf("org.apache.axis.wsdl.symbolTable.CElementDecl.getMinOccrs")>-1)
               	{
               		System.out.println("We have caught the following error - "+noSuchMethodError);
   					System.out.println("");
  
  
  
  1.1                  ws-axis/c/src/wsdl/org/apache/axis/wsdl/symbolTable/CElementDecl.java
  
  Index: CElementDecl.java
  ===================================================================
  /*
   *   Copyright 2003-2004 The Apache Software Foundation.
   *
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   *
   *       http://www.apache.org/licenses/LICENSE-2.0
   *
   *   Unless required by applicable law or agreed to in writing, software
   *   distributed under the License is distributed on an "AS IS" BASIS,
   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *   See the License for the specific language governing permissions and
   *   limitations under the License.
   */
  
  package org.apache.axis.wsdl.symbolTable;
  
  import javax.xml.namespace.QName;
  
  /**
   * Simple utility struct for holding element declarations.
   * 
   * This simply correlates a QName to a TypeEntry.
   * 
   * @author Glen Daniels (gdaniels@apache.org)
   * @author Tom Jordahl (tomj@apache.org)
   */
  public class CElementDecl extends ElementDecl
  {
      private QName name;
      private TypeEntry type;
  
      private int minOccurs = 1;
      private int maxOccurs = 1;
      private boolean nillable = false;
  
      // The following property is set if minOccurs=0.
      // An item that is not set and has minOccurs=0 
      // should not be passed over the wire.  This
      // is slightly different than nillable=true which
      // causes nil=true to be passed over the wire.
      private boolean minOccursIs0 = false;
  
      // Indicate if the CElementDecl represents
      // an xsd:any element
      private boolean anyElement = false;
  
      /** Field documentation */
      private String documentation;
  
      public CElementDecl()
      {}
  
      public CElementDecl(TypeEntry type, QName name)
      {
          this.type = type;
          this.name = name;
      }
  
      public TypeEntry getType()
      {
          return type;
      }
  
      public void setType(TypeEntry type)
      {
          this.type = type;
      }
  
      public QName getName()
      {
          return name;
      }
  
      public void setName(QName name)
      {
          this.name = name;
      }
  
      public boolean getMinOccursIs0()
      {
          return minOccursIs0;
      }
  
      public void setMinOccursIs0(boolean minOccursIs0)
      {
          this.minOccursIs0 = minOccursIs0;
      }
  
      public boolean getAnyElement()
      {
          return anyElement;
      }
  
      public void setAnyElement(boolean anyElement)
      {
          this.anyElement = anyElement;
      }
      /**
       * @return
       */
      public int getMaxOccurs()
      {
          return maxOccurs;
      }
  
      /**
       * @return
       */
      public int getMinOccurs()
      {
          return minOccurs;
      }
  
      /**
       * @return
       */
      public boolean isNillable()
      {
          return nillable;
      }
  
      /**
       * @param i
       */
      public void setMaxOccurs(int i)
      {
          maxOccurs = i;
      }
  
      /**
       * @param i
       */
      public void setMinOccurs(int i)
      {
          minOccurs = i;
      }
  
      /**
       * @param b
       */
      public void setNillable(boolean b)
      {
          nillable = b;
      }
  
      /**
       *       Method getDocumentation
       *       @return string       
       */
  
      public String getDocumentation()
      {
          return documentation;
      }
  
      /**
       *       Method setDocumentation
       *       @param documentation
       */
  
      public void setDocumentation(String documentation)
      {
          this.documentation = documentation;
      }
  
  }
  
  
  
  1.1                  ws-axis/c/src/wsdl/org/apache/axis/wsdl/symbolTable/CSchemaUtils.java
  
  Index: CSchemaUtils.java
  ===================================================================
  /*
   * Copyright 2001-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.axis.wsdl.symbolTable;
  
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.Set;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  import javax.xml.namespace.QName;
  import javax.xml.rpc.holders.BooleanHolder;
  import javax.xml.rpc.holders.IntHolder;
  
  import org.apache.axis.Constants;
  import org.apache.axis.wsdl.wsdl2ws.info.ElementInfo;
  import org.w3c.dom.DOMException;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  /**
   * This class contains static utility methods specifically for schema type queries.
   * 
   * @author Rich Scheuerle  (scheu@us.ibm.com)
   */
  public class CSchemaUtils extends SchemaUtils
  {
  
      /** Field VALUE_QNAME */
      static final QName VALUE_QNAME = Utils.findQName("", "value");
  
      /**
       * This method checks mixed=true attribute is set either on
       * complexType or complexContent element.
       */
      public static boolean isMixed(Node node)
      {
          // Expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
              String mixed = ((Element) node).getAttribute("mixed");
              if (mixed != null && mixed.length() > 0)
              {
                  return ("true".equalsIgnoreCase(mixed) || "1".equals(mixed));
              }
              // Under the complexType there could be complexContent with
              // mixed="true"
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
                  if (isXSDNode(kid, "complexContent"))
                  {
                      mixed = ((Element) kid).getAttribute("mixed");
                      return (
                          "true".equalsIgnoreCase(mixed) || "1".equals(mixed));
                  }
              }
          }
          return false;
      }
  
      /**
       * This method checks out if the given node satisfies the 3rd condition
       * of the "wrapper" style:
       * such an element (a wrapper) must be of a complex type defined using the
       * xsd:sequence compositor and containing only elements declarations.
       * (excerpt from JAX-RPC spec 1.1 Maintenanace Review 2 Chapter 6 Section 4.1.)
       * 
       * @param node        
       * @return 
       */
      public static boolean isWrappedType(Node node)
      {
  
          if (node == null)
          {
              return false;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
              boolean hasComplexType = false;
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
                  if (isXSDNode(kid, "complexType"))
                  {
                      node = kid;
                      hasComplexType = true;
                      break;
                  }
              }
              if (!hasComplexType)
              {
                  return false;
              }
          }
  
          // Expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
              // Under the complexType there could be complexContent/simpleContent
              // and extension elements if this is a derived type.
              // A wrapper element must be complex-typed.
  
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent"))
                  {
                      return false;
                  }
                  else
                      if (isXSDNode(kid, "simpleContent"))
                      {
                          return false;
                      }
              }
  
              // Under the complexType there may be choice, sequence, group and/or all nodes.
              // (There may be other #text nodes, which we will ignore).
              // The complex type of a wrapper element must have only sequence 
              // and again element declarations in the sequence. 
              children = node.getChildNodes();
              for (int j = 0; j < children.getLength(); j++)
              {
                  QName subNodeKind = Utils.getNodeQName(children.item(j));
                  if ((subNodeKind != null)
                      && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
                  {
                      if (subNodeKind.getLocalPart().equals("sequence"))
                      {
                          Node sequenceNode = children.item(j);
                          NodeList sequenceChildren =
                              sequenceNode.getChildNodes();
                          for (int k = 0; k < sequenceChildren.getLength(); k++)
                          {
                              QName sequenceSubNodeKind =
                                  Utils.getNodeQName(sequenceChildren.item(k));
                              if ((sequenceSubNodeKind != null)
                                  && Constants.isSchemaXSD(
                                      sequenceSubNodeKind.getNamespaceURI()))
                              {
                                  if (!sequenceSubNodeKind
                                      .getLocalPart()
                                      .equals("element"))
                                  {
                                      return false;
                                  }
                              }
                          }
                          return true;
                      }
                      else
                      {
                          return false;
                      }
                  }
              }
          }
          // allows void type
          return true;
      }
  
      /**
       * If the specified node represents a supported JAX-RPC complexType or
       * simpleType, a Vector is returned which contains ElementDecls for the
       * child element names.
       * If the element is a simpleType, an ElementDecls is built representing
       * the restricted type with the special name "value".
       * If the element is a complexType which has simpleContent, an CElementDecl
       * is built representing the extended type with the special name "value".
       * This method does not return attribute names and types
       * (use the getContainedAttributeTypes)
       * If the specified node is not a supported
       * JAX-RPC complexType/simpleType/element null is returned.
       * 
       * @param node        
       * @param symbolTable 
       * @return 
       */
      public static Vector getContainedElementDeclarations(
          Node node,
          SymbolTable symbolTable)
      {
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType"))
                  {
                      node = kid;
  
                      break;
                  }
              }
          }
  
          // Expecting a schema complexType or simpleType
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be complexContent/simpleContent
              // and extension elements if this is a derived type.  Skip over these.
              NodeList children = node.getChildNodes();
              Node complexContent = null;
              Node simpleContent = null;
              Node extension = null;
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent"))
                  {
                      complexContent = kid;
  
                      break; // REMIND: should this be here or on either branch?
                  }
                  else
                      if (isXSDNode(kid, "simpleContent"))
                      {
                          simpleContent = kid;
                      }
              }
  
              if (complexContent != null)
              {
                  children = complexContent.getChildNodes();
  
                  for (int j = 0;
                      (j < children.getLength()) && (extension == null);
                      j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "extension")
                          || isXSDNode(kid, "restriction"))
                      {
                          extension = kid;
                      }
                  }
              }
  
              if (simpleContent != null)
              {
                  children = simpleContent.getChildNodes();
  
                  for (int j = 0;
                      (j < children.getLength()) && (extension == null);
                      j++)
                  {
                      QName extensionOrRestrictionKind =
                          Utils.getNodeQName(children.item(j));
  
                      if ((extensionOrRestrictionKind != null)
                          && (extensionOrRestrictionKind
                              .getLocalPart()
                              .equals("extension")
                              || extensionOrRestrictionKind.getLocalPart().equals(
                                  "restriction"))
                          && Constants.isSchemaXSD(
                              extensionOrRestrictionKind.getNamespaceURI()))
                      {
  
                          // get the type of the extension/restriction from the "base" attribute
                          QName extendsOrRestrictsType =
                              Utils.getTypeQName(
                                  children.item(j),
                                  new BooleanHolder(),
                                  false);
  
                          // Return an element declaration with a fixed name
                          // ("value") and the correct type.
                          Vector v = new Vector();
                          CElementDecl elem = new CElementDecl();
  
                          elem.setType(
                              symbolTable.getTypeEntry(
                                  extendsOrRestrictsType,
                                  false));
                          elem.setName(VALUE_QNAME);
                          v.add(elem);
  
                          return v;
                      }
                  }
              }
  
              if (extension != null)
              {
                  node = extension; // Skip over complexContent and extension
              }
  
              // Under the complexType there may be choice, sequence, group and/or all nodes.
              // (There may be other #text nodes, which we will ignore).
              children = node.getChildNodes();
  
              Vector v = new Vector();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  QName subNodeKind = Utils.getNodeQName(children.item(j));
  
                  if ((subNodeKind != null)
                      && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
                  {
                      if (subNodeKind.getLocalPart().equals("sequence"))
                      {
                          v.addAll(
                              processSequenceNode(children.item(j), symbolTable));
                      }
                      else
                          if (subNodeKind.getLocalPart().equals("all"))
                          {
                              v.addAll(
                                  processAllNode(children.item(j), symbolTable));
                          }
                          else
                              if (subNodeKind.getLocalPart().equals("choice"))
                              {
                                  v.addAll(
                                      processChoiceNode(
                                          children.item(j),
                                          symbolTable));
                              }
                              else
                                  if (subNodeKind.getLocalPart().equals("group"))
                                  {
                                      v.addAll(
                                          processGroupNode(
                                              children.item(j),
                                              symbolTable));
                                  }
                  }
              }
  
              return v;
          }
          else
              if (isXSDNode(node, "group"))
              {
                  NodeList children = node.getChildNodes();
                  Vector v = new Vector();
                  for (int j = 0; j < children.getLength(); j++)
                  {
                      QName subNodeKind = Utils.getNodeQName(children.item(j));
                      if ((subNodeKind != null)
                          && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
                      {
                          if (subNodeKind.getLocalPart().equals("sequence"))
                          {
                              v.addAll(
                                  processSequenceNode(
                                      children.item(j),
                                      symbolTable));
                          }
                          else
                              if (subNodeKind.getLocalPart().equals("all"))
                              {
                                  v.addAll(
                                      processAllNode(
                                          children.item(j),
                                          symbolTable));
                              }
                              else
                                  if (subNodeKind
                                      .getLocalPart()
                                      .equals("choice"))
                                  {
                                      v.addAll(
                                          processChoiceNode(
                                              children.item(j),
                                              symbolTable));
                                  }
                      }
                  }
                  return v;
              }
              else
              {
  
                  // This may be a simpleType, return the type with the name "value"
                  QName[] simpleQName = getContainedSimpleTypes(node);
  
                  if (simpleQName != null)
                  {
                      Vector v = null;
  
                      for (int i = 0; i < simpleQName.length; i++)
                      {
                          TypeEntry simpleType =
                              symbolTable.getType(simpleQName[i]);
  
                          if (simpleType != null)
                          {
                              if (v == null)
                              {
                                  v = new Vector();
                              }
  
                              CElementDecl elem = new CElementDecl();
  
                              elem.setType(simpleType);
  
                              if (simpleQName.length > 1)
                              {
                                  elem.setName(
                                      new javax.xml.namespace.QName(
                                          "",
                                          simpleQName[i].getLocalPart()
                                              + "Value"));
                              }
                              else
                              {
                                  elem.setName(
                                      new javax.xml.namespace.QName("", "value"));
                              }
  
                              v.add(elem);
                          }
                      }
  
                      return v;
                  }
              }
  
          return null;
      }
  
      /**
       * Invoked by getContainedElementDeclarations to get the child element types
       * and child element names underneath a Choice Node
       * 
       * @param choiceNode  
       * @param symbolTable 
       * @return 
       */
      private static Vector processChoiceNode(
          Node choiceNode,
          SymbolTable symbolTable)
      {
  
          Vector v = new Vector();
          NodeList children = choiceNode.getChildNodes();
  
          for (int j = 0; j < children.getLength(); j++)
          {
              QName subNodeKind = Utils.getNodeQName(children.item(j));
  
              if ((subNodeKind != null)
                  && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
              {
                  if (subNodeKind.getLocalPart().equals("choice"))
                  {
                      v.addAll(processChoiceNode(children.item(j), symbolTable));
                  }
                  else
                      if (subNodeKind.getLocalPart().equals("sequence"))
                      {
                          v.addAll(
                              processSequenceNode(children.item(j), symbolTable));
                      }
                      else
                          if (subNodeKind.getLocalPart().equals("group"))
                          {
                              v.addAll(
                                  processGroupNode(
                                      children.item(j),
                                      symbolTable));
                          }
                          else
                              if (subNodeKind.getLocalPart().equals("element"))
                              {
                                  CElementDecl elem =
                                      processChildElementNode(
                                          children.item(j),
                                          symbolTable);
  
                                  if (elem != null)
                                  {
                                      v.add(elem);
                                  }
                              }
              }
          }
  
          return v;
      }
  
      /**
       * Returns named child node.
       * 
       * @param parentNode Parent node.
       * @param name Element name of child node to return.
       */
      private static Node getChildByName(Node parentNode, String name)
          throws DOMException
      {
          if (parentNode == null)
              return null;
          NodeList children = parentNode.getChildNodes();
          if (children != null)
          {
              for (int i = 0; i < children.getLength(); i++)
              {
                  Node child = children.item(i);
                  if (child != null)
                  {
                      if (child.getNodeName() != null
                          && name.equals(child.getNodeName()))
                      {
                          return child;
                      }
                  }
              }
          }
          return null;
      }
  
      /**
       * Returns all textual nodes of a subnode defined by a parent node
       * and a path of element names to that subnode.
       * 
       * @param root Parent node.
       * @param path Path of element names to text of interest, delimited by "/". 
       */
      public static String getTextByPath(Node root, String path)
          throws DOMException
      {
          StringTokenizer st = new StringTokenizer(path, "/");
          Node node = root;
          while (st.hasMoreTokens())
          {
              String elementName = st.nextToken();
              Node child = getChildByName(node, elementName);
              if (child == null)
                  throw new DOMException(
                      DOMException.NOT_FOUND_ERR,
                      "could not find " + elementName);
              node = child;
          }
  
          // should have found the node
          String text = "";
          NodeList children = node.getChildNodes();
          if (children != null)
          {
              for (int i = 0; i < children.getLength(); i++)
              {
                  Node child = children.item(i);
                  if (child != null)
                  {
                      if (child.getNodeName() != null
                          && (child.getNodeName().equals("#text")
                              || child.getNodeName().equals("#cdata-section")))
                      {
                          text += child.getNodeValue();
                      }
                  }
              }
          }
          return text;
      }
  
      /**
       * Returns the complete text of the child xsd:annotation/xsd:documentation 
       * element from the provided node.  Only the first annotation element and 
       * the first documentation element in the annotation element will be used.
       * 
       * @param root Parent node.
       * @param path Path of element names to text of interest, delimited by "/". 
       */
      public static String getAnnotationDocumentation(Node typeNode)
      {
          Node annotationNode = typeNode.getFirstChild();
          while (annotationNode != null)
          {
              if (isXSDNode(annotationNode, "annotation"))
              {
                  break;
              }
              annotationNode = annotationNode.getNextSibling();
          }
          Node documentationNode;
          if (annotationNode != null)
          {
              documentationNode = annotationNode.getFirstChild();
              while (documentationNode != null)
              {
                  if (isXSDNode(documentationNode, "documentation"))
                  {
                      break;
                  }
                  documentationNode = documentationNode.getNextSibling();
              }
          }
          else
          {
              documentationNode = null;
          }
  
          // should have found the node if it exists
          String text = "";
          if (documentationNode != null)
          {
              NodeList children = documentationNode.getChildNodes();
              if (children != null)
              {
                  for (int i = 0; i < children.getLength(); i++)
                  {
                      Node child = children.item(i);
                      if (child != null)
                      {
                          if (child.getNodeName() != null
                              && (child.getNodeName().equals("#text")
                                  || child.getNodeName().equals("#cdata-section")))
                          {
                              text += child.getNodeValue();
                          }
                      }
                  }
              }
          }
          return text;
      }
  
      /**
       * Invoked by getContainedElementDeclarations to get the child element types
       * and child element names underneath a Sequence Node
       * 
       * @param sequenceNode 
       * @param symbolTable  
       * @return 
       */
      private static Vector processSequenceNode(
          Node sequenceNode,
          SymbolTable symbolTable)
      {
  
          Vector v = new Vector();
          NodeList children = sequenceNode.getChildNodes();
  
          for (int j = 0; j < children.getLength(); j++)
          {
              QName subNodeKind = Utils.getNodeQName(children.item(j));
  
              if ((subNodeKind != null)
                  && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
              {
                  if (subNodeKind.getLocalPart().equals("choice"))
                  {
                      v.addAll(processChoiceNode(children.item(j), symbolTable));
                  }
                  else
                      if (subNodeKind.getLocalPart().equals("sequence"))
                      {
                          v.addAll(
                              processSequenceNode(children.item(j), symbolTable));
                      }
                      else
                          if (subNodeKind.getLocalPart().equals("group"))
                          {
                              v.addAll(
                                  processGroupNode(
                                      children.item(j),
                                      symbolTable));
                          }
                          else
                              if (subNodeKind.getLocalPart().equals("any"))
                              {
  
                                  // Represent this as an element named any of type any type.
                                  // This will cause it to be serialized with the element
                                  // serializer.
                                  TypeEntry type =
                                      symbolTable.getType(Constants.XSD_ANY);
                                  CElementDecl elem =
                                      new CElementDecl(
                                          type,
                                          Utils.findQName("", "any"));
  
                                  elem.setAnyElement(true);
                                  v.add(elem);
                              }
                              else
                                  if (subNodeKind
                                      .getLocalPart()
                                      .equals("element"))
                                  {
                                      CElementDecl elem =
                                          processChildElementNode(
                                              children.item(j),
                                              symbolTable);
  
                                      if (elem != null)
                                      {
                                          v.add(elem);
                                      }
                                  }
              }
          }
  
          return v;
      }
  
      /**
       * Invoked by getContainedElementDeclarations to get the child element types
       * and child element names underneath a group node. If a ref attribute is 
       * specified, only the referenced group element is returned.
       * 
       * @param groupNode   
       * @param symbolTable 
       * @return 
       */
      private static Vector processGroupNode(
          Node groupNode,
          SymbolTable symbolTable)
      {
  
          Vector v = new Vector();
          if (groupNode.getAttributes().getNamedItem("ref") == null)
          {
              NodeList children = groupNode.getChildNodes();
              for (int j = 0; j < children.getLength(); j++)
              {
                  QName subNodeKind = Utils.getNodeQName(children.item(j));
  
                  if ((subNodeKind != null)
                      && Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
                  {
                      if (subNodeKind.getLocalPart().equals("choice"))
                      {
                          v.addAll(
                              processChoiceNode(children.item(j), symbolTable));
                      }
                      else
                          if (subNodeKind.getLocalPart().equals("sequence"))
                          {
                              v.addAll(
                                  processSequenceNode(
                                      children.item(j),
                                      symbolTable));
                          }
                          else
                              if (subNodeKind.getLocalPart().equals("all"))
                              {
                                  v.addAll(
                                      processAllNode(
                                          children.item(j),
                                          symbolTable));
                              }
                  }
              }
          }
          else
          {
              BooleanHolder forElement = new BooleanHolder();
              QName nodeName = Utils.getTypeQName(groupNode, forElement, false);
              TypeEntry type =
                  symbolTable.getTypeEntry(nodeName, forElement.value);
  
              if (type != null)
              {
                  v.add(new CElementDecl(type, nodeName));
              }
          }
          return v;
      }
  
      /**
       * Invoked by getContainedElementDeclarations to get the child element types
       * and child element names underneath an all node.
       * 
       * @param allNode     
       * @param symbolTable 
       * @return 
       */
      private static Vector processAllNode(Node allNode, SymbolTable symbolTable)
      {
  
          Vector v = new Vector();
          NodeList children = allNode.getChildNodes();
  
          for (int j = 0; j < children.getLength(); j++)
          {
              Node kid = children.item(j);
  
              if (isXSDNode(kid, "element"))
              {
                  CElementDecl elem = processChildElementNode(kid, symbolTable);
  
                  if (elem != null)
                  {
                      v.add(elem);
                  }
              }
          }
  
          return v;
      }
  
      /**
       * Invoked by getContainedElementDeclarations to get the child element type
       * and child element name for a child element node.
       * <p/>
       * If the specified node represents a supported JAX-RPC child element,
       * we return an CElementDecl containing the child element name and type.
       * 
       * @param elementNode 
       * @param symbolTable 
       * @return 
       */
      private static CElementDecl processChildElementNode(
          Node elementNode,
          SymbolTable symbolTable)
      {
  
          // Get the name qnames.
          QName nodeName = Utils.getNodeNameQName(elementNode);
          BooleanHolder forElement = new BooleanHolder();
          String comments = null;
          comments = getAnnotationDocumentation(elementNode);
  
          // The type qname is used to locate the TypeEntry, which is then
          // used to retrieve the proper java name of the type.
          QName nodeType = Utils.getTypeQName(elementNode, forElement, false);
          TypeEntry type = symbolTable.getTypeEntry(nodeType, forElement.value);
  
          // An element inside a complex type is either qualified or unqualified.
          // If the ref= attribute is used, the name of the ref'd element is used
          // (which must be a root element).  If the ref= attribute is not
          // used, the name of the element is unqualified.
          if (!forElement.value)
          {
  
              // check the Form (or elementFormDefault) attribute of this node to
              // determine if it should be namespace quailfied or not.
              String form = Utils.getAttribute(elementNode, "form");
  
              if ((form != null) && form.equals("unqualified"))
              {
  
                  // Unqualified nodeName
                  nodeName = Utils.findQName("", nodeName.getLocalPart());
              }
              else
                  if (form == null)
                  {
  
                      // check elementForDefault on schema element
                      String def =
                          Utils.getScopedAttribute(
                              elementNode,
                              "elementFormDefault");
  
                      if ((def == null) || def.equals("unqualified"))
                      {
  
                          // Unqualified nodeName
                          nodeName = Utils.findQName("", nodeName.getLocalPart());
                      }
                  }
          }
  
          if (type != null)
          {
              CElementDecl elem = new CElementDecl(type, nodeName);
              elem.setDocumentation(comments);
              String minOccurs = Utils.getAttribute(elementNode, "minOccurs");
  
              if ((minOccurs != null) && minOccurs.equals("0"))
              {
                  elem.setMinOccursIs0(true);
              }
              if (minOccurs == null)
              {}
              else
                  if ("unbounded".equals(minOccurs))
                      elem.setMinOccurs(ElementInfo.UNBOUNDED);
                  else
                  {
                      elem.setMinOccurs(Integer.parseInt(minOccurs));
                  }
  
              String maxOccurs = Utils.getAttribute(elementNode, "maxOccurs");
  
              if (maxOccurs == null)
              {}
              else
                  if ("unbounded".equals(maxOccurs))
                      elem.setMaxOccurs(ElementInfo.UNBOUNDED);
                  else
                      elem.setMaxOccurs(Integer.parseInt(maxOccurs));
              String nillable = Utils.getAttribute(elementNode, "nilable");
              if (nillable != null && "true".equals(nillable))
                  elem.setNillable(true);
  
              return elem;
  
              /*elem.setNillable(
              		JavaUtils.isTrueExplicitly(
              				Utils.getAttribute(elementNode, "nillable")));
              
              return elem;
              */
  
          }
  
          return null;
      }
  
      /**
       * Returns the WSDL2Java QName for the anonymous type of the element
       * or null.
       * 
       * @param node 
       * @return 
       */
      public static QName getElementAnonQName(Node node)
      {
  
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType")
                      || isXSDNode(kid, "simpleType"))
                  {
                      return Utils.getNodeNameQName(kid);
                  }
              }
          }
  
          return null;
      }
  
      /**
       * Returns the WSDL2Java QName for the anonymous type of the attribute
       * or null.
       * 
       * @param node 
       * @return 
       */
      public static QName getAttributeAnonQName(Node node)
      {
  
          if (isXSDNode(node, "attribute"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType")
                      || isXSDNode(kid, "simpleType"))
                  {
                      return Utils.getNodeNameQName(kid);
                  }
              }
          }
  
          return null;
      }
  
      /**
       * If the specified node is a simple type or contains simpleContent, return true
       * 
       * @param node 
       * @return 
       */
      public static boolean isSimpleTypeOrSimpleContent(Node node)
      {
  
          if (node == null)
          {
              return false;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType"))
                  {
                      node = kid;
  
                      break;
                  }
                  else
                      if (isXSDNode(kid, "simpleType"))
                      {
                          return true;
                      }
              }
          }
  
          // Expecting a schema complexType or simpleType
          if (isXSDNode(node, "simpleType"))
          {
              return true;
          }
  
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be complexContent/simpleContent
              // and extension elements if this is a derived type.  Skip over these.
              NodeList children = node.getChildNodes();
              Node complexContent = null;
              Node simpleContent = null;
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent"))
                  {
                      complexContent = kid;
  
                      break;
                  }
                  else
                      if (isXSDNode(kid, "simpleContent"))
                      {
                          simpleContent = kid;
                      }
              }
  
              if (complexContent != null)
              {
                  return false;
              }
  
              if (simpleContent != null)
              {
                  return true;
              }
          }
  
          return false;
      }
  
      /**
       * Test whether <tt>node</tt> is not null, belongs to the XML
       * Schema namespace, and has a localName that matches
       * <tt>schemaLocalName</tt>
       * <p/>
       * This can be used to determine that a given Node defines a
       * schema "complexType" "element" and so forth.
       * 
       * @param node            a <code>Node</code> value
       * @param schemaLocalName a <code>String</code> value
       * @return true if the node is matches the name in the schema namespace.
       */
      private static boolean isXSDNode(Node node, String schemaLocalName)
      {
  
          if ((node != null) && Constants.isSchemaXSD(node.getNamespaceURI()))
          {
              String localName = node.getLocalName();
  
              return ((localName != null) && localName.equals(schemaLocalName));
          }
  
          return false;
      }
  
      /**
       * Look for the base type of node iff node is a complex type that has been
       * derived by restriction; otherwise return null.
       * 
       * @param node        
       * @param symbolTable 
       * @return 
       */
      public static TypeEntry getComplexElementRestrictionBase(
          Node node,
          SymbolTable symbolTable)
      {
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
              Node complexNode = null;
  
              for (int j = 0;
                  (j < children.getLength()) && (complexNode == null);
                  j++)
              {
                  if (isXSDNode(children.item(j), "complexType"))
                  {
                      complexNode = children.item(j);
                      node = complexNode;
                  }
              }
          }
  
          // Expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be should be a complexContent &
              // restriction elements if this is a derived type.
              NodeList children = node.getChildNodes();
              Node content = null;
              Node restriction = null;
  
              for (int j = 0;
                  (j < children.getLength()) && (content == null);
                  j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent"))
                  {
                      content = kid;
                  }
              }
  
              if (content != null)
              {
                  children = content.getChildNodes();
  
                  for (int j = 0;
                      (j < children.getLength()) && (restriction == null);
                      j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "restriction"))
                      {
                          restriction = kid;
                      }
                  }
              }
  
              if (restriction == null)
              {
                  return null;
              }
              else
              {
  
                  // Get the QName of the extension base
                  QName restrictionType =
                      Utils.getTypeQName(restriction, new BooleanHolder(), false);
  
                  if (restrictionType == null)
                  {
                      return null;
                  }
                  else
                  {
  
                      // Return associated Type
                      return symbolTable.getType(restrictionType);
                  }
              }
          }
          else
          {
              return null;
          }
      }
  
      /**
       * If the specified node represents a supported JAX-RPC complexType/element
       * which extends another complexType.  The Type of the base is returned.
       * 
       * @param node        
       * @param symbolTable 
       * @return 
       */
      public static TypeEntry getComplexElementExtensionBase(
          Node node,
          SymbolTable symbolTable)
      {
  
          if (node == null)
          {
              return null;
          }
  
          TypeEntry cached = (TypeEntry) symbolTable.node2ExtensionBase.get(node);
  
          if (cached != null)
          {
              return cached; // cache hit
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
              Node complexNode = null;
  
              for (int j = 0;
                  (j < children.getLength()) && (complexNode == null);
                  j++)
              {
                  if (isXSDNode(children.item(j), "complexType"))
                  {
                      complexNode = children.item(j);
                      node = complexNode;
                  }
              }
          }
  
          // Expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be should be a complexContent &
              // extension elements if this is a derived type.
              NodeList children = node.getChildNodes();
              Node content = null;
              Node extension = null;
  
              for (int j = 0;
                  (j < children.getLength()) && (content == null);
                  j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent")
                      || isXSDNode(kid, "simpleContent"))
                  {
                      content = kid;
                  }
              }
  
              if (content != null)
              {
                  children = content.getChildNodes();
  
                  for (int j = 0;
                      (j < children.getLength()) && (extension == null);
                      j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "extension"))
                      {
                          extension = kid;
                      }
                  }
              }
  
              if (extension == null)
              {
                  cached = null;
              }
              else
              {
  
                  // Get the QName of the extension base
                  QName extendsType =
                      Utils.getTypeQName(extension, new BooleanHolder(), false);
  
                  if (extendsType == null)
                  {
                      cached = null;
                  }
                  else
                  {
  
                      // Return associated Type
                      cached = symbolTable.getType(extendsType);
                  }
              }
          }
  
          symbolTable.node2ExtensionBase.put(node, cached);
  
          return cached;
      }
  
      /**
       * If the specified node represents a 'normal' non-enumeration simpleType,
       * the QName of the simpleType base is returned.
       * 
       * @param node 
       * @return 
       */
      public static QName getSimpleTypeBase(Node node)
      {
  
          QName[] qname = getContainedSimpleTypes(node);
  
          if ((qname != null) && (qname.length > 0))
          {
              return qname[0];
          }
  
          return null;
      }
  
      /**
       * Method getContainedSimpleTypes
       * 
       * @param node 
       * @return 
       */
      public static QName[] getContainedSimpleTypes(Node node)
      {
  
          QName[] baseQNames = null;
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  if (isXSDNode(children.item(j), "simpleType"))
                  {
                      node = children.item(j);
  
                      break;
                  }
              }
          }
  
          // Get the node kind, expecting a schema simpleType
          if (isXSDNode(node, "simpleType"))
          {
  
              // Under the simpleType there should be a restriction.
              // (There may be other #text nodes, which we will ignore).
              NodeList children = node.getChildNodes();
              Node restrictionNode = null;
              Node unionNode = null;
  
              for (int j = 0;
                  (j < children.getLength()) && (restrictionNode == null);
                  j++)
              {
                  if (isXSDNode(children.item(j), "restriction"))
                  {
                      restrictionNode = children.item(j);
                  }
                  else
                      if (isXSDNode(children.item(j), "union"))
                      {
                          unionNode = children.item(j);
                      }
              }
  
              // The restriction node indicates the type being restricted
              // (the base attribute contains this type).
              if (restrictionNode != null)
              {
                  baseQNames = new QName[1];
                  baseQNames[0] =
                      Utils.getTypeQName(
                          restrictionNode,
                          new BooleanHolder(),
                          false);
              }
  
              if (unionNode != null)
              {
                  baseQNames = Utils.getMemberTypeQNames(unionNode);
              }
  
              // Look for enumeration elements underneath the restriction node
              if ((baseQNames != null)
                  && (restrictionNode != null)
                  && (unionNode != null))
              {
                  NodeList enums = restrictionNode.getChildNodes();
  
                  for (int i = 0; i < enums.getLength(); i++)
                  {
                      if (isXSDNode(enums.item(i), "enumeration"))
                      {
  
                          // Found an enumeration, this isn't a
                          // 'normal' simple type.
                          return null;
                      }
                  }
              }
          }
  
          return baseQNames;
      }
  
      /**
       * Returns the contained restriction or extension node underneath
       * the specified node.  Returns null if not found
       * 
       * @param node 
       * @return 
       */
      public static Node getRestrictionOrExtensionNode(Node node)
      {
  
          Node re = null;
  
          if (node == null)
          {
              return re;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node n = children.item(j);
  
                  if (isXSDNode(n, "simpleType")
                      || isXSDNode(n, "complexType")
                      || isXSDNode(n, "simpleContent"))
                  {
                      node = n;
  
                      break;
                  }
              }
          }
  
          // Get the node kind, expecting a schema simpleType
          if (isXSDNode(node, "simpleType") || isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be a complexContent.
              NodeList children = node.getChildNodes();
              Node complexContent = null;
  
              if (node.getLocalName().equals("complexType"))
              {
                  for (int j = 0;
                      (j < children.getLength()) && (complexContent == null);
                      j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "complexContent")
                          || isXSDNode(kid, "simpleContent"))
                      {
                          complexContent = kid;
                      }
                  }
  
                  node = complexContent;
              }
  
              // Now get the extension or restriction node
              if (node != null)
              {
                  children = node.getChildNodes();
  
                  for (int j = 0;(j < children.getLength()) && (re == null); j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "extension")
                          || isXSDNode(kid, "restriction"))
                      {
                          re = kid;
                      }
                  }
              }
          }
  
          return re;
      }
  
      /**
       * If the specified node represents an array encoding of one of the following
       * forms, then return the qname repesenting the element type of the array.
       * 
       * @param node is the node
       * @param dims is the output value that contains the number of dimensions if return is not null
       * @return QName or null
       */
      public static QName getArrayComponentQName(
          Node node,
          IntHolder dims,
          SymbolTable symbolTable)
      {
  
          dims.value = 1; // assume 1 dimension
  
          QName qName = getCollectionComponentQName(node);
  
          if (qName == null)
          {
              qName = getArrayComponentQName_JAXRPC(node, dims, symbolTable);
          }
  
          return qName;
      }
  
      /**
       * If the specified node represents an element that references a collection
       * then return the qname repesenting the component of the collection.
       * <p/>
       * <xsd:element name="alias" type="xsd:string" maxOccurs="unbounded"/>
       * returns qname for"xsd:string"
       * <xsd:element ref="alias"  maxOccurs="unbounded"/>
       * returns qname for "alias"
       * 
       * @param node is the Node
       * @return QName of the compoent of the collection
       */
      public static QName getCollectionComponentQName(Node node)
      {
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive get its type.
          if (isXSDNode(node, "element"))
          {
  
              // Compare the componentQName with the name of the
              // full name.  If different, return componentQName
              BooleanHolder forElement = new BooleanHolder();
              QName componentQName = Utils.getTypeQName(node, forElement, true);
  
              if (componentQName != null)
              {
                  QName fullQName = Utils.getTypeQName(node, forElement, false);
  
                  if (!componentQName.equals(fullQName))
                  {
                      return componentQName;
                  }
              }
          }
  
          return null;
      }
  
      /**
       * If the specified node represents an array encoding of one of the following
       * forms, then return the qname repesenting the element type of the array.
       * 
       * @param node is the node
       * @param dims is the output value that contains the number of dimensions if return is not null
       * @return QName or null
       *         <p/>
       *         JAX-RPC Style 2:
       *         <xsd:complexType name="hobbyArray">
       *         <xsd:complexContent>
       *         <xsd:restriction base="soapenc:Array">
       *         <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
       *         </xsd:restriction>
       *         </xsd:complexContent>
       *         </xsd:complexType>
       *         <p/>
       *         JAX-RPC Style 3:
       *         <xsd:complexType name="petArray">
       *         <xsd:complexContent>
       *         <xsd:restriction base="soapenc:Array">
       *         <xsd:sequence>
       *         <xsd:element name="alias" type="xsd:string" maxOccurs="unbounded"/>
       *         </xsd:sequence>
       *         </xsd:restriction>
       *         </xsd:complexContent>
       *         </xsd:complexType>
       */
      private static QName getArrayComponentQName_JAXRPC(
          Node node,
          IntHolder dims,
          SymbolTable symbolTable)
      {
  
          dims.value = 0; // Assume 0
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType"))
                  {
                      node = kid;
  
                      break;
                  }
              }
          }
  
          // Get the node kind, expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there should be a complexContent.
              // (There may be other #text nodes, which we will ignore).
              NodeList children = node.getChildNodes();
              Node complexContentNode = null;
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent")
                      || isXSDNode(kid, "simpleContent"))
                  {
                      complexContentNode = kid;
  
                      break;
                  }
              }
  
              // Under the complexContent there should be a restriction.
              // (There may be other #text nodes, which we will ignore).
              Node restrictionNode = null;
  
              if (complexContentNode != null)
              {
                  children = complexContentNode.getChildNodes();
  
                  for (int j = 0; j < children.getLength(); j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "restriction"))
                      {
                          restrictionNode = kid;
  
                          break;
                      }
                  }
              }
  
              // The restriction node must have a base of soapenc:Array.
              QName baseType = null;
  
              if (restrictionNode != null)
              {
                  baseType =
                      Utils.getTypeQName(
                          restrictionNode,
                          new BooleanHolder(),
                          false);
  
                  if (baseType != null)
                  {
                      if (!baseType.getLocalPart().equals("Array")
                          || !Constants.isSOAP_ENC(baseType.getNamespaceURI()))
                      {
                          if (!symbolTable.arrayTypeQNames.contains(baseType))
                          {
                              baseType = null; // Did not find base=soapenc:Array
                          }
                      }
                  }
              }
  
              // Under the restriction there should be an attribute OR a sequence/all group node.
              // (There may be other #text nodes, which we will ignore).
              Node groupNode = null;
              Node attributeNode = null;
  
              if (baseType != null)
              {
                  children = restrictionNode.getChildNodes();
  
                  for (int j = 0;
                      (j < children.getLength())
                          && (groupNode == null)
                          && (attributeNode == null);
                      j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "sequence") || isXSDNode(kid, "all"))
                      {
                          groupNode = kid;
  
                          if (groupNode.getChildNodes().getLength() == 0)
                          {
  
                              // This covers the rather odd but legal empty sequence.
                              // <complexType name="ArrayOfString">
                              // <complexContent>
                              // <restriction base="soapenc:Array">
                              // <sequence/>
                              // <attribute ref="soapenc:arrayType" wsdl:arrayType="string[]"/>
                              // </restriction>
                              // </complexContent>
                              // </complexType>
                              groupNode = null;
                          }
                      }
  
                      if (isXSDNode(kid, "attribute"))
                      {
  
                          // If the attribute node does not have ref="soapenc:arrayType"
                          // then keep looking.
                          BooleanHolder isRef = new BooleanHolder();
                          QName refQName = Utils.getTypeQName(kid, isRef, false);
  
                          if ((refQName != null)
                              && isRef.value
                              && refQName.getLocalPart().equals("arrayType")
                              && Constants.isSOAP_ENC(refQName.getNamespaceURI()))
                          {
                              attributeNode = kid;
                          }
                      }
                  }
              }
  
              // If there is an attribute node, look at wsdl:arrayType to get the element type
              if (attributeNode != null)
              {
                  String wsdlArrayTypeValue = null;
                  Vector attrs =
                      Utils.getAttributesWithLocalName(
                          attributeNode,
                          "arrayType");
  
                  for (int i = 0;
                      (i < attrs.size()) && (wsdlArrayTypeValue == null);
                      i++)
                  {
                      Node attrNode = (Node) attrs.elementAt(i);
                      String attrName = attrNode.getNodeName();
                      QName attrQName =
                          Utils.getQNameFromPrefixedName(attributeNode, attrName);
  
                      if (Constants.isWSDL(attrQName.getNamespaceURI()))
                      {
                          wsdlArrayTypeValue = attrNode.getNodeValue();
                      }
                  }
  
                  // The value could have any number of [] or [,] on the end
                  // Strip these off to get the prefixed name.
                  // The convert the prefixed name into a qname.
                  // Count the number of [ and , to get the dim information.
                  if (wsdlArrayTypeValue != null)
                  {
                      int i = wsdlArrayTypeValue.indexOf('[');
  
                      if (i > 0)
                      {
                          String prefixedName =
                              wsdlArrayTypeValue.substring(0, i);
                          String mangledString =
                              wsdlArrayTypeValue.replace(',', '[');
  
                          dims.value = 0;
  
                          int index = mangledString.indexOf('[');
  
                          while (index > 0)
                          {
                              dims.value++;
  
                              index = mangledString.indexOf('[', index + 1);
                          }
  
                          return Utils.getQNameFromPrefixedName(
                              restrictionNode,
                              prefixedName);
                      }
                  }
              }
              else
                  if (groupNode != null)
                  {
  
                      // Get the first element node under the group node.
                      NodeList elements = groupNode.getChildNodes();
                      Node elementNode = null;
  
                      for (int i = 0;
                          (i < elements.getLength()) && (elementNode == null);
                          i++)
                      {
                          Node kid = elements.item(i);
  
                          if (isXSDNode(kid, "element"))
                          {
                              elementNode = elements.item(i);
  
                              break;
                          }
                      }
  
                      // The element node should have maxOccurs="unbounded" and
                      // a type
                      if (elementNode != null)
                      {
                          String maxOccursValue =
                              Utils.getAttribute(elementNode, "maxOccurs");
  
                          if ((maxOccursValue != null)
                              && maxOccursValue.equalsIgnoreCase("unbounded"))
                          {
  
                              // Get the QName of the type without considering maxOccurs
                              dims.value = 1;
  
                              return Utils.getTypeQName(
                                  elementNode,
                                  new BooleanHolder(),
                                  true);
                          }
                      }
                  }
          }
  
          return null;
      }
  
      /**
       * adds an attribute node's type and name to the vector
       * helper used by getContainedAttributeTypes
       * 
       * @param v           
       * @param child       
       * @param symbolTable 
       */
      private static void addAttributeToVector(
          Vector v,
          Node child,
          SymbolTable symbolTable)
      {
  
          // Get the name and type qnames.
          // The type qname is used to locate the TypeEntry, which is then
          // used to retrieve the proper java name of the type.
          QName attributeName = Utils.getNodeNameQName(child);
          BooleanHolder forElement = new BooleanHolder();
          QName attributeType = Utils.getTypeQName(child, forElement, false);
  
          // An attribute is either qualified or unqualified.
          // If the ref= attribute is used, the name of the ref'd element is used
          // (which must be a root element).  If the ref= attribute is not
          // used, the name of the attribute is unqualified.
          if (!forElement.value)
          {
  
              // check the Form (or attributeFormDefault) attribute of
              // this node to determine if it should be namespace
              // quailfied or not.
              String form = Utils.getAttribute(child, "form");
  
              if ((form != null) && form.equals("unqualified"))
              {
  
                  // Unqualified nodeName
                  attributeName =
                      Utils.findQName("", attributeName.getLocalPart());
              }
              else
                  if (form == null)
                  {
  
                      // check attributeFormDefault on schema element
                      String def =
                          Utils.getScopedAttribute(child, "attributeFormDefault");
  
                      if ((def == null) || def.equals("unqualified"))
                      {
  
                          // Unqualified nodeName
                          attributeName =
                              Utils.findQName("", attributeName.getLocalPart());
                      }
                  }
          }
          else
          {
              attributeName = attributeType;
          }
  
          // Get the corresponding TypeEntry from the symbol table
          TypeEntry type =
              symbolTable.getTypeEntry(attributeType, forElement.value);
  
          // add type and name to vector, skip it if we couldn't parse it
          // XXX - this may need to be revisited.
          //attributeName.getLocalPart().equals("name>lang")
          if ((type != null) && (attributeName != null))
          {
              v.add(type);
              v.add(attributeName);
          }
      }
  
      /**
       * adds an attribute to the vector
       * helper used by addAttributeGroupToVector
       * 
       * @param v           
       * @param symbolTable 
       * @param type        
       * @param name        
       */
      private static void addAttributeToVector(
          Vector v,
          SymbolTable symbolTable,
          QName type,
          QName name)
      {
  
          TypeEntry typeEnt = symbolTable.getTypeEntry(type, false);
  
          if (typeEnt != null) // better not be null
          {
              v.add(typeEnt);
              v.add(name);
          }
      }
  
      /**
       * adds each attribute group's attribute node to the vector
       * helper used by getContainedAttributeTypes
       * 
       * @param v           
       * @param attrGrpnode 
       * @param symbolTable 
       */
      private static void addAttributeGroupToVector(
          Vector v,
          Node attrGrpnode,
          SymbolTable symbolTable)
      {
  
          // get the type of the attributeGroup
          QName attributeGroupType =
              Utils.getTypeQName(attrGrpnode, new BooleanHolder(), false);
          TypeEntry type = symbolTable.getTypeEntry(attributeGroupType, false);
  
          if (type != null)
          {
              if (type.getNode() != null)
              {
  
                  // for each attribute or attributeGroup defined in the attributeGroup...
                  NodeList children = type.getNode().getChildNodes();
  
                  for (int j = 0; j < children.getLength(); j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "attribute"))
                      {
                          addAttributeToVector(v, kid, symbolTable);
                      }
                      else
                          if (isXSDNode(kid, "attributeGroup"))
                          {
                              addAttributeGroupToVector(v, kid, symbolTable);
                          }
                  }
              }
              else
                  if (type.isBaseType())
                  {
  
                      // soap/encoding is treated as a "known" schema
                      // so let's act like we know it
                      if (type.getQName().equals(Constants.SOAP_COMMON_ATTRS11))
                      {
  
                          // 1.1 commonAttributes contains two attributes
                          addAttributeToVector(
                              v,
                              symbolTable,
                              Constants.XSD_ID,
                              new QName(Constants.URI_SOAP11_ENC, "id"));
                          addAttributeToVector(
                              v,
                              symbolTable,
                              Constants.XSD_ANYURI,
                              new QName(Constants.URI_SOAP11_ENC, "href"));
                      }
                      else
                          if (type
                              .getQName()
                              .equals(Constants.SOAP_COMMON_ATTRS12))
                          {
  
                              // 1.2 commonAttributes contains one attribute
                              addAttributeToVector(
                                  v,
                                  symbolTable,
                                  Constants.XSD_ID,
                                  new QName(Constants.URI_SOAP12_ENC, "id"));
                          }
                          else
                              if (type
                                  .getQName()
                                  .equals(Constants.SOAP_ARRAY_ATTRS11))
                              {
  
                                  // 1.1 arrayAttributes contains two attributes
                                  addAttributeToVector(
                                      v,
                                      symbolTable,
                                      Constants.XSD_STRING,
                                      new QName(
                                          Constants.URI_SOAP12_ENC,
                                          "arrayType"));
                                  addAttributeToVector(
                                      v,
                                      symbolTable,
                                      Constants.XSD_STRING,
                                      new QName(
                                          Constants.URI_SOAP12_ENC,
                                          "offset"));
                              }
                              else
                                  if (type
                                      .getQName()
                                      .equals(Constants.SOAP_ARRAY_ATTRS12))
                                  {
  
                                      // 1.2 arrayAttributes contains two attributes
                                      // the type of "arraySize" is really "2003soapenc:arraySize"
                                      // which is rather of a hairy beast that is not yet supported
                                      // in Axis, so let's just use string; nobody should care for
                                      // now because arraySize wasn't used at all up until this
                                      // bug 23145 was fixed, which had nothing to do, per se, with
                                      // adding support for arraySize
                                      addAttributeToVector(
                                          v,
                                          symbolTable,
                                          Constants.XSD_STRING,
                                          new QName(
                                              Constants.URI_SOAP12_ENC,
                                              "arraySize"));
                                      addAttributeToVector(
                                          v,
                                          symbolTable,
                                          Constants.XSD_QNAME,
                                          new QName(
                                              Constants.URI_SOAP12_ENC,
                                              "itemType"));
                                  }
                  }
          }
      }
  
      /**
       * Return the attribute names and types if any in the node
       * The even indices are the attribute types (TypeEntry) and
       * the odd indices are the corresponding names (Strings).
       * <p/>
       * Example:
       * <complexType name="Person">
       * <sequence>
       * <element minOccurs="1" maxOccurs="1" name="Age" type="double" />
       * <element minOccurs="1" maxOccurs="1" name="ID" type="xsd:float" />
       * </sequence>
       * <attribute name="Name" type="string" />
       * <attribute name="Male" type="boolean" />
       * <attributeGroup ref="s0:MyAttrSet" />
       * </complexType>
       * 
       * @param node        
       * @param symbolTable 
       * @return 
       */
      public static Vector getContainedAttributeTypes(
          Node node,
          SymbolTable symbolTable)
      {
  
          Vector v = null; // return value
  
          if (node == null)
          {
              return null;
          }
  
          // Check for SimpleContent
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexType"))
                  {
                      node = kid;
  
                      break;
                  }
              }
          }
  
          // Expecting a schema complexType
          if (isXSDNode(node, "complexType"))
          {
  
              // Under the complexType there could be complexContent/simpleContent
              // and extension elements if this is a derived type.  Skip over these.
              NodeList children = node.getChildNodes();
              Node content = null;
  
              for (int j = 0; j < children.getLength(); j++)
              {
                  Node kid = children.item(j);
  
                  if (isXSDNode(kid, "complexContent")
                      || isXSDNode(kid, "simpleContent"))
                  {
                      content = kid;
  
                      break;
                  }
              }
  
              // Check for extensions or restrictions
              if (content != null)
              {
                  children = content.getChildNodes();
  
                  for (int j = 0; j < children.getLength(); j++)
                  {
                      Node kid = children.item(j);
  
                      if (isXSDNode(kid, "extension")
                          || isXSDNode(kid, "restriction"))
                      {
                          node = kid;
  
                          break;
                      }
                  }
              }
  
              // examine children of the node for <attribute> elements
              children = node.getChildNodes();
  
              for (int i = 0; i < children.getLength(); i++)
              {
                  Node child = children.item(i);
  
                  if (!isXSDNode(child, "attribute")
                      && !isXSDNode(child, "attributeGroup"))
                  {
                      continue;
                  }
  
                  // we have an attribute or attributeGroup node
                  if (v == null)
                  {
                      v = new Vector();
                  }
  
                  if (isXSDNode(child, "attributeGroup"))
                  {
                      addAttributeGroupToVector(v, child, symbolTable);
                  }
                  else
                  {
  
                      // we have an attribute
                      addAttributeToVector(v, child, symbolTable);
                  }
              }
          }
  
          return v;
      }
  
      // list of all of the XSD types in Schema 2001
  
      /** Field schemaTypes[] */
      private static String schemaTypes[] =
          {
              "string",
              "normalizedString",
              "token",
              "byte",
              "unsignedByte",
              "base64Binary",
              "hexBinary",
              "integer",
              "positiveInteger",
              "negativeInteger",
              "nonNegativeInteger",
              "nonPositiveInteger",
              "int",
              "unsignedInt",
              "long",
              "unsignedLong",
              "short",
              "unsignedShort",
              "decimal",
              "float",
              "double",
              "boolean",
              "time",
              "dateTime",
              "duration",
              "date",
              "gMonth",
              "gYear",
              "gYearMonth",
              "gDay",
              "gMonthDay",
              "Name",
              "QName",
              "NCName",
              "anyURI",
              "language",
              "ID",
              "IDREF",
              "IDREFS",
              "ENTITY",
              "ENTITIES",
              "NOTATION",
              "NMTOKEN",
              "NMTOKENS",
              "anySimpleType" };
  
      /** Field schemaTypeSet */
      private static final Set schemaTypeSet =
          new HashSet(Arrays.asList(schemaTypes));
  
      /**
       * Determine if a string is a simple XML Schema type
       * 
       * @param s 
       * @return 
       */
      private static boolean isSimpleSchemaType(String s)
      {
  
          if (s == null)
          {
              return false;
          }
  
          return schemaTypeSet.contains(s);
      }
  
      /**
       * Determine if a QName is a simple XML Schema type
       * 
       * @param qname 
       * @return 
       */
      public static boolean isSimpleSchemaType(QName qname)
      {
  
          if ((qname == null) || !Constants.isSchemaXSD(qname.getNamespaceURI()))
          {
              return false;
          }
  
          return isSimpleSchemaType(qname.getLocalPart());
      }
  
      /**
       * Returns the base type of a given type with its symbol table.
       * This logic is extracted from JavaTypeWriter's constructor() method
       * for reusing.
       * 
       * @param type 
       * @param symbolTable 
       * @return 
       */
      public static TypeEntry getBaseType(
          TypeEntry type,
          SymbolTable symbolTable)
      {
          Node node = type.getNode();
          TypeEntry base = getComplexElementExtensionBase(node, symbolTable);
          if (base == null)
          {
              base = getComplexElementRestrictionBase(node, symbolTable);
          }
  
          if (base == null)
          {
              QName baseQName = getSimpleTypeBase(node);
              if (baseQName != null)
              {
                  base = symbolTable.getType(baseQName);
              }
          }
          return base;
      }
  
      /**
       * Returns whether the specified node represents a <xsd:simpleType> 
       * with a nested <xsd:list itemType="...">.
       * @param node 
       * @return 
       */
      public static boolean isListWithItemType(Node node)
      {
  
          return getListItemType(node) != null;
      }
  
      /**
       * Returns the value of itemType attribute of <xsd:list> in <xsd:simpleType> 
       * @param node 
       * @return 
       */
      public static QName getListItemType(Node node)
      {
  
          if (node == null)
          {
              return null;
          }
  
          // If the node kind is an element, dive into it.
          if (isXSDNode(node, "element"))
          {
              NodeList children = node.getChildNodes();
              for (int j = 0; j < children.getLength(); j++)
              {
                  if (isXSDNode(children.item(j), "simpleType"))
                  {
                      node = children.item(j);
                      break;
                  }
              }
          }
          // Get the node kind, expecting a schema simpleType
          if (isXSDNode(node, "simpleType"))
          {
              NodeList children = node.getChildNodes();
              for (int j = 0; j < children.getLength(); j++)
              {
                  if (isXSDNode(children.item(j), "list"))
                  {
                      Node listNode = children.item(j);
                      org.w3c.dom.Element listElement =
                          (org.w3c.dom.Element) listNode;
                      String type = listElement.getAttribute("itemType");
                      if (type.equals(""))
                      {
                          return null;
                      }
                      int colonIndex = type.lastIndexOf(":");
                      if (colonIndex > 0)
                      {
                          type = type.substring(colonIndex + 1);
                      }
                      return new QName(
                          Constants.URI_2001_SCHEMA_XSD,
                          type + "[]");
                  }
              }
          }
          return null;
      }
  }