OPENJPA-1993: Deadlock Potential with XML ORM Processing

git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/1.0.x@1099630 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jody Grassel 2011-05-04 22:33:24 +00:00
parent 78d4af337f
commit 8fbaaf527c
5 changed files with 105 additions and 23 deletions

View File

@ -31,6 +31,7 @@ public class Compatibility {
private boolean _quotedNumbers = false;
private boolean _nonOptimisticVersionCheck = false;
private boolean _flushBeforeDetach = true;
private boolean _overrideContextClassloader = false;
/**
* Whether to require exact identity value types when creating object
@ -192,4 +193,22 @@ public class Compatibility {
_flushBeforeDetach = beforeDetach;
}
/**
* Whether to temporally override the thread's Context Classloader when processing
* ORM XML documents to avoid deadlock potential with certain Classloader hierarchy
* configurations. Defaults to false.
*/
public boolean getOverrideContextClassloader() {
return _overrideContextClassloader;
}
/**
* Whether to temporally override the thread's Context Classloader when processing
* ORM XML documents to avoid deadlock potential with certain Classloader hierarchy
* configurations. Defaults to false.
*/
public void setOverrideContextClassloader(boolean overrideContextClassloader) {
_overrideContextClassloader = overrideContextClassloader;
}
}

View File

@ -106,6 +106,16 @@ public abstract class XMLMetaDataParser extends DefaultHandler
private int _depth = -1;
private int _ignore = Integer.MAX_VALUE;
private boolean _overrideContextClassloader = false;
public boolean getOverrideContextClassloader() {
return _overrideContextClassloader;
}
public void setOverrideContextClassloader(boolean overrideCCL) {
_overrideContextClassloader = overrideCCL;
}
/**
* Whether to parse element text.
*/
@ -349,7 +359,19 @@ public abstract class XMLMetaDataParser extends DefaultHandler
// parse the metadata with a SAX parser
try {
_sourceName = sourceName;
SAXParser parser = XMLFactory.getSAXParser(validating, true);
SAXParser parser = null;
ClassLoader oldLoader = null;
try {
if (_overrideContextClassloader == true) {
oldLoader = (ClassLoader) AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
AccessController.doPrivileged(J2DoPrivHelper.setContextClassLoaderAction(
XMLMetaDataParser.class.getClassLoader()));
}
parser = XMLFactory.getSAXParser(validating, true);
Object schema = null;
if (validating) {
schema = schemaSource;
@ -379,6 +401,19 @@ public abstract class XMLMetaDataParser extends DefaultHandler
IOException ioe = new IOException(se.toString());
JavaVersions.initCause(ioe, se);
throw ioe;
} finally {
if (_overrideContextClassloader == true && oldLoader != null) {
// Restore the old ContextClassloader
try {
AccessController.doPrivileged(J2DoPrivHelper.setContextClassLoaderAction(oldLoader));
} catch (Throwable t) {
if (_log != null && _log.isTraceEnabled()) {
_log.trace(_loc.get("restore-contextclassloader-failed"));
}
}
}
}
} finally {
reset();
}

View File

@ -789,6 +789,24 @@ public abstract class J2DoPrivHelper {
};
}
/**
* Return a PrivilegeAction object for Thread.currentThread
* .setContextClassLoader().
*
* Requires security policy:
* 'permission java.lang.RuntimePermission "setContextClassLoader";'
*
* @return ClassLoader
*/
public static final PrivilegedAction setContextClassLoaderAction(final ClassLoader loader) {
return new PrivilegedAction() {
public Object run() {
Thread.currentThread().setContextClassLoader(loader);
return Boolean.TRUE;
}
};
}
/**
* Return a PrivilegedAction object for new Thread().
*

View File

@ -25,6 +25,8 @@ cant-diff-elems: Unable to differentiate between given package and class \
elements for class arg parsing. No element can be a complete prefix of \
another.
class-arg: Error extracting class information from "{0}".
restore-contextclassloader-failed: An error occurred restoring the Thread's \
context classloader.
parse-error: An error was encountered while parsing element "{0}". Make sure \
the metadata file is correctly formatted.
no-file: No source file found for "{0}".

View File

@ -235,6 +235,14 @@ public class XMLPersistenceMetaDataParser
if (repos != null
&& (repos.getValidate() & repos.VALIDATE_RUNTIME) != 0)
setParseComments(false);
if (repos != null) {
// Determine if the Thread Context Classloader needs to be temporally overridden to the Classloader
// that loaded the OpenJPA classes, to avoid a potential deadlock issue with the way Xerces
// handles parsers and classloaders.
this.setOverrideContextClassloader(repos.getConfiguration().getCompatibilityInstance().
getOverrideContextClassloader());
}
}
/**