/******************************************************************************* * Copyright (c) 2001, 2005 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.jem.internal.proxy.core; /* */ import java.util.Hashtable; import java.util.Iterator; import org.eclipse.jem.util.TimerTests; /** * Registry of proxy factories on a per-VM basis. * There can be multiple VM's, this would be required by the * desktop because more than one project could be open, and each * would require their own VM because the classpaths would be different. * This class may be subclassed to provide more factories for a particular * VM. * Creation date: (3/13/00 10:48:10 AM) * @author: Richard Lee Kulp */ public abstract class ProxyFactoryRegistry { protected boolean fIsValid = true; // The registry is valid until terminated. protected ListenerList registryListeners = new ListenerList(); /** * IRegistryListener * Listen for the registry being terminated. */ public interface IRegistryListener { /** * Method registryTerminated. * * The registry has been terminated. When this is called the registry * is no longer valid. It should not be assumed any calls can be made * to the registry. * * @param registry */ public void registryTerminated(ProxyFactoryRegistry registry); } // Factory registration IS NOT a dynamic registration. Once registered for a VM or an instance // they should not be changed. This is because references are cached in other objects. // The VM associated with this Registry shouldn't exited and restarted because // the cached object will then have invalid references to no longer existing objects. // If the VM needs to be restarted, then all proxies need to be tossed. // // Individual ProxyFactoryRegistry, applies to a particular VM. // // *************************** // // IBeanProxyFactory Registry // // The standard bean proxy factory, the one the desktop will use for packages that have not // been extended and registered by customization developers. protected IStandardBeanProxyFactory fCurrentStandardBeanProxyFactory; // The directory of registered extension factories, typically registered by package. final protected Hashtable fRegisteredExtensionBeanProxyFactories = new Hashtable(); // *************************** // // IBeanTypeProxyFactory Registry // // The standard bean type proxy factory, the one the desktop will use for packages that have not // been extended and registered by customization developers. protected IStandardBeanTypeProxyFactory fCurrentStandardBeanTypeProxyFactory; // The directory of registered extension factories, typically registered by package. final protected Hashtable fRegisteredExtensionBeanTypeProxyFactories = new Hashtable(); // *************************** // // Other factories // protected IMethodProxyFactory fMethodProxyFactory = null; // Method Proxy Factory // *************************** // // Constants Registry. Different extensions can store // objects by key as a registry of constants. // For example, java.awt extension will store an object // which has some pre-fetched method proxies stored in it so // that they don't need to be continually recreated. // // This feature should be used with care, so that // only proxies that really need to be cached should // be cached. // // Don't store proxies to live beans in here because // those will be created and destroyed over and over, // and the instance in this cache will get stale. // Should only store things like often used method // proxies that once created are rarely changed. // // Since the proxies can be on any VM, you should have // an interface defining what's available in your // constants entry, and access it through that. protected final Hashtable fRegisteredConstants = new Hashtable(); /** * ProxyFactoryRegistry constructor comment. */ public ProxyFactoryRegistry() { super(); } /** * Method addRegistryListener. * @param listener */ public void addRegistryListener(IRegistryListener listener) { registryListeners.add(listener); } /** * Method removeRegistryListener. * @param listener */ public void removeRegistryListener(IRegistryListener listener) { registryListeners.remove(listener); } protected void fireRegistryTerminated() { if (!registryListeners.isEmpty()) { Object[] list = registryListeners.getListeners(); for (int i = 0; i < list.length; i++) { ((IRegistryListener) list[i]).registryTerminated(this); } } } /** Return the current factory to be used for creating IBeanProxy instances */ public IStandardBeanProxyFactory getBeanProxyFactory() { if (fCurrentStandardBeanProxyFactory == null) { throw new RuntimeException(ProxyMessages.ProxyFactory_EXC__NoBeanProxyFactory); } return fCurrentStandardBeanProxyFactory; } /** Return the current registered bean proxy factory to be used for creating IBeanProxy instances */ public IBeanProxyFactory getBeanProxyFactoryExtension(String packageName) { return (IBeanProxyFactory)fRegisteredExtensionBeanProxyFactories.get(packageName); } /** Return the current factory to be used for creating IBeanTypeProxy instances */ public IStandardBeanTypeProxyFactory getBeanTypeProxyFactory() { if (fCurrentStandardBeanTypeProxyFactory == null) { throw new RuntimeException(ProxyMessages.ProxyFactory_EXC__NoBeanTypeProxyFactory); } return fCurrentStandardBeanTypeProxyFactory; } /** Return the current registered bean type proxy factory to be used for creating IBeanTypeProxy instances */ public IBeanTypeProxyFactory getBeanTypeProxyFactoryExtension(String packageName) { return (IBeanTypeProxyFactory)fRegisteredExtensionBeanTypeProxyFactories.get(packageName); } /** * Return the requested constants entry */ public Object getConstants(Object key) { return fRegisteredConstants.get(key); } /** * Return the MethodProxyFactory for this VM. * Creation date: (3/13/00 10:54:59 AM) * @return org.eclipse.jem.internal.proxy.core.IMethodProxyFactory */ public IMethodProxyFactory getMethodProxyFactory() { return fMethodProxyFactory; } /** * Set the requested constants entry for this VM. */ public void registerConstants(Object key, Object constant) { fRegisteredConstants.put(key, constant); } /** * Remove the constants for the given key. * @param key * * @since 1.1.0 */ public void deregisterConstants(Object key) { fRegisteredConstants.remove(key); } /** * Release the proxy, no longer needed. * This is a helper method to easily access the release from the bean proxy factory. */ public void releaseProxy(IBeanProxy proxy) { // To simply things if release is called when the factory is down (invalid), then just // go on because the proxy is already released. if (fCurrentStandardBeanProxyFactory != null) fCurrentStandardBeanProxyFactory.releaseProxy(proxy); } /** * Is this a valid registry, i.e. is it not terminated. */ public boolean isValid() { return fIsValid; } /** * Terminate the registry without waiting. * <p> * Terminate the registry, but don't necessarily wait for it. * * @see #terminateRegistry(boolean) * @since 1.0.0 */ public final void terminateRegistry() { terminateRegistry(false); } /** * Terminate the registry. * <p> * This will go through each factory and terminate it, and * let the subclass terminate. It will then remove all of the factories so that * if there are any proxies still hanging around they won't hold onto everything, * just the this registry will be held onto. *<p> * Note during termination, the factories should not reference any other factory. * It can assume that the factories will take care of themselves and they should * only release their resources. * <p> * The constants registry will not be terminated because they aren't factories. * However, they will be cleared (no longer referenced) from here so that they * can be GC'd. * * @param wait <code>true</code> to wait for complete termination, <code>false</code> to kick off termination but return ASAP. * @since 1.0.2 */ public final void terminateRegistry(boolean wait) { if (!fIsValid) return; // Already or are already terminating. Don't do it again and don't notify again. fIsValid = false; if (fCurrentStandardBeanTypeProxyFactory != null) { // TimerTests.basicTest.startStep("Terminate Bean Type Factory"); fCurrentStandardBeanTypeProxyFactory.terminateFactory(wait); // TimerTests.basicTest.stopStep("Terminate Bean Type Factory"); fCurrentStandardBeanTypeProxyFactory = null; } if (fCurrentStandardBeanProxyFactory != null) { fCurrentStandardBeanProxyFactory.terminateFactory(wait); fCurrentStandardBeanProxyFactory = null; } if (fMethodProxyFactory != null) { fMethodProxyFactory.terminateFactory(wait); fMethodProxyFactory = null; } Iterator itr = fRegisteredExtensionBeanTypeProxyFactories.values().iterator(); while (itr.hasNext()) { ((IBeanProxyFactory) itr.next()).terminateFactory(wait); } fRegisteredExtensionBeanTypeProxyFactories.clear(); itr = fRegisteredExtensionBeanProxyFactories.values().iterator(); while (itr.hasNext()) { ((IBeanProxyFactory) itr.next()).terminateFactory(wait); } fRegisteredExtensionBeanProxyFactories.clear(); fRegisteredConstants.clear(); TimerTests.basicTest.startStep("Registry Terminated"); //$NON-NLS-1$ registryTerminated(wait); TimerTests.basicTest.stopStep("Registry Terminated"); //$NON-NLS-1$ // TimerTests.basicTest.startStep("Registry Terminated Notification"); fireRegistryTerminated(); // Let everyone know that we are gone. This is fired even if wait is false because at this point in time the registry is invalid. // TimerTests.basicTest.stopStep("Registry Terminated Notification"); } /** * Terminate the Registry. * <p> * It is up to each registry to determine what this means. * <p> * The wait parm is a suggestion if it is <code>false</code>, but it must be honoured if <code>true</code> * * @param wait wait for registry to terminate flag. * * @since 1.0.2 */ protected abstract void registryTerminated(boolean wait); /** * Get the callback registry. */ public abstract ICallbackRegistry getCallbackRegistry(); }