
org.apache.axis.wsdl.symbolTable.SymbolTable Maven / Gradle / Ivy
/*
* 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.constants.Style;
import org.apache.axis.constants.Use;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.URLHashSet;
import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Import;
import javax.wsdl.Input;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Output;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.mime.MIMEContent;
import javax.wsdl.extensions.mime.MIMEMultipartRelated;
import javax.wsdl.extensions.mime.MIMEPart;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.wsdl.extensions.soap.SOAPFault;
import javax.wsdl.extensions.soap.SOAPHeader;
import javax.wsdl.extensions.soap.SOAPHeaderFault;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.rpc.holders.BooleanHolder;
import javax.xml.rpc.holders.IntHolder;
import javax.xml.rpc.holders.QNameHolder;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
/**
* This class represents a table of all of the top-level symbols from a set of WSDL Definitions and
* DOM Documents: XML types; WSDL messages, portTypes, bindings, and services.
*
* This symbolTable contains entries of the form where key is of type QName and value is
* of type Vector. The Vector's elements are all of the objects that have the given QName. This is
* necessary since names aren't unique among the WSDL types. message, portType, binding, service,
* could all have the same QName and are differentiated merely by type. SymbolTable contains
* type-specific getters to bypass the Vector layer:
* public PortTypeEntry getPortTypeEntry(QName name), etc.
*/
public class SymbolTable {
// used to cache dervied types
protected HashMap derivedTypes = new HashMap();
// Should the contents of imported files be added to the symbol table?
/** Field addImports */
private boolean addImports;
// The actual symbol table. This symbolTable contains entries of the form
// where key is of type QName and value is of type Vector. The
// Vector's elements are all of the objects that have the given QName. This
// is necessary since names aren't unique among the WSDL types. message,
// portType, binding, service, could all have the same QName and are
// differentiated merely by type. SymbolTable contains type-specific
// getters to bypass the Vector layer:
// public PortTypeEntry getPortTypeEntry(QName name), etc.
/** Field symbolTable */
private HashMap symbolTable = new HashMap();
// a map of qnames -> Elements in the symbol table
/** Field elementTypeEntries */
private final Map elementTypeEntries = new HashMap();
// an unmodifiable wrapper so that we can share the index with others, safely
/** Field elementIndex */
private final Map elementIndex =
Collections.unmodifiableMap(elementTypeEntries);
// a map of qnames -> Types in the symbol table
/** Field typeTypeEntries */
private final Map typeTypeEntries = new HashMap();
// an unmodifiable wrapper so that we can share the index with others, safely
/** Field typeIndex */
private final Map typeIndex = Collections.unmodifiableMap(typeTypeEntries);
/**
* cache of nodes -> base types for complexTypes. The cache is
* built on nodes because multiple TypeEntry objects may use the
* same node.
*/
protected final Map node2ExtensionBase =
new HashMap(); // allow friendly access
/** Field verbose */
private boolean verbose;
/** Field quiet */
protected boolean quiet;
/** Field btm */
private BaseTypeMapping btm = null;
// should we attempt to treat document/literal WSDL as "rpc-style"
/** Field nowrap */
private boolean nowrap;
// Did we encounter wraped mode WSDL
/** Field wrapped */
private boolean wrapped = false;
/** Field ANON_TOKEN */
public static final String ANON_TOKEN = ">";
/** Field def */
private Definition def = null;
/** Field wsdlURI */
private String wsdlURI = null;
/** If this is false, we will "unwrap" literal arrays, generating a plan "String[]" instead
* of "ArrayOfString" when encountering an element containing a single maxOccurs="unbounded"
* inner element.
*/
private boolean wrapArrays;
Set arrayTypeQNames = new HashSet();
/** Field elementFormDefaults */
private final Map elementFormDefaults = new HashMap();
/**
* Construct a symbol table with the given Namespaces.
*
* @param btm
* @param addImports
* @param verbose
* @param nowrap
*/
public SymbolTable(BaseTypeMapping btm, boolean addImports,
boolean verbose, boolean nowrap) {
this.btm = btm;
this.addImports = addImports;
this.verbose = verbose;
this.nowrap = nowrap;
} // ctor
/**
* Method isQuiet
*
* @return
*/
public boolean isQuiet() {
return quiet;
}
/**
* Method setQuiet
*
* @param quiet
*/
public void setQuiet(boolean quiet) {
this.quiet = quiet;
}
/**
* Get the raw symbol table HashMap.
*
* @return
*/
public HashMap getHashMap() {
return symbolTable;
} // getHashMap
/**
* Get the list of entries with the given QName. Since symbols can share QNames, this list is
* necessary. This list will not contain any more than one element of any given SymTabEntry.
*
* @param qname
* @return
*/
public Vector getSymbols(QName qname) {
return (Vector) symbolTable.get(qname);
} // get
/**
* Get the entry with the given QName of the given class. If it does not exist, return null.
*
* @param qname
* @param cls
* @return
*/
public SymTabEntry get(QName qname, Class cls) {
Vector v = (Vector) symbolTable.get(qname);
if (v == null) {
return null;
} else {
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (cls.isInstance(entry)) {
return entry;
}
}
return null;
}
} // get
/**
* Get the type entry for the given qname.
*
* @param qname
* @param wantElementType boolean that indicates type or element (for type= or ref=)
* @return
*/
public TypeEntry getTypeEntry(QName qname, boolean wantElementType) {
if (wantElementType) {
return getElement(qname);
} else {
return getType(qname);
}
} // getTypeEntry
/**
* Get the Type TypeEntry with the given QName. If it doesn't
* exist, return null.
*
* @param qname
* @return
*/
public Type getType(QName qname) {
return (Type) typeTypeEntries.get(qname);
} // getType
/**
* Get the Element TypeEntry with the given QName. If it doesn't
* exist, return null.
*
* @param qname
* @return
*/
public Element getElement(QName qname) {
return (Element) elementTypeEntries.get(qname);
} // getElement
/**
* Get the MessageEntry with the given QName. If it doesn't exist, return null.
*
* @param qname
* @return
*/
public MessageEntry getMessageEntry(QName qname) {
return (MessageEntry) get(qname, MessageEntry.class);
} // getMessageEntry
/**
* Get the PortTypeEntry with the given QName. If it doesn't exist, return null.
*
* @param qname
* @return
*/
public PortTypeEntry getPortTypeEntry(QName qname) {
return (PortTypeEntry) get(qname, PortTypeEntry.class);
} // getPortTypeEntry
/**
* Get the BindingEntry with the given QName. If it doesn't exist, return null.
*
* @param qname
* @return
*/
public BindingEntry getBindingEntry(QName qname) {
return (BindingEntry) get(qname, BindingEntry.class);
} // getBindingEntry
/**
* Get the ServiceEntry with the given QName. If it doesn't exist, return null.
*
* @param qname
* @return
*/
public ServiceEntry getServiceEntry(QName qname) {
return (ServiceEntry) get(qname, ServiceEntry.class);
} // getServiceEntry
/**
* Get the list of all the XML schema types in the symbol table. In other words, all entries
* that are instances of TypeEntry.
*
* @return
* @deprecated use specialized get{Element,Type}Index() methods instead
*/
public Vector getTypes() {
Vector v = new Vector();
v.addAll(elementTypeEntries.values());
v.addAll(typeTypeEntries.values());
return v;
} // getTypes
/**
* Return an unmodifiable map of qnames -> Elements in the symbol
* table.
*
* @return an unmodifiable Map
value
*/
public Map getElementIndex() {
return elementIndex;
}
/**
* Return an unmodifiable map of qnames -> Elements in the symbol
* table.
*
* @return an unmodifiable Map
value
*/
public Map getTypeIndex() {
return typeIndex;
}
/**
* Return the count of TypeEntries in the symbol table.
*
* @return an int
value
*/
public int getTypeEntryCount() {
return elementTypeEntries.size() + typeTypeEntries.size();
}
/**
* Get the Definition. The definition is null until
* populate is called.
*
* @return
*/
public Definition getDefinition() {
return def;
} // getDefinition
/**
* Get the WSDL URI. The WSDL URI is null until populate
* is called, and ONLY if a WSDL URI is provided.
*
* @return
*/
public String getWSDLURI() {
return wsdlURI;
} // getWSDLURI
/**
* Are we wrapping literal soap body elements.
*
* @return
*/
public boolean isWrapped() {
return wrapped;
}
/**
* Turn on/off element wrapping for literal soap body's.
*
* @param wrapped
*/
public void setWrapped(boolean wrapped) {
this.wrapped = wrapped;
}
/**
* Dump the contents of the symbol table. For debugging purposes only.
*
* @param out
*/
public void dump(java.io.PrintStream out) {
out.println();
out.println(Messages.getMessage("symbolTable00"));
out.println("-----------------------");
Iterator it = symbolTable.values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
out.println(v.elementAt(i).getClass().getName());
out.println(v.elementAt(i));
}
}
out.println("-----------------------");
} // dump
/**
* Call this method if you have a uri for the WSDL document
*
* @param uri wsdlURI the location of the WSDL file.
* @throws IOException
* @throws WSDLException
* @throws SAXException
* @throws ParserConfigurationException
*/
public void populate(String uri)
throws IOException, WSDLException, SAXException,
ParserConfigurationException {
populate(uri, null, null);
} // populate
/**
* Method populate
*
* @param uri
* @param username
* @param password
* @throws IOException
* @throws WSDLException
* @throws SAXException
* @throws ParserConfigurationException
*/
public void populate(String uri, String username, String password)
throws IOException, WSDLException, SAXException,
ParserConfigurationException {
if (verbose) {
System.out.println(Messages.getMessage("parsing00", uri));
}
Document doc = XMLUtils.newDocument(uri, username, password);
this.wsdlURI = uri;
try {
File f = new File(uri);
if (f.exists()) {
uri = f.toURL().toString();
}
} catch (Exception e) {
}
populate(uri, doc);
} // populate
/**
* Call this method if your WSDL document has already been parsed as an XML DOM document.
*
* @param context context This is directory context for the Document. If the Document were from file "/x/y/z.wsdl" then the context could be "/x/y" (even "/x/y/z.wsdl" would work). If context is null, then the context becomes the current directory.
* @param doc doc This is the XML Document containing the WSDL.
* @throws IOException
* @throws SAXException
* @throws WSDLException
* @throws ParserConfigurationException
*/
public void populate(String context, Document doc)
throws IOException, SAXException, WSDLException,
ParserConfigurationException {
WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
reader.setFeature("javax.wsdl.verbose", verbose);
this.def = reader.readWSDL(context, doc);
add(context, def, doc);
} // populate
/**
* Add the given Definition and Document information to the symbol table (including imported
* symbols), populating it with SymTabEntries for each of the top-level symbols. When the
* symbol table has been populated, iterate through it, setting the isReferenced flag
* appropriately for each entry.
*
* @param context
* @param def
* @param doc
* @throws IOException
* @throws SAXException
* @throws WSDLException
* @throws ParserConfigurationException
*/
protected void add(String context, Definition def, Document doc)
throws IOException, SAXException, WSDLException,
ParserConfigurationException {
URL contextURL = (context == null)
? null
: getURL(null, context);
populate(contextURL, def, doc, null);
processTypes();
checkForUndefined();
populateParameters();
setReferences(def, doc); // uses wrapped flag set in populateParameters
} // add
/**
* Scan the Definition for undefined objects and throw an error.
*
* @param def
* @param filename
* @throws IOException
*/
private void checkForUndefined(Definition def, String filename)
throws IOException {
if (def != null) {
// Bindings
Iterator ib = def.getBindings().values().iterator();
while (ib.hasNext()) {
Binding binding = (Binding) ib.next();
if (binding.isUndefined()) {
if (filename == null) {
throw new IOException(
Messages.getMessage(
"emitFailtUndefinedBinding01",
binding.getQName().getLocalPart()));
} else {
throw new IOException(
Messages.getMessage(
"emitFailtUndefinedBinding02",
binding.getQName().getLocalPart(), filename));
}
}
}
// portTypes
Iterator ip = def.getPortTypes().values().iterator();
while (ip.hasNext()) {
PortType portType = (PortType) ip.next();
if (portType.isUndefined()) {
if (filename == null) {
throw new IOException(
Messages.getMessage(
"emitFailtUndefinedPort01",
portType.getQName().getLocalPart()));
} else {
throw new IOException(
Messages.getMessage(
"emitFailtUndefinedPort02",
portType.getQName().getLocalPart(), filename));
}
}
}
/*
* tomj: This is a bad idea, faults seem to be undefined
* / RJB reply: this MUST be done for those systems that do something with
* / messages. Perhaps we have to do an extra step for faults? I'll leave
* / this commented for now, until someone uses this generator for something
* / other than WSDL2Java.
* // Messages
* Iterator i = def.getMessages().values().iterator();
* while (i.hasNext()) {
* Message message = (Message) i.next();
* if (message.isUndefined()) {
* throw new IOException(
* Messages.getMessage("emitFailtUndefinedMessage01",
* message.getQName().getLocalPart()));
* }
* }
*/
}
}
/**
* Scan the symbol table for undefined types and throw an exception.
*
* @throws IOException
*/
private void checkForUndefined() throws IOException {
Iterator it = symbolTable.values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.get(i);
// Report undefined types
if (entry instanceof UndefinedType) {
QName qn = entry.getQName();
// Special case dateTime/timeInstant that changed
// from version to version.
if ((qn.getLocalPart().equals(
"dateTime") && !qn.getNamespaceURI().equals(
Constants.URI_2001_SCHEMA_XSD)) || (qn.getLocalPart().equals(
"timeInstant") && qn.getNamespaceURI().equals(
Constants.URI_2001_SCHEMA_XSD))) {
throw new IOException(
Messages.getMessage(
"wrongNamespace00", qn.getLocalPart(),
qn.getNamespaceURI()));
}
// Check for a undefined XSD Schema Type and throw
// an unsupported message instead of undefined
if (SchemaUtils.isSimpleSchemaType(qn)) {
throw new IOException(
Messages.getMessage(
"unsupportedSchemaType00", qn.getLocalPart()));
}
// last case, its some other undefined thing
throw new IOException(
Messages.getMessage(
"undefined00", qn.toString()));
} // if undefined
else if (entry instanceof UndefinedElement) {
throw new IOException(
Messages.getMessage(
"undefinedElem00", entry.getQName().toString()));
}
}
}
} // checkForUndefined
/**
* Add the given Definition and Document information to the symbol table (including imported
* symbols), populating it with SymTabEntries for each of the top-level symbols.
* NOTE: filename is used only by checkForUndefined so that it can report which WSDL file
* has the problem. If we're on the primary WSDL file, then we don't know the name and
* filename will be null. But we know the names of all imported files.
*/
private URLHashSet importedFiles = new URLHashSet();
/**
* Method populate
*
* @param context
* @param def
* @param doc
* @param filename
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
* @throws WSDLException
*/
private void populate(
URL context, Definition def, Document doc, String filename)
throws IOException, ParserConfigurationException, SAXException,
WSDLException {
if (doc != null) {
populateTypes(context, doc);
if (addImports) {
// Add the symbols from any xsd:import'ed documents.
lookForImports(context, doc);
}
}
if (def != null) {
checkForUndefined(def, filename);
if (addImports) {
// Add the symbols from the wsdl:import'ed WSDL documents
Map imports = def.getImports();
Object[] importKeys = imports.keySet().toArray();
for (int i = 0; i < importKeys.length; ++i) {
Vector v = (Vector) imports.get(importKeys[i]);
for (int j = 0; j < v.size(); ++j) {
Import imp = (Import) v.get(j);
if (!importedFiles.contains(imp.getLocationURI())) {
importedFiles.add(imp.getLocationURI());
URL url = getURL(context, imp.getLocationURI());
populate(url, imp.getDefinition(),
XMLUtils.newDocument(url.toString()),
url.toString());
}
}
}
}
populateMessages(def);
populatePortTypes(def);
populateBindings(def);
populateServices(def);
}
} // populate
/**
* This is essentially a call to "new URL(contextURL, spec)" with extra handling in case spec is
* a file.
*
* @param contextURL
* @param spec
* @return
* @throws IOException
*/
private static URL getURL(URL contextURL, String spec) throws IOException {
// First, fix the slashes as windows filenames may have backslashes
// in them, but the URL class wont do the right thing when we later
// process this URL as the contextURL.
String path = spec.replace('\\', '/');
// See if we have a good URL.
URL url = null;
try {
// first, try to treat spec as a full URL
url = new URL(contextURL, path);
// if we are deail with files in both cases, create a url
// by using the directory of the context URL.
if ((contextURL != null) && url.getProtocol().equals("file")
&& contextURL.getProtocol().equals("file")) {
url = getFileURL(contextURL, path);
}
} catch (MalformedURLException me) {
// try treating is as a file pathname
url = getFileURL(contextURL, path);
}
// Everything is OK with this URL, although a file url constructed
// above may not exist. This will be caught later when the URL is
// accessed.
return url;
} // getURL
/**
* Method getFileURL
*
* @param contextURL
* @param path
* @return
* @throws IOException
*/
private static URL getFileURL(URL contextURL, String path)
throws IOException {
if (contextURL != null) {
// get the parent directory of the contextURL, and append
// the spec string to the end.
String contextFileName = contextURL.getFile();
URL parent = null;
File parentFile = new File(contextFileName).getParentFile();
if ( parentFile != null ) {
parent = parentFile.toURL();
}
if (parent != null) {
return new URL(parent, path);
}
}
return new URL("file", "", path);
} // getFileURL
/**
* Recursively find all xsd:import'ed objects and call populate for each one.
*
* @param context
* @param node
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
* @throws WSDLException
*/
private void lookForImports(URL context, Node node)
throws IOException, ParserConfigurationException, SAXException,
WSDLException {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if ("import".equals(child.getLocalName())) {
NamedNodeMap attributes = child.getAttributes();
Node namespace = attributes.getNamedItem("namespace");
// skip XSD import of soap encoding
if ((namespace != null)
&& isKnownNamespace(namespace.getNodeValue())) {
continue;
}
Node importFile = attributes.getNamedItem("schemaLocation");
if (importFile != null) {
URL url = getURL(context, importFile.getNodeValue());
if (!importedFiles.contains(url)) {
importedFiles.add(url);
String filename = url.toString();
populate(url, null, XMLUtils.newDocument(filename),
filename);
}
}
}
lookForImports(context, child);
}
} // lookForImports
/**
* Check if this is a known namespace (soap-enc or schema xsd or schema xsi or xml)
*
* @param namespace
* @return true if this is a know namespace.
*/
public boolean isKnownNamespace(String namespace) {
if (Constants.isSOAP_ENC(namespace)) {
return true;
}
if (Constants.isSchemaXSD(namespace)) {
return true;
}
if (Constants.isSchemaXSI(namespace)) {
return true;
}
if (namespace.equals(Constants.NS_URI_XML)) {
return true;
}
return false;
}
/**
* Populate the symbol table with all of the Types from the Document.
*
* @param context
* @param doc
* @throws IOException
* @throws SAXException
* @throws WSDLException
* @throws ParserConfigurationException
*/
public void populateTypes(URL context, Document doc)
throws IOException, SAXException, WSDLException,
ParserConfigurationException {
addTypes(context, doc, ABOVE_SCHEMA_LEVEL);
} // populateTypes
/**
* Utility method which walks the Document and creates Type objects for
* each complexType, simpleType, attributeGroup or element referenced or defined.
*
* What goes into the symbol table? In general, only the top-level types
* (ie., those just below
* the schema tag). But base types and references can
* appear below the top level. So anything
* at the top level is added to the symbol table,
* plus non-Element types (ie, base and refd)
* that appear deep within other types.
*/
private static final int ABOVE_SCHEMA_LEVEL = -1;
/** Field SCHEMA_LEVEL */
private static final int SCHEMA_LEVEL = 0;
/**
* Method addTypes
*
* @param context
* @param node
* @param level
* @throws IOException
* @throws ParserConfigurationException
* @throws WSDLException
* @throws SAXException
*/
private void addTypes(URL context, Node node, int level)
throws IOException, ParserConfigurationException, WSDLException,
SAXException {
if (node == null) {
return;
}
// Get the kind of node (complexType, wsdl:part, etc.)
String localPart = node.getLocalName();
if (localPart != null) {
boolean isXSD =
Constants.isSchemaXSD(node.getNamespaceURI());
if (((isXSD && localPart.equals("complexType"))
|| localPart.equals("simpleType"))) {
// If an extension or restriction is present,
// create a type for the reference
Node re = SchemaUtils.getRestrictionOrExtensionNode(node);
if ((re != null) && (Utils.getAttribute(re, "base") != null)) {
createTypeFromRef(re);
}
Node list = SchemaUtils.getListNode(node);
if (list != null && Utils.getAttribute(list,"itemType") != null) {
createTypeFromRef(list);
}
Node union = SchemaUtils.getUnionNode(node);
if (union != null) {
QName [] memberTypes = Utils.getMemberTypeQNames(union);
if (memberTypes != null) {
for (int i=0;i SCHEMA_LEVEL);
} else if (isXSD && localPart.equals("attributeGroup")) {
// bug 23145: support attributeGroup (Brook Richan)
// Create a type entry for the referenced type
createTypeFromRef(node);
// Create a type representing an attributeGroup.
createTypeFromDef(node, false, level > SCHEMA_LEVEL);
} else if (isXSD && localPart.equals("group")) {
// Create a type entry for the referenced type
createTypeFromRef(node);
// Create a type representing an group
createTypeFromDef(node, false, level > SCHEMA_LEVEL);
} else if (isXSD && localPart.equals("attribute")) {
// Create a type entry for the referenced type
BooleanHolder forElement = new BooleanHolder();
QName refQName = Utils.getTypeQName(node, forElement,
false);
if ((refQName != null) && !forElement.value) {
createTypeFromRef(node);
// Get the symbol table entry and make sure it is a simple
// type
if (refQName != null) {
TypeEntry refType = getTypeEntry(refQName, false);
if ((refType != null)
&& (refType instanceof Undefined)) {
// Don't know what the type is.
// It better be simple so set it as simple
refType.setSimpleType(true);
} else if ((refType == null)
|| (!(refType instanceof BaseType)
&& !refType.isSimpleType())) {
// Problem if not simple
throw new IOException(
Messages.getMessage(
"AttrNotSimpleType01",
refQName.toString()));
}
}
}
createTypeFromDef(node, true, level > SCHEMA_LEVEL);
} else if (isXSD && localPart.equals("any")) {
// Map xsd:any element to special xsd:any "type"
if (getType(Constants.XSD_ANY) == null) {
Type type = new BaseType(Constants.XSD_ANY);
symbolTablePut(type);
}
} else if (localPart.equals("part")
&& Constants.isWSDL(node.getNamespaceURI())) {
// This is a wsdl part. Create an TypeEntry representing the reference
createTypeFromRef(node);
} else if (isXSD && localPart.equals("include")) {
String includeName = Utils.getAttribute(node, "schemaLocation");
if (includeName != null) {
URL url = getURL(context, includeName);
Document includeDoc = XMLUtils.newDocument(url.toString());
// Vidyanand : Fix for Bug #15124
org.w3c.dom.Element schemaEl =
includeDoc.getDocumentElement();
if (!schemaEl.hasAttribute("targetNamespace")) {
org.w3c.dom.Element parentSchemaEl =
(org.w3c.dom.Element) node.getParentNode();
if (parentSchemaEl.hasAttribute("targetNamespace")) {
// we need to set two things in here
// 1. targetNamespace
// 2. setup the xmlns= attribute
String tns =
parentSchemaEl.getAttribute("targetNamespace");
schemaEl.setAttribute("targetNamespace", tns);
schemaEl.setAttribute("xmlns", tns);
}
}
populate(url, null, includeDoc, url.toString());
}
}
}
if (level == ABOVE_SCHEMA_LEVEL) {
if ((localPart != null)
&& localPart.equals("schema")) {
level = SCHEMA_LEVEL;
String targetNamespace = ((org.w3c.dom.Element) node).getAttribute("targetNamespace");
String elementFormDefault = ((org.w3c.dom.Element) node).getAttribute("elementFormDefault");
if (targetNamespace != null && targetNamespace.length() > 0) {
elementFormDefault = (elementFormDefault == null || elementFormDefault.length() == 0) ?
"unqualified" : elementFormDefault;
if(elementFormDefaults.get(targetNamespace)==null) {
elementFormDefaults.put(targetNamespace, elementFormDefault);
}
}
}
} else {
++level;
}
// Recurse through children nodes
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
addTypes(context, children.item(i), level);
}
} // addTypes
/**
* Create a TypeEntry from the indicated node, which defines a type
* that represents a complexType, simpleType or element (for ref=).
*
* @param node
* @param isElement
* @param belowSchemaLevel
* @throws IOException
*/
private void createTypeFromDef(
Node node, boolean isElement, boolean belowSchemaLevel)
throws IOException {
// Get the QName of the node's name attribute value
QName qName = Utils.getNodeNameQName(node);
if (qName != null) {
// If the qname is already registered as a base type,
// don't create a defining type/element.
if (!isElement && (btm.getBaseName(qName) != null)) {
return;
}
// If the node has a type or ref attribute, get the
// qname representing the type
BooleanHolder forElement = new BooleanHolder();
QName refQName = Utils.getTypeQName(node, forElement,
false);
if (refQName != null) {
// Error check - bug 12362
if (qName.getLocalPart().length() == 0) {
String name = Utils.getAttribute(node, "name");
if (name == null) {
name = "unknown";
}
throw new IOException(Messages.getMessage("emptyref00",
name));
}
// Now get the TypeEntry
TypeEntry refType = getTypeEntry(refQName, forElement.value);
if (!belowSchemaLevel) {
if (refType == null) {
throw new IOException(
Messages.getMessage(
"absentRef00", refQName.toString(),
qName.toString()));
}
symbolTablePut(new DefinedElement(qName, refType, node,
""));
}
} else {
// Flow to here indicates no type= or ref= attribute.
// See if this is an array or simple type definition.
IntHolder numDims = new IntHolder();
BooleanHolder underlTypeNillable = new BooleanHolder();
// If we're supposed to unwrap arrays, supply someplace to put the "inner" QName
// so we can propagate it into the appropriate metadata container.
QNameHolder itemQName = wrapArrays ? null : new QNameHolder();
BooleanHolder forElement2 = new BooleanHolder();
numDims.value = 0;
QName arrayEQName =
SchemaUtils.getArrayComponentQName(node,
numDims,
underlTypeNillable,
itemQName,
forElement2,
this);
if (arrayEQName != null) {
// Get the TypeEntry for the array element type
refQName = arrayEQName;
TypeEntry refType = getTypeEntry(refQName, forElement2.value);
if (refType == null) {
// arrayTypeQNames.add(refQName);
// Not defined yet, add one
String baseName = btm.getBaseName(refQName);
if (baseName != null) {
refType = new BaseType(refQName);
} else if(forElement2.value) {
refType = new UndefinedElement(refQName);
} else {
refType = new UndefinedType(refQName);
}
symbolTablePut(refType);
}
// Create a defined type or element that references refType
String dims = "";
while (numDims.value > 0) {
dims += "[]";
numDims.value--;
}
TypeEntry defType = null;
if (isElement) {
if (!belowSchemaLevel) {
defType =
new DefinedElement(qName, refType, node, dims);
// Save component type for ArraySerializer
defType.setComponentType(arrayEQName);
if (itemQName != null)
defType.setItemQName(itemQName.value);
}
} else {
defType = new DefinedType(qName, refType, node, dims);
// Save component type for ArraySerializer
defType.setComponentType(arrayEQName);
defType.setUnderlTypeNillable(underlTypeNillable.value);
if (itemQName != null)
defType.setItemQName(itemQName.value);
}
if (defType != null) {
symbolTablePut(defType);
}
} else {
// Create a TypeEntry representing this type/element
String baseName = btm.getBaseName(qName);
if (baseName != null) {
symbolTablePut(new BaseType(qName));
} else {
// Create a type entry, set whether it should
// be mapped as a simple type, and put it in the
// symbol table.
TypeEntry te = null;
TypeEntry parentType = null;
if (!isElement) {
te = new DefinedType(qName, node);
// check if we are an anonymous type underneath
// an element. If so, we point the refType of the
// element to us (the real type).
if (qName.getLocalPart().indexOf(ANON_TOKEN) >= 0) {
Node parent = node.getParentNode();
QName parentQName =
Utils.getNodeNameQName(parent);
parentType = getElement(parentQName);
}
} else {
if (!belowSchemaLevel) {
te = new DefinedElement(qName, node);
}
}
if (te != null) {
if (SchemaUtils.isSimpleTypeOrSimpleContent(node)) {
te.setSimpleType(true);
}
te = (TypeEntry)symbolTablePut(te);
if (parentType != null) {
parentType.setRefType(te);
}
}
}
}
}
}
} // createTypeFromDef
/**
* Node may contain a reference (via type=, ref=, or element= attributes) to
* another type. Create a Type object representing this referenced type.
*
* @param node
* @throws IOException
*/
protected void createTypeFromRef(Node node) throws IOException {
// Get the QName of the node's type attribute value
BooleanHolder forElement = new BooleanHolder();
QName qName = Utils.getTypeQName(node, forElement, false);
if (qName == null || (Constants.isSchemaXSD(qName.getNamespaceURI()) &&
qName.getLocalPart().equals("simpleRestrictionModel"))) {
return;
}
// Error check - bug 12362
if (qName.getLocalPart().length() == 0) {
String name = Utils.getAttribute(node, "name");
if (name == null) {
name = "unknown";
}
throw new IOException(Messages.getMessage("emptyref00", name));
}
// Get Type or Element depending on whether type attr was used.
TypeEntry type = getTypeEntry(qName, forElement.value);
// A symbol table entry is created if the TypeEntry is not found
if (type == null) {
// See if this is a special QName for collections
if (qName.getLocalPart().indexOf("[") > 0) {
QName containedQName = Utils.getTypeQName(node,
forElement, true);
TypeEntry containedTE = getTypeEntry(containedQName,
forElement.value);
if (!forElement.value) {
// Case of type and maxOccurs
if (containedTE == null) {
// Collection Element Type not defined yet, add one.
String baseName = btm.getBaseName(containedQName);
if (baseName != null) {
containedTE = new BaseType(containedQName);
} else {
containedTE = new UndefinedType(containedQName);
}
symbolTablePut(containedTE);
}
boolean wrapped = qName.getLocalPart().endsWith("wrapped");
symbolTablePut(new CollectionType(qName, containedTE,
node, "[]", wrapped));
} else {
// Case of ref and maxOccurs
if (containedTE == null) {
containedTE = new UndefinedElement(containedQName);
symbolTablePut(containedTE);
}
symbolTablePut(new CollectionElement(qName,
containedTE, node,
"[]"));
}
} else {
// Add a BaseType or Undefined Type/Element
String baseName = btm.getBaseName(qName);
if (baseName != null) {
symbolTablePut(new BaseType(qName));
// bugzilla 23145: handle attribute groups
// soap/encoding is treated as a "known" schema
// so now let's act like we know it
} else if (qName.equals(Constants.SOAP_COMMON_ATTRS11)) {
symbolTablePut(new BaseType(qName));
// the 1.1 commonAttributes type contains two attributes
// make sure those attributes' types are in the symbol table
// attribute name = "id" type = "xsd:ID"
if (getTypeEntry(Constants.XSD_ID, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_ID));
}
// attribute name = "href" type = "xsd:anyURI"
if (getTypeEntry(Constants.XSD_ANYURI, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_ANYURI));
}
} else if (qName.equals(Constants.SOAP_COMMON_ATTRS12)) {
symbolTablePut(new BaseType(qName));
// the 1.2 commonAttributes type contains one attribute
// make sure the attribute's type is in the symbol table
// attribute name = "id" type = "xsd:ID"
if (getTypeEntry(Constants.XSD_ID, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_ID));
}
} else if (qName.equals(Constants.SOAP_ARRAY_ATTRS11)) {
symbolTablePut(new BaseType(qName));
// the 1.1 arrayAttributes type contains two attributes
// make sure the attributes' types are in the symbol table
// attribute name = "arrayType" type = "xsd:string"
if (getTypeEntry(Constants.XSD_STRING, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_STRING));
}
// attribute name = "offset" type = "soapenc:arrayCoordinate"
// which is really an xsd:string
} else if (qName.equals(Constants.SOAP_ARRAY_ATTRS12)) {
symbolTablePut(new BaseType(qName));
// the 1.2 arrayAttributes type contains two attributes
// make sure the attributes' types are in the symbol table
// attribute name = "arraySize" type = "2003soapenc:arraySize"
// which is really a hairy beast that is not
// supported, yet; so let's just use string
if (getTypeEntry(Constants.XSD_STRING, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_STRING));
}
// attribute name = "itemType" type = "xsd:QName"
if (getTypeEntry(Constants.XSD_QNAME, false) == null) {
symbolTablePut(new BaseType(Constants.XSD_QNAME));
}
} else if (forElement.value == false) {
symbolTablePut(new UndefinedType(qName));
} else {
symbolTablePut(new UndefinedElement(qName));
}
}
}
} // createTypeFromRef
/**
* Populate the symbol table with all of the MessageEntry's from the Definition.
*
* @param def
* @throws IOException
*/
private void populateMessages(Definition def) throws IOException {
Iterator i = def.getMessages().values().iterator();
while (i.hasNext()) {
Message message = (Message) i.next();
MessageEntry mEntry = new MessageEntry(message);
symbolTablePut(mEntry);
}
} // populateMessages
/**
* ensures that a message in a <input>
, <output>
,
* or <fault> element in an <operation>
* element is valid. In particular, ensures that
*
* - an attribute
message
is present (according to the
* XML Schema for WSDL 1.1 message
is required
*
* - the value of attribute
message
(a QName) refers to
* an already defined message
*
*
* Note: this method should throw a javax.wsdl.WSDLException
rather than
* a java.io.IOException
*
* @param message the message object
* @throws IOException thrown, if the message is not valid
*/
protected void ensureOperationMessageValid(Message message)
throws IOException {
// make sure the message is not null (i.e. there is an
// attribute 'message ')
//
if (message == null) {
throw new IOException(
",
© 2015 - 2025 Weber Informatics LLC | Privacy Policy