OPENJPA-1993: Deadlock Potential with XML ORM Processing

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1100363 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jody Grassel 2011-05-06 20:22:23 +00:00
parent c00af8d5e8
commit 6fc7d55a09
4 changed files with 92 additions and 29 deletions

View File

@ -67,6 +67,7 @@ public class Compatibility {
private boolean _reloadOnDetach = false;
private boolean _ignoreDetachedStateFieldForProxySerialization = false;
private boolean _checkDatabaseForCascadePersistToDetachedEntity = false;
private boolean _overrideContextClassloader = true;
/**
* Whether to require exact identity value types when creating object
@ -558,4 +559,22 @@ public class Compatibility {
public void setCheckDatabaseForCascadePersistToDetachedEntity(boolean b){
_checkDatabaseForCascadePersistToDetachedEntity = b;
}
/**
* 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

@ -107,6 +107,16 @@ public abstract class XMLMetaDataParser extends DefaultHandler
private int _ignore = Integer.MAX_VALUE;
private boolean _parsing = false;
private boolean _overrideContextClassloader = false;
public boolean getOverrideContextClassloader() {
return _overrideContextClassloader;
}
public void setOverrideContextClassloader(boolean overrideCCL) {
_overrideContextClassloader = overrideCCL;
}
/*
* Whether the parser is currently parsing.
@ -366,36 +376,60 @@ public abstract class XMLMetaDataParser extends DefaultHandler
try {
setParsing(true);
_sourceName = sourceName;
SAXParser parser = XMLFactory.getSAXParser(validating, true);
Object schema = null;
if (validating) {
schema = schemaSource;
if (schema == null && getDocType() != null)
xml = new DocTypeReader(xml, getDocType());
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;
if (schema == null && getDocType() != null)
xml = new DocTypeReader(xml, getDocType());
}
if (_parseComments || _lh != null)
parser.setProperty
("http://xml.org/sax/properties/lexical-handler", this);
if (schema != null) {
parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaSource",
schema);
}
InputSource is = new InputSource(xml);
if (_systemId && sourceName != null)
is.setSystemId(sourceName);
parser.parse(is, this);
finish();
} catch (SAXException se) {
IOException ioe = new IOException(se.toString());
ioe.initCause(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"));
}
}
}
}
if (_parseComments || _lh != null)
parser.setProperty
("http://xml.org/sax/properties/lexical-handler", this);
if (schema != null) {
parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
parser.setProperty
("http://java.sun.com/xml/jaxp/properties/schemaSource",
schema);
}
InputSource is = new InputSource(xml);
if (_systemId && sourceName != null)
is.setSystemId(sourceName);
parser.parse(is, this);
finish();
} catch (SAXException se) {
IOException ioe = new IOException(se.toString());
ioe.initCause(se);
throw ioe;
} finally {
reset();
}

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

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