diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configuration.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configuration.java
index dc9749d63..250b81b4b 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configuration.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configuration.java
@@ -29,6 +29,7 @@ import java.util.Set;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.log.LogFactory;
import org.apache.openjpa.lib.util.Closeable;
+import org.apache.openjpa.persistence.PersistenceProviderImpl;
/**
* Interface for generic configuration objects. Includes the ability
@@ -252,26 +253,22 @@ public interface Configuration
public Object clone();
/**
- * Modifies a dynamic property of this receiver even when
- * {@link #setReadOnly(boolean) frozen}.
- *
- * @since 1.0.0
+ * Gets a class loader that can be additionally used to load custom plugin values.
+ *
+ * @see Configurations#newInstance(String, ClassLoader)
+ * @return an additional classloader for loading custom plugins. Can be null.
+ * @since 2.3.0
*/
-// public void modifyDynamic(String property, Object newValue);
-//
-// /**
-// * Affirms if the given property can be modified dynamically i.e.
-// * even after the receiver is {@link #setReadOnly(boolean) frozen}.
-// *
-// * @since 1.0.0
-// */
-// public boolean isDynamic(String property);
-//
-// /**
-// * Gets the values that can be modified dynamically i.e.
-// * even after the receiver is {@link #setReadOnly(boolean) frozen}.
-// *
-// * @since 1.0.0
-// */
-// public Value[] getDynamicValues();
+ ClassLoader getUserClassLoader();
+
+ /**
+ * Sets an additional classloader to load custom plugin values.
+ * In OSGi environment, we internally set the bundle class loader as
+ * the user class loader.
+ *
+ * @param loader a class loader to load custom plugin values
+ * @see PersistenceProviderImpl#createEntityManagerFactory(String, Map)
+ * @since 2.3.0
+ */
+ void setUserClassLoader(ClassLoader loader);
}
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
index 7447bb025..a311b6a0b 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
@@ -106,8 +106,7 @@ public class ConfigurationImpl
private static final String SEP = J2DoPrivHelper.getLineSeparator();
- private static final Localizer _loc = Localizer.forPackage
- (ConfigurationImpl.class);
+ private static final Localizer _loc = Localizer.forPackage(ConfigurationImpl.class);
public ObjectValue logFactoryPlugin;
public StringValue id;
@@ -126,10 +125,15 @@ public class ConfigurationImpl
// cache descriptors
private PropertyDescriptor[] _pds = 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
//until the classpath setting is loaded properly
private boolean _deferResourceLoading = false;
+
/**
* Default constructor. Attempts to load default properties through
* system's configured {@link ProductDerivation}s.
@@ -1107,4 +1111,12 @@ public class ConfigurationImpl
addValue(val);
return val;
}
+
+ public ClassLoader getUserClassLoader() {
+ return _userCL;
+ }
+
+ public void setUserClassLoader(ClassLoader cl) {
+ _userCL = cl;
+ }
}
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java
index 81ac83329..7130c5867 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java
@@ -21,6 +21,7 @@ package org.apache.openjpa.lib.conf;
import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedActionException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -186,6 +187,34 @@ public class Configurations {
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> 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, loader);
+ loaderCache.put(clsName, cls);
+ } catch (RuntimeException re) {
+
+ }
+ }
+ return cls;
+ }
+
/**
* Helper method used by members of this package to instantiate plugin
* values.
@@ -195,53 +224,30 @@ public class Configurations {
if (StringUtils.isEmpty(clsName))
return null;
- Class cls = null;
-
- while (cls == null) {
- // can't have a null reference in the map, so use symbolic
- // constant as key
- Object key = loader == null ? NULL_LOADER : loader;
- 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;
- }
- }
- }
+ Class> cls = loadClass(clsName, findDerivedLoader(conf, loader));
+ if (cls == null) {
+ cls = loadClass(clsName, findDerivedLoader(conf, null));
+ }
+ if (cls == null && conf.getUserClassLoader() != null) {
+ cls = loadClass(clsName, conf.getUserClassLoader());
}
+ 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 {
- return AccessController.doPrivileged(
- J2DoPrivHelper.newInstanceAction(cls));
+ return AccessController.doPrivileged(J2DoPrivHelper.newInstanceAction(cls));
} catch (Exception e) {
if (e instanceof PrivilegedActionException) {
e = ((PrivilegedActionException) e).getException();
}
- RuntimeException re = new NestableRuntimeException(_loc.get
- ("obj-create", cls).getMessage(), e);
+ RuntimeException re = new NestableRuntimeException(_loc.get("obj-create", cls).getMessage(), e);
if (fatal)
throw re;
Log log = (conf == null) ? null : conf.getConfigurationLog();
@@ -256,42 +262,42 @@ public class Configurations {
* This allows application loaders that delegate appropriately for known
* classes first crack at class names.
*/
- private static ClassLoader findDerivedLoader(Configuration conf,
- ClassLoader loader) {
+ private static ClassLoader findDerivedLoader(Configuration conf, ClassLoader loader) {
// we always prefer the thread loader, because it's the only thing we
// can access that isn't bound to the OpenJPA classloader, unless
// the conf object is of a custom class
- ClassLoader ctxLoader = AccessController.doPrivileged(
- J2DoPrivHelper.getContextClassLoaderAction());
+ ClassLoader ctxLoader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
if (loader == null) {
- if (ctxLoader != null)
+ if (ctxLoader != null) {
return ctxLoader;
- if (conf != null)
- return AccessController.doPrivileged(
- J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
- return Configurations.class.getClassLoader();
+ } else if (conf != null) {
+ return classLoaderOf(conf.getClass());
+ } else {
+ return classLoaderOf(Configurations.class);
+ }
}
- for (ClassLoader parent = ctxLoader; parent != null;
- parent = AccessController.doPrivileged(
- J2DoPrivHelper.getParentAction(parent))) {
+ for (ClassLoader parent = ctxLoader; parent != null; parent = parentClassLoaderOf(parent)) {
if (parent == loader)
return ctxLoader;
}
if (conf != null) {
- for (ClassLoader parent = (ClassLoader)
- AccessController.doPrivileged(
- J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
- parent != null;
- parent = AccessController.doPrivileged(
- J2DoPrivHelper.getParentAction(parent))) {
+ for (ClassLoader parent = classLoaderOf(conf.getClass()); parent != null;
+ parent = parentClassLoaderOf(parent)) {
if (parent == loader)
- return AccessController.doPrivileged(
- J2DoPrivHelper.getClassLoaderAction(conf.getClass()));
+ return classLoaderOf(conf.getClass());
}
}
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 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.
*/
- private static RuntimeException getCreateException(String clsName,
- Value val, Exception e) {
+ private static RuntimeException getCreateException(String clsName, Value val, Exception e) {
// re-throw the exception with some better information
final String msg;
final Object[] params;
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
index a73bb20ab..e15406acd 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
@@ -90,6 +90,7 @@ public class PersistenceProviderImpl
BrokerFactory factory = getBrokerFactory(cp, poolValue, BundleUtils.getBundleClassLoader());
OpenJPAConfiguration conf = factory.getConfiguration();
+ conf.setUserClassLoader(BundleUtils.getBundleClassLoader());
_log = conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
pd.checkPuNameCollisions(_log,name);