Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-08-28 16:48:40 -0400
committerChristian W. Damus2013-08-29 21:45:27 -0400
commit49517c2f5d35409c38dcd92ba381447be68578ce (patch)
tree5f41cceefd3bb66da17bc17217dc85eb5406797f /plugins/views/org.eclipse.papyrus.views.search
parente6eddb1a7fe488abaff88f70c534dfd140b6a693 (diff)
downloadorg.eclipse.papyrus-49517c2f5d35409c38dcd92ba381447be68578ce.tar.gz
org.eclipse.papyrus-49517c2f5d35409c38dcd92ba381447be68578ce.tar.xz
org.eclipse.papyrus-49517c2f5d35409c38dcd92ba381447be68578ce.zip
416145: Clean up service registries used by search scopes.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=416145 Track references to ScopeEntry instances so that the service registries they create can be properly disposed of. This fixes leaking of large numbers of ModelSets and UML Resources in the UML CacheAdapter.
Diffstat (limited to 'plugins/views/org.eclipse.papyrus.views.search')
-rw-r--r--plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/scope/ScopeEntry.java472
-rw-r--r--plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/DefaultServiceRegistryTracker.java182
-rw-r--r--plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/IServiceRegistryTracker.java73
3 files changed, 493 insertions, 234 deletions
diff --git a/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/scope/ScopeEntry.java b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/scope/ScopeEntry.java
index 6c81f513b19..40dd73e3b01 100644
--- a/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/scope/ScopeEntry.java
+++ b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/scope/ScopeEntry.java
@@ -1,234 +1,238 @@
-/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
- *
- *
- * 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:
- * CEA LIST - Initial API and implementation
- *
- *****************************************************************************/
-package org.eclipse.papyrus.views.search.scope;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
-import org.eclipse.papyrus.infra.core.resource.ModelSet;
-import org.eclipse.papyrus.infra.core.services.ServiceException;
-import org.eclipse.papyrus.infra.core.services.ServiceMultiException;
-import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
-import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
-import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
-import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceInitializerService;
-import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
-import org.eclipse.papyrus.infra.services.labelprovider.service.impl.LabelProviderServiceImpl;
-import org.eclipse.papyrus.infra.services.openelement.service.OpenElementService;
-import org.eclipse.papyrus.infra.services.openelement.service.impl.OpenElementServiceImpl;
-import org.eclipse.papyrus.views.search.Activator;
-import org.eclipse.papyrus.views.search.Messages;
-import org.eclipse.papyrus.views.search.utils.ModelUtils;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorReference;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.ide.ResourceUtil;
-
-/**
- *
- * This class is used to aggregate information about the resource that contains the element that raised a match
- *
- */
-public class ScopeEntry {
-
- /**
- * The modelSet that contains the model element
- */
- private ModelSet modelSet;
-
- /**
- * The corresponding {@link ServicesRegistry}
- */
- private ServicesRegistry servicesRegistry;
-
- /**
- * The resource that contains the element that raised a match
- */
- // private IResource resource;
-
- private IPath pathResource;
-
-
- public ScopeEntry(IResource resource) {
- super();
- // this.resource = resource;
-
- this.pathResource = resource.getFullPath();
- this.modelSet = getModelSet();
- this.servicesRegistry = getServicesRegistry();
- }
-
- // public boolean isOpen() {
- // return isOpen;
- // }
- //
- //
- // public void setOpen(boolean isOpen) {
- // this.isOpen = isOpen;
- // }
-
- private Collection<IEditorPart> getEditors() {
- Collection<IEditorPart> results = new HashSet<IEditorPart>();
- IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
- for(IWorkbenchWindow iWorkbenchWindow : windows) {
- IWorkbenchPage[] pages = iWorkbenchWindow.getPages();
- for(IWorkbenchPage iWorkbenchPage : pages) {
- IEditorReference[] references = iWorkbenchPage.getEditorReferences();
- for(IEditorReference ref : references) {
- IEditorPart editor = ref.getEditor(true);
- results.add(editor);
- }
- }
- }
-
- return results;
- }
-
- private ServicesRegistry createServicesRegistry() {
-
- try {
- ServicesRegistry serviceRegistry = new ServicesRegistry();
- serviceRegistry.add(LabelProviderService.class, 10, new LabelProviderServiceImpl());
- serviceRegistry.add(OpenElementService.class, 10, new OpenElementServiceImpl());
- // PageIconRegistryServiceFactory factory = new PageIconRegistryServiceFactory();
- // Object instance = factory.createServiceInstance();
- // serviceRegistry.add(IPageIconsRegistry.class, 10, instance);
- // serviceRegistry.add(IPageIconsRegistry.class, 10, new PageIconRegistryServiceFactory());
- serviceRegistry.startRegistry();
-
- return serviceRegistry;
- } catch (ServiceException e) {
- Activator.log.error(Messages.ScopeEntry_0, e);
- }
- return null;
- }
-
- public ModelSet getModelSet() {
- //If null, try to find one or create one
- if(modelSet == null) {
- try {
- modelSet = ServiceUtils.getInstance().getModelSet(getServicesRegistry());
- } catch (ServiceException e) {
- //Create one
- try {
-
- modelSet = ModelUtils.openFile(this.getResource());
- getServicesRegistry().add(ModelSet.class, 10, modelSet);
- getServicesRegistry().add(ServiceUtilsForResourceInitializerService.class, 10, new ServiceUtilsForResourceInitializerService());
- getServicesRegistry().startServicesByClassKeys(ModelSet.class, ServiceUtilsForResourceInitializerService.class);
- } catch (ModelMultiException modelMultiException) {
- Activator.log.error(Messages.ScopeEntry_1 + this.getResource(), modelMultiException);
- } catch (ServiceMultiException e1) {
- Activator.log.error(e1);
- } catch (ServiceNotFoundException e1) {
- Activator.log.error(e1);
- }
- }
- }
- return modelSet;
- }
-
- public void setModelSet(ModelSet modelSet) {
- this.modelSet = modelSet;
- }
-
- private IEditorPart editorOnResource() {
- Collection<IEditorPart> editors = getEditors();
-
- for(IEditorPart editor : editors) {
-
- if(editor != null) {
- if(ResourceUtil.getResource(editor.getEditorInput()).equals(this.getResource())) {
- return editor;
- }
- }
- }
-
- return null;
- }
-
- private ServicesRegistry getUpdatedServiceRegistry() {
- IEditorPart editor = editorOnResource();
- if(editor != null) {
-
- ServicesRegistry registry = (ServicesRegistry)editor.getAdapter(ServicesRegistry.class);
-
- return registry;
-
- }
-
- return servicesRegistry;
- }
-
- public ServicesRegistry getServicesRegistry() {
-
- if(servicesRegistry == null) {
- //Try to find existing
- ServicesRegistry registry = getUpdatedServiceRegistry();
- if(registry != null) {
- //If the OpenElementService is no yet available, we must start it
- try {
- registry.getService(OpenElementService.class);
- } catch (ServiceException e) {
- registry.add(OpenElementService.class, 10, new OpenElementServiceImpl());
- }
-
- servicesRegistry = registry;
- // this.isOpen = true;
-
- } else {
- // this.isOpen = false;
- servicesRegistry = createServicesRegistry();
- }
- }
-
- return servicesRegistry;
- }
-
- public void setServicesRegistry(ServicesRegistry servicesRegistry) {
- this.servicesRegistry = servicesRegistry;
- }
-
- public IResource getResource() {
-
-
- IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
- IFile file = root.getFile(pathResource);
-
- return (IResource)file;
- // if(this.uriResource != null) {
- //
- // IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
- //
- //
- // IPath path = new Path(this.uriResource.getPath());
- // return root.getFile(path);
- // } else {
- // return null;
- // }
- }
-
- public void setResource(IResource resource) {
- this.pathResource = resource.getFullPath();
- }
-
-}
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ *
+ * 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:
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus (CEA LIST) - Fix leaking of all UML models in search results
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.views.search.scope;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceMultiException;
+import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceInitializerService;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.services.labelprovider.service.impl.LabelProviderServiceImpl;
+import org.eclipse.papyrus.infra.services.openelement.service.OpenElementService;
+import org.eclipse.papyrus.infra.services.openelement.service.impl.OpenElementServiceImpl;
+import org.eclipse.papyrus.views.search.Activator;
+import org.eclipse.papyrus.views.search.Messages;
+import org.eclipse.papyrus.views.search.utils.IServiceRegistryTracker;
+import org.eclipse.papyrus.views.search.utils.ModelUtils;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.ResourceUtil;
+
+/**
+ *
+ * This class is used to aggregate information about the resource that contains the element that raised a match
+ *
+ */
+public class ScopeEntry {
+ /**
+ * Tracks service registries created implicitly (not borrowed from editors) by scope entries, so that they may
+ * be properly shut down when no longer needed.
+ */
+ private final IServiceRegistryTracker serviceRegistryTracker;
+
+ /**
+ * The modelSet that contains the model element
+ */
+ private ModelSet modelSet;
+
+ /**
+ * The corresponding {@link ServicesRegistry}
+ */
+ private ServicesRegistry servicesRegistry;
+
+ /**
+ * The resource that contains the element that raised a match
+ */
+ // private IResource resource;
+
+ private IPath pathResource;
+
+ public ScopeEntry(IResource resource) {
+ this(resource, null);
+ }
+
+ public ScopeEntry(IResource resource, IServiceRegistryTracker serviceRegistryTracker) {
+ super();
+
+ this.serviceRegistryTracker = serviceRegistryTracker;
+ this.pathResource = resource.getFullPath();
+ this.modelSet = getModelSet();
+ this.servicesRegistry = getServicesRegistry();
+ }
+
+ private Collection<IEditorPart> getEditors() {
+ Collection<IEditorPart> results = new HashSet<IEditorPart>();
+ IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
+ for(IWorkbenchWindow iWorkbenchWindow : windows) {
+ IWorkbenchPage[] pages = iWorkbenchWindow.getPages();
+ for(IWorkbenchPage iWorkbenchPage : pages) {
+ IEditorReference[] references = iWorkbenchPage.getEditorReferences();
+ for(IEditorReference ref : references) {
+ IEditorPart editor = ref.getEditor(true);
+ results.add(editor);
+ }
+ }
+ }
+
+ return results;
+ }
+
+ private ServicesRegistry createServicesRegistry() {
+
+ try {
+ ServicesRegistry serviceRegistry = new ServicesRegistry();
+ serviceRegistry.add(LabelProviderService.class, 10, new LabelProviderServiceImpl());
+ serviceRegistry.add(OpenElementService.class, 10, new OpenElementServiceImpl());
+ // PageIconRegistryServiceFactory factory = new PageIconRegistryServiceFactory();
+ // Object instance = factory.createServiceInstance();
+ // serviceRegistry.add(IPageIconsRegistry.class, 10, instance);
+ // serviceRegistry.add(IPageIconsRegistry.class, 10, new PageIconRegistryServiceFactory());
+ serviceRegistry.startRegistry();
+
+ if(serviceRegistryTracker != null) {
+ // register this service registry for automatic shut-down when it is no longer needed
+ serviceRegistryTracker.track(this, serviceRegistry);
+ }
+
+ return serviceRegistry;
+ } catch (ServiceException e) {
+ Activator.log.error(Messages.ScopeEntry_0, e);
+ }
+ return null;
+ }
+
+ public ModelSet getModelSet() {
+ //If null, try to find one or create one
+ if(modelSet == null) {
+ try {
+ modelSet = ServiceUtils.getInstance().getModelSet(getServicesRegistry());
+ } catch (ServiceException e) {
+ //Create one
+ try {
+
+ modelSet = ModelUtils.openFile(this.getResource());
+ getServicesRegistry().add(ModelSet.class, 10, modelSet);
+ getServicesRegistry().add(ServiceUtilsForResourceInitializerService.class, 10, new ServiceUtilsForResourceInitializerService());
+ getServicesRegistry().startServicesByClassKeys(ModelSet.class, ServiceUtilsForResourceInitializerService.class);
+ } catch (ModelMultiException modelMultiException) {
+ Activator.log.error(Messages.ScopeEntry_1 + this.getResource(), modelMultiException);
+ } catch (ServiceMultiException e1) {
+ Activator.log.error(e1);
+ } catch (ServiceNotFoundException e1) {
+ Activator.log.error(e1);
+ }
+ }
+ }
+ return modelSet;
+ }
+
+ public void setModelSet(ModelSet modelSet) {
+ this.modelSet = modelSet;
+ }
+
+ private IEditorPart editorOnResource() {
+ Collection<IEditorPart> editors = getEditors();
+
+ for(IEditorPart editor : editors) {
+
+ if(editor != null) {
+ if(ResourceUtil.getResource(editor.getEditorInput()).equals(this.getResource())) {
+ return editor;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private ServicesRegistry getUpdatedServiceRegistry() {
+ IEditorPart editor = editorOnResource();
+ if(editor != null) {
+
+ ServicesRegistry registry = (ServicesRegistry)editor.getAdapter(ServicesRegistry.class);
+
+ return registry;
+
+ }
+
+ return servicesRegistry;
+ }
+
+ public ServicesRegistry getServicesRegistry() {
+
+ if(servicesRegistry == null) {
+ //Try to find existing
+ ServicesRegistry registry = getUpdatedServiceRegistry();
+ if(registry != null) {
+ //If the OpenElementService is no yet available, we must start it
+ try {
+ registry.getService(OpenElementService.class);
+ } catch (ServiceException e) {
+ registry.add(OpenElementService.class, 10, new OpenElementServiceImpl());
+ }
+
+ servicesRegistry = registry;
+
+ } else {
+ servicesRegistry = createServicesRegistry();
+ }
+ }
+
+ return servicesRegistry;
+ }
+
+ public void setServicesRegistry(ServicesRegistry servicesRegistry) {
+ this.servicesRegistry = servicesRegistry;
+ }
+
+ public IResource getResource() {
+
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile file = root.getFile(pathResource);
+
+ return (IResource)file;
+ // if(this.uriResource != null) {
+ //
+ // IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ //
+ //
+ // IPath path = new Path(this.uriResource.getPath());
+ // return root.getFile(path);
+ // } else {
+ // return null;
+ // }
+ }
+
+ public void setResource(IResource resource) {
+ this.pathResource = resource.getFullPath();
+ }
+
+}
diff --git a/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/DefaultServiceRegistryTracker.java b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/DefaultServiceRegistryTracker.java
new file mode 100644
index 00000000000..2323b40b257
--- /dev/null
+++ b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/DefaultServiceRegistryTracker.java
@@ -0,0 +1,182 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * 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:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.views.search.utils;
+
+import java.lang.ref.ReferenceQueue;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.views.search.Activator;
+
+
+/**
+ * This is the DefaultServiceRegistryTracker type. Enjoy.
+ */
+public class DefaultServiceRegistryTracker implements IServiceRegistryTracker {
+
+ private static final ExecutorService EXEC = Executors.newCachedThreadPool(new ThreadFactory() {
+
+ private final AtomicInteger threadNum = new AtomicInteger();
+
+ private final ThreadGroup group = new ThreadGroup(Thread.currentThread().getThreadGroup(), "Service Registry Tracker Threads"); //$NON-NLS-1$
+
+ public Thread newThread(Runnable r) {
+ Thread result = new Thread(group, r, "SvcRegTracker-" + threadNum.incrementAndGet()); //$NON-NLS-1$
+ result.setDaemon(true);
+ return result;
+ }
+ });
+
+ private Set<TrackerReference> references = new java.util.HashSet<TrackerReference>();
+
+ private ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+
+ private int count = 0;
+
+ private boolean active = true;
+
+ private Runnable reaper;
+
+ public DefaultServiceRegistryTracker() {
+ super();
+ }
+
+ public synchronized boolean isActive() {
+ return active;
+ }
+
+ // requires monitor
+ private void checkActive() {
+ if(!active) {
+ throw new IllegalStateException("not active"); //$NON-NLS-1$
+ }
+ }
+
+ public synchronized void track(Object owner, ServicesRegistry serviceRegistry) {
+ checkActive();
+
+ TrackerReference existing = getReference(serviceRegistry);
+ if(existing == null) {
+ // only in this case would we ever track
+ references.add(new TrackerReference(owner, serviceRegistry));
+ count++;
+ reapLater();
+ } else {
+ Object actualOwner = existing.get();
+
+ // the reference may have been cleared, in which case we assume the registry
+ // was disposed and the reference did track this owner
+ if((actualOwner != null) && (actualOwner != owner)) {
+ throw new IllegalArgumentException("registry already tracked against a different owner"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public synchronized void untrack(Object owner, ServicesRegistry serviceRegistry) {
+ checkActive();
+
+ TrackerReference existing = getReference(serviceRegistry);
+ if((existing != null) && (existing.get() == owner)) {
+ references.remove(existing);
+ // it will still be enqueued later, but we will ignore it
+ }
+ }
+
+ // requires monitor
+ private TrackerReference getReference(ServicesRegistry serviceRegistry) {
+ TrackerReference result = null;
+
+ for(TrackerReference next : references) {
+ if(next.matches(serviceRegistry)) {
+ result = next;
+ }
+ }
+
+ return result;
+ }
+
+ // requires monitor
+ private void reapLater() {
+ if(reaper == null) {
+ reaper = new Runnable() {
+
+ public void run() {
+ for(;;) {
+ try {
+ if(!dequeue()) {
+ // done!
+ break;
+ }
+ } catch (InterruptedException e) {
+ Activator.log.error("Service registry reaper thread interrupted. How?", e); //$NON-NLS-1$
+ }
+ }
+ }
+ };
+
+ EXEC.execute(reaper);
+ }
+ }
+
+ private boolean dequeue() throws InterruptedException {
+ boolean result = true;
+
+ TrackerReference ref = (TrackerReference)queue.remove();
+
+ synchronized(this) {
+ if(references.remove(ref)) {
+ // only dispose the service registry if we didn't untrack it!
+ ref.dispose();
+ }
+
+ if(--count <= 0) {
+ // nothing more to reap
+ reaper = null;
+ active = false;
+ result = false;
+ }
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private class TrackerReference extends java.lang.ref.WeakReference<Object> {
+
+ private final ServicesRegistry serviceRegistry;
+
+ TrackerReference(Object owner, ServicesRegistry serviceRegistry) {
+ super(owner, queue);
+
+ this.serviceRegistry = serviceRegistry;
+ }
+
+ void dispose() {
+ try {
+ serviceRegistry.disposeRegistry();
+ } catch (Exception e) {
+ Activator.log.error("Exception in disposal of service registry that is no longer in use.", e); //$NON-NLS-1$
+ }
+ }
+
+ boolean matches(ServicesRegistry serviceRegistry) {
+ return this.serviceRegistry == serviceRegistry;
+ }
+ }
+}
diff --git a/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/IServiceRegistryTracker.java b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/IServiceRegistryTracker.java
new file mode 100644
index 00000000000..fcc65372964
--- /dev/null
+++ b/plugins/views/org.eclipse.papyrus.views.search/src/org/eclipse/papyrus/views/search/utils/IServiceRegistryTracker.java
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * 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:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.views.search.utils;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.views.search.scope.ScopeEntry;
+
+
+/**
+ * A tracker of references to service registries used by {@linkplain ScopeEntry scope entries}, which automatically shuts them down
+ * when they are no longer needed.
+ */
+public interface IServiceRegistryTracker {
+
+ /**
+ * Queries whether I am still actively tracking service registries and able to handle requests to
+ * {@link IServiceRegistryTracker#track(Object, ServicesRegistry) track} or {@link #untrack(Object, ServicesRegistry) un-track} service
+ * registries.
+ *
+ * @return whether I am currently active
+ */
+ boolean isActive();
+
+ /**
+ * <p>
+ * Adds a service registry for me to track. Multiple service registries may be tracked against one owner, but a service registry may only be
+ * tracked against at most one owner.
+ * </p>
+ * <p>
+ * Has no effect if this {@code serviceRegistry} is already tracked against this {@code owner}.
+ * </p>
+ *
+ * @param owner
+ * the owner of the {@code serviceRegistry}. I track references to this object; when it is no longer in use, the {@code serviceRegistry} is
+ * shut down.
+ *
+ * @param serviceRegistry
+ * a service registry to shut down when its {@code owner} is no longer in use
+ *
+ * @throws IllegalArgumentException
+ * if this {@code serviceRegistry} is already tracked against a different owner than the given {@code owner}
+ *
+ * @throws IllegalStateException
+ * if I am not {@link #isActive() active}
+ *
+ * @see #untrack(Object, ServicesRegistry)
+ * @see #isActive()
+ */
+ void track(Object owner, ServicesRegistry serviceRegistry);
+
+ /**
+ * Stops tracking the given service registry. Has no effect if this {@code serviceRegistry} is not currently being
+ * {@linkplain #track(Object, ServicesRegistry) tracked} against this {@code owner}.
+ *
+ * @param owner
+ * the owner of the {@code serviceRegistry}
+ * @param serviceRegistry
+ * a service registry that I may be tracking against its {@code owner}
+ *
+ * @throws IllegalStateException
+ * if I am not {@link #isActive() active}
+ */
+ void untrack(Object owner, ServicesRegistry serviceRegistry);
+}

Back to the top