/******************************************************************************* * Copyright (c) 2004-2008 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.api; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.incquery.runtime.exception.IncQueryException; /** * Global registry of active EMF-IncQuery engines. * * <p> * Manages an {@link IncQueryEngine} for each EMF model, that is created on demand. Managed engines are shared between * clients querying the same EMF model. * * <p> * It is also possible to create private, unmanaged engines that are not shared between clients. * * <p> * Only weak references are retained on the managed engines. So if there are no other references to the matchers or the * engine, they can eventually be GC'ed, and they won't block the EMF model from being GC'ed either. * * * @author Bergmann Gabor * */ public class EngineManager { private static EngineManager instance = new EngineManager(); /** * @return the singleton instance */ public static EngineManager getInstance() { return instance; } /** * Only a weak reference is kept on engine, so that it can be GC'ed if the model becomes unreachable. * * <p> * it will not be GC'ed before because of {@link BaseIndexListener#iqEngine} */ Map<Notifier, WeakReference<IncQueryEngine>> engines; EngineManager() { super(); engines = new WeakHashMap<Notifier, WeakReference<IncQueryEngine>>(); } /** * Creates a managed EMF-IncQuery engine at an EMF model root (recommended: Resource or ResourceSet) or retrieves an * already existing one. Repeated invocations for a single model root will return the same engine. Consequently, the * engine will be reused between different clients querying the same model, providing performance benefits. * * <p> * The scope of pattern matching will be the given EMF model root and below (see FAQ for more precise definition). * The match set of any patterns will be incrementally refreshed upon updates from this scope. * * @param emfRoot * the root of the EMF containment hierarchy where this engine should operate. Recommended: Resource or * ResourceSet. * @return a new or previously existing engine * @throws IncQueryException */ public IncQueryEngine getIncQueryEngine(Notifier emfRoot) throws IncQueryException { IncQueryEngine engine = getEngineInternal(emfRoot); if (engine == null) { engine = new IncQueryEngine(this, emfRoot); engines.put(emfRoot, new WeakReference<IncQueryEngine>(engine)); } return engine; } /** * Retrieves an already existing managed EMF-IncQuery engine. * * @param emfRoot * the root of the EMF containment hierarchy where this engine operates. * @return a previously existing engine, or null if no engine is active for the given EMF model root */ public IncQueryEngine getIncQueryEngineIfExists(Notifier emfRoot) { return getEngineInternal(emfRoot); } /** * Creates a new unmanaged EMF-IncQuery engine at an EMF model root (recommended: Resource or ResourceSet). Repeated * invocations will return different instances, so other clients are unable to independently access and influence * the returned engine. Note that unmanaged engines do not benefit from some performance improvements that stem from * sharing incrementally maintained indices and caches. * * <p> * The scope of pattern matching will be the given EMF model root and below (see FAQ for more precise definition). * The match set of any patterns will be incrementally refreshed upon updates from this scope. * * @param emfRoot * the root of the EMF containment hierarchy where this engine should operate. Recommended: Resource or * ResourceSet. * @return a new existing engine * @throws IncQueryException */ public IncQueryEngine createUnmanagedIncQueryEngine(Notifier emfRoot) throws IncQueryException { return new IncQueryEngine(null, emfRoot); } /** * Disconnects the managed engine that was previously attached at the given EMF model root. Matcher objects will * continue to return stale results. Subsequent invocations of {@link #getIncQueryEngine(Notifier)} with the same * EMF root will return a new managed engine. * * <p> * The engine will not impose on the model its update overhead anymore. If no references are retained to the * matchers or the engine, GC'ing the engine and its caches is presumably made easier, although (due to weak * references) a dispose() call is not strictly necessary. * <p> * If the engine is managed (see {@link IncQueryEngine#isManaged()}), there may be other clients using it. Care * should be taken with disposing such engines. * * @return true is an engine was found and disconnected, false if no engine was found for the given root. */ public boolean disposeEngine(Notifier emfRoot) { IncQueryEngine engine = getEngineInternal(emfRoot); if (engine == null) return false; else { engine.dispose(); return true; } } /** * @param emfRoot */ void killInternal(Notifier emfRoot) { engines.remove(emfRoot); } /** * @param emfRoot * @return */ private IncQueryEngine getEngineInternal(Notifier emfRoot) { final WeakReference<IncQueryEngine> engineRef = engines.get(emfRoot); IncQueryEngine engine = engineRef == null ? null : engineRef.get(); return engine; } }