All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.axis.wsdl.symbolTable.Utils Maven / Gradle / Ivy

The newest version!
/*
 * 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 org.apache.axis.Constants;
import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import javax.xml.namespace.QName;
import javax.xml.rpc.holders.BooleanHolder;
import java.util.*;

/**
 * This class contains static utility methods for the emitter.
 * 
 * @author Rich Scheuerle  ([email protected])
 * @author Tom Jordahl ([email protected])
 */
public class Utils {

    /** cache of namespaces -> maps of localNames -> QNames */
    static final Map nsmap = new HashMap();

    /**
     * Find or create a QName with the specified namespace/localName.
     * 
     * @param namespace 
     * @param localName 
     * @return 
     */
    static QName findQName(String namespace, String localName) {

        QName qname = null;

        // get the inner map, using the namespace as a key
        Map ln2qn = (Map) nsmap.get(namespace);

        if (null == ln2qn) {        // cache miss
            ln2qn = new HashMap();

            nsmap.put(namespace, ln2qn);

            qname = new QName(namespace, localName);

            ln2qn.put(localName, qname);
        } else {                    // cache hit
            qname = (QName) ln2qn.get(localName);

            if (null == qname) {    // cache miss
                qname = new QName(namespace, localName);

                ln2qn.put(localName, qname);
            } else {

                // cache hit
            }
        }

        return qname;
    }

    /**
     * Given a node, return the value of the given attribute.
     * If the attribute does not exist, searching continues through ancestor nodes until found.
     * This method is useful for finding attributes that pertain to a group of contained
     * nodes (i.e. xlmns, xmlns:tns, targetNamespace, name)
     * 
     * @param node 
     * @param attr 
     * @return 
     */
    public static String getScopedAttribute(Node node, String attr) {

        if (node == null) {
            return null;
        }

        if (node.getAttributes() == null) {
            return getScopedAttribute(node.getParentNode(), attr);
        }

        Node attrNode = node.getAttributes().getNamedItem(attr);

        if (attrNode != null) {
            return attrNode.getNodeValue();
        } else {
            return getScopedAttribute(node.getParentNode(), attr);
        }
    }

    /**
     * Given a node, return the value of the given attribute.
     * Returns null if the attribute is not found
     * 
     * @param node 
     * @param attr 
     * @return 
     */
    public static String getAttribute(Node node, String attr) {

        if ((node == null) || (node.getAttributes() == null)) {
            return null;
        }

        Node attrNode = node.getAttributes().getNamedItem(attr);

        if (attrNode != null) {
            return attrNode.getNodeValue();
        } else {
            return null;
        }
    }

    /**
     * Given a node, return the attributes that have the specified local name.
     * Returns null if the attribute is not found
     * 
     * @param node      
     * @param localName 
     * @return 
     */
    public static Vector getAttributesWithLocalName(Node node,
                                                    String localName) {

        Vector v = new Vector();

        if (node == null) {
            return v;
        }

        NamedNodeMap map = node.getAttributes();

        if (map != null) {
            for (int i = 0; i < map.getLength(); i++) {
                Node attrNode = map.item(i);

                if ((attrNode != null)
                        && attrNode.getLocalName().equals(localName)) {
                    v.add(attrNode);
                }
            }
        }

        return v;
    }

    /**
     * An xml element may have a name.
     * For example <.element name="foo" type="b:bar">.
     * has the name "element".  This routine gets the full QName of the element.
     * 
     * @param node 
     * @return 
     */
    public static QName getNodeQName(Node node) {

        if (node == null) {
            return null;
        }

        String localName = node.getLocalName();

        if (localName == null) {
            return null;
        }

        String namespace = node.getNamespaceURI();

        return (findQName(namespace, localName));
    }

    /**
     * XML nodes may have a name attribute.
     * For example <.element name="foo" type="b:bar">.
     * has the name attribute value "foo".  This routine gets the QName of the name attribute value.
     * 
     * @param node 
     * @return 
     */
    public static QName getNodeNameQName(Node node) {

        if (node == null) {
            return null;
        }

        String localName = null;
        String namespace = null;

        // First try to get the name directly
        localName = getAttribute(node, "name");

        // If this fails and the node has a ref, use the ref name.
        if (localName == null) {
            QName ref = getTypeQNameFromAttr(node, "ref");

            if (ref != null) {
                localName = ref.getLocalPart();
                namespace = ref.getNamespaceURI();
            }
        }

        // This routine may be called for complexType elements.  In some cases,
        // the complexType may be anonymous, which is why the getScopedAttribute
        // method is used.

            Node search = node.getParentNode();

            while (search != null) {
                String ln = search.getLocalName();

                if (ln.equals("schema")) {
                    search = null;
                } else if (ln.equals("element")
                        || ln.equals("attribute")) {
                    localName = SymbolTable.ANON_TOKEN
                            + getNodeNameQName(search).getLocalPart();
                    search = null;
                } else if (ln.equals("complexType")
                        || ln.equals("simpleType")) {
                    localName = getNodeNameQName(search).getLocalPart()
                            + SymbolTable.ANON_TOKEN + localName;
                    search = null;
                } else {
                    search = search.getParentNode();
                }
            }

        if (localName == null) {
            return null;
        }

        // Build and return the QName
        if (namespace == null) {
            namespace = getScopedAttribute(node, "targetNamespace");
        }

        return (findQName(namespace, localName));
    }

    /**
     * An XML element or attribute node has several ways of
     * identifying the type of the element or attribute:
     * - use the type attribute to reference a complexType/simpleType
     * - use the ref attribute to reference another element, group or attributeGroup
     * - use of an anonymous type (i.e. a nested type underneath itself)
     * - a wsdl:part can use the element attribute.
     * - an extension can use the base attribute.
     * 

* This routine returns a QName representing this "type". * The forElement value is also returned to indicate whether the * QName represents an element (i.e. obtained using the ref attribute) * or a type. *

* Other attributes affect the QName that is returned. * If the "minOccurs" and "maxOccurs" are set such that the * type is a collection of "types", then an artificial qname is * returned to represent the collection. * * @param node of the reference * @param forElement output parameter is set to true if QName is for an element * (i.e. ref= or element= attribute was used). * @param ignoreMaxOccurs indicates whether minOccurs/maxOccurs affects the QName * @return QName representing the type of this element */ public static QName getTypeQName(Node node, BooleanHolder forElement, boolean ignoreMaxOccurs) { if (node == null) { return null; } forElement.value = false; // Assume QName returned is for a type // Try getting the QName of the type attribute. // Note this also retrieves the type if an anonymous type is used. QName qName = getTypeQNameFromAttr(node, "type"); // If not successful, try using the ref attribute. if (qName == null) { String localName = node.getLocalName(); // bug 23145: support attributeGroup (Brook Richan) // a ref can be for an element or attributeGroup if ((localName != null) && !(localName.equals("attributeGroup") || localName.equals("group") || localName.equals("list"))) { forElement.value = true; } qName = getTypeQNameFromAttr(node, "ref"); } // in case of a list get the itemType if (qName == null) { qName = getTypeQNameFromAttr(node, "itemType"); } // If the node has "type"/"ref" and "maxOccurs" then the type is really // a collection. There is no qname in the wsdl which we can use to represent // the collection, so we need to invent one. // The local part of the qname is changed to [minOccurs, maxOccurs] // The namespace uri is changed to the targetNamespace of this node if (!ignoreMaxOccurs) { if (qName != null) { String maxOccursValue = getAttribute(node, "maxOccurs"); String minOccursValue = getAttribute(node, "minOccurs"); String nillableValue = getAttribute(node, "nillable"); if (maxOccursValue == null) { maxOccursValue = "1"; } if (minOccursValue == null) { minOccursValue = "1"; } if (minOccursValue.equals("0") && maxOccursValue.equals("1")) { // If we have a minoccurs="0"/maxoccurs="1", this is just // like a nillable single value, so treat it as such. // qName = getNillableQName(qName); } else if (!maxOccursValue.equals("1") || !minOccursValue.equals("1")) { String localPart = qName.getLocalPart(); String wrapped = (nillableValue != null && nillableValue.equals("true") ? " wrapped" : ""); String range = "["; if (!minOccursValue.equals("1")) { range += minOccursValue; } range += ","; if (!maxOccursValue.equals("1")) { range += maxOccursValue; } range += "]"; localPart += range + wrapped; qName = findQName(qName.getNamespaceURI(), localPart); } } } // A WSDL Part uses the element attribute instead of the ref attribute if (qName == null) { forElement.value = true; qName = getTypeQNameFromAttr(node, "element"); } // "base" references a "type" if (qName == null) { forElement.value = false; qName = getTypeQNameFromAttr(node, "base"); } return qName; } /** * Method getMemberTypeQNames * * @param node * @return */ public static QName[] getMemberTypeQNames(Node node) { String attribute = getAttribute(node, "memberTypes"); if (attribute == null) { return null; } StringTokenizer tokenizer = new StringTokenizer(attribute, " "); QName[] memberTypes = new QName[tokenizer.countTokens()]; for (int i = 0; tokenizer.hasMoreElements(); i++) { String element = (String) tokenizer.nextElement(); memberTypes[i] = XMLUtils.getFullQNameFromString(element, node); } return memberTypes; } /** * Gets the QName of the type of the node via the specified attribute * name. *

* If "type", the QName represented by the type attribute's value is * returned. If the type attribute is not set, the anonymous type * or anyType is returned if no other type information is available. * Note that the QName returned in these cases is affected by * the presence of the nillable attribute. *

* If "ref", the QName represented by the ref attribute's value is * returned. *

* If "base" or "element", the QName represented by the base/element * attribute's value is returned. * * @param node in the dom * @param typeAttrName (type, base, element, ref) * @return */ private static QName getTypeQNameFromAttr(Node node, String typeAttrName) { if (node == null) { return null; } // Get the raw prefixed value String prefixedName = getAttribute(node, typeAttrName); // If "type" was specified but there is no type attribute, // check for an anonymous type. If no anonymous type // then the type is anyType. if ((prefixedName == null) && typeAttrName.equals("type")) { if ((getAttribute(node, "ref") == null) && (getAttribute(node, "base") == null) && (getAttribute(node, "element") == null)) { // Try getting the anonymous qname QName anonQName = SchemaUtils.getElementAnonQName(node); if (anonQName == null) { anonQName = SchemaUtils.getAttributeAnonQName(node); } if (anonQName != null) { return anonQName; } // Try returning anyType String localName = node.getLocalName(); if ((localName != null) && Constants.isSchemaXSD(node.getNamespaceURI()) && (localName.equals("element") || localName.equals("attribute"))) { return Constants.XSD_ANYTYPE; } } } // Return null if not found if (prefixedName == null) { return null; } // Change the prefixed name into a full qname QName qName = getQNameFromPrefixedName(node, prefixedName); // An alternate qname is returned if nillable // if (typeAttrName.equals("type")) { // if (JavaUtils.isTrueExplicitly(getAttribute(node, "nillable"))) { // qName = getNillableQName(qName); // } // } return qName; } /** * Convert a prefixed name into a qname * * @param node * @param prefixedName * @return */ public static QName getQNameFromPrefixedName(Node node, String prefixedName) { String localName = prefixedName.substring(prefixedName.lastIndexOf(":") + 1); String namespace = null; // Associate the namespace prefix with a namespace if (prefixedName.length() == localName.length()) { namespace = getScopedAttribute( node, "xmlns"); // Get namespace for unqualified reference } else { namespace = getScopedAttribute(node, "xmlns:" + prefixedName.substring(0, prefixedName.lastIndexOf(":"))); } return (findQName(namespace, localName)); } /** * This method returns a set of all types that are derived * from this type via an extension of a complexType * * @param type * @param symbolTable * @return */ public static HashSet getDerivedTypes(TypeEntry type, SymbolTable symbolTable) { HashSet types = (HashSet)symbolTable.derivedTypes.get(type); if (types != null) { return types; } types = new HashSet(); symbolTable.derivedTypes.put(type, types); if ((type != null) && (type.getNode() != null)) { getDerivedTypes(type, types, symbolTable); } else if (type != null && Constants.isSchemaXSD(type.getQName().getNamespaceURI()) && (type.getQName().getLocalPart().equals("anyType") || type.getQName().getLocalPart().equals("any"))) { // All types are derived from anyType, except anonymous ones final Collection typeValues = symbolTable.getTypeIndex().values(); types.addAll(typeValues); // Currently we are unable to mark anonymous types correctly. // So, this filtering has to wait until a fix is made. /* for (Iterator it = typeValues.iterator(); it.hasNext();) { SymTabEntry e = (SymTabEntry) it.next(); if (! e.getQName().getLocalPart().startsWith(SymbolTable.ANON_TOKEN)) types.add(e); } */ } return types; } // getNestedTypes /** * Method getDerivedTypes * * @param type * @param types * @param symbolTable */ private static void getDerivedTypes(TypeEntry type, HashSet types, SymbolTable symbolTable) { // If all types are in the set, return if (types.size() == symbolTable.getTypeEntryCount()) { return; } // Search the dictionary for derived types of type for (Iterator it = symbolTable.getTypeIndex().values().iterator(); it.hasNext();) { Type t = (Type) it.next(); if ((t instanceof DefinedType) && (t.getNode() != null) && !types.contains(t) && (((DefinedType) t).getComplexTypeExtensionBase(symbolTable) == type)) { types.add(t); getDerivedTypes(t, types, symbolTable); } } } // getDerivedTypes /** * This method returns a set of all the nested types. * Nested types are types declared within this TypeEntry (or descendents) * plus any extended types and the extended type nested types * The elements of the returned HashSet are Types. * * @param type is the type entry to consider * @param symbolTable is the symbolTable * @param derivedFlag should be set if all dependendent derived types should also be * returned. * @return */ protected static HashSet getNestedTypes(TypeEntry type, SymbolTable symbolTable, boolean derivedFlag) { HashSet types = new HashSet(); getNestedTypes(type, types, symbolTable, derivedFlag); return types; } // getNestedTypes /** * Method getNestedTypes * * @param type * @param types * @param symbolTable * @param derivedFlag */ private static void getNestedTypes(TypeEntry type, HashSet types, SymbolTable symbolTable, boolean derivedFlag) { if (type == null) { return; } // If all types are in the set, return if (types.size() == symbolTable.getTypeEntryCount()) { return; } // Process types derived from this type if (derivedFlag) { HashSet derivedTypes = getDerivedTypes(type, symbolTable); Iterator it = derivedTypes.iterator(); while (it.hasNext()) { TypeEntry derivedType = (TypeEntry) it.next(); if (!types.contains(derivedType)) { types.add(derivedType); getNestedTypes(derivedType, types, symbolTable, derivedFlag); } } } // Continue only if the node exists if (type.getNode() == null) { return; } Node node = type.getNode(); // Process types declared in this type Vector v = SchemaUtils.getContainedElementDeclarations(node, symbolTable); if (v != null) { for (int i = 0; i < v.size(); i++) { ElementDecl elem = (ElementDecl) v.get(i); if (!types.contains(elem.getType())) { types.add(elem.getType()); getNestedTypes(elem.getType(), types, symbolTable, derivedFlag); } } } // Process attributes declared in this type v = SchemaUtils.getContainedAttributeTypes(node, symbolTable); if (v != null) { for (int i = 0; i < v.size(); i++) { ContainedAttribute attr = (ContainedAttribute) v.get(i); TypeEntry te = attr.getType(); if (!types.contains(te)) { types.add(te); getNestedTypes(te, types, symbolTable, derivedFlag); } } } // Process referenced types if ((type.getRefType() != null) && !types.contains(type.getRefType())) { types.add(type.getRefType()); getNestedTypes(type.getRefType(), types, symbolTable, derivedFlag); } /* * Anonymous processing and should be automatically handled by the * reference processing above * // Get the anonymous type of the element * QName anonQName = SchemaUtils.getElementAnonQName(node); * if (anonQName != null) { * TypeEntry anonType = symbolTable.getType(anonQName); * if (anonType != null && !types.contains(anonType)) { * types.add(anonType); * } * } * * // Get the anonymous type of an attribute * anonQName = SchemaUtils.getAttributeAnonQName(node); * if (anonQName != null) { * TypeEntry anonType = symbolTable.getType(anonQName); * if (anonType != null && !types.contains(anonType)) { * types.add(anonType); * } * } */ // Process extended types TypeEntry extendType = SchemaUtils.getComplexElementExtensionBase(node, symbolTable); if (extendType != null) { if (!types.contains(extendType)) { types.add(extendType); getNestedTypes(extendType, types, symbolTable, derivedFlag); } } /* * Array component processing should be automatically handled by the * reference processing above. * // Process array components * QName componentQName = SchemaUtils.getArrayComponentQName(node, new IntHolder(0)); * TypeEntry componentType = symbolTable.getType(componentQName); * if (componentType == null) { * componentType = symbolTable.getElement(componentQName); * } * if (componentType != null) { * if (!types.contains(componentType)) { * types.add(componentType); * getNestedTypes(componentType, types, symbolTable, derivedFlag); * } * } */ } // getNestedTypes /** * Generate an XML prefixed attribute value with a corresponding xmlns * declaration for the prefix. If there is no namespace, * don't prefix the name or emit the xmlns attribute. *

* Caller should provide the enclosing quotes. *

* Usage: println("name=\"" + genXMLQNameString(qname, "foo") + "\"" * * @param qname * @param prefix * @return */ public static String genQNameAttributeString(QName qname, String prefix) { if ((qname.getNamespaceURI() == null) || qname.getNamespaceURI().equals("")) { return qname.getLocalPart(); } return prefix + ":" + qname.getLocalPart() + "\" xmlns:" + prefix + "=\"" + qname.getNamespaceURI(); } public static String genQNameAttributeStringWithLastLocalPart(QName qname, String prefix) { String lastLocalPart = getLastLocalPart(qname.getLocalPart()); if ((qname.getNamespaceURI() == null) || qname.getNamespaceURI().equals("")) { return lastLocalPart; } return prefix + ":" + lastLocalPart + "\" xmlns:" + prefix + "=\"" + qname.getNamespaceURI(); } public static String getLastLocalPart(String localPart) { int anonymousDelimitorIndex = localPart.lastIndexOf('>'); if (anonymousDelimitorIndex > -1 && anonymousDelimitorIndex < localPart.length()-1) { localPart = localPart.substring(anonymousDelimitorIndex + 1); } return localPart; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy