| /******************************************************************************* |
| * Copyright (c) 2001, 2004 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.beaninfo.adapters; |
| /* |
| * $RCSfile: BeaninfoAdapterFactory.java,v $ |
| * $Revision: 1.6 $ $Date: 2005/02/15 22:44:20 $ |
| */ |
| import java.lang.ref.ReferenceQueue; |
| import java.lang.ref.WeakReference; |
| import java.util.*; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl; |
| |
| import org.eclipse.jem.internal.beaninfo.core.*; |
| import org.eclipse.jem.internal.java.beaninfo.IIntrospectionAdapter; |
| import org.eclipse.jem.internal.proxy.core.ProxyFactoryRegistry; |
| import org.eclipse.jem.java.ArrayType; |
| /** |
| * BeaninfoAdapterFactory - the factory for |
| * beaninfo introspection to populate the Java Model. |
| * Creation date: (11/1/2000 11:52:55 AM) |
| * @author: Administrator |
| */ |
| public class BeaninfoAdapterFactory extends AdapterFactoryImpl { |
| protected IBeaninfoSupplier fInfoSupplier; |
| |
| // Maintain a mapping of the source objects to the adaptors which have |
| // introspected from them. This allows a close operation to force those |
| // adapters to clear out the data. It also allows for marking an adapter as stale |
| // so that next time it introspects it will re-get the data. |
| // |
| // This is a WeakReference so that we don't hold onto adapters that were |
| // explicitly removed in other ways. |
| private Map fIntrospected = new HashMap(); // NOTE: This is to be accessed only under sync(this)! |
| private ReferenceQueue fRefQ = new ReferenceQueue(); |
| private static class WeakValue extends WeakReference { |
| private Object key; |
| public WeakValue(Object aKey, Object value, ReferenceQueue que) { |
| super(value, que); |
| key = aKey; |
| } |
| |
| public Object getKey() { |
| return key; |
| } |
| }; |
| |
| public BeaninfoAdapterFactory(IBeaninfoSupplier supplier) { |
| fInfoSupplier = supplier; |
| } |
| |
| public Adapter createAdapter(Notifier target, Object type) { |
| if (type == IIntrospectionAdapter.ADAPTER_KEY) { |
| return !(target instanceof ArrayType) ? new BeaninfoClassAdapter(this) : null; // Array types don't have beaninfo adapters. |
| } else |
| return new BeaninfoSuperAdapter(); |
| } |
| |
| /** |
| * @see org.eclipse.emf.common.notify.AdapterFactory#isFactoryForType(Object) |
| */ |
| public boolean isFactoryForType(Object type) { |
| return IIntrospectionAdapter.ADAPTER_KEY == type || BeaninfoSuperAdapter.ADAPTER_KEY == type; |
| } |
| |
| public ProxyFactoryRegistry getRegistry() { |
| return fInfoSupplier.getRegistry(); |
| } |
| |
| public boolean isRegistryCreated() { |
| return fInfoSupplier.isRegistryCreated(); |
| } |
| |
| public ProxyFactoryRegistry recycleRegistry() { |
| markAllStale(); // At this point in time we need to mark them all stale because we are recycling. MarkAllStale also closes the registry. |
| return getRegistry(); |
| } |
| |
| public IProject getProject() { |
| return fInfoSupplier.getProject(); |
| } |
| |
| /** |
| * Close ALL adapters. Also remove the adapters so that they |
| * are not being held onto. This means we are closing the project or removing the nature. |
| */ |
| public void closeAll(boolean clearResults) { |
| processQueue(); |
| synchronized (this) { |
| // We are going to be removing all of them, so just set introspected to an empty one |
| // and use the real one. This way we won't get concurrent modifications as we remove |
| // it from the notifier removeAdapter. |
| Map intr = fIntrospected; |
| fIntrospected = Collections.EMPTY_MAP; // Since we are closing we can keep the unmodifiable one here. |
| Iterator i = intr.values().iterator(); |
| while (i.hasNext()) { |
| BeaninfoClassAdapter a = (BeaninfoClassAdapter) ((WeakValue) i.next()).get(); |
| if (a != null) { |
| if (clearResults) |
| a.clearIntrospection(); |
| Notifier notifier = a.getTarget(); |
| if (notifier != null) |
| notifier.eAdapters().remove(a); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Mark ALL adapters as stale. This occurs because we've recycled the registry. |
| */ |
| public void markAllStale() { |
| ProxyFactoryRegistry fact = isRegistryCreated() ? getRegistry() : null; |
| processQueue(); |
| synchronized (this) { |
| Iterator i = fIntrospected.values().iterator(); |
| while (i.hasNext()) { |
| BeaninfoClassAdapter a = (BeaninfoClassAdapter) ((WeakValue) i.next()).get(); |
| if (a != null) |
| a.markStaleFactory(fact); |
| } |
| fInfoSupplier.closeRegistry(); // Get rid of the registry now since it is not needed. This way we won't accidentily hold onto it when not needed. |
| } |
| } |
| /** |
| * Mark the introspection as stale for a source object. Also clear results if told to. |
| * @param sourceName Fully qualified source name, use type for reflection, i.e. "a.b.c.Class1$InnerClass" |
| * @param clearResults clear out the results. If false, they will be reused if possible on recycle. |
| */ |
| public void markStaleIntrospection(String sourceName, boolean clearResults) { |
| processQueue(); |
| synchronized (this) { |
| WeakValue ref = (WeakValue) fIntrospected.get(sourceName); |
| if (ref != null) { |
| BeaninfoClassAdapter a = (BeaninfoClassAdapter) ref.get(); |
| if (a != null) { |
| if (clearResults) |
| a.clearIntrospection(); |
| a.markStaleFactory(isRegistryCreated() ? getRegistry() : null); // Mark it stale with the current registry. |
| } |
| } |
| } |
| } |
| |
| public void markStaleIntrospectionPlusInner(String sourceName, boolean clearResults) { |
| processQueue(); |
| String sourceNameForInner = sourceName + '$'; |
| synchronized (this) { |
| Iterator itr = fIntrospected.entrySet().iterator(); |
| while (itr.hasNext()) { |
| Map.Entry entry = (Map.Entry) itr.next(); |
| String entryName = (String) entry.getKey(); |
| if (entryName.equals(sourceName) || entryName.startsWith(sourceNameForInner)) { |
| // It is the item or one of its inner classes. |
| WeakValue ref = (WeakValue) entry.getValue(); |
| BeaninfoClassAdapter a = (BeaninfoClassAdapter) ref.get(); |
| if (a != null) { |
| if (clearResults) |
| a.clearIntrospection(); |
| a.markStaleFactory(isRegistryCreated() ? getRegistry() : null); // Mark it stale with the current registry. |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Register an adapter for introspection. |
| * @param sourceName Fully qualified source name, use type for reflection, i.e. "a.b.c.Class1$InnerClass" |
| * @param adapter The adapter to register |
| */ |
| public void registerIntrospection(String sourceName, BeaninfoClassAdapter adapter) { |
| // Create it as a weak reference so that it doesn't hold onto the adapter if it is ever removed |
| // and thrown away (or the MOF resource itself is thrown away). |
| processQueue(); |
| synchronized (this) { |
| fIntrospected.put(sourceName, new WeakValue(sourceName, adapter, fRefQ)); |
| } |
| } |
| |
| /** |
| * Remove adapter. This happens in the case that adapter is being removed and |
| * we want to remove it from our list. This is an internal API only for use by |
| * the adapter itself. |
| */ |
| public synchronized void removeAdapter(BeaninfoClassAdapter a) { |
| fIntrospected.remove(a.getJavaClass().getQualifiedNameForReflection()); |
| } |
| |
| private synchronized void processQueue() { |
| WeakValue wv; |
| while ((wv = (WeakValue) fRefQ.poll()) != null) { |
| fIntrospected.remove(wv.getKey()); |
| } |
| } |
| } |