mirror of https://github.com/apache/openjpa.git
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:
parent
78d4af337f
commit
8fbaaf527c
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,6 +105,16 @@ public abstract class XMLMetaDataParser extends DefaultHandler
|
|||
private LexicalHandler _lh = null;
|
||||
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,36 +359,61 @@ public abstract class XMLMetaDataParser extends DefaultHandler
|
|||
// parse the metadata with a SAX parser
|
||||
try {
|
||||
_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;
|
||||
|
||||
if (_parseComments || _lh != null)
|
||||
parser.setProperty
|
||||
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
|
||||
if (schema != null) {
|
||||
parser.setProperty
|
||||
("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
|
||||
"http://www.w3.org/2001/XMLSchema");
|
||||
parser.setProperty
|
||||
"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());
|
||||
JavaVersions.initCause(ioe, se);
|
||||
throw ioe;
|
||||
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());
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -788,6 +788,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().
|
||||
|
|
|
@ -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}".
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue