| /******************************************************************************* |
| * Copyright (c) 2006, 2008 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.services; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.ui.services.AbstractServiceFactory; |
| import org.eclipse.ui.services.IDisposable; |
| import org.eclipse.ui.services.IServiceLocator; |
| |
| /** |
| * @since 3.2 |
| * |
| */ |
| public final class ServiceLocator implements IDisposable, INestable, |
| IServiceLocator { |
| boolean activated = false; |
| |
| private static class ParentLocator implements IServiceLocator { |
| private IServiceLocator locator; |
| private Class key; |
| |
| public ParentLocator(IServiceLocator parent, Class serviceInterface) { |
| locator = parent; |
| key = serviceInterface; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.services.IServiceLocator#getService(java.lang.Class) |
| */ |
| public Object getService(Class api) { |
| if (key.equals(api)) { |
| return locator.getService(key); |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.services.IServiceLocator#hasService(java.lang.Class) |
| */ |
| public boolean hasService(Class api) { |
| if (key.equals(api)) { |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| private AbstractServiceFactory factory; |
| |
| /** |
| * The parent for this service locator. If a service can't be found in this |
| * locator, then the parent is asked. This value may be <code>null</code> |
| * if there is no parent. |
| */ |
| private IServiceLocator parent; |
| |
| /** |
| * The map of servicesThis value is <code>null</code> until a service is |
| * registered. |
| */ |
| private Map services = null; |
| |
| private boolean disposed; |
| |
| private final IDisposable owner; |
| |
| /** |
| * Constructs a service locator with no parent. |
| */ |
| public ServiceLocator() { |
| this(null, null, null); |
| } |
| |
| /** |
| * Constructs a service locator with the given parent. |
| * |
| * @param parent |
| * The parent for this service locator; this value may be |
| * <code>null</code>. |
| * @param factory |
| * a local factory that can provide services at this level |
| * @param owner |
| */ |
| public ServiceLocator(final IServiceLocator parent, |
| AbstractServiceFactory factory, IDisposable owner) { |
| this.parent = parent; |
| this.factory = factory; |
| this.owner = owner; |
| } |
| |
| public final void activate() { |
| activated = true; |
| if (services != null) { |
| final Iterator serviceItr = services.values().iterator(); |
| while (serviceItr.hasNext()) { |
| final Object service = serviceItr.next(); |
| if (service instanceof INestable) { |
| final INestable nestableService = (INestable) service; |
| nestableService.activate(); |
| } |
| } |
| } |
| } |
| |
| public final void deactivate() { |
| activated = false; |
| if (services != null) { |
| final Iterator serviceItr = services.values().iterator(); |
| while (serviceItr.hasNext()) { |
| final Object service = serviceItr.next(); |
| if (service instanceof INestable) { |
| final INestable nestableService = (INestable) service; |
| nestableService.deactivate(); |
| } |
| } |
| } |
| } |
| |
| public final void dispose() { |
| if (services != null) { |
| final Iterator serviceItr = services.values().iterator(); |
| while (serviceItr.hasNext()) { |
| final Object object = serviceItr.next(); |
| if (object instanceof IDisposable) { |
| final IDisposable service = (IDisposable) object; |
| service.dispose(); |
| } |
| } |
| services = null; |
| } |
| parent = null; |
| disposed = true; |
| } |
| |
| public final Object getService(final Class key) { |
| if (disposed) { |
| return null; |
| } |
| Object service; |
| if (services != null) { |
| service = services.get(key); |
| } else { |
| service = null; |
| } |
| if (service == null) { |
| // if we don't have a service in our cache then: |
| // 1. check our local factory |
| // 2. go to the registry |
| // or 3. use the parent service |
| IServiceLocator factoryParent = WorkbenchServiceRegistry.GLOBAL_PARENT; |
| if (parent != null) { |
| factoryParent = new ParentLocator(parent, key); |
| } |
| if (factory != null) { |
| service = factory.create(key, factoryParent, this); |
| } |
| if (service == null) { |
| service = WorkbenchServiceRegistry.getRegistry().getService( |
| key, factoryParent, this); |
| } |
| if (service == null) { |
| service = factoryParent.getService(key); |
| } else { |
| registerService(key, service); |
| } |
| } |
| return service; |
| } |
| |
| public final boolean hasService(final Class key) { |
| if (disposed) { |
| return false; |
| } |
| if (services != null) { |
| if (services.containsKey(key)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Registers a service with this locator. If there is an existing service |
| * matching the same <code>api</code> and it implements |
| * {@link IDisposable}, it will be disposed. |
| * |
| * @param api |
| * This is the interface that the service implements. Must not be |
| * <code>null</code>. |
| * @param service |
| * The service to register. This must be some implementation of |
| * <code>api</code>. This value must not be <code>null</code>. |
| */ |
| public final void registerService(final Class api, final Object service) { |
| if (api == null) { |
| throw new NullPointerException("The service key cannot be null"); //$NON-NLS-1$ |
| } |
| |
| if (!api.isInstance(service)) { |
| throw new IllegalArgumentException( |
| "The service does not implement the given interface"); //$NON-NLS-1$ |
| } |
| |
| if (services == null) { |
| services = new HashMap(); |
| } |
| |
| if (services.containsKey(api)) { |
| final Object currentService = services.remove(api); |
| if (currentService instanceof IDisposable) { |
| final IDisposable disposable = (IDisposable) currentService; |
| disposable.dispose(); |
| } |
| } |
| |
| if (service == null) { |
| if (services.isEmpty()) { |
| services = null; |
| } |
| } else { |
| services.put(api, service); |
| if (service instanceof INestable && activated) { |
| ((INestable)service).activate(); |
| } |
| } |
| } |
| |
| /** |
| * @return |
| */ |
| public boolean isDisposed() { |
| return disposed; |
| } |
| |
| /** |
| * Some services that were contributed to this locator are no longer available |
| * (because the plug-in containing the AbstractServiceFactory is no longer |
| * available). Notify the owner of the locator about this. |
| */ |
| public void unregisterServices(String[] serviceNames) { |
| if (owner != null) { |
| owner.dispose(); |
| } |
| } |
| |
| } |