/** * <copyright> * </copyright> * * $Id$ */ package tefkat.engine.runtime.impl; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.NotificationChain; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import tefkat.engine.runtime.Binding; import tefkat.engine.runtime.BindingPair; import tefkat.engine.runtime.Context; import tefkat.engine.runtime.DynamicObject; import tefkat.engine.runtime.Extent; import tefkat.engine.runtime.NotGroundException; import tefkat.engine.runtime.ResolutionException; import tefkat.engine.runtime.WrappedVar; import tefkat.engine.runtime.Expression; import tefkat.engine.runtime.MofInstance; import tefkat.engine.runtime.RuntimePackage; import tefkat.engine.runtime.Var; import tefkat.model.internal.ModelUtils; /** * <!-- begin-user-doc --> * An implementation of the model object '<em><b>Mof Instance</b></em>'. * <!-- end-user-doc --> * <p> * The following features are implemented: * <ul> * <li>{@link tefkat.engine.runtime.impl.MofInstanceImpl#getTypeName <em>Type Name</em>}</li> * <li>{@link tefkat.engine.runtime.impl.MofInstanceImpl#getInstance <em>Instance</em>}</li> * <li>{@link tefkat.engine.runtime.impl.MofInstanceImpl#isExact <em>Exact</em>}</li> * </ul> * </p> * * @generated */ public class MofInstanceImpl extends MofTermImpl implements MofInstance { /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public static final String copyright = "Copyright michael lawley 2004"; private static final String NOT_BOUND_MESSAGE = " was not bound in source term!"; /** * The cached value of the '{@link #getTypeName() <em>Type Name</em>}' containment reference. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getTypeName() * @generated * @ordered */ protected Expression typeName = null; /** * The cached value of the '{@link #getInstance() <em>Instance</em>}' containment reference. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getInstance() * @generated * @ordered */ protected Expression instance = null; /** * The default value of the '{@link #isExact() <em>Exact</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #isExact() * @generated * @ordered */ protected static final boolean EXACT_EDEFAULT = false; /** * The cached value of the '{@link #isExact() <em>Exact</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #isExact() * @generated * @ordered */ protected boolean exact = EXACT_EDEFAULT; /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ protected MofInstanceImpl() { super(); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ protected EClass eStaticClass() { return RuntimePackage.Literals.MOF_INSTANCE; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public Expression getTypeName() { return typeName; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public NotificationChain basicSetTypeName(Expression newTypeName, NotificationChain msgs) { Expression oldTypeName = typeName; typeName = newTypeName; if (eNotificationRequired()) { ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, RuntimePackage.MOF_INSTANCE__TYPE_NAME, oldTypeName, newTypeName); if (msgs == null) msgs = notification; else msgs.add(notification); } return msgs; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void setTypeName(Expression newTypeName) { if (newTypeName != typeName) { NotificationChain msgs = null; if (typeName != null) msgs = ((InternalEObject)typeName).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - RuntimePackage.MOF_INSTANCE__TYPE_NAME, null, msgs); if (newTypeName != null) msgs = ((InternalEObject)newTypeName).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - RuntimePackage.MOF_INSTANCE__TYPE_NAME, null, msgs); msgs = basicSetTypeName(newTypeName, msgs); if (msgs != null) msgs.dispatch(); } else if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, RuntimePackage.MOF_INSTANCE__TYPE_NAME, newTypeName, newTypeName)); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public Expression getInstance() { return instance; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public NotificationChain basicSetInstance(Expression newInstance, NotificationChain msgs) { Expression oldInstance = instance; instance = newInstance; if (eNotificationRequired()) { ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, RuntimePackage.MOF_INSTANCE__INSTANCE, oldInstance, newInstance); if (msgs == null) msgs = notification; else msgs.add(notification); } return msgs; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void setInstance(Expression newInstance) { if (newInstance != instance) { NotificationChain msgs = null; if (instance != null) msgs = ((InternalEObject)instance).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - RuntimePackage.MOF_INSTANCE__INSTANCE, null, msgs); if (newInstance != null) msgs = ((InternalEObject)newInstance).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - RuntimePackage.MOF_INSTANCE__INSTANCE, null, msgs); msgs = basicSetInstance(newInstance, msgs); if (msgs != null) msgs.dispatch(); } else if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, RuntimePackage.MOF_INSTANCE__INSTANCE, newInstance, newInstance)); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public boolean isExact() { return exact; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void setExact(boolean newExact) { boolean oldExact = exact; exact = newExact; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, RuntimePackage.MOF_INSTANCE__EXACT, oldExact, exact)); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { switch (featureID) { case RuntimePackage.MOF_INSTANCE__TYPE_NAME: return basicSetTypeName(null, msgs); case RuntimePackage.MOF_INSTANCE__INSTANCE: return basicSetInstance(null, msgs); } return super.eInverseRemove(otherEnd, featureID, msgs); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case RuntimePackage.MOF_INSTANCE__TYPE_NAME: return getTypeName(); case RuntimePackage.MOF_INSTANCE__INSTANCE: return getInstance(); case RuntimePackage.MOF_INSTANCE__EXACT: return isExact() ? Boolean.TRUE : Boolean.FALSE; } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void eSet(int featureID, Object newValue) { switch (featureID) { case RuntimePackage.MOF_INSTANCE__TYPE_NAME: setTypeName((Expression)newValue); return; case RuntimePackage.MOF_INSTANCE__INSTANCE: setInstance((Expression)newValue); return; case RuntimePackage.MOF_INSTANCE__EXACT: setExact(((Boolean)newValue).booleanValue()); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void eUnset(int featureID) { switch (featureID) { case RuntimePackage.MOF_INSTANCE__TYPE_NAME: setTypeName((Expression)null); return; case RuntimePackage.MOF_INSTANCE__INSTANCE: setInstance((Expression)null); return; case RuntimePackage.MOF_INSTANCE__EXACT: setExact(EXACT_EDEFAULT); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public boolean eIsSet(int featureID) { switch (featureID) { case RuntimePackage.MOF_INSTANCE__TYPE_NAME: return typeName != null; case RuntimePackage.MOF_INSTANCE__INSTANCE: return instance != null; case RuntimePackage.MOF_INSTANCE__EXACT: return exact != EXACT_EDEFAULT; } return super.eIsSet(featureID); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated NOT */ public String toString() { return getTypeName() + " " + getInstance() + " " + getExtent(); } public void match(Context context) throws ResolutionException, NotGroundException { /** * Find all instances of the specified class in the (context) extent */ Var extentVar = getExtent(); Collection results = getTypeName().eval(context); if (results.size() != 1) { context.error("Expected only a single type name, got: " + results); } Object typeObj = results.toArray()[0]; EClassifier theClass = null; String className; if (typeObj instanceof EClassifier) { theClass = (EClassifier) typeObj; className = ModelUtils.getFullyQualifiedName(theClass); } else if (typeObj instanceof WrappedVar) { context.error("Unsupported mode (unbound typeName) for MofInstance: " + this); // satisfy the compiler (it doesn't know the previous line always throws an exception) className = null; } else { className = String.valueOf(typeObj); if (!"_".equals(className)) { theClass = context.findClassifierByName(className); if (null == theClass) { context.warn("Could not find class named: " + className); return; } } } // Our "package instance" wrapper around an EMOF ExtentUtil (EMF Resource) // FIXME why don't we call "eval" on Vars? Extent extent = (null == extentVar ? null : (Extent) context.lookup(extentVar)); Collection instances = getInstance().eval(context); boolean success = false; for (Iterator itr = instances.iterator(); itr.hasNext(); ) { Object instance = itr.next(); if (instance instanceof WrappedVar) { // handle the ??- mode // // does lazy expansion of the tree. // This will cause relatively untested code (and broken?) to be used in // other parts of Abstract/Source/TargetResolver and Evaluator // FIXME make this stuff work // FIXME I think it works, but some Unit tests would make me more comfortable WrappedVar wVar = (WrappedVar) instance; wVar.setExtent(extent); if ("_".equals(className)) { // Any type will do, isExact in this context is meaningless // hence, no need to call setType on the WrappedVar Binding unifier = new Binding(); unifier.add(wVar.getVar(), wVar); context.createBranch(unifier); success = true; } else if (!(theClass instanceof EClass)) { context.warn("Could not find class named: " + className); } else if (wVar.setType((EClass) theClass, isExact())) { Binding unifier = new Binding(); unifier.add(wVar.getVar(), wVar); context.createBranch(unifier); success = true; } } else { // handle the ??+ mode Binding unifier = null; if (instance instanceof BindingPair) { unifier = (Binding) instance; instance = ((BindingPair) instance).getValue(); } if (instance instanceof EObject && (null == extent || extent.contains((EObject) instance))) { // FIXME ExtentUtil.highlightNode(instance, ExtentUtil.OBJECT_LOOKUP); boolean isOfType = null == theClass || (isExact() ? theClass.equals(((EObject) instance).eClass()) : theClass.isInstance(instance)); if (isOfType) { /** * Create a new branch of the tree, and continue * resolution from the newly created node. */ context.createBranch(unifier); success = true; } } } } if (!success) { context.fail(); } } public void ensure(Context context) throws ResolutionException, NotGroundException { Collection instances = getInstance().eval(context); // deal with type List results = getTypeName().eval(context); if (results.size() != 1) { context.error("Expected only a single type name, got: " + results); } Object typeObj = results.get(0); Binding unifier = new Binding(); for (Iterator itr = instances.iterator(); itr.hasNext(); ) { Object obj = itr.next(); // System.err.println(obj); // TODO delete if (obj instanceof WrappedVar) { // ruleEval.fireInfo(obj + DELAYING_MESSAGE); context.delay(obj + NOT_BOUND_MESSAGE); } else { EObject eObj = (EObject) obj; boolean makeExact = isExact(); if (typeObj instanceof WrappedVar) { unifier.add(((WrappedVar) typeObj).getVar(), eObj.eClass().getName()); } else if (typeObj instanceof String) { // _ is the universal type -> it always matches if (!"_".equals(typeObj)) { String typeName = (String) typeObj; EClassifier eClassifier = context.findClassifierByName(typeName); if (null == eClassifier) { // for (final Iterator nItr = nameMap.keySet().iterator(); nItr.hasNext(); ) { // Object entry = nItr.next(); // System.out.println(entry); // } context.error("Expected an EClass called: " + typeName + ", but found nothing"); } else if (!(eClassifier instanceof EClass)) { context.error("Expected an EClass called: " + typeName + ", but found an EDataType or EEnum"); } EClass subCls = (EClass) eClassifier; boolean result = conformToType(eObj, subCls); if (!result) { context.error("Type mismatch, " + typeName + " not compatible with " + eObj.eClass()); } } else { // It's not possible to make an instance exactly no type // (although we _might_ consider the possibilty that one // would like the possiblity to freeze the current type) makeExact = false; } } else if (typeObj instanceof EClass) { EClass subCls = (EClass) typeObj; boolean result = conformToType(eObj, subCls); if (!result) { context.error("Type mismatch, " + subCls + " not compatible with " + eObj.eClass()); } } else { context.error("Invalid Expression type for MofInstance.typeName: " + typeObj); } if (makeExact && eObj instanceof DynamicObject) { if (eObj.eResource() != null) { eObj.eResource().getContents().remove(eObj); // System.err.println(" ...removed: " + eObj.hashCode()); } eObj = ((DynamicObject) eObj).getStaticInstance(); } // deal with extent Extent extentObj = (Extent) context.lookup(getExtent()); if (null != extentObj) { // Extents are optional, but dangling objects may be created that // should cause errors when the Resource is saved, but only if there // is a reference to the object, but no containment reference. Resource res = eObj.eResource(); if (null == res) { extentObj.add(eObj); } else if (!extentObj.contains(eObj)) { context.error("Object (" + eObj + ") cannot exist in multiple resources, " + res + " and " + extentObj); } } } } context.createBranch(unifier); } /** * @param eObj * @param subCls * @return */ private static boolean conformToType(EObject eObj, EClass subCls) { boolean result = true; EClass cls = eObj.eClass(); if (eObj instanceof DynamicObject) { if (cls.equals(EcorePackage.eINSTANCE.getEObject())) { // EObject is a supertype of all types ((DynamicObject) eObj).narrow(subCls); } else if (subCls.isSuperTypeOf(cls)) { // never widen the type of the object (this catches the // equals case also, so must come before next test) } else if (cls.isSuperTypeOf(subCls)) { // narrow the type of the previously created object ((DynamicObject) eObj).narrow(subCls); } else { result = false; } } else { if (subCls.isSuperTypeOf(cls)) { // never widen the type of the object (this catches the // equals case also, so must come before next test) // } else if (cls.isSuperTypeOf(subCls)) { // throw new RuntimeException("Can't narrow the type of a non-dynamic instance"); } else { result = false; } } return result; } } //MofInstanceImpl