blob: 06b02e9a2b3e8e1f47daea33a73a32d831f4cad7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 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 Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.model.util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.QName;
import org.eclipse.bpel.model.messageproperties.MessagepropertiesPackage;
import org.eclipse.bpel.model.messageproperties.Property;
import org.eclipse.bpel.model.partnerlinktype.PartnerLinkType;
import org.eclipse.bpel.model.partnerlinktype.PartnerlinktypePackage;
import org.eclipse.bpel.model.partnerlinktype.Role;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.Message;
import org.eclipse.wst.wsdl.Operation;
import org.eclipse.wst.wsdl.Part;
import org.eclipse.wst.wsdl.PortType;
import org.eclipse.wst.wsdl.Service;
import org.eclipse.wst.wsdl.Types;
import org.eclipse.wst.wsdl.WSDLPackage;
import org.eclipse.wst.wsdl.XSDSchemaExtensibilityElement;
import org.eclipse.wst.wsdl.internal.impl.ImportImpl;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDPackage;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.impl.XSDSchemaImpl;
import org.eclipse.xsd.util.XSDConstants;
/**
* WSDLUtil supplies resolution (lookup) of various things that are useful in the BPEL
* world.
*
*/
public class WSDLUtil
{
/** The WSDL Message attribute/name, most likely "message" */
public static final String WSDL_MESSAGE = WSDLPackage.eINSTANCE.getMessage().getName();
/** The WSDL Port Type attribute/name, most likely "portType" */
public static final String WSDL_PORT_TYPE = WSDLPackage.eINSTANCE.getPortType().getName();
/** The WSDL Operation attribute/name, most likely "operation" */
public static final String WSDL_OPERATION = WSDLPackage.eINSTANCE.getOperation().getName();
/** The WSDL Part attribute/name, most likely "part" */
public static final String WSDL_PART = WSDLPackage.eINSTANCE.getPart().getName();
/** The WSDL Service attribute/name, most likely "service" */
public static final String WSDL_SERVICE = WSDLPackage.eINSTANCE.getService().getName();
/** The XSD Type Definition attribute/name, most likely "type" */
public static final String XSD_TYPE_DEFINITION = XSDPackage.eINSTANCE.getXSDTypeDefinition().getName();
/** The XSD Element Declaration attribute/name, most likely "element" */
public static final String XSD_ELEMENT_DECLARATION = XSDPackage.eINSTANCE.getXSDElementDeclaration().getName();
/** The BPEL Partner Link Type attribute/name, most likely "partnerLinkType" */
public static final String BPEL_PARTNER_LINK_TYPE = PartnerlinktypePackage.eINSTANCE.getPartnerLinkType().getName();
/** The BPEL Role attribute/name, most likely "role" */
public static final String BPEL_ROLE = PartnerlinktypePackage.eINSTANCE.getRole().getName();
/** The BPEL Property attribute/name, most likely "property" */
public static final String BPEL_PROPERTY = MessagepropertiesPackage.eINSTANCE.getProperty().getName();
/** This should be a preference that can be easily turned on/off */
private static boolean RESOLVING_DEEPLY = true; // TODO: Preference based ?
/**
* Answer true if the type name passed is a WSDL thing.
*
* @param typeName
* @return true if yes, false if no.
*/
public static boolean isWSDLType(String typeName)
{
return typeName == null ? false :
WSDL_MESSAGE.equals(typeName)
|| WSDL_PORT_TYPE.equals(typeName)
|| WSDL_OPERATION.equals(typeName)
|| WSDL_PART.equals(typeName)
|| WSDL_SERVICE.equals(typeName)
|| XSD_TYPE_DEFINITION.equals(typeName)
|| XSD_ELEMENT_DECLARATION.equals(typeName)
|| BPEL_PARTNER_LINK_TYPE.equals(typeName)
|| BPEL_ROLE.equals(typeName)
|| BPEL_PROPERTY.equals(typeName);
}
/**
* Set to resolve deeply.
* @param resolveDeeply
*/
public static void setResolveDeeply ( boolean resolveDeeply ) {
RESOLVING_DEEPLY = resolveDeeply;
}
/**
* Answer if resolving deeply.
* @return answer true if resolving deeply, false otherwise.
*/
public static boolean isResolvingDeeply () {
return RESOLVING_DEEPLY;
}
/**
* Resolve with the given definition the QName given.
* @param definition the definition to use.
* @param qname the QName to resolve.
* @param name
* @param refType what to resolve (that things from WSDL that we can resolve).
* @return the EMF object that the QName resolves to.
*/
public static EObject resolveWSDLReference(Definition definition, QName qname, String name, String refType)
{
EObject resolvedObject = null;
if (WSDL_PORT_TYPE.equals(refType)) {
resolvedObject = resolvePortType(definition, qname);
} else if (WSDL_MESSAGE.equals(refType)) {
resolvedObject = resolveMessage(definition, qname);
} else if (WSDL_OPERATION.equals(refType)) {
resolvedObject = resolveOperation(definition, qname, name);
} else if (WSDL_PART.equals(refType)) {
resolvedObject = resolvePart(definition, qname, name);
} else if (WSDL_SERVICE.equals(refType)) {
resolvedObject = resolveService(definition, qname);
} else if (XSD_TYPE_DEFINITION.equals(refType)) {
resolvedObject = resolveXSDTypeDefinition(definition, qname);
} else if (XSD_ELEMENT_DECLARATION.equals(refType)) {
resolvedObject = resolveXSDElementDeclaration(definition, qname);
} else if (BPEL_PARTNER_LINK_TYPE.equals(refType)) {
resolvedObject = resolveBPELPartnerLinkType(definition, qname);
} else if (BPEL_ROLE.equals(refType)) {
resolvedObject = resolveBPELRole(definition, qname, name);
} else if (BPEL_PROPERTY.equals(refType)) {
resolvedObject = resolveBPELProperty(definition, qname);
} else {
System.err.println(WSDLUtil.class.getName() + ": unrecognized refType: " + refType); //$NON-NLS-1$
}
return resolvedObject;
}
/**
* Use Java generics to write the "finders" of various elements, so that the general code
* which does the lookups and follows imports does not need to be repeated.
*
* @author Michal Chmielewski (michal.chmielewski@oracle.com)
* @date Feb 27, 2007
*
* @param <T> the type that we are looking up (PortType, Message, PartnerLinkType)
*/
interface Finder<S,T> {
/**
* Find the thing in the container
*
* @param source the source where to look (definition, schema)
* @param qname the QName to lookup
* @return the resolved entity, or null
*/
T find (S source, QName qname);
}
/** Generic way of looking up port types */
static final Finder<Definition,PortType> PORT_TYPE_FINDER = new Finder<Definition, PortType>() {
@Override
public PortType find (Definition defn, QName qname) {
return (PortType) defn.getPortType(qname) ;
}
};
/** Generic way of looking up messages */
static final Finder<Definition,Message> MESSAGE_FINDER = new Finder<Definition,Message> () {
@Override
public Message find (Definition defn, QName qname) {
return (Message) defn.getMessage(qname);
}
};
/** Generic way of looking up partner link types */
static final Finder<Definition,PartnerLinkType> PARTNER_LINK_TYPE_FINDER = new Finder<Definition,PartnerLinkType>() {
@Override
public PartnerLinkType find (Definition defn, QName qname) {
if (defn.getTargetNamespace() == null)
return null;
if (defn.getTargetNamespace().equals(qname.getNamespaceURI()) == false) {
return null;
}
Iterator<?> it = defn.getExtensibilityElements().iterator();
while (it.hasNext()) {
Object e = it.next();
if (e instanceof PartnerLinkType) {
PartnerLinkType plt = (PartnerLinkType) e;
if (plt.getName().equals(qname.getLocalPart())) {
return plt;
}
}
}
return null;
}
};
/** Generic way of lookup up BPEL properties */
static final Finder<Definition,Property> PROPERTY_FINDER = new Finder<Definition,Property>() {
@Override
public Property find(Definition defn, QName qname) {
if (defn.getTargetNamespace().equals(qname.getNamespaceURI()) == false) {
return null;
}
Iterator<?> it = defn.getExtensibilityElements().iterator();
while (it.hasNext()) {
Object e = it.next();
if (e instanceof Property) {
Property property = (Property) e;
if (property.getName().equals(qname.getLocalPart())) {
return property;
}
}
}
return null;
}
};
/** Type definition finder */
static private final Finder<XSDSchema,XSDTypeDefinition> TYPE_DEFINITION_FINDER = new Finder<XSDSchema,XSDTypeDefinition>() {
@Override
public XSDTypeDefinition find(XSDSchema schema, QName typeName) {
// Perhaps this is what we want ...
// http://www.eclipse.org/modeling/emf/faq/#dev20040602-1383194195
//
XSDTypeDefinition typeDef = schema.resolveTypeDefinition(typeName.getNamespaceURI(), typeName.getLocalPart());
if (typeDef.getContainer() == null) {
return null;
}
return typeDef;
}
};
/** Element declaration finder */
static private final Finder<XSDSchema,XSDElementDeclaration> ELEMENT_DECLARATION_FINDER = new Finder<XSDSchema,XSDElementDeclaration> () {
@Override
public XSDElementDeclaration find(XSDSchema schema, QName qn) {
XSDElementDeclaration decl = schema.resolveElementDeclaration( qn.getNamespaceURI(), qn.getLocalPart());
// TODO: (Hack)
// Why has this started returning instances of XSDElementDeclrarion that are not proxies or null
// if the element declaration is missing in the schema ?
// Perhaps this is what we want: http://www.eclipse.org/modeling/emf/faq/#dev20040602-1383194195
if (decl.getContainer() == null) {
return null;
}
return decl;
}
};
/**
* Resolve the port type in the definition given.
*
* @param definition the WSDL definition
* @param qname the QName of the portType
* @return the resolved portType, or null
*/
public static PortType resolvePortType (Definition definition, QName qname)
{
return resolveUsingFinder ( definition, qname, PORT_TYPE_FINDER, new HashSet<Definition>() );
}
/**
* Resolve using finder resolves the QName in the definitions passed. The return object
* extends from EObject (so PortType, Message, PartnerLinkType, etc). The finder has the actual lookup
* code while the general code flow that deals with following the imports is shared among the lookup
* methods in this class.
*
* @param <T> the type
* @param defn the definition to use as the lookup
* @param qname the QName to lookup
* @param finder the finder to use.
* @param seen the seen set
* @return the object to be resolved.
*/
@SuppressWarnings("restriction")
static <T extends EObject> T resolveUsingFinder ( Definition defn, QName qname, Finder<Definition,T> finder , Set<Definition> seen) {
if (seen.contains(defn)) {
return null;
}
seen.add(defn);
T result = finder.find ( defn, qname );
if (result != null || RESOLVING_DEEPLY == false) {
return result;
}
Iterator<?> it = defn.getImports(qname.getNamespaceURI()).iterator();
while (it.hasNext() && result == null) {
ImportImpl imp = (ImportImpl) it.next();
imp.importDefinitionOrSchema();
Definition importedDefinition = (Definition) imp.getDefinition();
if (importedDefinition != null) {
result = resolveUsingFinder (importedDefinition, qname, finder, seen );
}
}
return result;
}
/**
* Resolve the message name in the definitions passed.
* @param definition the definitions
* @param qname the message name
* @return the message name or null
*/
public static Message resolveMessage(Definition definition, QName qname)
{
return resolveUsingFinder(definition, qname, MESSAGE_FINDER, new HashSet<Definition>());
}
/**
* Resolve operation within a portType. First lookup portType, then find the operation by name given.
* @param definition the definition to search
* @param portTypeQName QName of the portType to lookup operation on
* @param operationName the operation name.
* @return the operation or null
*/
public static Operation resolveOperation(Definition definition, QName portTypeQName, String operationName)
{
PortType portType = resolvePortType(definition, portTypeQName);
return findOperation(portType, operationName);
}
/**
* Resolve the part within a message.
* @param definition the definition to use
* @param qname QName of the message
* @param name the name of the message part.
* @return the part, or null
*/
public static Part resolvePart(Definition definition, QName qname, String name)
{
return findPart( resolveMessage(definition, qname) , name );
}
/**
* Resolve (lookup) a partner link type in the definitions given.
* @param defn the definitions to use
* @param qname the QName to lookup
* @return the partner link type or null
*/
public static PartnerLinkType resolveBPELPartnerLinkType(Definition defn, QName qname)
{
return resolveUsingFinder(defn, qname, PARTNER_LINK_TYPE_FINDER, new HashSet<Definition>() );
}
/**
* Resolve BPEL Role on the partner link specified.
*
* @param definition the definition to use
* @param qname QNAme of the partner link type
* @param name the name of the role on that partner link type
* @return the BPEL role, or null
*/
public static EObject resolveBPELRole(Definition definition, QName qname, String name)
{
return findRole ( resolveBPELPartnerLinkType(definition, qname) , name );
}
/**
* Lookup the BPEL property in the definition given.
*
* @param defn the definition
* @param qname the property QName to lookup
* @return the property or null
*/
public static Property resolveBPELProperty(Definition defn, QName qname)
{
return resolveUsingFinder(defn, qname, PROPERTY_FINDER, new HashSet<Definition>());
}
private static Service resolveService(Definition definition, QName qname) {
return (Service) definition.getService(qname);
}
/**
* Common code for resolving XSDTypeDefinitions and XSDElementDeclarations
*/
@SuppressWarnings("restriction")
static <T> T resolveXSD (Definition definition, QName qname, Finder<XSDSchema,T> finder, Set<Definition> seen )
{
T result = null;
if (seen.contains(definition)) {
return result;
}
seen.add(definition);
// Check for built-in types
// TODO Slightly inefficient to evaluate this when recursing
XSDSchema schema = null;
String namespace = qname.getNamespaceURI();
if ("".equals(namespace)) { //$NON-NLS-1$
namespace = null;
}
if (XSDConstants.isSchemaForSchemaNamespace(namespace)) {
schema = XSDSchemaImpl.getSchemaForSchema(namespace);
} else if (XSDConstants.isSchemaInstanceNamespace(namespace)) {
schema = XSDSchemaImpl.getSchemaInstance(namespace);
}
if (schema != null) {
result = finder.find(schema, qname);
if (result != null) {
return result;
}
}
// Check in-line schema
Types types = definition.getETypes();
if (types != null) {
Iterator<?> it = types.getExtensibilityElements().iterator();
while (it.hasNext()) {
Object e = it.next();
if (e instanceof XSDSchemaExtensibilityElement == false) {
continue;
}
XSDSchemaExtensibilityElement schemaEE = (XSDSchemaExtensibilityElement) e;
schema = schemaEE.getSchema();
if (schema != null) {
result = finder.find(schema, qname);
if (result != null)
return result;
}
}
}
/**
* Check imported schemas and definitions.
* If we are here, then result is still null
*/
// TODO: I think I need to check all imports, not just those
// matching the same namespace...
Iterator<?> it = definition.getImports(qname.getNamespaceURI()).iterator();
while (it.hasNext()) {
ImportImpl imp = (ImportImpl) it.next();
imp.importDefinitionOrSchema();
schema = imp.getESchema();
if (schema != null) {
result = finder.find(schema, qname);
if (result != null)
return result;
}
Definition importedDefinition = imp.getEDefinition();
if (importedDefinition != null) {
result = resolveXSD(importedDefinition, qname, finder, seen );
if (result != null) {
return result;
}
}
}
return result;
}
/**
* Resolve type definition. Basically lookup type by QName.
*
* @param definition
* @param qname
* @return the XSDTypeDefinition found or null if it does not exist.
*/
public static XSDTypeDefinition resolveXSDTypeDefinition(Definition definition, QName qname)
{
return resolveXSD(definition, qname ,TYPE_DEFINITION_FINDER, new HashSet<Definition>() );
}
/**
* Resolve the XSDElement declaration in this definition. Basically, lookup element declaration using the
* QName specified in the definition indicated.
*
* @param definition
* @param qname
* @return the XSDElement declaration if found. null otherwise.
*/
public static XSDElementDeclaration resolveXSDElementDeclaration(Definition definition, QName qname)
{
return resolveXSD(definition, qname, ELEMENT_DECLARATION_FINDER, new HashSet<Definition>() );
}
/**
* Find a role in the partner link type.
* @param plt the partner link type
* @param name the role name to find.
* @return the found role or null if it does not exist.
*/
public static Role findRole ( PartnerLinkType plt, String name ) {
if (plt != null) {
Iterator<Role> it = plt.getRole().iterator();
while (it.hasNext()) {
Role role = it.next();
if (name.equals(role.getName())) {
return role;
}
}
}
return null;
}
/**
* Find the operation in the port type.
* @param portType the port type
* @param operationName the operation name
* @return return the operation in the port type or null
*/
@SuppressWarnings("unchecked")
public static Operation findOperation (PortType portType, String operationName) {
if (portType != null) {
Iterator<Operation> it = portType.getOperations().iterator();
while (it.hasNext()) {
Operation operation = it.next();
if (operation.getName().equals(operationName)) {
return operation;
}
}
}
return null;
}
/**
* Find the message part in the message structure.
* @param message
* @param name
* @return the part or null
*/
public static Part findPart(Message message, String name) {
Part result = null;
if (message != null) {
result = (Part) message.getPart(name);
}
return result;
}
}