blob: 01a389e15dc15c881e31a1a1c6b4413f24f9c59d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002-2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*******************************************************************************/
package org.eclipse.wst.wsi.internal.core.util;
import java.util.Collection;
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 javax.wsdl.*;
import javax.wsdl.Import;
import javax.wsdl.Types;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.soap.*;
import javax.xml.namespace.QName;
import org.eclipse.wst.wsi.internal.core.WSITag;
import org.eclipse.wst.wsi.internal.core.profile.validator.BaseValidator;
import org.eclipse.wst.wsi.internal.core.wsdl.traversal.WSDLTraversal;
import org.eclipse.wst.wsi.internal.core.wsdl.traversal.WSDLTraversalContext;
import org.eclipse.wst.wsi.internal.core.wsdl.traversal.WSDLVisitor;
import org.eclipse.wst.wsi.internal.core.xml.XMLUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* The class extracts XSD schema information from the given WSDL.
*
* @author Kulik
*/
public final class TypesRegistry implements WSITag, WSDLVisitor
{
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(javax.wsdl.Part, java.lang.Object, org.wsi.wsdl.traversal.WSDLTraversalContext)
*/
public void visit(Part obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(javax.wsdl.Service, java.lang.Object, org.wsi.wsdl.traversal.WSDLTraversalContext)
*/
public void visit(Service obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Types, Object,
* WSDLTraversalContext)
*/
public void visit(Types obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Operation, Object,
* WSDLTraversalContext)
*/
public void visit(Operation obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Input, Object,
* WSDLTraversalContext)
*/
public void visit(Input obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Output, Object,
* WSDLTraversalContext)
*/
public void visit(Output obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Fault, Object,
* WSDLTraversalContext)
*/
public void visit(Fault obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Binding, Object,
* WSDLTraversalContext)
*/
public void visit(Binding obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(BindingOperation, Object,
* WSDLTraversalContext)
*/
public void visit(
BindingOperation obj,
Object parent,
WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(BindingInput, Object,
* WSDLTraversalContext)
*/
public void visit(BindingInput obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(BindingOutput, Object,
* WSDLTraversalContext)
*/
public void visit(BindingOutput obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(BindingFault, Object,
* WSDLTraversalContext)
*/
public void visit(BindingFault obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Element, Object,
* WSDLTraversalContext)
*/
public void visit(Element obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Message, Object,
* WSDLTraversalContext)
*/
public void visit(Message obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Port, Object,
* WSDLTraversalContext)
*/
public void visit(Port obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(PortType, Object,
* WSDLTraversalContext)
*/
public void visit(PortType obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(Definition, Object,
* WSDLTraversalContext)
*/
public void visit(Definition obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(ExtensibilityElement,
* Object, WSDLTraversalContext)
*/
public void visit(
ExtensibilityElement obj,
Object parent,
WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPBinding, Object,
* WSDLTraversalContext)
*/
public void visit(SOAPBinding obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPBody, Object,
* WSDLTraversalContext)
*/
public void visit(SOAPBody obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPHeader, Object,
* WSDLTraversalContext)
*/
public void visit(SOAPHeader obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPHeaderFault, Object,
* WSDLTraversalContext)
*/
public void visit(
SOAPHeaderFault obj,
Object parent,
WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPFault, Object,
* WSDLTraversalContext)
*/
public void visit(SOAPFault obj, Object parent, WSDLTraversalContext ctx)
{
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(SOAPOperation, Object,
* WSDLTraversalContext)
*/
public void visit(SOAPOperation obj, Object parent, WSDLTraversalContext ctx)
{
}
private Map element2Type = new HashMap();
private Set extendsArray = new HashSet();
private Set usesWsdlArrayType = new HashSet();
protected BaseValidator baseValidator = null;
/**
* Constructor creates the types registry. by the given WSDL definition
* object.
*
* @param def a WSDL definition.
* @param baseValidator a base validator.
*/
public TypesRegistry(Definition def, BaseValidator baseValidator)
{
this.baseValidator = baseValidator;
if (def == null)
throw new IllegalArgumentException("Definition can not be null");
WSDLTraversal traversal = new WSDLTraversal();
//VisitorAdaptor.adapt(this);
traversal.setVisitor(this);
traversal.visitImport(true);
processTypes(def.getTypes(), def.getDocumentBaseURI());
traversal.traverse(def);
}
/**
* Constructor creates the types registry by given WSDL types object and
* location context URI.
* @param types WSDL types object.
* @param context location context URI.
* @param baseValidator a base validator.
*/
public TypesRegistry(
Types types,
String context,
BaseValidator baseValidator)
{
this.baseValidator = baseValidator;
processTypes(types, context);
}
/**
* The method returns type's qname by given element's qname.
* @param elementName a qualified element name.
* @return type's qname by given element's qname.
*/
public QName getType(QName elementName)
{
return (QName) element2Type.get(elementName);
}
/**
* The method returns set of types which is array attribute.
* @return set of types which is array attribute.
*/
public Set getArrayTypes()
{
Set s = new HashSet();
s.addAll((Collection) usesWsdlArrayType);
s.addAll((Collection) extendsArray);
return s;
}
/**
* The method returns set of elements defined in types element.
* @return set of elements defined in types element.
*/
public Set getElementList()
{
return this.element2Type.keySet();
}
/**
* The method returns true if the given type declares wsdl:arrayType
* attribute within declaration.
* @param type a type.
* @return true if the given type declares wsdl:arrayType
* attribute within declaration.
*/
public boolean isUsesWSDLArrayType(QName type)
{
return usesWsdlArrayType.contains(type);
}
/**
* The method returns true if given type extends soapenc:Array type.
* @param type a type.
* @return true if given type extends soapenc:Array type.
*/
public boolean isExtendsArray(QName type)
{
return extendsArray.contains(type);
}
/* (non-Javadoc)
* @see org.wsi.wsdl.traversal.WSDLVisitor#visit(javax.wsdl.Import, java.lang.Object, org.wsi.wsdl.traversal.WSDLTraversalContext)
*/
public void visit(Import im, Object parent, WSDLTraversalContext ctx)
{
if (im.getDefinition() != null)
processWSDL(im.getDefinition());
}
/**
* Internal method processes WSDL definition.
* @param def a WSDL definition.
*/
private void processWSDL(Definition def)
{
if (def.getTypes() != null)
processTypes(def.getTypes(), def.getDocumentBaseURI());
}
/**
* Internal method processes WSDL types.
* @param types WSDL types.
* @param context a context.
*/
private void processTypes(Types types, String context)
{
if (types == null)
return;
List exts = types.getExtensibilityElements();
if (exts != null)
{
Iterator it = exts.iterator();
while (it.hasNext())
{
ExtensibilityElement el = (ExtensibilityElement) it.next();
if (el instanceof UnknownExtensibilityElement)
searchForSchema(
((UnknownExtensibilityElement) el).getElement(),
context);
}
}
}
/**
* Internal method searches XSD schema declaration and XSD import
* statements.
* @param n
* @param context
*/
private void searchForSchema(Node n, String context)
{
while (n != null)
{
// searches for xsd:import element
if (Node.ELEMENT_NODE == n.getNodeType())
{
// if xsd:schema element is found -> process schema
if (XMLUtils.equals(n, ELEM_XSD_SCHEMA))
processSchema(n, context);
else
// if xsd:import element is found -> load schema and process schema
if (XMLUtils.equals(n, ELEM_XSD_IMPORT))
loadSchema(n, context);
// if xsd:include element is found -> load schema and process schema
else if (XMLUtils.equals(n, ELEM_XSD_INCLUDE))
loadSchema(n, context);
else
// else iterate element recursively
searchForSchema(n.getFirstChild(), context);
}
n = n.getNextSibling();
}
}
/**
* Internal method loads XSD schema by using schema location and
* location context.
* @param importNode
* @param context
*/
private void loadSchema(Node importNode, String context)
{
Element im = (Element) importNode;
Attr schemaLocation = XMLUtils.getAttribute(im, ATTR_XSD_SCHEMALOCATION);
// try to parse imported XSD
if (schemaLocation != null && schemaLocation.getValue() != null)
try
{
// if any error or root element is not XSD schema -> error
Document schema =
baseValidator.parseXMLDocumentURL(
schemaLocation.getValue(),
context,
null);
if (XMLUtils.equals(schema.getDocumentElement(), ELEM_XSD_SCHEMA))
processSchema(
schema.getDocumentElement(),
XMLUtils.createURLString(schemaLocation.getValue(), context));
}
catch (Throwable t)
{
//t.printStackTrace();
// nothing. it's not a schema
}
}
/**
* Internal method processes XSD schema and retrieves types declaration from
* it.
* @param schema
* @param context
*/
private void processSchema(Node schema, String context)
{
Attr a = XMLUtils.getAttribute((Element) schema, ATTR_XSD_TARGETNAMESPACE);
String targetNamespace = (a != null) ? a.getValue() : "";
// iterate schema
Node n = schema.getFirstChild();
// !! we suppose that xsd:import element is occured only within xsd:schema element
while (n != null)
{
if (Node.ELEMENT_NODE == n.getNodeType())
{
if (XMLUtils.equals(n, ELEM_XSD_ELEMENT))
{
Element el = (Element) n;
a = XMLUtils.getAttribute(el, ATTR_XSD_NAME);
QName element =
new QName(targetNamespace, (a != null) ? a.getValue() : "");
a = XMLUtils.getAttribute(el, ATTR_XSD_TYPE);
QName type = null;
if (a != null)
{
String t = a.getValue();
// if type contains ':', it means that it contains qname
int i = t.indexOf(':');
if (i != -1)
{
String prefix = t.substring(0, i);
String nsURI = XMLUtils.findNamespaceURI(n, prefix);
type = new QName(nsURI, t.substring(i + 1));
}
else
type = new QName(targetNamespace, t);
}
else
{
// suppose that element directly contains type declaration
type = element;
checkType(n, type);
}
element2Type.put(element, type);
}
else if (XMLUtils.equals(n, ELEM_XSD_IMPORT))
loadSchema(n, context);
else if (XMLUtils.equals(n, ELEM_XSD_INCLUDE))
loadSchema(n, context);
else if (XMLUtils.equals(n, ELEM_XSD_COMPLEXTYPE))
{
Element el = (Element) n;
a = XMLUtils.getAttribute(el, ATTR_XSD_NAME);
QName type =
new QName(targetNamespace, (a != null) ? a.getValue() : "");
checkType(n, type);
}
}
n = n.getNextSibling();
}
}
/**
* Internal method checks whether specified type has WSDL array type
* attribute in the XSD declaration.
* @param n
* @param name
*/
private void checkType(Node n, QName name)
{
while (n != null)
{
if (Node.ELEMENT_NODE == n.getNodeType())
{
// check such sentence
// xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="tns:MyArray2Type[]"/>
if (XMLUtils.equals(n, ELEM_XSD_ATTRIBUTE))
{
Attr a = XMLUtils.getAttribute((Element) n, ATTR_WSDL_ARRAYTYPE);
if (a != null)
usesWsdlArrayType.add(name);
}
// retrieve base attribute may be from restriction or extension
Attr a = XMLUtils.getAttribute((Element) n, ATTR_XSD_BASE);
if (a != null)
{
String base = a.getValue();
int i = base.indexOf(":");
if (i != -1)
{
String prefix = base.substring(0, i);
String local = base.substring(i + 1);
String namespace = XMLUtils.findNamespaceURI(n, prefix);
if (SOAPENC_ARRAY.equals(new QName(namespace, local)))
extendsArray.add(name);
}
}
checkType(n.getFirstChild(), name);
}
n = n.getNextSibling();
}
}
}