mirror of https://github.com/apache/openjpa.git
OPENJPA-2057: Add additional class loader to configuration to load custom plugins
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1425072 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
56107fc73c
commit
0a8d89da00
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||||
import org.apache.openjpa.lib.log.Log;
|
import org.apache.openjpa.lib.log.Log;
|
||||||
import org.apache.openjpa.lib.log.LogFactory;
|
import org.apache.openjpa.lib.log.LogFactory;
|
||||||
import org.apache.openjpa.lib.util.Closeable;
|
import org.apache.openjpa.lib.util.Closeable;
|
||||||
|
import org.apache.openjpa.persistence.PersistenceProviderImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for generic configuration objects. Includes the ability
|
* Interface for generic configuration objects. Includes the ability
|
||||||
|
@ -252,26 +253,22 @@ public interface Configuration
|
||||||
public Object clone();
|
public Object clone();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies a <em>dynamic</em> property of this receiver even when
|
* Gets a class loader that can be additionally used to load custom plugin values.
|
||||||
* {@link #setReadOnly(boolean) frozen}.
|
*
|
||||||
*
|
* @see Configurations#newInstance(String, ClassLoader)
|
||||||
* @since 1.0.0
|
* @return an additional classloader for loading custom plugins. Can be null.
|
||||||
|
* @since 2.3.0
|
||||||
*/
|
*/
|
||||||
// public void modifyDynamic(String property, Object newValue);
|
ClassLoader getUserClassLoader();
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Affirms if the given property can be modified <em>dynamically</em> i.e.
|
* Sets an additional classloader to load custom plugin values.
|
||||||
// * even after the receiver is {@link #setReadOnly(boolean) frozen}.
|
* In OSGi environment, we internally set the bundle class loader as
|
||||||
// *
|
* the user class loader.
|
||||||
// * @since 1.0.0
|
*
|
||||||
// */
|
* @param loader a class loader to load custom plugin values
|
||||||
// public boolean isDynamic(String property);
|
* @see PersistenceProviderImpl#createEntityManagerFactory(String, Map)
|
||||||
//
|
* @since 2.3.0
|
||||||
// /**
|
*/
|
||||||
// * Gets the values that can be modified <em>dynamically</em> i.e.
|
void setUserClassLoader(ClassLoader loader);
|
||||||
// * even after the receiver is {@link #setReadOnly(boolean) frozen}.
|
|
||||||
// *
|
|
||||||
// * @since 1.0.0
|
|
||||||
// */
|
|
||||||
// public Value[] getDynamicValues();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,8 +106,7 @@ public class ConfigurationImpl
|
||||||
|
|
||||||
private static final String SEP = J2DoPrivHelper.getLineSeparator();
|
private static final String SEP = J2DoPrivHelper.getLineSeparator();
|
||||||
|
|
||||||
private static final Localizer _loc = Localizer.forPackage
|
private static final Localizer _loc = Localizer.forPackage(ConfigurationImpl.class);
|
||||||
(ConfigurationImpl.class);
|
|
||||||
|
|
||||||
public ObjectValue logFactoryPlugin;
|
public ObjectValue logFactoryPlugin;
|
||||||
public StringValue id;
|
public StringValue id;
|
||||||
|
@ -126,10 +125,15 @@ public class ConfigurationImpl
|
||||||
// cache descriptors
|
// cache descriptors
|
||||||
private PropertyDescriptor[] _pds = null;
|
private PropertyDescriptor[] _pds = null;
|
||||||
private MethodDescriptor[] _mds = null;
|
private MethodDescriptor[] _mds = null;
|
||||||
|
|
||||||
|
// An additional (and optional) classloader to load custom plugins.
|
||||||
|
private ClassLoader _userCL;
|
||||||
|
|
||||||
//Ant task needs to defer the resource loading
|
//Ant task needs to defer the resource loading
|
||||||
//until the classpath setting is loaded properly
|
//until the classpath setting is loaded properly
|
||||||
private boolean _deferResourceLoading = false;
|
private boolean _deferResourceLoading = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor. Attempts to load default properties through
|
* Default constructor. Attempts to load default properties through
|
||||||
* system's configured {@link ProductDerivation}s.
|
* system's configured {@link ProductDerivation}s.
|
||||||
|
@ -1107,4 +1111,12 @@ public class ConfigurationImpl
|
||||||
addValue(val);
|
addValue(val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClassLoader getUserClassLoader() {
|
||||||
|
return _userCL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserClassLoader(ClassLoader cl) {
|
||||||
|
_userCL = cl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.openjpa.lib.conf;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -186,6 +187,34 @@ public class Configurations {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class name by the given loader.
|
||||||
|
* For efficiency, a cache per class loader is maintained of classes already loader.
|
||||||
|
* @param clsName
|
||||||
|
* @param loader
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static Class<?> loadClass(String clsName, ClassLoader loader) {
|
||||||
|
Class<?> cls = null;
|
||||||
|
Object key = loader == null ? NULL_LOADER : loader;
|
||||||
|
Map<String,Class<?>> loaderCache = (Map<String,Class<?>>) _loaders.get(key);
|
||||||
|
if (loaderCache == null) { // We don't have a cache for this loader.
|
||||||
|
loaderCache = new ConcurrentHashMap<String,Class<?>>();
|
||||||
|
_loaders.put(key, loaderCache);
|
||||||
|
} else { // We have a cache for this loader.
|
||||||
|
cls = (Class<?>) loaderCache.get(clsName);
|
||||||
|
}
|
||||||
|
if (cls == null) {
|
||||||
|
try {
|
||||||
|
cls = Strings.toClass(clsName, loader);
|
||||||
|
loaderCache.put(clsName, cls);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method used by members of this package to instantiate plugin
|
* Helper method used by members of this package to instantiate plugin
|
||||||
* values.
|
* values.
|
||||||
|
@ -195,53 +224,30 @@ public class Configurations {
|
||||||
if (StringUtils.isEmpty(clsName))
|
if (StringUtils.isEmpty(clsName))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Class cls = null;
|
Class<?> cls = loadClass(clsName, findDerivedLoader(conf, loader));
|
||||||
|
if (cls == null) {
|
||||||
while (cls == null) {
|
cls = loadClass(clsName, findDerivedLoader(conf, null));
|
||||||
// can't have a null reference in the map, so use symbolic
|
}
|
||||||
// constant as key
|
if (cls == null && conf.getUserClassLoader() != null) {
|
||||||
Object key = loader == null ? NULL_LOADER : loader;
|
cls = loadClass(clsName, conf.getUserClassLoader());
|
||||||
Map loaderCache = (Map) _loaders.get(key);
|
|
||||||
if (loaderCache == null) { // We don't have a cache for this loader.
|
|
||||||
loaderCache = new ConcurrentHashMap();
|
|
||||||
_loaders.put(key, loaderCache);
|
|
||||||
} else { // We have a cache for this loader.
|
|
||||||
cls = (Class) loaderCache.get(clsName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cls == null) {
|
|
||||||
try {
|
|
||||||
cls = Strings.toClass(clsName, findDerivedLoader(conf,
|
|
||||||
loader));
|
|
||||||
loaderCache.put(clsName, cls);
|
|
||||||
} catch (RuntimeException re) {
|
|
||||||
if (loader != null) // Try one more time with loader=null
|
|
||||||
loader = null;
|
|
||||||
else {
|
|
||||||
if (val != null)
|
|
||||||
re = getCreateException(clsName, val, re);
|
|
||||||
if (fatal)
|
|
||||||
throw re;
|
|
||||||
Log log = (conf == null) ? null : conf
|
|
||||||
.getConfigurationLog();
|
|
||||||
if (log != null && log.isErrorEnabled())
|
|
||||||
log.error(_loc
|
|
||||||
.get("plugin-creation-exception", val), re);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cls == null) {
|
||||||
|
if (fatal)
|
||||||
|
throw getCreateException(clsName, val, new ClassNotFoundException(clsName));
|
||||||
|
Log log = (conf == null) ? null : conf.getConfigurationLog();
|
||||||
|
if (log != null && log.isErrorEnabled())
|
||||||
|
log.error(_loc.get("plugin-creation-exception", val));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(
|
return AccessController.doPrivileged(J2DoPrivHelper.newInstanceAction(cls));
|
||||||
J2DoPrivHelper.newInstanceAction(cls));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof PrivilegedActionException) {
|
if (e instanceof PrivilegedActionException) {
|
||||||
e = ((PrivilegedActionException) e).getException();
|
e = ((PrivilegedActionException) e).getException();
|
||||||
}
|
}
|
||||||
RuntimeException re = new NestableRuntimeException(_loc.get
|
RuntimeException re = new NestableRuntimeException(_loc.get("obj-create", cls).getMessage(), e);
|
||||||
("obj-create", cls).getMessage(), e);
|
|
||||||
if (fatal)
|
if (fatal)
|
||||||
throw re;
|
throw re;
|
||||||
Log log = (conf == null) ? null : conf.getConfigurationLog();
|
Log log = (conf == null) ? null : conf.getConfigurationLog();
|
||||||
|
@ -256,42 +262,42 @@ public class Configurations {
|
||||||
* This allows application loaders that delegate appropriately for known
|
* This allows application loaders that delegate appropriately for known
|
||||||
* classes first crack at class names.
|
* classes first crack at class names.
|
||||||
*/
|
*/
|
||||||
private static ClassLoader findDerivedLoader(Configuration conf,
|
private static ClassLoader findDerivedLoader(Configuration conf, ClassLoader loader) {
|
||||||
ClassLoader loader) {
|
|
||||||
// we always prefer the thread loader, because it's the only thing we
|
// we always prefer the thread loader, because it's the only thing we
|
||||||
// can access that isn't bound to the OpenJPA classloader, unless
|
// can access that isn't bound to the OpenJPA classloader, unless
|
||||||
// the conf object is of a custom class
|
// the conf object is of a custom class
|
||||||
ClassLoader ctxLoader = AccessController.doPrivileged(
|
ClassLoader ctxLoader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
|
||||||
J2DoPrivHelper.getContextClassLoaderAction());
|
|
||||||
if (loader == null) {
|
if (loader == null) {
|
||||||
if (ctxLoader != null)
|
if (ctxLoader != null) {
|
||||||
return ctxLoader;
|
return ctxLoader;
|
||||||
if (conf != null)
|
} else if (conf != null) {
|
||||||
return AccessController.doPrivileged(
|
return classLoaderOf(conf.getClass());
|
||||||
J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
|
} else {
|
||||||
return Configurations.class.getClassLoader();
|
return classLoaderOf(Configurations.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ClassLoader parent = ctxLoader; parent != null;
|
for (ClassLoader parent = ctxLoader; parent != null; parent = parentClassLoaderOf(parent)) {
|
||||||
parent = AccessController.doPrivileged(
|
|
||||||
J2DoPrivHelper.getParentAction(parent))) {
|
|
||||||
if (parent == loader)
|
if (parent == loader)
|
||||||
return ctxLoader;
|
return ctxLoader;
|
||||||
}
|
}
|
||||||
if (conf != null) {
|
if (conf != null) {
|
||||||
for (ClassLoader parent = (ClassLoader)
|
for (ClassLoader parent = classLoaderOf(conf.getClass()); parent != null;
|
||||||
AccessController.doPrivileged(
|
parent = parentClassLoaderOf(parent)) {
|
||||||
J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
|
|
||||||
parent != null;
|
|
||||||
parent = AccessController.doPrivileged(
|
|
||||||
J2DoPrivHelper.getParentAction(parent))) {
|
|
||||||
if (parent == loader)
|
if (parent == loader)
|
||||||
return AccessController.doPrivileged(
|
return classLoaderOf(conf.getClass());
|
||||||
J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ClassLoader classLoaderOf(Class<?> cls) {
|
||||||
|
return AccessController.doPrivileged(J2DoPrivHelper.getClassLoaderAction(cls));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClassLoader parentClassLoaderOf(ClassLoader loader) {
|
||||||
|
return AccessController.doPrivileged(J2DoPrivHelper.getParentAction(loader));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a List<String> of all the fully-qualified anchors specified in the
|
* Return a List<String> of all the fully-qualified anchors specified in the
|
||||||
|
@ -386,8 +392,7 @@ public class Configurations {
|
||||||
/**
|
/**
|
||||||
* Helper method to throw an informative description on instantiation error.
|
* Helper method to throw an informative description on instantiation error.
|
||||||
*/
|
*/
|
||||||
private static RuntimeException getCreateException(String clsName,
|
private static RuntimeException getCreateException(String clsName, Value val, Exception e) {
|
||||||
Value val, Exception e) {
|
|
||||||
// re-throw the exception with some better information
|
// re-throw the exception with some better information
|
||||||
final String msg;
|
final String msg;
|
||||||
final Object[] params;
|
final Object[] params;
|
||||||
|
|
|
@ -90,6 +90,7 @@ public class PersistenceProviderImpl
|
||||||
|
|
||||||
BrokerFactory factory = getBrokerFactory(cp, poolValue, BundleUtils.getBundleClassLoader());
|
BrokerFactory factory = getBrokerFactory(cp, poolValue, BundleUtils.getBundleClassLoader());
|
||||||
OpenJPAConfiguration conf = factory.getConfiguration();
|
OpenJPAConfiguration conf = factory.getConfiguration();
|
||||||
|
conf.setUserClassLoader(BundleUtils.getBundleClassLoader());
|
||||||
_log = conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
|
_log = conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
|
||||||
pd.checkPuNameCollisions(_log,name);
|
pd.checkPuNameCollisions(_log,name);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue