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 _quotedNumbers = false;
private boolean _nonOptimisticVersionCheck = false; private boolean _nonOptimisticVersionCheck = false;
private boolean _flushBeforeDetach = true; private boolean _flushBeforeDetach = true;
private boolean _overrideContextClassloader = false;
/** /**
* Whether to require exact identity value types when creating object * Whether to require exact identity value types when creating object
@ -192,4 +193,22 @@ public class Compatibility {
_flushBeforeDetach = beforeDetach; _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 _depth = -1;
private int _ignore = Integer.MAX_VALUE; 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. * Whether to parse element text.
*/ */
@ -349,36 +359,61 @@ public abstract class XMLMetaDataParser extends DefaultHandler
// parse the metadata with a SAX parser // parse the metadata with a SAX parser
try { try {
_sourceName = sourceName; _sourceName = sourceName;
SAXParser parser = XMLFactory.getSAXParser(validating, true); SAXParser parser = null;
Object schema = null; ClassLoader oldLoader = null;
if (validating) {
schema = schemaSource;
if (schema == null && getDocType() != null)
xml = new DocTypeReader(xml, getDocType());
}
if (_parseComments || _lh != null) try {
parser.setProperty 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;
if (schema == null && getDocType() != null)
xml = new DocTypeReader(xml, getDocType());
}
if (_parseComments || _lh != null)
parser.setProperty
("http://xml.org/sax/properties/lexical-handler", this); ("http://xml.org/sax/properties/lexical-handler", this);
if (schema != null) { if (schema != null) {
parser.setProperty parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaLanguage", ("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema"); "http://www.w3.org/2001/XMLSchema");
parser.setProperty parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaSource", ("http://java.sun.com/xml/jaxp/properties/schemaSource",
schema); schema);
} }
InputSource is = new InputSource(xml); InputSource is = new InputSource(xml);
if (_systemId && sourceName != null) if (_systemId && sourceName != null)
is.setSystemId(sourceName); is.setSystemId(sourceName);
parser.parse(is, this); parser.parse(is, this);
finish(); finish();
} catch (SAXException se) { } catch (SAXException se) {
IOException ioe = new IOException(se.toString()); IOException ioe = new IOException(se.toString());
JavaVersions.initCause(ioe, se); JavaVersions.initCause(ioe, se);
throw ioe; 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 { } finally {
reset(); 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(). * 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 \ elements for class arg parsing. No element can be a complete prefix of \
another. another.
class-arg: Error extracting class information from "{0}". 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 \ parse-error: An error was encountered while parsing element "{0}". Make sure \
the metadata file is correctly formatted. the metadata file is correctly formatted.
no-file: No source file found for "{0}". no-file: No source file found for "{0}".

View File

@ -235,6 +235,14 @@ public class XMLPersistenceMetaDataParser
if (repos != null if (repos != null
&& (repos.getValidate() & repos.VALIDATE_RUNTIME) != 0) && (repos.getValidate() & repos.VALIDATE_RUNTIME) != 0)
setParseComments(false); 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());
}
} }
/** /**