You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jg...@apache.org on 2011/09/26 22:25:44 UTC
svn commit: r1176024 - in /openjpa/branches/1.2.x:
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/
openjpa-lib/src/main/java/org/apache/openjpa/lib/util/
openjpa-lib/src/main/resources/org/ap...
Author: jgrassel
Date: Mon Sep 26 20:25:44 2011
New Revision: 1176024
URL: http://svn.apache.org/viewvc?rev=1176024&view=rev
Log:
OPENJPA-1993: Deadlock Potential with ORM XML Processing
Modified:
openjpa/branches/1.2.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
openjpa/branches/1.2.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
openjpa/branches/1.2.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
Modified: openjpa/branches/1.2.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java?rev=1176024&r1=1176023&r2=1176024&view=diff
==============================================================================
--- openjpa/branches/1.2.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java (original)
+++ openjpa/branches/1.2.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java Mon Sep 26 20:25:44 2011
@@ -58,6 +58,7 @@ public class Compatibility {
private boolean _flushBeforeDetach = true;
private boolean _reorderMetaDataResolution = false;
private boolean _reloadOnDetach = true;
+ private boolean _overrideContextClassloader = false;
/**
* Whether to require exact identity value types when creating object
@@ -318,6 +319,23 @@ public class Compatibility {
_reloadOnDetach = reloadOnDetach;
}
+ /**
+ * 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;
+ }
}
Modified: openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java?rev=1176024&r1=1176023&r2=1176024&view=diff
==============================================================================
--- openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java (original)
+++ openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java Mon Sep 26 20:25:44 2011
@@ -105,7 +105,17 @@ public abstract class XMLMetaDataParser
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,68 @@ public abstract class XMLMetaDataParser
// 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;
+ boolean overrideCL = _overrideContextClassloader;
+ ClassLoader oldLoader = null;
+ ClassLoader newLoader = null;
+
+ try {
+ if (overrideCL == true) {
+ oldLoader = (ClassLoader) AccessController.doPrivileged(
+ J2DoPrivHelper.getContextClassLoaderAction());
+ newLoader = XMLMetaDataParser.class.getClassLoader();
+ AccessController.doPrivileged(J2DoPrivHelper.setContextClassLoaderAction(newLoader));
+
+ if (_log != null && _log.isTraceEnabled()) {
+ _log.trace(_loc.get("override-contextclassloader-begin", oldLoader, newLoader));
+ }
+ }
+
+ 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);
- }
+ 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());
- 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 (overrideCL == true) {
+ // Restore the old ContextClassloader
+ try {
+ if (_log != null && _log.isTraceEnabled()) {
+ _log.trace(_loc.get("override-contextclassloader-end", newLoader, oldLoader));
+ }
+ AccessController.doPrivileged(J2DoPrivHelper.setContextClassLoaderAction(oldLoader));
+ } catch (Throwable t) {
+ if (_log != null && _log.isWarnEnabled()) {
+ _log.warn(_loc.get("restore-contextclassloader-failed"));
+ }
+ }
+ }
+ }
} finally {
reset();
}
Modified: openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java?rev=1176024&r1=1176023&r2=1176024&view=diff
==============================================================================
--- openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java (original)
+++ openjpa/branches/1.2.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java Mon Sep 26 20:25:44 2011
@@ -789,6 +789,25 @@ 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<Boolean>
+ setContextClassLoaderAction(final ClassLoader loader) {
+ return new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ Thread.currentThread().setContextClassLoader(loader);
+ return Boolean.TRUE;
+ }
+ };
+ }
/**
* Return a PrivilegedAction object for new Thread().
Modified: openjpa/branches/1.2.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties?rev=1176024&r1=1176023&r2=1176024&view=diff
==============================================================================
--- openjpa/branches/1.2.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties (original)
+++ openjpa/branches/1.2.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties Mon Sep 26 20:25:44 2011
@@ -25,6 +25,12 @@ cant-diff-elems: Unable to differentiate
elements for class arg parsing. No element can be a complete prefix of \
another.
class-arg: Error extracting class information from "{0}".
+override-contextclassloader-begin: Overriding thread context classloader \
+ from "{0}" to "{1}".
+override-contextclassloader-end: Restoring thread context classloader \
+ from "{0}" to "{1}".
+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}".
Modified: openjpa/branches/1.2.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java?rev=1176024&r1=1176023&r2=1176024&view=diff
==============================================================================
--- openjpa/branches/1.2.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java (original)
+++ openjpa/branches/1.2.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java Mon Sep 26 20:25:44 2011
@@ -238,6 +238,14 @@ public class XMLPersistenceMetaDataParse
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());
+ }
}
/**