blob: 611ebc844b9e934fa5a0ad4e379d32b58997bfd5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 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
*******************************************************************************/
/*
* Created on Dec 1, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.eclipse.wst.common.internal.emfworkbench.integration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.edit.provider.ChangeNotifier;
import org.eclipse.emf.edit.provider.IChangeNotifier;
import org.eclipse.emf.edit.provider.IDisposable;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.jem.util.emf.workbench.ProjectUtilities;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.wst.common.frameworks.internal.enablement.EnablementIdentifier;
import org.eclipse.wst.common.frameworks.internal.enablement.EnablementIdentifierEvent;
import org.eclipse.wst.common.frameworks.internal.enablement.EnablementManager;
import org.eclipse.wst.common.frameworks.internal.enablement.IEnablementIdentifier;
import org.eclipse.wst.common.frameworks.internal.enablement.IEnablementIdentifierListener;
import org.eclipse.wst.common.frameworks.internal.enablement.IEnablementManager;
import org.eclipse.wst.common.internal.emfworkbench.EMFWorkbenchEditResourceHandler;
import org.eclipse.wst.common.internal.emfworkbench.edit.AdapterFactoryDescriptor;
import org.eclipse.wst.common.internal.emfworkbench.edit.AdapterFactoryRegistry;
import org.eclipse.wst.common.internal.emfworkbench.edit.ExtendedComposedAdapterFactory;
/**
* @author schacher
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class DynamicAdapterFactory implements AdapterFactory, IChangeNotifier, IDisposable, INotifyChangedListener, IEnablementIdentifierListener {
private static final AdapterFactory NULL_FACTORY = new AdapterFactoryImpl();
private ResourceItemProviderAdapterFactory resourceItemProviderAdapterFactory = null;
private String viewID;
//Each of the two maps below are keyed by the project
private Map adapterFactoriesByPackage;
private Map adapterFactoriesByType;
private Set allFactories;
/**
* This is used to implement {@link IChangeNotifier}
*/
protected ChangeNotifier changeNotifier = new ChangeNotifier();
private boolean respectingActivities = false;
protected static final Object NO_PROJECT = "NO_PROJECT"; //$NON-NLS-1$
/**
*/
public DynamicAdapterFactory(String viewID, boolean respectActivies) {
this.viewID = viewID;
this.respectingActivities = respectActivies;
initialize();
}
/**
*/
public DynamicAdapterFactory(String viewID) {
this.viewID = viewID;
initialize();
}
private void initialize() {
adapterFactoriesByPackage = new HashMap();
adapterFactoriesByType = new HashMap();
allFactories = new HashSet();
}
public boolean isFactoryForType(Object type) {
return getFactoryForType(type) != null;
}
private AdapterFactory getFactoryForType(Object type) {
if (type == null)
return null;
if (type instanceof EObject)
return getFactoryForType((EObject) type);
Object aProject = ProjectUtilities.getProject(type);
if (aProject == null)
aProject = NO_PROJECT;
AdapterFactory factory = getExistingFactoryForType(aProject, type);
if (factory == NULL_FACTORY)
return null;
else if (factory == null) {
factory = findFactoryForType(aProject, type);
if (factory == null)
addAdapterFactory(aProject, type, NULL_FACTORY);
else
addAdapterFactory(aProject, type, factory);
}
return factory;
}
private AdapterFactory getExistingFactoryForType(Object p, Object type) {
if (p == null)
return null;
Map aMap = (Map) adapterFactoriesByType.get(p);
if (aMap == null)
return null;
return (AdapterFactory) adapterFactoriesByType.get(type);
}
/*
* The factory was not cached by type, so we will search the cache of factories for the project
* and see if it can be found there
*/
private AdapterFactory findFactoryForType(Object project, Object type) {
if (project == null)
return null;
Map aMap = (Map) adapterFactoriesByPackage.get(project);
if (aMap == null)
return null;
Iterator iter = aMap.values().iterator();
AdapterFactory factory = null;
while (iter.hasNext()) {
factory = (AdapterFactory) iter.next();
if (factory.isFactoryForType(type))
return factory;
}
// adapt the resource to its contents
if (getResourceItemProviderAdapterFactory().isFactoryForType(type))
return getResourceItemProviderAdapterFactory();
return null;
}
private AdapterFactory getFactoryForType(EObject obj) {
EClass eClass = obj.eClass();
if (eClass == null)
return null;
EPackage ePackage = eClass.getEPackage();
Object aProject = ProjectUtilities.getProject(obj);
if (aProject == null)
aProject = NO_PROJECT;
AdapterFactory result = getFactoryForPackage(aProject, ePackage);
if (result == null) {
Set failedPackageSet = new HashSet();
failedPackageSet.add(ePackage);
Iterator supertypes = eClass.getEAllSuperTypes().iterator();
while (supertypes.hasNext()) {
eClass = (EClass) supertypes.next();
if (eClass != null) {
ePackage = eClass.getEPackage();
if (failedPackageSet.add(ePackage)) {
result = getFactoryForPackage(aProject, ePackage);
if (result != null)
break;
}
}
}
}
return result;
}
private AdapterFactory getFactoryForPackage(Object aProject, EPackage aPackage) {
if (aProject == null || aPackage == null)
return null;
AdapterFactory factory = getExistingFactoryForPackage(aProject, aPackage);
if (factory == NULL_FACTORY)
return null;
else if (factory == null) {
try {
factory = createAdapterFactory(aProject, aPackage);
if (factory == null)
addAdapterFactory(aProject, aPackage, NULL_FACTORY);
else
addAdapterFactory(aProject, aPackage, factory);
} catch (RuntimeException re) {
Logger.getLogger().logError(re);
}
}
return factory;
}
private AdapterFactory getFactoryForTypes(Object p, List types) {
Map aMap = (Map) adapterFactoriesByPackage.get(p);
if (aMap == null)
return adaptResourceTypes(types);
Iterator factories = aMap.values().iterator();
AdapterFactory factory = null;
while (factories.hasNext()) {
factory = (AdapterFactory) factories.next();
if (isFactoryForAllTypes(factory, types)) {
return factory;
}
}
return null;
}
private AdapterFactory adaptResourceTypes(List types) {
// adapt the resource to its contents
if (isFactoryForAllTypes(getResourceItemProviderAdapterFactory(), types))
return getResourceItemProviderAdapterFactory();
return null;
}
private void removeFactoryForTypes(Object p, List types) {
Map aMap = (Map) adapterFactoriesByPackage.get(p);
if (aMap == null)
return;
Iterator factories = aMap.values().iterator();
AdapterFactory factory = null;
while (factories.hasNext()) {
factory = (AdapterFactory) factories.next();
if (isFactoryForAllTypes(factory, types)) {
aMap.remove(factory);
}
}
}
private boolean isFactoryForAllTypes(AdapterFactory factory, List types) {
for (int i = 0; i < types.size(); i++) {
if (!factory.isFactoryForType(types.get(i))) {
return false;
}
}
return true;
}
private AdapterFactory getExistingFactoryForPackage(Object p, EPackage aPackage) {
if (p == null)
return null;
Map aMap = (Map) adapterFactoriesByPackage.get(p);
if (aMap == null)
return null;
return (AdapterFactory) aMap.get(aPackage);
}
private void addAdapterFactory(Object p, EPackage aPackage, AdapterFactory adapterFactory) {
Map aMap = getOrCreateMap(p, adapterFactoriesByPackage);
aMap.put(aPackage, adapterFactory);
if (adapterFactory == NULL_FACTORY)
return;
if (adapterFactory instanceof IChangeNotifier) {
((IChangeNotifier) adapterFactory).addListener(this);
}
allFactories.add(adapterFactory);
}
private Map getOrCreateMap(Object p, Map container) {
Map aMap = (Map) container.get(p);
if (aMap == null) {
aMap = new HashMap(10);
container.put(p, aMap);
}
return aMap;
}
private void addAdapterFactory(Object p, Object type, AdapterFactory adapterFactory) {
Map aMap = getOrCreateMap(p, adapterFactoriesByType);
aMap.put(type, adapterFactory);
if (adapterFactory == NULL_FACTORY)
return;
if (adapterFactory instanceof IChangeNotifier) {
((IChangeNotifier) adapterFactory).addListener(this);
}
allFactories.add(adapterFactory);
}
public Object adapt(Object target, Object type) {
Object adapter = target;
if (target instanceof Notifier) {
adapter = adapt((Notifier) target, type);
}
if (!(type instanceof Class) || (((Class) type).isInstance(adapter))) {
return adapter;
}
return null;
}
public Adapter adapt(Notifier target, Object type) {
Adapter result = null;
if (target instanceof EObject)
result = adapt((EObject) target, type);
else {
Object p = ProjectUtilities.getProject(target);
if (p == null)
p = NO_PROJECT;
result = adapt(p, target, type, new HashSet(), target.getClass());
}
return result;
}
public Adapter adapt(EObject target, Object type) {
EClass eClass = target.eClass();
if (eClass == null)
return null;
EPackage ePackage = eClass.getEPackage();
Adapter result = adapt(target, ePackage, type);
if (result == null) {
Set failedPackageSet = new HashSet();
failedPackageSet.add(ePackage);
Iterator supertypes = eClass.getEAllSuperTypes().iterator();
while (supertypes.hasNext()) {
eClass = (EClass) supertypes.next();
if (eClass != null) {
ePackage = eClass.getEPackage();
if (failedPackageSet.add(ePackage)) {
result = adapt(target, ePackage, type);
if (result != null)
break;
}
}
}
}
return result;
}
private Adapter adapt(EObject target, EPackage ePackage, Object type) {
Object aProject = ProjectUtilities.getProject(target);
if (aProject == null)
aProject = NO_PROJECT;
AdapterFactory delegate = getFactoryForPackage(aProject, ePackage);
if (delegate != null && delegate.isFactoryForType(type)) {
return delegate.adapt(target, type);
}
return null;
}
/*
* Code borrowed from {@link ComposedAdapterFactory}
*
*/
private Adapter adapt(Object p, Notifier target, Object type, Collection failedPackages, Class javaClass) {
if (p == null)
return null;
Adapter result = null;
Package javaPackage = javaClass.getPackage();
if (failedPackages.add(javaPackage)) {
List types = new ArrayList(2);
types.add(javaPackage);
if (type != null) {
types.add(type);
}
/* when an error occurs, remove the delegate and try again */
boolean attemptAdaptAgain = true;
while (result == null && attemptAdaptAgain) {
attemptAdaptAgain = false;
AdapterFactory delegateAdapterFactory = getFactoryForTypes(p, types);
if (delegateAdapterFactory != null) {
try {
result = delegateAdapterFactory.adapt(target, type);
} catch (RuntimeException re) {
Logger.getLogger().logError(re);
removeFactoryForTypes(p, types);
attemptAdaptAgain = true;
}
}
}
}
if (result == null) {
Class superclass = javaClass.getSuperclass();
if (superclass != null) {
result = adapt(p, target, type, failedPackages, javaClass.getSuperclass());
}
if (result == null) {
Class[] interfaces = javaClass.getInterfaces();
for (int i = 0; i < interfaces.length; ++i) {
result = adapt(p, target, type, failedPackages, interfaces[i]);
if (result != null) {
break;
}
}
}
}
return result;
}
public Adapter adaptNew(Notifier target, Object type) {
AdapterFactory factory = getFactoryForType(target);
if (factory != null)
return factory.adaptNew(target, type);
return null;
}
public void adaptAllNew(Notifier target) {
AdapterFactory factory = getFactoryForType(target);
if (factory != null)
factory.adaptAllNew(target);
}
public void addListener(INotifyChangedListener notifyChangedListener) {
changeNotifier.add(notifyChangedListener);
}
public void removeListener(INotifyChangedListener notifyChangedListener) {
changeNotifier.remove(notifyChangedListener);
}
public void fireNotifyChanged(Notification notification) {
if (changeNotifier == null || changeNotifier.isEmpty() || changeNotifier.get(0) == null)
return;
changeNotifier.fireNotifyChanged(notification);
}
public void dispose() {
Iterator iter = allFactories.iterator();
Object factory = null;
while (iter.hasNext()) {
factory = iter.next();
disposeFactory(factory);
}
for (Iterator itr = getEnablementIdentifiers().iterator(); itr.hasNext();) {
((IEnablementIdentifier) itr.next()).removeIdentifierListener(this);
}
if (resourceItemProviderAdapterFactory != null)
resourceItemProviderAdapterFactory.removeListener(this);
}
private void disposeFactory(Object factory) {
if (factory instanceof IDisposable) {
((IDisposable) factory).dispose();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.edit.provider.INotifyChangedListener#notifyChanged(org.eclipse.emf.common.notify.Notification)
*/
public void notifyChanged(Notification notification) {
//Foward the notification on to all my listeners
fireNotifyChanged(notification);
}
/**
* @param project
*/
private void removeAdapterFactories(Object project) {
adapterFactoriesByType.remove(project);
Map aMap = (Map) adapterFactoriesByPackage.remove(project);
if (aMap == null)
return;
Iterator factories = aMap.values().iterator();
Object adapterFactory;
while (factories.hasNext()) {
adapterFactory = factories.next();
allFactories.remove(adapterFactory);
disposeFactory(adapterFactory);
}
}
private AdapterFactory createAdapterFactory(Object project, EPackage ePackage) {
if (ePackage == null)
throw new IllegalArgumentException(EMFWorkbenchEditResourceHandler.getString("DynamicAdapterFactory_ERROR_0")); //$NON-NLS-1$
return createAdapterFactory(project, AdapterFactoryRegistry.instance().getDescriptors(ePackage, viewID));
}
private AdapterFactory createAdapterFactory(Object project, List descriptors) {
if (descriptors == null || descriptors.isEmpty())
return null;
AdapterFactory fact = null;
IEnablementIdentifier identifier = null;
AdapterFactoryDescriptor desc = null;
if (descriptors.size() == 1) {
desc = (AdapterFactoryDescriptor) descriptors.get(0);
identifier = getIdentifier(project, desc);
addListenerIfNecessary(identifier);
if (project.equals(NO_PROJECT) || (identifier != null && identifier.isEnabled()))
return desc.createInstance();
return null;
}
List factories = new ArrayList(descriptors.size());
for (int i = 0; i < descriptors.size(); i++) {
desc = (AdapterFactoryDescriptor) descriptors.get(i);
identifier = getIdentifier(project, desc);
addListenerIfNecessary(identifier);
if (project.equals(NO_PROJECT) || (identifier != null && identifier.isEnabled())) {
fact = desc.createInstance();
if (fact != null)
factories.add(fact);
}
}
if (factories.isEmpty())
return null;
return new ExtendedComposedAdapterFactory(factories);
}
/**
* @param project
* @param desc
* @return
*/
private IEnablementIdentifier getIdentifier(Object project, AdapterFactoryDescriptor desc) {
IEnablementIdentifier identifier = null;
if (isRespectingActivities() && project instanceof IProject)
identifier = IEnablementManager.INSTANCE.getIdentifier(desc.getID(), (IProject) project);
else if (project instanceof IProject)
identifier = EnablementManager.INSTANCE.getIdentifier(desc.getID(), (IProject) project);
return identifier;
}
/**
* @return
*/
private boolean isRespectingActivities() {
return respectingActivities;
}
protected void addListenerIfNecessary(IEnablementIdentifier identifier) {
if (identifier == null)
return;
identifier.addIdentifierListener(this);
getEnablementIdentifiers().add(identifier);
}
protected boolean isListeningTo(IEnablementIdentifier identifier) {
return getEnablementIdentifiers().contains(identifier);
}
/**
* @return Returns the enablementIdentifiers.
*/
protected Set getEnablementIdentifiers() {
if (enablementIdentifiers == null)
enablementIdentifiers = new HashSet();
return enablementIdentifiers;
}
private Set enablementIdentifiers;
/*
* (non-Javadoc)
*
* @see org.eclipse.wst.common.frameworks.internal.enablement.IEnablementIdentifierListener#identifierChanged(org.eclipse.wst.common.frameworks.internal.enablement.EnablementIdentifierEvent)
*/
public void identifierChanged(EnablementIdentifierEvent identifierEvent) {
if (identifierEvent.hasEnabledChanged() || identifierEvent.hasFunctionGroupIdsChanged()) {
Object project = ((EnablementIdentifier) identifierEvent.getIdentifier()).getProject();
if (project != null) {
removeAdapterFactories(project);
/*
* final Notifier notifier = (Notifier) getCachedRoots().get(project);
*/
/* force a viewer refresh */
notifyChanged(new NotificationImpl(Notification.ADD, null, null) {
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.notify.impl.NotificationImpl#getNotifier()
*/
public Object getNotifier() {
return null; // notifier;
}
});
}
/* else replace entire structure */
}
}
/**
* @return Returns the resourceItemProviderAdapterFactory.
*/
public ResourceItemProviderAdapterFactory getResourceItemProviderAdapterFactory() {
if (resourceItemProviderAdapterFactory == null) {
resourceItemProviderAdapterFactory = new ResourceItemProviderAdapterFactory();
resourceItemProviderAdapterFactory.addListener(this);
}
return resourceItemProviderAdapterFactory;
}
}