/**
* Copyright (c) 2002-2007 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 - Initial API and implementation
*/
package org.eclipse.emf.ecore.impl;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.eclipse.emf.common.EMFPlugin;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
/**
* An implementation of a package registry that can delegate failed lookup to another registry.
*/
public class EPackageRegistryImpl extends HashMap<String, Object> implements EPackage.Registry
{
private static final long serialVersionUID = 1L;
/**
* Creates the {@link EPackage.Registry#INSTANCE instance} of the global registry.
* If a {@link System#getSecurityManager() security manager} is active,
* and <code>"classLoader"</code> {@link RuntimePermission permission} is not granted,
* a secure delegator instance is created,
* i.e., a private registry implementation that securely accesses class loaders
* and keeps them private, will be used.
*/
public static EPackage.Registry createGlobalRegistry()
{
try
{
String className = System.getProperty("org.eclipse.emf.ecore.EPackage.Registry.INSTANCE");
if (className == null)
{
if (EcorePlugin.getDefaultRegistryImplementation() != null)
{
return EcorePlugin.getDefaultRegistryImplementation();
}
else if (!EMFPlugin.IS_ECLIPSE_RUNNING)
{
try
{
SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null)
{
securityManager.checkPermission(new RuntimePermission("classLoader"));
}
return new Delegator();
}
catch (Throwable throwable)
{
return new SecureDelegator();
}
}
else
{
return new EPackageRegistryImpl();
}
}
else
{
return (EPackage.Registry)Class.forName(className).newInstance();
}
}
catch (Exception exception)
{
EcorePlugin.INSTANCE.log(exception);
return new EPackageRegistryImpl();
}
}
/**
* The delegate registry.
*/
protected EPackage.Registry delegateRegistry;
/**
* Creates a non-delegating instance.
*/
public EPackageRegistryImpl()
{
super();
}
/**
* Creates a delegating instance.
*/
public EPackageRegistryImpl(EPackage.Registry delegateRegistry)
{
this.delegateRegistry = delegateRegistry;
}
/*
* Javadoc copied from interface.
*/
public EPackage getEPackage(String nsURI)
{
Object ePackage = get(nsURI);
if (ePackage instanceof EPackage)
{
EPackage result = (EPackage)ePackage;
if (result.getNsURI() == null)
{
initialize(result);
}
return result;
}
else if (ePackage instanceof EPackage.Descriptor)
{
EPackage.Descriptor ePackageDescriptor = (EPackage.Descriptor)ePackage;
EPackage result = ePackageDescriptor.getEPackage();
if (result != null)
{
if (result.getNsURI() == null)
{
initialize(result);
}
else
{
put(nsURI, result);
}
}
return result;
}
else
{
return delegatedGetEPackage(nsURI);
}
}
/*
* Javadoc copied from interface.
*/
public EFactory getEFactory(String nsURI)
{
Object ePackage = get(nsURI);
if (ePackage instanceof EPackage)
{
EPackage result = (EPackage)ePackage;
if (result.getNsURI() == null)
{
initialize(result);
}
return result.getEFactoryInstance();
}
else if (ePackage instanceof EPackage.Descriptor)
{
EPackage.Descriptor ePackageDescriptor = (EPackage.Descriptor)ePackage;
EFactory result = ePackageDescriptor.getEFactory();
return result;
}
else
{
return delegatedGetEFactory(nsURI);
}
}
/**
* Creates a delegating instance.
*/
protected void initialize(EPackage ePackage)
{
// Do nothing.
}
/**
* Returns the package from the delegate registry, if there is one.
* @return the package from the delegate registry.
*/
protected EPackage delegatedGetEPackage(String nsURI)
{
if (delegateRegistry != null)
{
return delegateRegistry.getEPackage(nsURI);
}
return null;
}
/**
* Returns the factory from the delegate registry, if there is one.
* @return the factory from the delegate registry.
*/
protected EFactory delegatedGetEFactory(String nsURI)
{
if (delegateRegistry != null)
{
return delegateRegistry.getEFactory(nsURI);
}
return null;
}
/**
* Returns whether this map or the delegate map contains this key. Note that
* if there is a delegate map, the result of this method may
* <em><b>not</b></em> be the same as <code>keySet().contains(key)</code>.
* @param key the key whose presence in this map is to be tested.
* @return whether this map or the delegate map contains this key.
*/
@Override
public boolean containsKey(Object key)
{
return super.containsKey(key) || delegateRegistry != null && delegateRegistry.containsKey(key);
}
/**
* A map from class loader to its associated registry.
*/
protected static Map<ClassLoader, EPackage.Registry> classLoaderToRegistryMap = new WeakHashMap<ClassLoader, EPackage.Registry>();
/**
* Returns the package registry associated with the given class loader.
* @param classLoader the class loader.
* @return the package registry associated with the given class loader.
*/
public static synchronized EPackage.Registry getRegistry(ClassLoader classLoader)
{
EPackage.Registry result = classLoaderToRegistryMap.get(classLoader);
if (result == null)
{
if (classLoader != null)
{
result = new EPackageRegistryImpl(getRegistry(classLoader.getParent()));
classLoaderToRegistryMap.put(classLoader, result);
}
}
return result;
}
/**
* A package registry implementation that delegates to a class loader specific registry.
*/
public static class Delegator implements EPackage.Registry
{
protected EPackage.Registry delegateRegistry(ClassLoader classLoader)
{
return getRegistry(classLoader);
}
protected EPackage.Registry delegateRegistry()
{
return delegateRegistry(getContextClassLoader());
}
protected ClassLoader getContextClassLoader()
{
return Thread.currentThread().getContextClassLoader();
}
protected ClassLoader getParent(ClassLoader classLoader)
{
return classLoader == null ? null : classLoader.getParent();
}
public EPackage getEPackage(String key)
{
return delegateRegistry().getEPackage(key);
}
public EFactory getEFactory(String key)
{
return delegateRegistry().getEFactory(key);
}
public int size()
{
return delegateRegistry().size();
}
public boolean isEmpty()
{
return delegateRegistry().isEmpty();
}
public boolean containsKey(Object key)
{
return delegateRegistry().containsKey(key);
}
public boolean containsValue(Object value)
{
return delegateRegistry().containsValue(value);
}
public Object get(Object key)
{
return delegateRegistry().get(key);
}
public Object put(String key, Object value)
{
// TODO Binary incompatibility; an old override must override putAll.
Class<?> valueClass = value.getClass();
if (valueClass == EPackageImpl.class)
{
return delegateRegistry().put(key, value);
}
else
{
String valueClassName = valueClass.getName();
// Find the uppermost class loader in the hierarchy that can load the class.
//
ClassLoader result = getContextClassLoader();
for (ClassLoader classLoader = getParent(result); classLoader != null; classLoader = getParent(classLoader))
{
try
{
Class<?> loadedClass = classLoader.loadClass(valueClassName);
if (loadedClass == valueClass)
{
result = classLoader;
}
else
{
// The class address was not equal, so we don't want this class loader,
// but instead want the last result that was able to load the class.
//
break;
}
}
catch (ClassNotFoundException exception)
{
// We can't find the class, so we don't want this class loader,
// but instead want the last result that was able to load the class.
//
break;
}
}
// Register with the upper most class loader that's able to load the class.
//
return delegateRegistry(result).put(key, value);
}
}
public Object remove(Object key)
{
return delegateRegistry().remove(key);
}
public void putAll(Map<? extends String, ? extends Object> map)
{
for (Map.Entry<? extends String, ? extends Object> entry : map.entrySet())
{
put(entry.getKey(), entry.getValue());
}
}
public void clear()
{
delegateRegistry().clear();
}
public Set<String> keySet()
{
return delegateRegistry().keySet();
}
public Collection<Object> values()
{
return delegateRegistry().values();
}
public Set<Entry<String, Object>> entrySet()
{
return delegateRegistry().entrySet();
}
}
private static class ParentClassLoaderGetter implements PrivilegedAction<ClassLoader>
{
private ClassLoader classLoader;
public ClassLoader run()
{
if (classLoader != null)
{
classLoader = classLoader.getParent();
}
return null;
}
public ClassLoader getParent(ClassLoader classLoader)
{
this.classLoader = classLoader;
AccessController.doPrivileged(this);
return this.classLoader;
}
}
private static final ParentClassLoaderGetter PARENT_CLASS_LOADER_GETTER = new ParentClassLoaderGetter();
private static final PrivilegedAction<ClassLoader> CONTEXT_CLASS_LOADER_ACTION =
new PrivilegedAction<ClassLoader>()
{
public ClassLoader run()
{
return Thread.currentThread().getContextClassLoader();
}
};
private static ClassLoader getContextClassLoaderSecurely()
{
return AccessController.doPrivileged(CONTEXT_CLASS_LOADER_ACTION);
}
private static final Map<ClassLoader, EPackage.Registry> secureClassLoaderToRegistryMap = new WeakHashMap<ClassLoader, EPackage.Registry>();
private static synchronized EPackage.Registry getRegistrySecurely(ClassLoader classLoader)
{
EPackage.Registry result = secureClassLoaderToRegistryMap.get(classLoader);
if (result == null)
{
if (classLoader != null)
{
result = new EPackageRegistryImpl(getRegistrySecurely(PARENT_CLASS_LOADER_GETTER.getParent(classLoader)));
secureClassLoaderToRegistryMap.put(classLoader, result);
}
}
return result;
}
private static final class SecureDelegator extends Delegator
{
private final ParentClassLoaderGetter parentClassLoaderGetter = new ParentClassLoaderGetter();
@Override
protected EPackage.Registry delegateRegistry(ClassLoader classLoader)
{
return getRegistrySecurely(classLoader);
}
@Override
protected ClassLoader getContextClassLoader()
{
return getContextClassLoaderSecurely();
}
@Override
protected ClassLoader getParent(ClassLoader classLoader)
{
return parentClassLoaderGetter.getParent(classLoader);
}
}
}