blob: 073762e3f59990d6a1b08f7cd6647d3c7b215e81 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Oracle 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:
* Oracle Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.validator;
import java.util.Iterator;
import javax.xml.namespace.QName;
import org.eclipse.bpel.fnmeta.FunctionLibrary;
import org.eclipse.bpel.fnmeta.FunctionRegistry;
import org.eclipse.bpel.model.adapters.AdapterRegistry;
import org.eclipse.bpel.validator.helpers.ModelQueryImpl;
import org.eclipse.bpel.validator.model.IConstants;
import org.eclipse.bpel.validator.model.IFunctionMeta;
import org.eclipse.bpel.validator.model.INode;
import org.eclipse.bpel.validator.model.UndefinedNode;
import org.eclipse.bpel.validator.model.XNotImplemented;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.wst.wsdl.WSDLElement;
import org.eclipse.xsd.XSDConcreteComponent;
import org.w3c.dom.Element;
/**
* Implementation of the IModelQuery interface for the EMF BPEL
* object model used in the designer.
* <p>
* Basically, the validation model is much thinner as the BPEL EMF model.
* Because of this, various BPEL entity models (such as the EMF) one
* can be adapted to the validator BPEL model.
*
* @author Michal Chmielewski (michal.chmielewski@oracle.com)
* @date Sep 21, 2006
*
*/
@SuppressWarnings("nls")
public class ModelQuery extends ModelQueryImpl {
/**
* Return an answer that decides whether the model has support for
* the given aspects that the validator wants.
* @param item
* @param value
* @return true if support present, false otherwise.
*
* @see org.eclipse.bpel.validator.model.IModelQuery#hasSupport(int, java.lang.String)
*/
@Override
public boolean hasSupport (int item, String value) {
switch (item) {
case SUPPORT_QUERY_LANGUAGE :
return
IConstants.XMLNS_XPATH_QUERY_LANGUAGE.equals ( value ) ||
IConstants.XMLNS_XPATH_QUERY_LANGUAGE_2.equals( value );
case SUPPORT_EXPRESSION_LANGUAGE :
return
IConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE.equals ( value ) ||
IConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE_2.equals( value );
case SUPPORT_IMPORT_TYPE :
return IConstants.AT_VAL_IMPORT_XSD.equals ( value ) ||
IConstants.AT_VAL_IMPORT_WSDL.equals ( value ) ;
case SUPPORT_EXTENSION :
// by default we have no extensions that we support
return false;
}
throw new XNotImplemented("Not implemented: hasSupport(item=" + item + ")");
}
/**
* Answer if these two nodes are the same thing.
* @param test the test to perform
* @param n1 node 1
* @param n2 node 2
*
* @return true/false depending if the objects are the same.
*/
@Override
public boolean check ( int test, INode n1, INode n2 ) {
switch (test) {
case TEST_EQUAL :
// is this enough for EMF model ?
if (n1 == n2) {
return true;
}
if (n1 == null || n2 == null) {
return false;
}
// TODO: this is not this simple ...
Object v1 = n1.nodeValue();
Object v2 = n2.nodeValue();
// both identical or null
if (v1 == v2) {
return true;
}
// not identical and *not* both null.
if (v1 != null) {
return v1.equals(v2);
}
// v1 is null and not identical to v2 so false.
return false;
case TEST_COMPATIBLE_PARTNER_ACTIVITY_MESSAGE:
// n1 is source
// n2 is destination
return EmfModelQuery.compatiblePartnerActivityMessages (
adapt(n1,EObject.class,ADAPT_HINT_NONE),
adapt(n2,EObject.class,ADAPT_HINT_NONE) );
case TEST_COMPATIBLE_TYPE :
// n1 is the source
// n2 is the destination
return EmfModelQuery.compatibleType ( adapt(n1,EObject.class,ADAPT_HINT_NONE), adapt(n2,EObject.class,ADAPT_HINT_NONE));
case TEST_IS_SIMPLE_TYPE :
if (n1 == null || n1.isResolved() == false) {
return false;
}
return EmfModelQuery.isSimpleType ( adapt(n1,EObject.class,ADAPT_HINT_NONE) ) ;
case TEST_RESOVLED :
if (n1 == null) {
return false;
}
return n1.isResolved();
}
throw new XNotImplemented("Not implemented: check(test=" + test + ")");
}
/**
* Lookup the function meta which is identified by this QName.
* @return the function name
* @see org.eclipse.bpel.validator.model.IModelQuery#lookupFunction(String language, String ns, String name)
*/
@Override
public IFunctionMeta lookupFunction (String language, String ns, String name) {
FunctionRegistry registry = FunctionLibrary.INSTANCE.getRegistryForLanguage(language);
if (registry == null) {
return null;
}
return AdapterRegistry.INSTANCE.adapt(registry.lookupFunction ( ns, name ) , IFunctionMeta.class);
}
/** Make sure there is a reference from the element
* to the EMF model.
*
* @param eObj
* @param elm
*/
void ensureEMFReference (EObject eObj, Element elm) {
Object obj = elm.getUserData("emf.model");
// check if already set
if (obj != null && obj == eObj) {
return ;
}
// set it.
elm.setUserData("emf.model", eObj, null);
// set it on all the children of this element as well.
//
Iterator<EObject> it = eObj.eAllContents();
while (it.hasNext()) {
Object next = it.next();
Element domElement = null;
if (next instanceof WSDLElement) {
domElement = ((WSDLElement)next).getElement();
} else if (next instanceof XSDConcreteComponent) {
domElement = ((XSDConcreteComponent)next).getElement();
}
if ( domElement != null ) {
domElement.setUserData("emf.model",next,null);
}
}
}
/**
* General node lookup.
*
* @param context the context node, it cannot be null.
* @param what the thing to lookup
* @param qname the QName of the node to lookup
* @return the result of the lookup
*/
@Override
public INode lookup ( INode context, int what, QName qname ) {
if (qname == null) {
return null;
}
String name = qname.getLocalPart();
EObject eObj = null;
INode result = null;
// Make sure all the lookup items are switched.
switch (what) {
case LOOKUP_NODE_VARIABLE :
if (context.isResolved()) {
result = lookupVariable(context,name);
}
if (result == null) {
result = new UndefinedNode(IConstants.ND_VARIABLE, IConstants.AT_NAME, name);
}
break;
case LOOKUP_NODE_LINK :
if (context.isResolved()) {
result = lookupLink(context, name);
}
if (result == null) {
result = new UndefinedNode(IConstants.ND_LINK,IConstants.AT_NAME,name);
}
break;
case LOOKUP_NODE_IMPORT :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupImport(adapt(context,EObject.class,ADAPT_HINT_NONE), name );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.ND_IMPORT);
}
break;
case LOOKUP_NODE_PARTNER_LINK :
if (context.isResolved() ) {
result = lookupPartnerLink (context, name);
}
if (result == null) {
result = new UndefinedNode(IConstants.ND_PARTNER_LINK,IConstants.AT_NAME,name);
}
break;
case LOOKUP_NODE_CORRELLETION_SET :
if (context.isResolved()) {
result = lookupCorrelationSet (context,name);
}
if (result == null) {
result = new UndefinedNode(IConstants.ND_CORRELATION_SET,IConstants.AT_NAME,name);
}
break;
/**
* The items below are queried from the EMF model. These are largely resolved
* by the model and we rely on that resolution to produce the right result.
*
*/
case LOOKUP_NODE_PARTNER_LINK_TYPE :
if ( context.isResolved() ) {
eObj = EmfModelQuery.lookupPartnerLinkType ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.PLNK_ND_PARTNER_LINK_TYPE, IConstants.AT_NAME, qname.getLocalPart() );
}
break;
case LOOKUP_NODE_ROLE :
if ( context.isResolved() ) {
eObj = EmfModelQuery.lookupRole ( adapt(context,EObject.class,ADAPT_HINT_NONE), name ) ;
}
if (eObj == null) {
result = new UndefinedNode(IConstants.PLNK_ND_PARTNER_LINK_TYPE, IConstants.AT_NAME, name );
}
break;
case LOOKUP_NODE_OPERATION :
if ( context.isResolved()) {
eObj = EmfModelQuery.lookupOperation ( adapt(context,EObject.class,ADAPT_HINT_NONE), name );
}
if (eObj == null) {
result = new UndefinedNode ( IConstants.WSDL_ND_OPERATION, IConstants.AT_NAME, name );
}
break;
case LOOKUP_NODE_PORT_TYPE :
if ( context.isResolved() ) {
eObj = EmfModelQuery.lookupPortType ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname) ;
}
if (eObj == null) {
result = new UndefinedNode ( IConstants.WSDL_ND_PORT_TYPE, IConstants.AT_NAME, qname.getLocalPart() );
}
break;
case LOOKUP_NODE_MESSAGE_TYPE :
if ( context.isResolved() ) {
eObj = EmfModelQuery.lookupMessage ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname) ;
}
if (eObj == null) {
result = new UndefinedNode(IConstants.WSDL_ND_MESSAGE, IConstants.AT_NAME, qname.getLocalPart() );
}
break;
case LOOKUP_NODE_MESSAGE_PART :
return adapt(EmfModelQuery.lookupMessagePart ( adapt(context,EObject.class,ADAPT_HINT_NONE), name),INode.class,ADAPT_HINT_NONE );
case LOOKUP_NODE_XSD_ELEMENT :
if ( context.isResolved() ) {
eObj = EmfModelQuery.lookupXSDElement ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname);
}
if (eObj == null) {
result = new UndefinedNode(IConstants.AT_ELEMENT,IConstants.AT_NAME, qname.getLocalPart());
}
break;
case LOOKUP_NODE_XSD_TYPE :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupXSDType ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname);
}
if (eObj == null) {
result = new UndefinedNode(IConstants.AT_TYPE,IConstants.AT_NAME, qname.getLocalPart());
}
break;
case LOOKUP_NODE_PROPERTY :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupProperty ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.VPROP_ND_PROPERTY, IConstants.AT_NAME, qname.getLocalPart());
}
break;
case LOOKUP_NODE_NAME_STEP :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupNameStep( adapt(context,EObject.class,ADAPT_HINT_NONE), qname, 0 );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.AT_ELEMENT,IConstants.AT_NAME,qname.getLocalPart() );
}
break;
case LOOKUP_NODE_NAME_STEP_ATTRIBUTE :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupNameStep( adapt(context,EObject.class,ADAPT_HINT_NONE), qname, 1 );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.AT_ELEMENT,IConstants.AT_NAME,qname.getLocalPart() );
}
break;
case LOOKUP_NODE_TYPE_OF_PART :
if (context.isResolved()) {
eObj = EmfModelQuery.lookupTypeOfPart ( adapt(context,EObject.class,ADAPT_HINT_NONE), qname );
}
if (eObj == null) {
result = new UndefinedNode(IConstants.AT_ELEMENT,IConstants.AT_NAME,"Unknown");
}
break ;
default :
throw new XNotImplemented("Not implemented: lookupNode(item=" + what + ")");
}
if (eObj == null) {
return result ;
}
return adapt ( eObj , INode.class,ADAPT_HINT_NONE );
}
/**
* Lookup some text related item in the model object.
*
* @param context the context node
* @param what what to lookup
* @param key the value to lookup
* @param def the default value to return
* @return the looked up value.
*
*/
@Override
@SuppressWarnings("nls")
public String lookup ( INode context, int what, String key, String def) {
EObject eObj;
switch (what) {
case LOOKUP_TEXT_LOCATION :
// Should this be anything else ?
return context.nodeName().getLocalPart();
case LOOKUP_TEXT_NS2PREFIX :
return super.lookup(context,what,key,def);
case LOOKUP_TEXT_PREFIX2NS :
return super.lookup(context, what,key,def);
case LOOKUP_TEXT_TEXT :
return super.lookup(context, what,key,def);
case LOOKUP_TEXT_HREF :
eObj = adapt(context,EObject.class,ADAPT_HINT_NONE);
if (eObj == null || eObj.eResource() == null) {
break;
}
return eObj.eResource().getURIFragment(eObj);
case LOOKUP_TEXT_RESOURCE_PATH :
eObj = adapt(context,EObject.class,ADAPT_HINT_NONE);
if (eObj == null || eObj.eResource() == null ) {
break;
}
URI uri = eObj.eResource().getURI();
if (uri.isFile()) {
return uri.toFileString();
}
return uri.toString();
case LOOKUP_TEXT_HREF_XPATH :
return super.lookup(context, what,key,def);
default :
throw new XNotImplemented("Not implemented: lookupText(item=" + what + ")");
}
return def;
}
/**
* Lookup a number value or parameter in the model.
* @param context
* @param what
* @param def
* @return the looked-up value, or the default return value passed.
*
*/
@Override
@SuppressWarnings("nls")
public int lookup ( INode context, int what, int def ) {
Element elm = adapt(context,Element.class,ADAPT_HINT_NONE);
if (elm == null) {
return def;
}
String key = null;
switch (what) {
case LOOKUP_NUMBER_LINE_NO :
key = "location.line";
break;
case LOOKUP_NUMBER_COLUMN_NO :
key = "location.column";
break;
case LOOKUP_NUMBER_CHAR_START :
key = "location.charStart";
break;
case LOOKUP_NUMBER_CHAR_END :
key = "location.charEnd";
break;
case LOOKUP_NUMBER_LINE_NO_2 :
key = "location2.line";
break;
case LOOKUP_NUMBER_COLUMN_NO_2 :
key = "location2.column";
break;
case LOOKUP_NUMBER_CHAR_START_2 :
key = "location2.charStart";
break;
case LOOKUP_NUMBER_CHAR_END_2 :
key = "location2.charEnd";
break;
default :
throw new XNotImplemented("Not implemented: lookupNumber(item=" + what + ")");
}
try {
return ((Number)elm.getUserData(key)).intValue();
} catch (Throwable t) {
//
}
return def;
}
/**
* Adapt the target to a type. This goes through the platform adapter
* mechanism.
*
* @param target
* @param type
* @param hint the hint
* @return an object that is the adapter the target with the given class.
*/
@Override
public <T extends Object> T adapt (Object target, Class<T> type, int hint ) {
// short cut
if (type.isInstance( target ) || target == null) {
return type.cast(target);
}
T result = super.adapt(target,type,hint);
if (result != null) {
return result;
}
if (target instanceof INode) {
INode aTarget = (INode) target;
// INode -> Element
if (type == Element.class) {
return type.cast(adaptINode2Element ( aTarget ));
}
if (type == EObject.class) {
return type.cast( adaptINode2EObject ( aTarget ) );
}
}
if (target instanceof EObject) {
EObject aTarget = (EObject)target;
if (type == INode.class) {
return type.cast(adaptEObject2INode ( aTarget ));
}
}
IAdapterManager manager = AdapterManagerHelper.getAdapterManager();
return type.cast(manager.getAdapter(target, type));
}
Element adaptINode2Element ( INode context ) {
Object value = context.nodeValue();
if (value instanceof Element) {
return (Element) value;
} else if (value instanceof WSDLElement) {
return ((WSDLElement)value).getElement();
} else if (value instanceof XSDConcreteComponent) {
return ((XSDConcreteComponent) value).getElement();
}
return null;
}
/**
* Adapt the target object to INode.
*
* @param target the target object to adapt
* @return the adapter for the EObject
*/
INode adaptEObject2INode (EObject target) {
if (target == null) {
return null;
}
Element domElement = null;
// Try to adapt the DOM element first.
if (target instanceof WSDLElement) {
domElement = ((WSDLElement)target).getElement();
} else if (target instanceof XSDConcreteComponent) {
domElement = ((XSDConcreteComponent)target).getElement();
}
if (domElement != null) {
ensureEMFReference( target,domElement );
return adapt (domElement, INode.class,ADAPT_HINT_NONE);
}
return null;
}
@SuppressWarnings("nls")
EObject adaptINode2EObject ( INode context ) {
Object value = context.nodeValue();
if (value instanceof Element) {
Element elm = (Element) value;
return (EObject) elm.getUserData("emf.model");
} else if (value instanceof EObject) {
return (EObject) value;
} else if (context.isResolved() == false) {
return null;
}
throw new RuntimeException("getEObject() - cannot find EMF Object");
}
}