/*
* 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.utils.Messages;
import org.w3c.dom.Node;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Vector;
/**
* This class represents a wsdl types entry that is supported by the WSDL2Java emitter.
* A TypeEntry has a QName representing its XML name and a name, which in the
* WSDL2Java back end is its full java name. The TypeEntry may also have a Node,
* which locates the definition of the emit type in the xml.
* A TypeEntry object extends SymTabEntry and is built by the SymbolTable class for
* each supported root complexType, simpleType, and elements that are
* defined or encountered.
* <p/>
* SymTabEntry
* |
* TypeEntry
* / \
* Type Element
* | |
* (BaseType, (DefinedElement,
* CollectionType CollectionElement,
* DefinedType, UndefinedElement)
* UndefinedType)
* <p/>
* UndefinedType and UndefinedElement are placeholders when the real type or element
* is not encountered yet. Both of these implement the Undefined interface.
* <p/>
* A TypeEntry whose java (or other language) name depends on an Undefined type, will
* have its name initialization deferred until the Undefined type is replaced with
* a defined type. The updateUndefined() method is invoked by the UndefinedDelegate to
* update the information.
* <p/>
* Each TypeEntry whose language name depends on another TypeEntry will have the refType
* field set. For example:
* <element name="foo" type="bar" />
* The TypeEntry for "foo" will have a refType set to the TypeEntry of "bar".
* <p/>
* Another Example:
* <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>
* The TypeEntry for "hobbyArray" will have a refType that locates the TypeEntry for xsd:string
* and the dims field will be "[]"
*
* @author Rich Scheuerle (scheu@us.ibm.com)
*/
public abstract class TypeEntry extends SymTabEntry implements Serializable {
/** Field node */
protected Node node; // Node
/** Field refType */
protected TypeEntry refType; // Some TypeEntries refer to other types.
/** Field dims */
protected String dims = ""; // If refType is an element, dims indicates
// the array dims (for example "[]").
protected boolean underlTypeNillable = false; // if this is an array, underlTypeNillable indicates
// whether the underlying type of the array is nillable.
protected QName componentType = null; // If this is an array, the component type
/** If this TypeEntry represents an array with elements inside a "wrapper"
* this field can optionally change the inner QName (default is <item>).
*/
protected QName itemQName = null;
/** Field undefined */
protected boolean undefined; // If refType is an Undefined type
// (or has a refType that is Undefined)
// then the undefined flag is set.
// The name cannot be determined
// until the Undefined type is found.
/** Field isBaseType */
protected boolean isBaseType; // Indicates if represented by a
// primitive or util class
/** Field isSimpleType */
protected boolean isSimpleType =
false; // Indicates if this type is a simple type
/** Field onlyLiteralReference */
protected boolean onlyLiteralReference = false; // Indicates
/** Field types */
protected HashSet types = null;
/** contained elements in the schema's type definition */
protected Vector containedElements;
/** contained attributes in the schema's type definition */
protected Vector containedAttributes;
// whether this type is only referenced
// via a binding's literal use.
/**
* Create a TypeEntry object for an xml construct that references another type.
* Defer processing until refType is known.
*
* @param pqName
* @param refType
* @param pNode
* @param dims
*/
protected TypeEntry(QName pqName, TypeEntry refType, Node pNode,
String dims) {
super(pqName);
node = pNode;
this.undefined = refType.undefined;
this.refType = refType;
if (dims == null) {
dims = "";
}
this.dims = dims;
if (refType.undefined) {
// Need to defer processing until known.
TypeEntry uType = refType;
while (!(uType instanceof Undefined)) {
uType = uType.refType;
}
((Undefined) uType).register(this);
} else {
isBaseType = (refType.isBaseType && refType.dims.equals("")
&& dims.equals(""));
}
}
/**
* Create a TypeEntry object for an xml construct that is not a base type
*
* @param pqName
* @param pNode
*/
protected TypeEntry(QName pqName, Node pNode) {
super(pqName);
node = pNode;
refType = null;
undefined = false;
dims = "";
isBaseType = false;
}
/**
* Create a TypeEntry object for an xml construct name that represents a base type
*
* @param pqName
*/
protected TypeEntry(QName pqName) {
super(pqName);
node = null;
undefined = false;
dims = "";
isBaseType = true;
}
/**
* Query the node for this type.
*
* @return
*/
public Node getNode() {
return node;
}
/**
* Returns the Base Type Name.
* For example if the Type represents a schema integer, "int" is returned.
* If this is a user defined type, null is returned.
*
* @return
*/
public String getBaseType() {
if (isBaseType) {
return name;
} else {
return null;
}
}
/**
* Method isBaseType
*
* @return
*/
public boolean isBaseType() {
return isBaseType;
}
/**
* Method setBaseType
*
* @param baseType
*/
public void setBaseType(boolean baseType) {
isBaseType = baseType;
}
/**
* Method isSimpleType
*
* @return
*/
public boolean isSimpleType() {
return isSimpleType;
}
/**
* Method setSimpleType
*
* @param simpleType
*/
public void setSimpleType(boolean simpleType) {
isSimpleType = simpleType;
}
/**
* Is this type references ONLY as a literal type? If a binding's
* message's soapBody says: use="literal", then a type is referenced
* literally. Note that that type's contained types (ie., an address
* contains a phone#) are not referenced literally. Since a type
* that is ONLY referenced as a literal may cause a generator to act
* differently (like WSDL2Java), this extra reference distinction is
* needed.
*
* @return
*/
public boolean isOnlyLiteralReferenced() {
return onlyLiteralReference;
} // isOnlyLiteralReferenced
/**
* Set the isOnlyLiteralReference flag.
*
* @param set
*/
public void setOnlyLiteralReference(boolean set) {
onlyLiteralReference = set;
} // setOnlyLiteralRefeerence
/**
* getUndefinedTypeRef returns the Undefined TypeEntry that this entry depends on or NULL.
*
* @return
*/
protected TypeEntry getUndefinedTypeRef() {
if (this instanceof Undefined) {
return this;
}
if (undefined && (refType != null)) {
if (refType.undefined) {
TypeEntry uType = refType;
while (!(uType instanceof Undefined)) {
uType = uType.refType;
}
return uType;
}
}
return null;
}
/**
* UpdateUndefined is called when the ref TypeEntry is finally known.
*
* @param oldRef The TypeEntry representing the Undefined TypeEntry
* @param newRef The replacement TypeEntry
* @return true if TypeEntry is changed in any way.
* @throws IOException
*/
protected boolean updateUndefined(TypeEntry oldRef, TypeEntry newRef)
throws IOException {
boolean changedState = false;
// Replace refType with the new one if applicable
if (refType == oldRef) {
refType = newRef;
changedState = true;
// Detect a loop
TypeEntry te = refType;
while ((te != null) && (te != this)) {
te = te.refType;
}
if (te == this) {
// Detected a loop.
undefined = false;
isBaseType = false;
node = null;
throw new IOException(
Messages.getMessage(
"undefinedloop00", getQName().toString()));
}
}
// Update information if refType is now defined
if ((refType != null) && undefined && (refType.undefined == false)) {
undefined = false;
changedState = true;
isBaseType = (refType.isBaseType && refType.dims.equals("")
&& dims.equals(""));
}
return changedState;
}
/**
* If this type references another type, return that type, otherwise return null.
*
* @return
*/
public TypeEntry getRefType() {
return refType;
} // getRefType
/**
* Method setRefType
*
* @param refType
*/
public void setRefType(TypeEntry refType) {
this.refType = refType;
}
/**
* Return the dimensions of this type, which can be 0 or more "[]".
*
* @return
*/
public String getDimensions() {
return dims;
} // getDimensions
/**
* Return whether the underlying type is nillable if this is an array type.
* @return true if it is an array and nillable
*/
public boolean getUnderlTypeNillable() {
// refType could refer to array with underlying nillable
// type - set the underlTypeNillable to true if this is
// the case.
if (!underlTypeNillable
&& !getDimensions().equals("")
&& refType != null) {
underlTypeNillable = refType.getUnderlTypeNillable();
}
return underlTypeNillable;
}
/**
* Set the boolean indicating whether underlying type of array is nillable.
*/
public void setUnderlTypeNillable(boolean underlTypeNillable) {
this.underlTypeNillable = underlTypeNillable;
}
/**
* Return the QName of the component if this is an array type
* @return QName of array elements or null
*/
public QName getComponentType()
{
return componentType;
}
/**
* Set the QName of the component if this is an array type
*/
public void setComponentType(QName componentType)
{
this.componentType = componentType;
}
public QName getItemQName() {
return itemQName;
}
public void setItemQName(QName itemQName) {
this.itemQName = itemQName;
}
/**
* Get string representation.
*
* @return
*/
public String toString() {
return toString("");
}
/**
* Get string representation with indentation
*
* @param indent
* @return
*/
protected String toString(String indent) {
String refString = indent + "RefType: null \n";
if (refType != null) {
refString = indent + "RefType:\n" + refType.toString(indent + " ")
+ "\n";
}
return super.toString(indent)
+ indent + "Class: " + this.getClass().getName() + "\n"
+ indent + "Base?: " + isBaseType + "\n"
+ indent + "Undefined?: " + undefined + "\n"
+ indent + "isSimpleType? " + isSimpleType + "\n"
+ indent + "Node: " + getNode() + "\n"
+ indent + "Dims: " + dims + "\n"
+ indent + "isOnlyLiteralReferenced: " + onlyLiteralReference + "\n"
+ refString;
}
/**
* 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 symbolTable is the symbolTable
* @param derivedFlag should be set if all dependendent derived types should also be
* returned.
* @return
*/
public HashSet getNestedTypes(SymbolTable symbolTable,
boolean derivedFlag) {
if( types == null) {
types = Utils.getNestedTypes(this, symbolTable, derivedFlag);
}
return types;
} // getNestedTypes
/**
* @return Returns the containedAttributes.
*/
public Vector getContainedAttributes() {
return containedAttributes;
}
/**
* @param containedAttributes The containedAttributes to set.
*/
public void setContainedAttributes(Vector containedAttributes) {
this.containedAttributes = containedAttributes;
}
/**
* @return Returns the containedElements.
*/
public Vector getContainedElements() {
return containedElements;
}
/**
* @param containedElements The containedElements to set.
*/
public void setContainedElements(Vector containedElements) {
this.containedElements = containedElements;
}
}
|