/******************************************************************************* * Copyright (c) 2004-2009 Gabor Bergmann and Daniel Varro * 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: * Gabor Bergmann - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.runtime.internal; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.concurrent.Callable; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.incquery.patternlanguage.patternLanguage.Pattern; import org.eclipse.incquery.runtime.api.IncQueryEngine; import org.eclipse.incquery.runtime.base.api.NavigationHelper; import org.eclipse.incquery.runtime.rete.boundary.IManipulationListener; import org.eclipse.incquery.runtime.rete.boundary.IPredicateTraceListener; import org.eclipse.incquery.runtime.rete.boundary.PredicateEvaluatorNode; import org.eclipse.incquery.runtime.rete.matcher.IPatternMatcherRuntimeContext; import org.eclipse.incquery.runtime.rete.matcher.ReteEngine; import org.eclipse.incquery.runtime.rete.tuple.Tuple; /** * @author Bergmann Gábor * */ public class EMFPatternMatcherRuntimeContext extends EMFPatternMatcherContext implements IPatternMatcherRuntimeContext<Pattern> { // protected abstract EMFContainmentHierarchyTraversal newTraversal(); // protected abstract ExtensibleEMFManipulationListener newListener(ReteEngine<PatternDescription> engine); // protected Collection<EMFVisitor> waitingVisitors; // boolean traversalCoalescing; // protected ExtensibleEMFManipulationListener listener; private final NavigationHelper baseIndex; private BaseIndexListener listener; // protected void traverse(EMFVisitor visitor) { // try { // newTraversal().accept(visitor); // } catch (Exception ex) { // iqEngine.getLogger().logError( // "EMF-IncQuery encountered an error in processing the EMF model. " + // "This happened while traversing the model for the initialization of pattern match caches.", ex); // } // } // /** // * @param visitor // */ // protected void doVisit(CustomizedEMFVisitor visitor) { // if (traversalCoalescing) waitingVisitors.add(visitor); // else traverse(visitor); // } // // // // class CustomizedEMFVisitor extends EMFVisitor { // @Override // public final void visitNonContainmentReference(EObject source, EReference feature, EObject target) { // if (target == null) return; // null-valued attributes / references are simply not stored // if (feature.getEOpposite() != null && feature.getEOpposite().isContainment()) return; // considerForExpansion(target); // doVisitReference(source, feature, target); // } // // @Override // public void visitInternalContainment(EObject source,EReference feature, EObject target) { // if (target == null) return; // null-valued attributes / references are simply not stored // if (feature.getEOpposite() != null) { // doVisitReference(target, feature.getEOpposite(), source); // } // doVisitReference(source, feature, target); // } // // @Override // // public void visitExternalReference(EObject source, EReference feature, EObject target) { // // if (target == null) return; // null-valued attributes / references are simply not stored // // if (feature.getEOpposite() != null && feature.getEOpposite().isContainment()) return; // // doVisitReference(source, feature, target); // // } // void doVisitReference(EObject source, EReference feature, EObject target) {} // } // public static class ForResourceSet<PatternDescription> extends // EMFPatternMatcherRuntimeContext<PatternDescription> { // ResourceSet root; // Collection<Resource> additionalResources; // public ForResourceSet(ResourceSet root, IncQueryEngine iqEngine) { // super(iqEngine); // this.root = root; // this.additionalResources = new HashSet<Resource>(); // } // @Override // protected EMFContainmentHierarchyTraversal newTraversal() { // return new EMFContainmentHierarchyTraversal(root, additionalResources); // } // @Override // protected ExtensibleEMFManipulationListener newListener(ReteEngine<PatternDescription> engine) { // ExtensibleEMFManipulationListener emfContentTreeViralListener = new EMFContentTreeViralListener(engine, root, // this, iqEngine.getLogger()); // for (Resource resource : additionalResources) { // emfContentTreeViralListener.addRoot(resource); // } // return emfContentTreeViralListener; // } // @Override // public void considerForExpansion(EObject obj) { // Resource eResource = obj.eResource(); // if (eResource != null && eResource.getResourceSet() == null && !additionalResources.contains(eResource)) { // additionalResources.add(eResource); // listener.addRoot(eResource); // } // } // } // public static class ForResource<PatternDescription> extends EMFPatternMatcherRuntimeContext<PatternDescription> { // Resource root; // public ForResource(Resource root, IncQueryEngine iqEngine) { // super(iqEngine); // this.root = root; // } // @Override // protected EMFContainmentHierarchyTraversal newTraversal() { // return new EMFContainmentHierarchyTraversal(root); // } // @Override // protected ExtensibleEMFManipulationListener newListener(ReteEngine<PatternDescription> engine) { // return new EMFContentTreeViralListener(engine, root, this, iqEngine.getLogger()); // } // @Override // public void considerForExpansion(EObject obj) {} // } // public static class ForEObject<PatternDescription> extends EMFPatternMatcherRuntimeContext<PatternDescription> { // EObject root; // public ForEObject(EObject root, IncQueryEngine iqEngine) { // super(iqEngine); // this.root = root; // } // @Override // protected EMFContainmentHierarchyTraversal newTraversal() { // return new EMFContainmentHierarchyTraversal(root); // } // @Override // protected ExtensibleEMFManipulationListener newListener(ReteEngine<PatternDescription> engine) { // return new EMFContentTreeViralListener(engine, root, this, iqEngine.getLogger()); // } // @Override // public void considerForExpansion(EObject obj) {} // } // public static class ForTransactionalEditingDomain<PatternDescription> extends // EMFPatternMatcherRuntimeContext<PatternDescription> { // TransactionalEditingDomain domain; // public ForTransactionalEditingDomain(TransactionalEditingDomain domain) { // super(); // this.domain = domain; // } // @Override // protected EMFContainmentHierarchyTraversal newTraversal() { // return new EMFContainmentHierarchyTraversal(domain.getResourceSet()); // } // @Override // protected ExtensibleEMFManipulationListener newListener(ReteEngine<PatternDescription> engine) { // return new EMFTransactionalEditingDomainListener(engine, domain, this); // } // @Override // public void considerForExpansion(EObject obj) {} // // } /** * Notifier must be EObject, Resource or ResourceSet * * @param notifier */ public EMFPatternMatcherRuntimeContext(IncQueryEngine iqEngine, NavigationHelper baseIndex) { super(iqEngine); this.baseIndex = baseIndex; // this.waitingVisitors = new ArrayList<EMFVisitor>(); // this.traversalCoalescing = false; } @Override public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException { return baseIndex.coalesceTraversals(callable); } // @Override // public void startCoalescing() { // assert(!traversalCoalescing); // traversalCoalescing = true; // } // @Override // public void finishCoalescing() { // assert(traversalCoalescing); // traversalCoalescing = false; // if (! waitingVisitors.isEmpty()){ // ArrayList<EMFVisitor> visitors = new ArrayList<EMFVisitor>(waitingVisitors); // waitingVisitors.clear(); // newTraversal().accept(new MultiplexerVisitor(visitors)); // } // } @Override public void enumerateAllBinaryEdges(final ModelElementPairCrawler crawler) { throw new UnsupportedOperationException(); // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (target != null) // Exclude NULL attribute values from RETE // crawler.crawl(source, target); // super.visitAttribute(source, feature, target); // } // @Override // public void doVisitReference(EObject source, EReference feature, EObject target) { // crawler.crawl(source, target); // } // }; // doVisit(visitor); } @Override public void enumerateAllGeneralizations(ModelElementPairCrawler crawler) { throw new UnsupportedOperationException(); } @Override // Only direct instantiation of unaries is supported now public void enumerateAllInstantiations(final ModelElementPairCrawler crawler) { throw new UnsupportedOperationException(); // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (target != null) // Exclude NULL attribute values from RETE // crawler.crawl(feature.getEAttributeType(), target); // } // @Override // public void visitElement(EObject source) { // crawler.crawl(source.eClass(), source); // } // }; // doVisit(visitor); } @Override public void enumerateAllTernaryEdges(final ModelElementCrawler crawler) { throw new UnsupportedOperationException(); } @Override public void enumerateAllUnaries(final ModelElementCrawler crawler) { throw new UnsupportedOperationException(); // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (target != null) // Exclude NULL attribute values from RETE // crawler.crawl(target); // super.visitAttribute(source, feature, target); // } // @Override // public void visitElement(EObject source) { // crawler.crawl(source); // super.visitElement(source); // } // }; // doVisit(visitor); } @Override public void enumerateAllUnaryContainments(final ModelElementPairCrawler crawler) { throw new UnsupportedOperationException(); // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // // FIXME: containment no longer holds between EObject and its raw attribute values. // // @Override // // public void visitAttribute(EObject source, EAttribute feature, Object target) { // // if (target != null) // Exclude NULL attribute values from RETE // // crawler.crawl(source, target); // // super.visitAttribute(source, feature, target); // // } // @Override // public void doVisitReference(EObject source, EReference feature, EObject target) { // if (feature.isContainment()) crawler.crawl(source, target); // } // }; // doVisit(visitor); } @Override public void enumerateDirectBinaryEdgeInstances(Object typeObject, final ModelElementPairCrawler crawler) { final EStructuralFeature structural = (EStructuralFeature) typeObject; listener.ensure(structural); final Collection<EObject> holders = baseIndex.getHoldersOfFeature(structural); for (EObject holder : holders) { if (structural.isMany()) { final Collection<?> values = (Collection<?>) holder.eGet(structural); for (Object value : values) { crawler.crawl(holder, value); } } else { final Object value = holder.eGet(structural); if (value != null) crawler.crawl(holder, value); } } // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (structural.equals(feature) && target != null) // NULL attribute values excluded from RETE // crawler.crawl(source, target); // super.visitAttribute(source, feature, target); // } // @Override // public void doVisitReference(EObject source, EReference feature, EObject target) { // if (structural.equals(feature)) crawler.crawl(source, target); // } // }; // doVisit(visitor); } @Override public void enumerateAllBinaryEdgeInstances(Object typeObject, final ModelElementPairCrawler crawler) { enumerateDirectBinaryEdgeInstances(typeObject, crawler); // No edge subtyping } @Override public void enumerateDirectTernaryEdgeInstances(Object typeObject, final ModelElementCrawler crawler) { throw new UnsupportedOperationException(); } @Override public void enumerateAllTernaryEdgeInstances(Object typeObject, final ModelElementCrawler crawler) { throw new UnsupportedOperationException(); } @Override public void enumerateDirectUnaryInstances(final Object typeObject, final ModelElementCrawler crawler) { if (typeObject instanceof EClass) { final EClass eClass = (EClass) typeObject; listener.ensure(eClass); final Collection<EObject> allInstances = baseIndex.getDirectInstances(eClass); for (EObject eObject : allInstances) { crawler.crawl(eObject); } // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitElement(EObject source) { // if (source.eClass().equals(typeObject)) crawler.crawl(source); // super.visitElement(source); // } // }; // doVisit(visitor); } else if (typeObject instanceof EDataType) { final EDataType eDataType = (EDataType) typeObject; listener.ensure(eDataType); final Collection<Object> allInstances = baseIndex.getDataTypeInstances(eDataType); for (Object value : allInstances) { crawler.crawl(value); } // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (target != null && ((EDataType)typeObject).isInstance(target)) // Exclude NULL attribute values from // RETE // crawler.crawl(target); // super.visitAttribute(source, feature, target); // } // }; // doVisit(visitor); } else throw new IllegalArgumentException("typeObject has invalid type " + typeObject.getClass().getName()); } @Override public void enumerateAllUnaryInstances(final Object typeObject, final ModelElementCrawler crawler) { if (typeObject instanceof EClass) { final EClass eClass = (EClass) typeObject; listener.ensure(eClass); final Collection<EObject> allInstances = baseIndex.getAllInstances(eClass); for (EObject eObject : allInstances) { crawler.crawl(eObject); } // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitElement(EObject source) { // if (((EClass)typeObject).isInstance(source)) crawler.crawl(source); // super.visitElement(source); // } // }; // doVisit(visitor); } else if (typeObject instanceof EDataType) { final EDataType eDataType = (EDataType) typeObject; listener.ensure(eDataType); final Collection<Object> allInstances = baseIndex.getDataTypeInstances(eDataType); for (Object value : allInstances) { crawler.crawl(value); } // CustomizedEMFVisitor visitor = new CustomizedEMFVisitor() { // @Override // public void visitAttribute(EObject source, EAttribute feature, Object target) { // if (target != null && ((EDataType)typeObject).isInstance(target)) // Exclude NULL attribute values from // RETE // crawler.crawl(target); // super.visitAttribute(source, feature, target); // } // }; // doVisit(visitor); } else throw new IllegalArgumentException("typeObject has invalid type " + typeObject.getClass().getName()); } @Override public void modelReadLock() { // TODO runnable? domain.runExclusive(read) } @Override public void modelReadUnLock() { // TODO runnable? domain.runExclusive(read) } // @Override // public String retrieveUnaryTypeFQN(Object typeObject) { // return contextMapping.retrieveFQN((EClassifier)typeObject); // } // // @Override // public String retrieveBinaryEdgeTypeFQN(Object typeObject) { // return contextMapping.retrieveFQN((EStructuralFeature)typeObject); // } // // @Override // public String retrieveTernaryEdgeTypeFQN(Object typeObject) { // throw new UnsupportedOperationException(); // } @Override // TODO Transactional? public IManipulationListener subscribePatternMatcherForUpdates(ReteEngine<Pattern> engine) { if (listener == null) listener = new BaseIndexListener(iqEngine, engine, baseIndex); return listener; } @Override public Object ternaryEdgeSource(Object relation) { throw new UnsupportedOperationException(); } @Override public Object ternaryEdgeTarget(Object relation) { throw new UnsupportedOperationException(); } @Override public IPredicateTraceListener subscribePatternMatcherForTraceInfluences(ReteEngine<Pattern> engine) { // No ASMFunctions, use DUMMY return new IPredicateTraceListener() { @Override public void registerSensitiveTrace(Tuple trace, PredicateEvaluatorNode node) { } @Override public void unregisterSensitiveTrace(Tuple trace, PredicateEvaluatorNode node) { } @Override public void disconnect() { } }; } // /** // * Consider expanding the notification scope to this object and surroundings. // * Hack added primarily to handle EPackage instances referenced by nsUri // * @param obj // */ // public abstract void considerForExpansion(EObject obj); }