Author: jgrassel
Date: Wed May 30 19:14:13 2012
New Revision: 1344422

URL: http://svn.apache.org/viewvc?rev=1344422&view=rev
Log:
OPENJPA-1993: Deadlock Potential with ORM XML Processing

Modified:
    
openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
    
openjpa/branches/2.0.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
    
openjpa/branches/2.0.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
    
openjpa/branches/2.0.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java

Modified: 
openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java?rev=1344422&r1=1344421&r2=1344422&view=diff
==============================================================================
--- 
openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
 (original)
+++ 
openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
 Wed May 30 19:14:13 2012
@@ -69,6 +69,7 @@ public class Compatibility {
     private boolean _ignoreDetachedStateFieldForProxySerialization = false;
     private boolean _parseAnnotationsForQueryMode = true;
     private boolean _resetFlushFlagForCascadePersist = false;//OPENJPA-2051
+    private boolean _overrideContextClassloader = false; //OPENJPA-1993
     
     /**
      * Whether to require exact identity value types when creating object
@@ -607,4 +608,22 @@ public class Compatibility {
     public void setResetFlushFlagForCascadePersist(boolean b){
         _resetFlushFlagForCascadePersist = 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;
+    }
 }

Modified: 
openjpa/branches/2.0.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java?rev=1344422&r1=1344421&r2=1344422&view=diff
==============================================================================
--- 
openjpa/branches/2.0.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
 (original)
+++ 
openjpa/branches/2.0.x/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/XMLMetaDataParser.java
 Wed May 30 19:14:13 2012
@@ -107,7 +107,17 @@ public abstract class XMLMetaDataParser 
     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,69 @@ public abstract class XMLMetaDataParser 
         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;
+            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());
+                ioe.initCause(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"));
+                        }
+                    }
+                }
             }
-
-            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 {
             reset();
         }

Modified: 
openjpa/branches/2.0.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
URL: 
http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties?rev=1344422&r1=1344421&r2=1344422&view=diff
==============================================================================
--- 
openjpa/branches/2.0.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
 (original)
+++ 
openjpa/branches/2.0.x/openjpa-lib/src/main/resources/org/apache/openjpa/lib/meta/localizer.properties
 Wed May 30 19:14:13 2012
@@ -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/2.0.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java?rev=1344422&r1=1344421&r2=1344422&view=diff
==============================================================================
--- 
openjpa/branches/2.0.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
 (original)
+++ 
openjpa/branches/2.0.x/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
 Wed May 30 19:14:13 2012
@@ -279,6 +279,14 @@ public class XMLPersistenceMetaDataParse
         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());
+        }
     }
 
     /**


Reply via email to