blob: 9998f55f8e3f9df79dd84d106c4d0f1c3f5e98aa [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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Oracle Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.validator.adapters;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.namespace.QName;
import org.eclipse.bpel.model.BPELExtensibleElement;
import org.eclipse.bpel.model.adapters.AbstractStatefulAdapter;
import org.eclipse.bpel.validator.Activator;
import org.eclipse.bpel.validator.helpers.ModelQueryImpl;
import org.eclipse.bpel.validator.model.IConstants;
import org.eclipse.bpel.validator.model.IModelQuery;
import org.eclipse.bpel.validator.model.IModelQueryLookups;
import org.eclipse.bpel.validator.model.INode;
import org.eclipse.bpel.validator.model.RuleFactory;
import org.eclipse.bpel.validator.model.Validator;
import org.eclipse.emf.ecore.EObject;
import org.w3c.dom.Element;
/**
* This adapter adapts the EMF BPEL model objects to the INode and IValidate interfaces.
* <p>
* INode is a very thin navigation interface that allows us to access aspects of
* the EMF BPEL model objects. It makes no assumptions about how such model is stored, other
* then it is a tree.
* <p>
* This is where the world of the validator and the BPEL editor is bridged.
*
* @author Michal Chmielewski (michal.chmielewski@oracle.com)
* @date Sep 18, 2006
*
*/
public class BasicAdapter extends AbstractStatefulAdapter
implements INode {
/** The validator that we want */
Validator mValidator = null;
QName mNodeName = null;
/**
* Since we are "adapting" the EMF BPEL model, the convention here is to use
* the validator classes defined in org.eclipse.bpel.validator.rules.
* <p>
* The name of the class which contain the rules is the name of the EMF class
* (which corresponds to the BPEL name) followed by the word "Validator".
* <p>
* Clearly, any adapters can override this validator creation step.
*
* @return returns a suitable validator, null, if one cannot be created.
*/
public Validator createValidator () {
EObject obj = (EObject) getTarget();
QName qname = new QName(IConstants.XMLNS_BPEL,obj.eClass().getName());
return RuleFactory.INSTANCE.createValidator( qname );
}
/**
* Returns the list of the children of this node, as INode objects.
* Only direct descendants of this node are returned.
*
* @return the list of children of this node.
*/
public List<INode> children() {
EObject obj = (EObject) getTarget();
List<?> childList = obj.eContents();
ArrayList<INode> list = new ArrayList<INode>(childList.size());
for(Object next : obj.eContents()) {
INode node = adapt(next, INode.class );
if (node != null) {
list.add( node );
}
}
return list;
}
/**
* Return the name of accessor method that we can call on the EMF model object
* to get the value of the property passed in propertyName.
* <p>
* By default, the bean interface is used to figure out the method name.
* <p>
* Classes can override this method.
*
* @param propertyName
* @return the name of the method.
*/
public String getAccessorMethodName ( String propertyName ) {
return "get" + //$NON-NLS-1$
Character.toUpperCase( propertyName.charAt(0)) +
propertyName.substring(1);
}
/**
* Return the actual method that can be called on the target object
* to retrieve the necessary information.
*
* @param name
* @return the method that will be called to get the value of the attributeName, or null
*/
Method methodFor ( String name ) {
Class<?> clazz = getTarget().getClass();
try {
return clazz.getMethod( getAccessorMethodName ( name ) );
} catch (NoSuchMethodException nsme) {
// we log this, as our validator code must have access to such methods
Activator.log(nsme);
}
return null;
}
/**
* TODO: At some point, when the DOM Facade is done in the EMF model, then
* we can getAttribute as follows ...
*
* // When DOM Facade is done.
// return eObj.getElement().getAttribute( AT_VARIABLES );
*/
/**
* Return the value of the attribute specified that belongs to this INode.
* <p>
* Classes may want to override this method when the "attribute" node is expressed as
* a complex object in the (EMF) model.
* <p>
*
* (non-Javadoc)
* @see org.eclipse.bpel.validator.model.INode#getAttribute(javax.xml.namespace.QName)
*/
public String getAttribute (QName name) {
BPELExtensibleElement obj = getTarget(getTarget(), BPELExtensibleElement.class);
// Turn to the DOM for that information
Element element = obj.getElement();
if (element != null) {
if (element.hasAttributeNS(name.getNamespaceURI(),name.getLocalPart())) {
return element.getAttributeNS(name.getNamespaceURI(),name.getLocalPart());
}
}
Method method = methodFor ( name.getLocalPart() ) ;
if (method == null) {
return null;
}
Object result = null;
try {
result = method.invoke( getTarget() );
} catch (Exception ex) {
// ignore
}
if (result == null) {
return null;
}
// If string return it ...
if (result instanceof String) {
return (String) result;
}
return null;
}
/**
* @see org.eclipse.bpel.validator.model.INode#getAttributeAsQName(javax.xml.namespace.QName)
*/
public QName getAttributeAsQName ( QName name ) {
String value = getAttribute(name);
if (value == null) {
return null;
}
return ModelQueryImpl.getModelQuery().createQName(this, value);
}
/**
* Return the child node which matches the name
* @param name the name of the child node
* @return the INode facade for that node.
*/
public INode getNode (QName name ) {
Method method = methodFor(name.getLocalPart());
if (method == null) {
return null;
}
try {
Object result = method.invoke(getTarget());
if (result != null) {
return adapt(result, INode.class);
}
} catch (Exception ex) {
// ignore
}
return null;
}
/**
* Return the list of nodes which matches the name.
* @param name the name of the "property"
* @return a list of relevant nodes, INode facaded.
*/
public List<INode> getNodeList ( QName name ) {
Method method = methodFor( name.getLocalPart() );
if (method == null) {
return null;
}
Object result = null;
try {
result = method.invoke(getTarget());
} catch (Exception ex) {
}
// If empty or not a list, then we ignore it.
if (result == null || (result instanceof List) == false ) {
return Collections.emptyList();
}
// convert to a list of INode objects.
List<?> r = (List<?>) result;
if (r.size() == 0) {
return Collections.emptyList();
}
List<INode> newList = new LinkedList<INode>();
Iterator<?> it = r.iterator();
while (it.hasNext()) {
newList.add ( adapt ( it.next(), INode.class ) );
}
return newList;
}
/**
* Return if the object under the facade is "resolved" in the model object
* space. This is useful in the validator code to check (for example) whether
* an variable's type is visible to the model (whether it is a proxy or not in
* EMF terms).
* @return true if the model object is resolved, false otherwise.
*/
public boolean isResolved ()
{
EObject eObj = (EObject) getTarget();
return (eObj.eIsProxy() == false);
}
/**
* @see org.eclipse.bpel.validator.model.INode#nodeName()
*/
public QName nodeName() {
if (mNodeName != null) {
return mNodeName;
}
EObject obj = (EObject) getTarget();
String name = obj.eClass().getName();
// by convention, this is how the EMF model is naming its BPEL activities.
mNodeName = new QName(IConstants.XMLNS_BPEL,Character.toLowerCase(name.charAt(0)) + name.substring(1));
return mNodeName;
}
/**
* @see org.eclipse.bpel.validator.model.INode#nodeValue()
*/
public Object nodeValue() {
return getTarget();
}
/**
* Return the node validator used to validate this INode
*
* @return the node validator used to validate this INode
*/
public Validator nodeValidator () {
if (mValidator == null) {
mValidator = createValidator();
if (mValidator != null) {
mValidator.setNode(this);
}
}
return mValidator;
}
/** (non-Javadoc)
* @see org.eclipse.bpel.validator.model.INode#parentNode()
*/
public INode parentNode() {
EObject obj = (EObject) getTarget();
EObject parent = obj.eContainer();
if (parent == null) {
return null;
}
return adapt ( parent, INode.class );
}
/**
* Return the root node of this tree.
*
* @return the root node of this tree
*/
public INode rootNode ()
{
EObject obj = (EObject) getTarget();
while (obj.eContainer() != null) {
obj = obj.eContainer();
}
return adapt ( obj, INode.class );
}
/**
* Adapt to whatever class we need.
*
* @param target
* @param type
* @return the object adapted.
*/
protected <T extends Object> T adapt ( Object target, Class<T> type) {
IModelQuery mq = ModelQueryImpl.getModelQuery();
return mq.adapt(target,type,IModelQueryLookups.ADAPT_HINT_NONE);
}
}