Use overridable factory method for EOLQueryEngine graph node wrapping

GraphNodeWrapper allows us to hold weak references to nodes, to save memory.
However, when using time-aware queries, we cannot just recover the original
node from its ID: we need the timepoint as well. That means that we need to
wrap the node with a different class.

Until now, we basically had it done on a case-by-case basis, but that was
prone to slips: for instance, following a model element reference from a
time-aware node would give you a non-time-aware wrapper. This was OK until
you tried to run a large query, which resulted in GC'ing of the weak references:
from that point onwards, you'd start to see odd NullPointerExceptions in places.
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/AbstractHawkModel.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/AbstractHawkModel.java
index 0ac330d..fc26a9a 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/AbstractHawkModel.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/AbstractHawkModel.java
@@ -27,7 +27,7 @@
 import org.eclipse.epsilon.eol.exceptions.models.EolModelElementTypeNotFoundException;

 import org.eclipse.epsilon.eol.exceptions.models.EolModelLoadingException;

 import org.eclipse.epsilon.eol.models.Model;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;

 import org.eclipse.hawk.graph.ModelElementNode;

 import org.eclipse.hawk.graph.util.GraphUtil;

 import org.slf4j.Logger;

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/DeriveFeature.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/DeriveFeature.java
index 718c4ca..e67d101 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/DeriveFeature.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/DeriveFeature.java
@@ -29,9 +29,9 @@
 import org.eclipse.epsilon.eol.execute.context.Variable;

 import org.eclipse.hawk.core.IModelIndexer;

 import org.eclipse.hawk.core.graph.IGraphNode;

+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;

 import org.eclipse.hawk.epsilon.emc.pgetters.GraphPropertyGetter;

 import org.eclipse.hawk.epsilon.emc.tracking.AccessListener;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

 import org.eclipse.hawk.graph.updater.DirtyDerivedFeaturesListener;

 import org.slf4j.Logger;

 import org.slf4j.LoggerFactory;

@@ -160,7 +160,7 @@
 		}

 

 		final IGraphNode modelElementNode = n.getIncoming().iterator().next().getStartNode();

-		final GraphNodeWrapper meGW = new GraphNodeWrapper(modelElementNode, containerModel);

+		final GraphNodeWrapper meGW = containerModel.wrap(modelElementNode);

 		currentModule.getContext().getFrameStack().put(Variable.createReadOnlyVariable("self", meGW));

 

 		return currentModule;

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/EOLQueryEngine.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/EOLQueryEngine.java
index a38bd85..213ad35 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/EOLQueryEngine.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/EOLQueryEngine.java
@@ -17,6 +17,7 @@
  ******************************************************************************/

 package org.eclipse.hawk.epsilon.emc;

 

+import java.lang.ref.WeakReference;

 import java.lang.reflect.Array;

 import java.util.ArrayList;

 import java.util.Arrays;

@@ -30,6 +31,7 @@
 import java.util.Map;

 import java.util.Map.Entry;

 import java.util.NoSuchElementException;

+import java.util.Objects;

 import java.util.Set;

 import java.util.function.Consumer;

 

@@ -55,6 +57,7 @@
 import org.eclipse.hawk.core.graph.IGraphIterable;

 import org.eclipse.hawk.core.graph.IGraphNode;

 import org.eclipse.hawk.core.graph.IGraphNodeIndex;

+import org.eclipse.hawk.core.graph.IGraphNodeReference;

 import org.eclipse.hawk.core.graph.IGraphTransaction;

 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;

 import org.eclipse.hawk.core.query.IQueryEngine;

@@ -66,7 +69,6 @@
 import org.eclipse.hawk.epsilon.emc.pgetters.GraphPropertyGetter;

 import org.eclipse.hawk.epsilon.emc.tracking.AccessListener;

 import org.eclipse.hawk.epsilon.emc.wrappers.FileNodeWrapper;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

 import org.eclipse.hawk.epsilon.emc.wrappers.MetamodelNodeWrapper;

 import org.eclipse.hawk.epsilon.emc.wrappers.TypeNodeWrapper;

 import org.eclipse.hawk.graph.FileNode;

@@ -93,6 +95,119 @@
  */

 public class EOLQueryEngine extends AbstractHawkModel implements IQueryEngine {

 

+	/**

+	 * Weak ID-based reference to a node. In cases of heavy memory usage, it can GC the node

+	 * itself and retrieve it again a later time.

+	 *

+	 * This class should only be instantiated from the query engine. Subclasses of EOLQueryEngine

+	 * may want to provide their own wrapper subclasses.

+	 */

+	public class GraphNodeWrapper implements IGraphNodeReference {

+

+		protected String id;

+		protected EOLQueryEngine containerModel;

+		protected WeakReference<IGraphNode> node;

+

+		protected GraphNodeWrapper(IGraphNode n, EOLQueryEngine containerModel) {

+			node = new WeakReference<IGraphNode>(n);

+			this.id = n.getId().toString();

+			this.containerModel = containerModel;

+		}

+

+		@Override

+		public IGraphNode getNode() {

+			IGraphNode ret = node.get();

+			if (ret == null) {

+				ret = containerModel.getBackend().getNodeById(id);

+				node = new WeakReference<IGraphNode>(ret);

+			}

+			return ret;

+		}

+

+		@Override

+		public String getId() {

+			return id;

+		}

+

+		@Override

+		public EOLQueryEngine getContainerModel() {

+			return containerModel;

+		}

+

+		@Override

+		public boolean equals(Object obj) {

+			if (this == obj)

+				return true;

+			if (obj == null)

+				return false;

+			if (getClass() != obj.getClass())

+				return false;

+			GraphNodeWrapper other = (GraphNodeWrapper) obj;

+			return Objects.equals(containerModel, other.containerModel) && Objects.equals(id, other.id);

+		}

+

+		public Object getFeature(String name) throws EolRuntimeException {

+			return containerModel.getPropertyGetter().invoke(this, name);

+		}

+

+		/**

+		 * Returns true if this model element is contained directly or indirectly

+		 * within the specified path at the specified repository.

+		 */

+		public boolean isContainedWithin(String repository, String path) {

+			try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

+				final ModelElementNode men = new ModelElementNode(getNode());

+				return men.isContainedWithin(repository, path);

+			} catch (Exception e) {

+				LOGGER.error(e.getMessage(), e);

+			}

+			return false;

+		}

+

+		@Override

+		public String getTypeName() {

+			String type = "";

+

+			try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

+				IGraphNode n = getNode();

+

+				final Iterator<IGraphEdge> itTypeNode = n.getOutgoingWithType(ModelElementNode.EDGE_LABEL_OFTYPE).iterator();

+				if (itTypeNode.hasNext()) {

+					final IGraphNode typeNode = itTypeNode.next().getEndNode();

+					type = typeNode.getProperty(IModelIndexer.IDENTIFIER_PROPERTY).toString();

+				} else {

+					LOGGER.error("No type node found for node {}", n);

+				}

+

+				t.success();

+			} catch (Exception e) {

+				LOGGER.error(e.getMessage(), e);

+			}

+

+			return type;

+		}

+

+		@Override

+		public String toString() {

+			String info = "";

+

+			try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

+				info += "type:" + getTypeName();

+				info += "";

+				t.success();

+			} catch (Exception e) {

+				LOGGER.error(e.getMessage(), e);

+			}

+			return "GNW|id:" + id + "|" + (info.equals("") ? "[no meta-info]" : info) + "";

+		}

+

+		@Override

+		public int hashCode() {

+			return Objects.hash(containerModel, id);

+		}

+	}

+	

+

 	protected class IGraphIterableCollection implements Collection<GraphNodeWrapper> {

 		private final IGraphIterable<? extends IGraphNode> iterableNodes;

 

@@ -131,7 +246,7 @@
 

 				@Override

 				public GraphNodeWrapper next() {

-					return new GraphNodeWrapper(itNodes.next(), EOLQueryEngine.this);

+					return wrap(itNodes.next());

 				}

 			};

 		}

@@ -329,7 +444,7 @@
 				for (FileNode fn : fileNodes) {

 					for (ModelElementNode me : fn.getModelElements()) {

 						if (me.isOfKind(targetTypeNode)) {

-							results.add(new GraphNodeWrapper(me.getNode(), this));

+							results.add(wrap(me.getNode()));

 						}

 					}

 				}

@@ -348,7 +463,7 @@
 		Collection<Object> nodes = createAllOfCollection(typeNode);

 

 		for (IGraphEdge n : typeNode.getIncomingWithType(typeorkind)) {

-			nodes.add(new GraphNodeWrapper(n.getStartNode(), this));

+			nodes.add(wrap(n.getStartNode()));

 		}

 

 		broadcastAllOfXAccess(nodes);

@@ -357,7 +472,7 @@
 

 	protected Collection<Object> createAllOfCollection(IGraphNode typeNode) {

 		Collection<Object> nodes = useOptimisableCollection

-			? new OptimisableCollection(this, new GraphNodeWrapper(typeNode, this)) : new EolSequence<>();

+			? new OptimisableCollection(this, wrap(typeNode)) : new EolSequence<>();

 		return nodes;

 	}

 

@@ -444,11 +559,8 @@
 

 	@Override

 	public Object getElementById(String id) {

-

 		IGraphNode ret = graph.getNodeById(id);

-

-		return ret == null ? null : new GraphNodeWrapper(ret, this);

-

+		return ret == null ? null : wrap(ret);

 	}

 

 	@Override

@@ -1004,4 +1116,12 @@
 		return "EOL Query Engine";

 	}

 

+	/**

+	 * Wraps the provided node for its use in EOL.

+	 *

+	 * TODO change return type to {@link IGraphNodeReference}

+	 */

+	public GraphNodeWrapper wrap(IGraphNode node) {

+		return new GraphNodeWrapper(node, this);

+	}

 }

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/CEOLQueryEngine.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/CEOLQueryEngine.java
index e715368..55e50dd 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/CEOLQueryEngine.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/CEOLQueryEngine.java
@@ -34,7 +34,6 @@
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;

 import org.eclipse.hawk.epsilon.emc.pgetters.CGraphPropertyGetter;

 import org.eclipse.hawk.epsilon.emc.wrappers.FileNodeWrapper;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

 import org.eclipse.hawk.graph.FileNode;

 import org.eclipse.hawk.graph.ModelElementNode;

 import org.slf4j.Logger;

@@ -81,7 +80,7 @@
 				elements = new HashSet<>();

 				for (IGraphIterable<ModelElementNode> iterable : iterables) {

 					for (ModelElementNode e : iterable) {

-						elements.add(new GraphNodeWrapper(e.getNode(), CEOLQueryEngine.this));

+						elements.add(wrap(e.getNode()));

 					}

 				}

 			}

@@ -221,12 +220,12 @@
 		// Backend does not support the more efficient #size operation		

 		final Set<GraphNodeWrapper> allContents = new HashSet<>();

 		for (ModelElementNode elem : firstFileElements) {

-			allContents.add(new GraphNodeWrapper(elem.getNode(), this));

+			allContents.add(wrap(elem.getNode()));

 		}

 		while (itFiles.hasNext()) {

 			final FileNode fn = new FileNode(itFiles.next());

 			for (ModelElementNode elem : fn.getModelElements()) {

-				allContents.add(new GraphNodeWrapper(elem.getNode(), this));

+				allContents.add(wrap(elem.getNode()));

 			}

 		}

 

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/DerivedAllOf.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/DerivedAllOf.java
index 8f8f7df..40d9c2c 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/DerivedAllOf.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/DerivedAllOf.java
@@ -27,7 +27,6 @@
 import org.eclipse.hawk.core.graph.IGraphEdge;
 import org.eclipse.hawk.core.graph.IGraphNode;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.eclipse.hawk.graph.FileNode;
 import org.eclipse.hawk.graph.GraphWrapper;
 import org.eclipse.hawk.graph.ModelElementNode;
@@ -72,7 +71,7 @@
 			for (IGraphEdge e : root.getNode().getIncomingWithType(ModelElementNode.DERIVED_EDGE_PREFIX + dedgeName)) {
 				final IGraphNode derivedFeatureNode = e.getStartNode();
 				final IGraphNode sourceElementNode = derivedFeatureNode.getIncoming().iterator().next().getStartNode();
-				nodes.add(new GraphNodeWrapper(sourceElementNode, engine));
+				nodes.add(engine.wrap(sourceElementNode));
 			}
 		}
 	}
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/FileFirstAllOf.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/FileFirstAllOf.java
index 8b1c7cf..4d4a3e4 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/FileFirstAllOf.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/FileFirstAllOf.java
@@ -21,7 +21,6 @@
 
 import org.eclipse.hawk.core.graph.IGraphNode;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.eclipse.hawk.graph.FileNode;
 import org.eclipse.hawk.graph.ModelElementNode;
 
@@ -45,7 +44,7 @@
 			final FileNode f = new FileNode(rawFileNode);
 			for (ModelElementNode me : f.getModelElements()) {
 				if (me.isOfKind(typeNode)) {
-					nodes.add(new GraphNodeWrapper(me.getNode(), engine));
+					nodes.add(engine.wrap(me.getNode()));
 				}
 			}
 		}
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/TypeFirstAllOf.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/TypeFirstAllOf.java
index bd8e7d1..b78f41f 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/TypeFirstAllOf.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/contextful/TypeFirstAllOf.java
@@ -24,7 +24,6 @@
 import org.eclipse.hawk.core.graph.IGraphEdge;
 import org.eclipse.hawk.core.graph.IGraphNode;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.eclipse.hawk.graph.ModelElementNode;
 
 /**
@@ -51,13 +50,10 @@
 			IGraphNode node = n.getStartNode();
 			for (IGraphEdge e : node.getOutgoingWithType(ModelElementNode.EDGE_LABEL_FILE)) {
 				if (files.contains(e.getEndNode())) {
-					nodes.add(wrap(node));
+					nodes.add(engine.wrap(node));
 				}
 			}
 		}
 	}
 
-	protected GraphNodeWrapper wrap(IGraphNode node) {
-		return new GraphNodeWrapper(node, engine);
-	}
 }
\ No newline at end of file
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollection.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollection.java
index efd9d54..1d3574d 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollection.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollection.java
@@ -22,7 +22,7 @@
 import org.eclipse.epsilon.eol.execute.operations.declarative.IAbstractOperationContributor;

 import org.eclipse.epsilon.eol.models.IModel;

 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;

 

 public class OptimisableCollection extends HashSet<Object> implements

 		IAbstractOperationContributor {

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollectionSelectOperation.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollectionSelectOperation.java
index 5059610..48b1c69 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollectionSelectOperation.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/optimisation/OptimisableCollectionSelectOperation.java
@@ -52,7 +52,6 @@
 import org.eclipse.hawk.core.util.Utils;
 import org.eclipse.hawk.epsilon.emc.AbstractHawkModel;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -370,7 +369,7 @@
 
 				for (IGraphNode hit : hits) {
 
-					filter.add(new GraphNodeWrapper(hit, model));
+					filter.add(model.wrap(hit));
 
 					// ((OptimisableCollection) modifiedlist)
 					// .add(new NeoIdWrapperDebuggable(graph, hit
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/CGraphPropertyGetter.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/CGraphPropertyGetter.java
index a7ed762..10dc717 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/CGraphPropertyGetter.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/CGraphPropertyGetter.java
@@ -33,8 +33,8 @@
 import org.eclipse.hawk.core.graph.IGraphEdge;

 import org.eclipse.hawk.core.graph.IGraphNode;

 import org.eclipse.hawk.core.util.Utils;

+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;

 import org.eclipse.hawk.epsilon.emc.contextful.CEOLQueryEngine;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

 import org.eclipse.hawk.graph.FileNode;

 import org.eclipse.hawk.graph.ModelElementNode;

 import org.eclipse.hawk.graph.updater.DirtyDerivedFeaturesListener;

@@ -194,7 +194,7 @@
 					if (ret == null) {

 						List<GraphNodeWrapper> derivedTargets = new EolSequence<>();

 						for (IGraphEdge edge : derivedNode.getOutgoingWithType(ModelElementNode.DERIVED_EDGE_PREFIX + property)) {

-							derivedTargets.add(new GraphNodeWrapper(edge.getEndNode(), model));

+							derivedTargets.add(model.wrap(edge.getEndNode()));

 							ret = derivedTargets;

 						}

 					}

@@ -357,12 +357,12 @@
 

 	private GraphNodeWrapper wrapIfInScope(IGraphNode node) {

 		if (!engine.isTraversalScopingEnabled())

-			return new GraphNodeWrapper(node, model);

+			return model.wrap(node);

 

 		// capture multiple file containment (ie for singleton nodes)

 		for (IGraphEdge e : node.getOutgoingWithType(ModelElementNode.EDGE_LABEL_FILE)) {

 			if (engine.getRawFileNodes().contains(e.getEndNode())) {

-				return new GraphNodeWrapper(node, model);

+				return model.wrap(node);

 			}

 		}

 

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/GraphPropertyGetter.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/GraphPropertyGetter.java
index 890ff3a..92c75a0 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/GraphPropertyGetter.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/pgetters/GraphPropertyGetter.java
@@ -40,9 +40,9 @@
 import org.eclipse.hawk.core.graph.IGraphNode;

 import org.eclipse.hawk.core.util.Utils;

 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;

+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;

 import org.eclipse.hawk.epsilon.emc.tracking.AccessListener;

 import org.eclipse.hawk.epsilon.emc.wrappers.GraphEdgeWrapper;

-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;

 import org.eclipse.hawk.graph.FileNode;

 import org.eclipse.hawk.graph.ModelElementNode;

 import org.eclipse.hawk.graph.TypeNode;

@@ -145,7 +145,7 @@
 							derivedTargets = new EolSequence<>();

 							derivedValue = derivedTargets;

 						}

-						derivedTargets.add(new GraphNodeWrapper(edge.getEndNode(), model));

+						derivedTargets.add(model.wrap(edge.getEndNode()));

 					}

 				}

 			}

@@ -166,7 +166,7 @@
 				retCollection.addAll(values);

 			}

 			for (IGraphEdge r : node.getOutgoingWithType(property)) {

-				retCollection.add(new GraphNodeWrapper(r.getEndNode(), model));

+				retCollection.add(model.wrap(r.getEndNode()));

 			}

 			return retCollection;

 

@@ -182,9 +182,9 @@
 

 			for (IGraphEdge r : node.getOutgoingWithType(property)) {

 				if (otherNodes != null)

-					otherNodes.add(new GraphNodeWrapper(r.getEndNode(), model));

+					otherNodes.add(model.wrap(r.getEndNode()));

 				else if (otherNode == null)

-					otherNode = new GraphNodeWrapper(r.getEndNode(), model);

+					otherNode = model.wrap(r.getEndNode());

 				else

 					throw new EolRuntimeException(

 							"A relationship with arity 1 ( " + property + " ) has more than 1 links");

@@ -202,12 +202,12 @@
 

 			final EolSequence<GraphNodeWrapper> ret = new EolSequence<GraphNodeWrapper>();

 			for (IGraphEdge r : node.getIncomingWithType(referenceName)) {

-				ret.add(new GraphNodeWrapper(r.getStartNode(), model));

+				ret.add(model.wrap(r.getStartNode()));

 			}

 			for (IGraphEdge r : node.getIncomingWithType(ModelElementNode.DERIVED_EDGE_PREFIX + referenceName)) {

 				IGraphNode derivedNode = r.getStartNode();

 				IGraphNode elementNode = derivedNode.getIncoming().iterator().next().getStartNode();

-				ret.add(new GraphNodeWrapper(elementNode, model));

+				ret.add(model.wrap(elementNode));

 			}

 

 			return ret;

@@ -254,14 +254,14 @@
 			GraphNodeWrapper ret = null;

 			for (IGraphEdge r : node.getIncoming()) {

 				if (r.getProperty(ModelElementNode.EDGE_PROPERTY_CONTAINMENT) != null) {

-					ret = new GraphNodeWrapper(r.getStartNode(), model);

+					ret = model.wrap(r.getStartNode());

 					break;

 				}

 			}

 			if (ret == null) {

 				for (IGraphEdge r : node.getOutgoing()) {

 					if (r.getProperty(ModelElementNode.EDGE_PROPERTY_CONTAINER) != null) {

-						ret = new GraphNodeWrapper(r.getEndNode(), model);

+						ret = model.wrap(r.getEndNode());

 						break;

 					}

 				}

@@ -276,13 +276,13 @@
 			GraphNodeWrapper ret = null;

 			for (IGraphEdge r : node.getIncoming()) {

 				if (r.getProperty(ModelElementNode.EDGE_PROPERTY_CONTAINMENT) != null) {

-					return Collections.singletonList(new GraphNodeWrapper(r.getStartNode(), model));

+					return Collections.singletonList(model.wrap(r.getStartNode()));

 				}

 			}

 			if (ret == null) {

 				for (IGraphEdge r : node.getOutgoing()) {

 					if (r.getProperty(ModelElementNode.EDGE_PROPERTY_CONTAINER) != null) {

-						return Collections.singletonList(new GraphNodeWrapper(r.getEndNode(), model));

+						return Collections.singletonList(model.wrap(r.getEndNode()));

 					}

 				}

 			}

@@ -309,11 +309,11 @@
 					for (IGraphEdge derivedEdge : it) {

 						final IGraphNode derivedEdgeNode = isIncoming ? derivedEdge.getStartNode()

 								: derivedEdge.getEndNode();

-						final GraphNodeWrapper edgeNodeWrapper = new GraphNodeWrapper(derivedEdgeNode, model);

+						final GraphNodeWrapper edgeNodeWrapper = model.wrap(derivedEdgeNode);

 						results.add(edgeNodeWrapper);

 					}

 				} else {

-					final GraphNodeWrapper edgeNodeWrapper = new GraphNodeWrapper(edgeNode, model);

+					final GraphNodeWrapper edgeNodeWrapper = model.wrap(edgeNode);

 					results.add(edgeNodeWrapper);

 				}

 			}

@@ -366,12 +366,12 @@
 				// TODO add ability to mark derived edges as containments to

 				// be able to use them here

 

-				results.add(new GraphNodeWrapper(r.getEndNode(), model));

+				results.add(model.wrap(r.getEndNode()));

 			}

 		}

 		for (IGraphEdge r : node.getIncoming()) {

 			if (r.getProperty(ModelElementNode.EDGE_PROPERTY_CONTAINER) != null) {

-				results.add(new GraphNodeWrapper(r.getStartNode(), model));

+				results.add(model.wrap(r.getStartNode()));

 			}

 		}

 		return results;

diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/FileNodeWrapper.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/FileNodeWrapper.java
index 3b82c8c..9d4b94d 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/FileNodeWrapper.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/FileNodeWrapper.java
@@ -24,6 +24,7 @@
 import org.eclipse.hawk.core.graph.IGraphNodeReference;
 import org.eclipse.hawk.core.query.IQueryEngine;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.graph.FileNode;
 import org.eclipse.hawk.graph.ModelElementNode;
 
@@ -68,7 +69,7 @@
 	public List<GraphNodeWrapper> getRoots() {
 		List<GraphNodeWrapper> results = new ArrayList<>();
 		for (ModelElementNode n : fileNode.getRootModelElements()) {
-			results.add(new GraphNodeWrapper(n.getNode(), model));
+			results.add(model.wrap(n.getNode()));
 		}
 		return results;
 	}
@@ -76,7 +77,7 @@
 	public List<GraphNodeWrapper> getContents() {
 		List<GraphNodeWrapper> results = new ArrayList<>();
 		for (ModelElementNode n : fileNode.getModelElements()) {
-			results.add(new GraphNodeWrapper(n.getNode(), model));
+			results.add(model.wrap(n.getNode()));
 		}
 		return results;
 	}
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphEdgeWrapper.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphEdgeWrapper.java
index c59f9f4..3cf2e3b 100644
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphEdgeWrapper.java
+++ b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphEdgeWrapper.java
@@ -50,7 +50,7 @@
 	}
 
 	public Object getEndNode() {
-		return new GraphNodeWrapper(edge.getEndNode(), containerModel);
+		return containerModel.wrap(edge.getEndNode());
 	}
 
 	public Object getTarget() {
@@ -58,7 +58,7 @@
 	}
 
 	public Object getStartNode() {
-		return new GraphNodeWrapper(edge.getStartNode(), containerModel);
+		return containerModel.wrap(edge.getStartNode());
 	}
 
 	public Object getSource() {
diff --git a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphNodeWrapper.java b/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphNodeWrapper.java
deleted file mode 100644
index 241ccea..0000000
--- a/core/plugins/org.eclipse.hawk.epsilon/src/org/eclipse/hawk/epsilon/emc/wrappers/GraphNodeWrapper.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*******************************************************************************

- * Copyright (c) 2011-2018 The University of York, Aston University.

- * 

- * This program and the accompanying materials are made available under the

- * terms of the Eclipse Public License 2.0 which is available at

- * http://www.eclipse.org/legal/epl-2.0.

- *

- * This Source Code may also be made available under the following Secondary

- * Licenses when the conditions for such availability set forth in the Eclipse

- * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.

- *

- * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0

- *

- * Contributors:

- *     Konstantinos Barmpis - initial API and implementation

- *     Antonio Garcia-Dominguez - add isContainedWithin (for EMF-Splitter integration), use logging

- ******************************************************************************/

-package org.eclipse.hawk.epsilon.emc.wrappers;

-

-import java.lang.ref.WeakReference;

-import java.util.Iterator;

-import java.util.Objects;

-

-import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;

-import org.eclipse.hawk.core.IModelIndexer;

-import org.eclipse.hawk.core.graph.IGraphEdge;

-import org.eclipse.hawk.core.graph.IGraphNode;

-import org.eclipse.hawk.core.graph.IGraphNodeReference;

-import org.eclipse.hawk.core.graph.IGraphTransaction;

-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;

-import org.eclipse.hawk.graph.ModelElementNode;

-import org.slf4j.Logger;

-import org.slf4j.LoggerFactory;

-

-public class GraphNodeWrapper implements IGraphNodeReference {

-

-	private static final Logger LOGGER = LoggerFactory.getLogger(GraphNodeWrapper.class);

-

-	protected String id;

-	protected EOLQueryEngine containerModel;

-	protected WeakReference<IGraphNode> node;

-

-	public GraphNodeWrapper(IGraphNode n, EOLQueryEngine containerModel) {

-

-		node = new WeakReference<IGraphNode>(n);

-		this.id = n.getId().toString();

-		this.containerModel = containerModel;

-

-	}

-

-	@Override

-	public IGraphNode getNode() {

-		IGraphNode ret = node.get();

-		if (ret == null) {

-			ret = containerModel.getBackend().getNodeById(id);

-			node = new WeakReference<IGraphNode>(ret);

-		}

-		return ret;

-	}

-

-	@Override

-	public String getId() {

-		return id;

-	}

-

-	@Override

-	public EOLQueryEngine getContainerModel() {

-		return containerModel;

-	}

-

-	@Override

-	public boolean equals(Object obj) {

-		if (this == obj)

-			return true;

-		if (obj == null)

-			return false;

-		if (getClass() != obj.getClass())

-			return false;

-		GraphNodeWrapper other = (GraphNodeWrapper) obj;

-		return Objects.equals(containerModel, other.containerModel) && Objects.equals(id, other.id);

-	}

-

-	public Object getFeature(String name) throws EolRuntimeException {

-		return containerModel.getPropertyGetter().invoke(this, name);

-	}

-

-	/**

-	 * Returns true if this model element is contained directly or indirectly

-	 * within the specified path at the specified repository.

-	 */

-	public boolean isContainedWithin(String repository, String path) {

-		try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

-			final ModelElementNode men = new ModelElementNode(getNode());

-			return men.isContainedWithin(repository, path);

-		} catch (Exception e) {

-			LOGGER.error(e.getMessage(), e);

-		}

-		return false;

-	}

-

-	@Override

-	public String getTypeName() {

-		String type = "";

-

-		try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

-			IGraphNode n = getNode();

-

-			final Iterator<IGraphEdge> itTypeNode = n.getOutgoingWithType(ModelElementNode.EDGE_LABEL_OFTYPE).iterator();

-			if (itTypeNode.hasNext()) {

-				final IGraphNode typeNode = itTypeNode.next().getEndNode();

-				type = typeNode.getProperty(IModelIndexer.IDENTIFIER_PROPERTY).toString();

-			} else {

-				LOGGER.error("No type node found for node {}", n);

-			}

-

-			t.success();

-		} catch (Exception e) {

-			LOGGER.error(e.getMessage(), e);

-		}

-

-		return type;

-	}

-

-	@Override

-	public String toString() {

-		String info = "";

-

-		try (IGraphTransaction t = containerModel.getBackend().beginTransaction()) {

-			info += "type:" + getTypeName();

-			info += "";

-			t.success();

-		} catch (Exception e) {

-			LOGGER.error(e.getMessage(), e);

-		}

-		return "GNW|id:" + id + "|" + (info.equals("") ? "[no meta-info]" : info) + "";

-	}

-

-	@Override

-	public int hashCode() {

-		return Objects.hash(containerModel, id);

-	}

-}

diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/StrongGraphNodeWrapper.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/StrongGraphNodeWrapper.java
deleted file mode 100644
index cf15909..0000000
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/StrongGraphNodeWrapper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2020 Aston University.
- * 
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the Eclipse
- * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
- *
- * Contributors:
- *     Antonio Garcia-Dominguez - initial API and implementation
- ******************************************************************************/
-package org.eclipse.hawk.timeaware.graph;
-
-import org.eclipse.hawk.core.graph.IGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
-
-/**
- * Variant of {@link GraphNodeWrapper} which keeps a strong reference, in case
- * we cannot be sure that we can simply retrieve the exact original node through
- * ID and optionally time. This is needed for the scoping wrappers in the
- * time-aware query DSL, as recreating those would essentially require
- * re-running the query itself.
- */
-public class StrongGraphNodeWrapper extends GraphNodeWrapper {
-
-	private IGraphNode node;
-
-	public StrongGraphNodeWrapper(IGraphNode n, EOLQueryEngine containerModel) {
-		super(n, containerModel);
-		this.node = n;
-	}
-
-	@Override
-	public IGraphNode getNode() {
-		return node;
-	}
-
-}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/TimeAwareGraphNodeWrapper.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/TimeAwareGraphNodeWrapper.java
deleted file mode 100644
index f4c78a3..0000000
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/graph/TimeAwareGraphNodeWrapper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2020 Aston University.
- * 
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * This Source Code may also be made available under the following Secondary
- * Licenses when the conditions for such availability set forth in the Eclipse
- * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
- *
- * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
- *
- * Contributors:
- *     Antonio Garcia-Dominguez - initial API and implementation
- ******************************************************************************/
-package org.eclipse.hawk.timeaware.graph;
-
-import java.lang.ref.WeakReference;
-
-import org.eclipse.hawk.core.graph.IGraphNode;
-import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
-import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
-
-/**
- * Wraps a standalone node while remembering its original time, so we can
- * retrieve the exact same node later if the weak reference has been GC'ed.
- */
-public class TimeAwareGraphNodeWrapper extends GraphNodeWrapper {
-
-	private long time;
-
-	public TimeAwareGraphNodeWrapper(IGraphNode n, TimeAwareEOLQueryEngine containerModel) {
-		super(n, containerModel);
-		this.time = ((ITimeAwareGraphNode) n).getTime();
-	}
-
-	@Override
-	public IGraphNode getNode() {
-		IGraphNode ret = node.get();
-		if (ret == null) {
-			TimeAwareEOLQueryEngine taQuery = (TimeAwareEOLQueryEngine)containerModel;
-			ret = taQuery.getBackend().getNodeById(id).travelInTime(time);
-			node = new WeakReference<IGraphNode>(ret);
-		}
-		return ret;
-	}
-
-	
-}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLOperationFactory.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLOperationFactory.java
index 559f1b5..894217d 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLOperationFactory.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLOperationFactory.java
@@ -19,7 +19,6 @@
 
 import org.eclipse.epsilon.eol.execute.operations.EolOperationFactory;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.patterns.AlwaysReducer;
 import org.eclipse.hawk.timeaware.queries.operations.patterns.BoundedVersionQuantifierOperation;
 import org.eclipse.hawk.timeaware.queries.operations.patterns.EventuallyAtLeastReducer;
@@ -47,9 +46,9 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(TimeAwareEOLOperationFactory.class);
 
-	private final EOLQueryEngine containerModel;
+	private final TimeAwareEOLQueryEngine containerModel;
 
-	public TimeAwareEOLOperationFactory(EOLQueryEngine model) {
+	public TimeAwareEOLOperationFactory(TimeAwareEOLQueryEngine model) {
 		this.containerModel = model;
 
 		operationCache.put("always",
@@ -148,7 +147,7 @@
 		operationCache.put("beforeAnnotated", new BeforeAnnotatedOperation(this::getContainerModel));
 	}
 
-	public EOLQueryEngine getContainerModel() {
+	public TimeAwareEOLQueryEngine getContainerModel() {
 		return containerModel;
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLQueryEngine.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLQueryEngine.java
index 4a7036a..78191eb 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLQueryEngine.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareEOLQueryEngine.java
@@ -16,6 +16,7 @@
  ******************************************************************************/
 package org.eclipse.hawk.timeaware.queries;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -45,18 +46,17 @@
 import org.eclipse.hawk.epsilon.emc.contextful.TypeFirstAllOf;
 import org.eclipse.hawk.epsilon.emc.pgetters.GraphPropertyGetter;
 import org.eclipse.hawk.epsilon.emc.wrappers.FileNodeWrapper;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.eclipse.hawk.graph.FileNode;
 import org.eclipse.hawk.graph.GraphWrapper;
 import org.eclipse.hawk.graph.ModelElementNode;
 import org.eclipse.hawk.graph.ProxyReferenceList;
 import org.eclipse.hawk.graph.updater.GraphModelBatchInjector;
 import org.eclipse.hawk.graph.updater.GraphModelUpdater;
-import org.eclipse.hawk.timeaware.graph.TimeAwareGraphNodeWrapper;
 import org.eclipse.hawk.timeaware.graph.VCSManagerIndex;
 import org.eclipse.hawk.timeaware.graph.VCSManagerIndex.RepositoryNode;
 import org.eclipse.hawk.timeaware.queries.operations.reflective.TimeAwareNodeHistoryOperationContributor;
 import org.eclipse.hawk.timeaware.queries.operations.reflective.TypeHistoryOperationContributor;
+import org.eclipse.hawk.timeaware.queries.operations.scopes.IScopingTimeAwareGraphNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,16 +73,47 @@
 public class TimeAwareEOLQueryEngine extends EOLQueryEngine {
 
 	/**
-	 * Time-aware variant of {@link TypeFirstAllOf}.
+	 * Wraps a standalone node while remembering its original time, so we can
+	 * retrieve the exact same node later if the weak reference has been GC'ed.
 	 */
-	protected final class TimeAwareTypeFirstAllOf extends TypeFirstAllOf {
-		private TimeAwareTypeFirstAllOf(Function<IGraphNode, Iterable<? extends IGraphNode>> allFiles, EOLQueryEngine engine) {
-			super(allFiles, engine);
+	public class TimeAwareGraphNodeWrapper extends GraphNodeWrapper {
+		private long time;
+
+		protected TimeAwareGraphNodeWrapper(IGraphNode n, TimeAwareEOLQueryEngine containerModel) {
+			super(n, containerModel);
+			this.time = ((ITimeAwareGraphNode) n).getTime();
 		}
 
 		@Override
-		protected GraphNodeWrapper wrap(IGraphNode node) {
-			return new TimeAwareGraphNodeWrapper(node, TimeAwareEOLQueryEngine.this);
+		public IGraphNode getNode() {
+			IGraphNode ret = node.get();
+			if (ret == null) {
+				TimeAwareEOLQueryEngine taQuery = (TimeAwareEOLQueryEngine)containerModel;
+				ret = taQuery.getBackend().getNodeById(id).travelInTime(time);
+				node = new WeakReference<IGraphNode>(ret);
+			}
+			return ret;
+		}
+	}
+
+	/**
+	 * Variant of {@link GraphNodeWrapper} which keeps a strong reference, in case
+	 * we cannot be sure that we can simply retrieve the exact original node through
+	 * ID and optionally time. This is needed for the scoping wrappers in the
+	 * time-aware query DSL, as recreating those would essentially require
+	 * re-running the query itself.
+	 */
+	public class StrongGraphNodeWrapper extends GraphNodeWrapper {
+		private IGraphNode node;
+
+		protected StrongGraphNodeWrapper(IGraphNode n, EOLQueryEngine containerModel) {
+			super(n, containerModel);
+			this.node = n;
+		}
+
+		@Override
+		public IGraphNode getNode() {
+			return node;
 		}
 	}
 
@@ -426,7 +457,21 @@
 			 */
 			final GlobPatternTimeAwareAllFiles innerAllFiles = new GlobPatternTimeAwareAllFiles(rplist, fplist);
 			setAllFiles(innerAllFiles);
-			setAllOf(new TimeAwareTypeFirstAllOf(innerAllFiles, this));
+			setAllOf(new TypeFirstAllOf(innerAllFiles, this));
 		}
 	}
+
+	@Override
+	public GraphNodeWrapper wrap(IGraphNode node) {
+		/*
+		 * If we're wrapping a scoping node, then it has to be a strong reference-based one.
+		 * Otherwise, use a weak reference-based one to save memory.
+		 */
+		if (node instanceof IScopingTimeAwareGraphNode) {
+			return new StrongGraphNodeWrapper(node, this);
+		} else {
+			return new TimeAwareGraphNodeWrapper(node, this);
+		}
+	}
+
 }
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareGraphPropertyGetter.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareGraphPropertyGetter.java
index 7e7bd47..bed37e9 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareGraphPropertyGetter.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/TimeAwareGraphPropertyGetter.java
@@ -24,9 +24,8 @@
 import org.eclipse.hawk.core.graph.IGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.epsilon.emc.pgetters.GraphPropertyGetter;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
-import org.eclipse.hawk.timeaware.graph.StrongGraphNodeWrapper;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.EndingTimeAwareNodeWrapper;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.IScopingTimeAwareGraphNode;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.StartingTimeAwareNodeWrapper;
@@ -54,33 +53,33 @@
 			case "versions":
 				return getVersions(taNode);
 			case "latest":
-				return new StrongGraphNodeWrapper(taNode.getLatest(), model);
+				return model.wrap(taNode.getLatest());
 			case "earliest":
-				return new StrongGraphNodeWrapper(taNode.getEarliest(), model);
+				return model.wrap(taNode.getEarliest());
 			case "previous":
 			case "prev":
 				final ITimeAwareGraphNode taPrevious = taNode.getPrevious();
 				if (taPrevious == null) {
 					return null;
 				} else {
-					return new StrongGraphNodeWrapper(taPrevious, model);
+					return model.wrap(taPrevious);
 				}
 			case "next":
 				final ITimeAwareGraphNode taNext = taNode.getNext();
 				if (taNext == null) {
 					return null;
 				} else {
-					return new StrongGraphNodeWrapper(taNext, model);
+					return model.wrap(taNext);
 				}
 			case "time":
 				return taNode.getTime();
 			case "sinceThen": {
 					final StartingTimeAwareNodeWrapper scoped = new StartingTimeAwareNodeWrapper(taNode);
-					return new StrongGraphNodeWrapper(scoped, model);
+					return model.wrap(scoped);
 				}
 			case "untilThen": {
 				final EndingTimeAwareNodeWrapper scoped = new EndingTimeAwareNodeWrapper(taNode);
-				return new StrongGraphNodeWrapper(scoped, model);
+				return model.wrap(scoped);
 			}
 			case "afterThen": {
 					ITimeAwareGraphNode nextVersion = taNode.getNext();
@@ -88,7 +87,7 @@
 						return null;
 					} else {
 						final StartingTimeAwareNodeWrapper scoped = new StartingTimeAwareNodeWrapper(nextVersion);
-						return new StrongGraphNodeWrapper(scoped, model);
+						return model.wrap(scoped);
 					}
 				}
 			case "beforeThen": {
@@ -97,7 +96,7 @@
 						return null;
 					} else {
 						final EndingTimeAwareNodeWrapper scoped = new EndingTimeAwareNodeWrapper(prevVersion);
-						return new StrongGraphNodeWrapper(scoped, model);
+						return model.wrap(scoped);
 					}
 				}
 			case "unscoped": {
@@ -107,7 +106,7 @@
 					} else {
 						unscoped = taNode;
 					}
-					return new StrongGraphNodeWrapper(unscoped, model);
+					return model.wrap(unscoped);
 				}
 			}
 		} catch (Exception ex) {
@@ -121,7 +120,7 @@
 	private List<GraphNodeWrapper> getVersions(ITimeAwareGraphNode taNode) throws Exception {
 		final List<GraphNodeWrapper> result = new ArrayList<>();
 		for (ITimeAwareGraphNode version : taNode.getAllVersions()) {
-			result.add(new StrongGraphNodeWrapper(version, model));
+			result.add(model.wrap(version));
 		}
 		return result;
 	}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/TimeAwareNodeFirstOrderOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/TimeAwareNodeFirstOrderOperation.java
index 0b43970..53f34bd 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/TimeAwareNodeFirstOrderOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/TimeAwareNodeFirstOrderOperation.java
@@ -26,11 +26,10 @@
 import org.eclipse.epsilon.eol.execute.context.Variable;
 import org.eclipse.epsilon.eol.execute.operations.declarative.FirstOrderOperation;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.epsilon.emc.wrappers.TypeNodeWrapper;
 import org.eclipse.hawk.graph.TypeNode;
-import org.eclipse.hawk.timeaware.graph.StrongGraphNodeWrapper;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,9 +41,9 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(TimeAwareNodeFirstOrderOperation.class);
 
-	protected final Supplier<EOLQueryEngine> containerModelSupplier;
+	protected final Supplier<TimeAwareEOLQueryEngine> containerModelSupplier;
 
-	public TimeAwareNodeFirstOrderOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public TimeAwareNodeFirstOrderOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		this.containerModelSupplier = containerModelSupplier;
 	}
 
@@ -65,7 +64,7 @@
 			final GraphNodeWrapper gnw = (GraphNodeWrapper)target;
 			if (gnw.getNode() instanceof ITimeAwareGraphNode) {
 				taNode = (ITimeAwareGraphNode) gnw.getNode();
-				varWrapper = (n) -> new StrongGraphNodeWrapper(n, containerModelSupplier.get());
+				varWrapper = (n) -> containerModelSupplier.get().wrap(n);
 			} else {
 				LOGGER.warn("called on non-timeaware node {}, returning false", target.getClass().getName());
 				return false;
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/BoundedVersionQuantifierOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/BoundedVersionQuantifierOperation.java
index a6dcb33..869f69e 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/BoundedVersionQuantifierOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/BoundedVersionQuantifierOperation.java
@@ -29,14 +29,14 @@
 import org.eclipse.epsilon.eol.types.EolModelElementType;
 import org.eclipse.epsilon.eol.types.EolNoType;
 import org.eclipse.epsilon.eol.types.EolType;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 
 public class BoundedVersionQuantifierOperation extends AbstractOperation {
 
 	private final Function<Integer, IShortCircuitReducer> reducerLambda;
-	private final Supplier<EOLQueryEngine> modelSupplier;
+	private final Supplier<TimeAwareEOLQueryEngine> modelSupplier;
 
-	public BoundedVersionQuantifierOperation(Supplier<EOLQueryEngine> containerModel, Function<Integer, IShortCircuitReducer> reducerLambda) {
+	public BoundedVersionQuantifierOperation(Supplier<TimeAwareEOLQueryEngine> containerModel, Function<Integer, IShortCircuitReducer> reducerLambda) {
 		this.modelSupplier = containerModel;
 		this.reducerLambda = reducerLambda;
 	}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/VersionQuantifierOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/VersionQuantifierOperation.java
index 6e0bbe3..443377e 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/VersionQuantifierOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/patterns/VersionQuantifierOperation.java
@@ -27,7 +27,7 @@
 import org.eclipse.epsilon.eol.execute.context.IEolContext;
 import org.eclipse.epsilon.eol.execute.context.Variable;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.TimeAwareNodeFirstOrderOperation;
 
 /**
@@ -39,7 +39,7 @@
 
 	private final IShortCircuitReducer reducer;
 
-	public VersionQuantifierOperation(Supplier<EOLQueryEngine> containerModelSupplier, IShortCircuitReducer reducer) {
+	public VersionQuantifierOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier, IShortCircuitReducer reducer) {
 		super(containerModelSupplier);
 		this.reducer = reducer;
 	}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/reflective/TimeAwareNodeHistoryOperationContributor.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/reflective/TimeAwareNodeHistoryOperationContributor.java
index 96f7f53..5aa9a69 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/reflective/TimeAwareNodeHistoryOperationContributor.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/reflective/TimeAwareNodeHistoryOperationContributor.java
@@ -23,19 +23,18 @@
 import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
 import org.eclipse.epsilon.eol.execute.operations.contributors.OperationContributor;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
-import org.eclipse.hawk.timeaware.graph.StrongGraphNodeWrapper;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.timeaware.queries.RiskyFunction;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class TimeAwareNodeHistoryOperationContributor extends OperationContributor {
 	private static final Logger LOGGER = LoggerFactory.getLogger(TimeAwareNodeHistoryOperationContributor.class);
 
-	private EOLQueryEngine model;
+	private TimeAwareEOLQueryEngine model;
 
-	public TimeAwareNodeHistoryOperationContributor(EOLQueryEngine q) {
+	public TimeAwareNodeHistoryOperationContributor(TimeAwareEOLQueryEngine q) {
 		this.model = q;
 	}
 
@@ -57,7 +56,7 @@
 	}
 
 	public GraphNodeWrapper travelInTime(long time) {
-		return new StrongGraphNodeWrapper(castTarget(getTarget()).travelInTime(time), model);
+		return model.wrap(castTarget(getTarget()).travelInTime(time));
 	}
 
 	private List<GraphNodeWrapper> getRelatedVersions(
@@ -66,7 +65,7 @@
 		final List<GraphNodeWrapper> results = new ArrayList<>();
 		try {
 			for (ITimeAwareGraphNode version : f.call(taNode)) {
-				results.add(new StrongGraphNodeWrapper(version, model));
+				results.add(model.wrap(version));
 			}
 		} catch (Exception e) {
 			LOGGER.error(e.getMessage(), e);
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AbstractAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AbstractAnnotatedOperation.java
index 1941a69..d59b1a4 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AbstractAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AbstractAnnotatedOperation.java
@@ -27,11 +27,10 @@
 import org.eclipse.epsilon.eol.execute.operations.AbstractOperation;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.graph.ModelElementNode;
 import org.eclipse.hawk.graph.Slot;
-import org.eclipse.hawk.timeaware.graph.StrongGraphNodeWrapper;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,9 +38,9 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAnnotatedOperation.class);
 
-	private final Supplier<EOLQueryEngine> modelSupplier;
+	private final Supplier<TimeAwareEOLQueryEngine> modelSupplier;
 
-	public AbstractAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public AbstractAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		this.modelSupplier = containerModelSupplier;
 	}
 
@@ -84,7 +83,7 @@
 		if (wrapper == null) {
 			return null;
 		} else {
-			return new StrongGraphNodeWrapper(wrapper, modelSupplier.get());
+			return modelSupplier.get().wrap(wrapper);
 		}
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AfterAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AfterAnnotatedOperation.java
index 396d370..ce91e36 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AfterAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/AfterAnnotatedOperation.java
@@ -20,7 +20,7 @@
 
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.StartingTimeAwareNodeWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,7 +32,7 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(AfterAnnotatedOperation.class);
 
-	public AfterAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public AfterAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/BeforeAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/BeforeAnnotatedOperation.java
index d76fd04..71b8966 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/BeforeAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/BeforeAnnotatedOperation.java
@@ -20,7 +20,7 @@
 
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.EndingTimeAwareNodeWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,7 +32,7 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(BeforeAnnotatedOperation.class);
 
-	public BeforeAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public BeforeAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/SinceAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/SinceAnnotatedOperation.java
index 9159546..62e7ebd 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/SinceAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/SinceAnnotatedOperation.java
@@ -20,7 +20,7 @@
 
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.StartingTimeAwareNodeWrapper;
 
 /**
@@ -28,7 +28,7 @@
  */
 public class SinceAnnotatedOperation extends AbstractAnnotatedOperation {
 
-	public SinceAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public SinceAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/UntilAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/UntilAnnotatedOperation.java
index e9b043c..ffc8ac4 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/UntilAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/UntilAnnotatedOperation.java
@@ -20,7 +20,7 @@
 
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.EndingTimeAwareNodeWrapper;
 
 /**
@@ -28,7 +28,7 @@
  */
 public class UntilAnnotatedOperation extends AbstractAnnotatedOperation {
 
-	public UntilAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public UntilAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/WhenAnnotatedOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/WhenAnnotatedOperation.java
index 3550d54..dbfd120 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/WhenAnnotatedOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/annotations/WhenAnnotatedOperation.java
@@ -21,7 +21,7 @@
 
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNodeIndex;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.WhenNodeWrapper;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.predicates.WhenOperation;
 
@@ -30,7 +30,7 @@
  */
 public class WhenAnnotatedOperation extends AbstractAnnotatedOperation {
 
-	public WhenAnnotatedOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public WhenAnnotatedOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/VersionRangeOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/VersionRangeOperation.java
index 70cd92e..3c05d5a 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/VersionRangeOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/VersionRangeOperation.java
@@ -28,7 +28,7 @@
 import org.eclipse.epsilon.eol.execute.context.IEolContext;
 import org.eclipse.epsilon.eol.execute.context.Variable;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.TimeAwareNodeFirstOrderOperation;
 
 /**
@@ -53,7 +53,7 @@
 
 	private final IRangeBasedNodeScoper nodeScoper;
 
-	public VersionRangeOperation(Supplier<EOLQueryEngine> containerModelSupplier, IRangeBasedNodeScoper nodeScoper) {
+	public VersionRangeOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier, IRangeBasedNodeScoper nodeScoper) {
 		super(containerModelSupplier);
 		this.nodeScoper = nodeScoper;
 	}
diff --git a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/WhenOperation.java b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/WhenOperation.java
index 7b934da..57df4f5 100644
--- a/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/WhenOperation.java
+++ b/core/plugins/org.eclipse.hawk.timeaware/src/org/eclipse/hawk/timeaware/queries/operations/scopes/predicates/WhenOperation.java
@@ -29,7 +29,7 @@
 import org.eclipse.epsilon.eol.execute.context.IEolContext;
 import org.eclipse.epsilon.eol.execute.context.Variable;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
-import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
 import org.eclipse.hawk.timeaware.queries.operations.TimeAwareNodeFirstOrderOperation;
 import org.eclipse.hawk.timeaware.queries.operations.scopes.WhenNodeWrapper;
 
@@ -44,7 +44,7 @@
  */
 public class WhenOperation extends TimeAwareNodeFirstOrderOperation {
 
-	public WhenOperation(Supplier<EOLQueryEngine> containerModelSupplier) {
+	public WhenOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier) {
 		super(containerModelSupplier);
 	}
 
diff --git a/core/tests/org.eclipse.hawk.integration.tests/src/org/eclipse/hawk/integration/tests/uml/UMLIndexingTest.java b/core/tests/org.eclipse.hawk.integration.tests/src/org/eclipse/hawk/integration/tests/uml/UMLIndexingTest.java
index bff76fe..54ee27f 100644
--- a/core/tests/org.eclipse.hawk.integration.tests/src/org/eclipse/hawk/integration/tests/uml/UMLIndexingTest.java
+++ b/core/tests/org.eclipse.hawk.integration.tests/src/org/eclipse/hawk/integration/tests/uml/UMLIndexingTest.java
@@ -31,8 +31,8 @@
 import org.eclipse.hawk.core.graph.IGraphNode;
 import org.eclipse.hawk.core.graph.IGraphTransaction;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.epsilon.emc.contextful.CEOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
diff --git a/core/tests/org.eclipse.hawk.timeaware.tests/src/org/eclipse/hawk/timeaware/tests/SubversionNodeHistoryTest.java b/core/tests/org.eclipse.hawk.timeaware.tests/src/org/eclipse/hawk/timeaware/tests/SubversionNodeHistoryTest.java
index 0c3bffc..c509adf 100644
--- a/core/tests/org.eclipse.hawk.timeaware.tests/src/org/eclipse/hawk/timeaware/tests/SubversionNodeHistoryTest.java
+++ b/core/tests/org.eclipse.hawk.timeaware.tests/src/org/eclipse/hawk/timeaware/tests/SubversionNodeHistoryTest.java
@@ -31,13 +31,14 @@
 import org.eclipse.hawk.backend.tests.factories.IGraphDatabaseFactory;
 import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
 import org.eclipse.hawk.epsilon.emc.EOLQueryEngine;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.graph.Slot;
 import org.eclipse.hawk.integration.tests.emf.EMFModelSupportFactory;
 import org.eclipse.hawk.integration.tests.mm.Tree.Tree;
 import org.eclipse.hawk.integration.tests.mm.Tree.TreeFactory;
 import org.eclipse.hawk.integration.tests.mm.Tree.TreePackage;
 import org.eclipse.hawk.svn.tests.rules.TemporarySVNRepository;
+import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine.TimeAwareGraphNodeWrapper;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -225,6 +226,18 @@
 	}
 
 	@Test
+	public void followReferences() throws Throwable {
+		keepAddingChildren();
+		scheduleAndWait(() -> {
+			Object taGNW = timeAwareEOL("return Tree.latest.all.selectOne(t|t.label='Root').earliest.next.children.first;");
+			assertTrue("Following a reference in a time-aware backend should result in a time-aware graph node wrapper",
+				taGNW instanceof TimeAwareGraphNodeWrapper);
+
+			return null;
+		});
+	}
+
+	@Test
 	public void rangesAreBothInclusive() throws Throwable {
 		keepAddingChildren();
 		scheduleAndWait(() -> {
diff --git a/server/tests/org.eclipse.hawk.service.servlet.tests/src/org/eclipse/hawk/service/servlet/ThriftEncodingTest.java b/server/tests/org.eclipse.hawk.service.servlet.tests/src/org/eclipse/hawk/service/servlet/ThriftEncodingTest.java
index becddb0..71a6fd1 100644
--- a/server/tests/org.eclipse.hawk.service.servlet.tests/src/org/eclipse/hawk/service/servlet/ThriftEncodingTest.java
+++ b/server/tests/org.eclipse.hawk.service.servlet.tests/src/org/eclipse/hawk/service/servlet/ThriftEncodingTest.java
@@ -30,7 +30,7 @@
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.hawk.backend.tests.factories.IGraphDatabaseFactory;
 import org.eclipse.hawk.core.graph.IGraphNode;
-import org.eclipse.hawk.epsilon.emc.wrappers.GraphNodeWrapper;
+import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
 import org.eclipse.hawk.graph.GraphWrapper;
 import org.eclipse.hawk.greycat.tests.LevelDBGreycatDatabaseFactory;
 import org.eclipse.hawk.integration.tests.emf.EMFModelSupportFactory;