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 rk...@apache.org on 2001/11/28 13:08:09 UTC

cvs commit: xml-axis/java/src/org/apache/axis/wsdlgen Types.java

rkumar      01/11/28 04:08:09

  Added:       java/src/org/apache/axis/wsdlgen Types.java
  Log:
  Another pass at setting up the Java2Wsdl framework -
  this batch is primarily namespaces and types related.
  
  Revision  Changes    Path
  1.1                  xml-axis/java/src/org/apache/axis/wsdlgen/Types.java
  
  Index: Types.java
  ===================================================================
  
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Axis" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.axis.wsdlgen;
  
  import org.apache.axis.Constants;
  import org.apache.axis.encoding.SOAPTypeMappingRegistry;
  import org.apache.axis.encoding.TypeMappingRegistry;
  import org.apache.axis.utils.XMLUtils;
  
  import org.w3c.dom.Attr;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.Element;
  import org.w3c.dom.NamedNodeMap;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  
  
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Method;
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  import javax.wsdl.Definition;
  import javax.wsdl.factory.WSDLFactory;
  import javax.wsdl.QName;
  
  import com.ibm.wsdl.util.xml.DOMUtils;
  
  import org.apache.xerces.dom.DocumentImpl;
  
  
  /**
   *
   * <p>Description: </p> This class is used to recursively serializes a Java Class into
   * an XML Schema representation.
   *
   * It has utility methods to create a schema node, assosiate namespaces to the various types
   *
   *
   * @author unascribed
   */
  public class Types {
  
      Definition def;
      Namespaces namespaces = null;
      TypeMappingRegistry reg;
      String targetNamespace;
      Element wsdlTypesElem = null;
      HashMap schemaTypes = null;
      HashMap schemaElementNames = null;
  
      /**
       * This class serailizes a <code>Class</code> to XML Schema. The constructor
       * provides the context for the streamed node within the WSDL document
       * @param def WSDL Definition Element to declare namespaces
       * @param doc Document element of the WSDL used to create child elements
       * @param reg TypeMappingRegistry to handle known types
       * @param namespaces user defined or autogenerated namespace and prefix maps
       * @param targetNamespace targetNamespace of the document
       */
      public Types(Definition def, TypeMappingRegistry reg, Namespaces namespaces, String targetNamespace) {
          this.def = def;
          createDocumentFragment();
          this.reg = reg;
          this.namespaces = namespaces;
          this.targetNamespace = targetNamespace;
          schemaElementNames = new HashMap();
          schemaTypes = new HashMap();
      }
  
      /**
       * Serialize the Class as XML schema to the document.
       * Create a types node for the WSDL if one doesn't exist
       * Create a schema node for the Class namespace, if one doesn't exist
       *
       * In case of a primitive type, no need to stream out anything, just return
       * the QName of the primitive type
       *
       * @param param <code>Class</code> to generate the XML Schema info for
       * @return the QName of the generated Schema type, null if void
       */
      public QName writePartType(Class type) throws Exception {
          if (type.getName().equals("void"))
            return null;
          if (isPrimitiveWsdlType(type)) {
              javax.xml.rpc.namespace.QName qName = reg.getTypeQName(type);
              return getWsdlQName(qName);
          }else {
              if (wsdlTypesElem == null)
                  writeWsdlTypesElement();
              return writeTypeAsElement(type);
          }
      }
  
      /**
       * Create a schema element for the given type
       * @param type the class type
       * @return the QName of the generated Element
       */
      private QName writeTypeAsElement(Class type) throws Exception {
          QName qName = writeTypeNamespace(type);
          String elementType = writeType(type);
          writeSchemaElement(qName, createElement(qName, elementType, isNullable(type)));
          return qName;
      }
  
      /**
       * write out the namespace declaration and return the type QName for the
       * given <code>Class</code>
       *
       * @param type input Class
       * @return QName for the schema type representing the class
       */
      private QName writeTypeNamespace(Class type) {
          javax.xml.rpc.namespace.QName qName = null;
          String typeName = null;
          if (type.isArray()) {
              Class componentType = type.getComponentType();
              typeName = "ArrayOf" + componentType.getName().substring(componentType.getName().lastIndexOf('.') + 1);
              if (isPrimitiveWsdlType(componentType))
                qName = new javax.xml.rpc.namespace.QName(targetNamespace, typeName);
              else
                qName = new javax.xml.rpc.namespace.QName(namespaces.getCreate(componentType.getName()), typeName);
          }else {
              typeName = type.getName().substring(type.getName().lastIndexOf('.') + 1);
              qName = new javax.xml.rpc.namespace.QName(namespaces.getCreate(type.getName()), typeName);
          }
          QName typeQName = getWsdlQName(qName);
          String pref = def.getPrefix(qName.getNamespaceURI());
          if (pref == null)
            def.addNamespace(namespaces.getCreatePrefix(qName.getNamespaceURI()), qName.getNamespaceURI());
          return typeQName;
      }
  
      /**
       * Write out the given Element into the appropriate schema node.
       * If need be create the schema node as well
       *
       * @param qName qName to get the namespace of the schema node
       * @param element the Element to append to the Schema node
       */
      private void writeSchemaElement(QName qName, Element element) {
          Element schemaElem = null;
          NodeList nl = wsdlTypesElem.getChildNodes();
          for (int i = 0; i < nl.getLength(); i++ ) {
              NamedNodeMap attrs = nl.item(i).getAttributes();
              for (int n = 0; n < attrs.getLength(); n++) {
                  Attr a = (Attr)attrs.item(n);
                  if (a.getName().equals("targetNamespace") &&
                      a.getValue().equals(qName.getNamespaceURI()))
                      schemaElem = (Element)nl.item(i);
              }
          }
          if (schemaElem == null) {
            schemaElem = docHolder.createElement("schema");
            wsdlTypesElem.appendChild(schemaElem);
            schemaElem.setAttribute("xmlns", Constants.URI_CURRENT_SCHEMA_XSD);
            schemaElem.setAttribute("targetNamespace", qName.getNamespaceURI());
          }
          schemaElem.appendChild(element);
      }
  
      /**
       * Get the Types element for the WSDL document. If not present, create one
       * @throws Exception
       */
      private void writeWsdlTypesElement() throws Exception {
          NodeList nl = docFragment.getChildNodes();
          for (int n = 0; n < nl.getLength(); n++) {
              if (nl.item(n).getLocalName().equals("types")) {
                  wsdlTypesElem = (Element)nl.item(n);
                  return;
              }
          }
          wsdlTypesElem = docHolder.createElement("types");
          docFragment.appendChild(wsdlTypesElem);
      }
  
      /**
       * Write a schema representation for the given <code>Class</code>. Recurse through all the
       * Public fields as well as fields represented by java bean compliant accesor
       * methods.
       * Then return the qualified string representation of the generated type
       *
       * @param type Class for which to generate schema
       * @return a prefixed string for the schema type
       * @throws Exception
       */
      private String writeType(Class type) throws Exception {
          if (isPrimitiveWsdlType(type))
              return "xsd:" + reg.getTypeQName(type).getLocalPart();
          QName qName = writeTypeNamespace(type);
          String typeName = null;
          String componentTypeName = null;
          Class componentType = null;
          if (type.isArray()) {
              componentType = type.getComponentType();
              componentTypeName = writeType(componentType);
              typeName = "ArrayOf" + componentTypeName.substring(componentTypeName.indexOf(":")+1);
          }
          else {
              typeName = type.getName().replace('$', '_');
          }
          String soapTypeName;
          if (typeName.indexOf('.') >= 0)
              soapTypeName = typeName.substring(typeName.lastIndexOf('.')+1);
          else
              soapTypeName = typeName;
  
          String prefixedName = namespaces.getCreatePrefix(qName.getNamespaceURI())+":"+soapTypeName;
  
          if (!addToTypesList(qName, soapTypeName))
            return prefixedName;
  
          Element complexType = docHolder.createElement("complexType");
          writeSchemaElement(qName, complexType);
          complexType.setAttribute("name", soapTypeName);
          Element sequence = docHolder.createElement("sequence");
          complexType.appendChild(sequence);
  
          if (type.isArray()) {
              Element elem = docHolder.createElement("element");
              elem.setAttribute("name", "item");
              String elType = componentTypeName;
              if (isNullable(componentType)) {
                  elem.setAttribute("nullable", "true");
              }
              elem.setAttribute("type", elType);
              complexType.setAttribute("base", "soap:Array");
              sequence.appendChild(elem);
          } else {
              Field[] fld= type.getDeclaredFields();
              for (int i=0;i<fld.length;i++) {
                if ((fld[i].getModifiers() == Modifier.PUBLIC) ||
                  (isJavaBean(type, fld[i]))) {
                  writeField (fld[i].getName(),fld[i].getType(),sequence);
                }
              }
          }
          return prefixedName;
      }
  
      /**
       * write a schema representation of the given Class field and append it to the where Node
       * recurse on complex types
       * @param fieldName name of the field
       * @param fieldType type of the field
       * @param where location for the generated schema node
       * @throws Exception
       */
      private void writeField(String fieldName, Class fieldType, Element where) throws Exception {
          String elementType = writeType(fieldType);
          Element elem = createElement(fieldName, elementType, isNullable(fieldType));
          where.appendChild(elem);
      }
  
      /**
       * Create Element with a unique name generated from the namespace information
       * @param qName the namespace of the created element
       * @param elementType schema type representation of the element
       * @param nullable nullable attribute of the element
       * @return the created Element
       */
      private Element createElement(QName qName, String elementType, boolean nullable) {
          Element element = docHolder.createElement("element");
          String name = generateUniqueElementName(qName);
          element.setAttribute("name", name);
          if (nullable)
              element.setAttribute("nullable", "true");
          element.setAttribute("type", elementType);
          return element;
      }
  
      /**
       * Create Element with a given name and type
       * @param elementName the name of the created element
       * @param elementType schema type representation of the element
       * @param nullable nullable attribute of the element
       * @return the created Element
       */
      private Element createElement(String elementName, String elementType, boolean nullable) {
          Element element = docHolder.createElement("element");
          element.setAttribute("name", elementName);
          if (nullable)
              element.setAttribute("nullable", "true");
          element.setAttribute("type", elementType);
          return element;
      }
  
      /**
       * convert from JAX-RPC QName to WSDL QName
       * @param qName JAX-RPC QName
       * @return WSDL QName
       */
      private QName getWsdlQName (javax.xml.rpc.namespace.QName qName) {
          return new QName(qName.getNamespaceURI(), qName.getLocalPart());
      }
  
      /**
       * Is the given class one of the WSDL primitive types
       * @param type input Class
       * @return true if the type is primitive
       */
      boolean isPrimitiveWsdlType(Class type) {
        return (type == java.lang.Boolean.class ||
                type == java.lang.Boolean.TYPE  ||
                type == java.lang.Byte.class ||
                type == java.lang.Byte.TYPE ||
                type == java.lang.Character.class ||
                type == java.lang.Character.TYPE ||
                type == java.lang.Double.class ||
                type == java.lang.Double.TYPE ||
                type == java.lang.Float.class ||
                type == java.lang.Float.TYPE ||
                type == java.lang.Integer.class ||
                type == java.lang.Integer.TYPE ||
                type == java.lang.Long.class ||
                type == java.lang.Long.TYPE ||
                type == java.lang.Short.class ||
                type == java.lang.Short.TYPE ||
                type == java.lang.String.class);
      }
  
      /**
       * Generates a unique element name for a given namespace of the form
       * el0, el1 ....
       *
       * @param qName the namespace for the generated element
       * @return elementname
       */
      private String generateUniqueElementName(QName qName) {
        Integer count = (Integer)schemaElementNames.get(qName);
        if (count == null)
          count = new Integer(0);
        else
          count = new Integer(count.intValue() + 1);
        schemaElementNames.put(qName, count);
        return "el" + count.intValue();
      }
  
      /**
       * Add the type to an ArrayList and return true to indicate that the Schema node
       * needs to be generated
       * If the type already exists, just return false to indicate that the type is already
       * generated in a previous iterration
       *
       * @param qName the name space of the type
       * @param typeName the name of the type
       * @return if the type is added returns true, else if the type is already present returns false
       */
      private boolean addToTypesList (QName qName, String typeName) {
          ArrayList types = (ArrayList)schemaTypes.get(qName.getNamespaceURI());
          if (types == null) {
              types = new ArrayList();
              types.add(typeName);
              schemaTypes.put(qName.getNamespaceURI(), types);
              return true;
          }
          else {
              if (!types.contains(typeName)) {
                 types.add(typeName);
                 return true;
              }
          }
          return false;
      }
  
      /**
       * Determines if the Field in the Class has bean compliant accessors. If so returns true,
       * else returns false
       * @param type the Class
       * @param field the Field
       * @return true if the Field has JavaBean style accessor
       */
      private boolean isJavaBean(Class type, Field field) {
          try {
              String setter = "set" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
              String getter = null;
              if (field.getType().getName() == "boolean")
                getter = "is" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
              else
                getter = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
              type.getMethod(setter, new Class[] {field.getType()});
              type.getMethod(getter, null);
          }
          catch (NoSuchMethodException ex) {
              return false;
          }
          return true;
      }
  
      /**
       * Determines if the field is nullable. All non-primitives are Nullable
       *
       * @param type input Class
       * @return true if nullable
       */
      private boolean isNullable(Class type) {
          return !type.isPrimitive();
      }
  
  
      /** @todo ravi: Get rid of Doccument fragment and import node stuuf,
       *  once I have a handle on the wsdl4j mechanism to get at types.
       *
       *  Switch over notes: remove docHolder, docFragment in favor of wsdl4j Types
       */
      DocumentFragment docFragment;
      Document docHolder;
  
      private void createDocumentFragment () {
          this.docHolder = new DocumentImpl();
          docFragment = docHolder.createDocumentFragment();
      }
      /**
       * Inserts the type fragment into the given wsdl document
       * @param doc
       */
      public void insertTypesFragment(Document doc) {
          doc.getDocumentElement().insertBefore(
              doc.importNode(docFragment, true),
              doc.getDocumentElement().getFirstChild());
      }
  }