You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by da...@apache.org on 2012/09/24 00:20:25 UTC

svn commit: r1389155 - in /jena/trunk/jena-arq: ReleaseNotes.txt src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java

Author: damian
Date: Sun Sep 23 22:20:24 2012
New Revision: 1389155

URL: http://svn.apache.org/viewvc?rev=1389155&view=rev
Log:
Fix JENA-328 (DatatypeFactory and classloader issue in OSGi)

Modified:
    jena/trunk/jena-arq/ReleaseNotes.txt
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java

Modified: jena/trunk/jena-arq/ReleaseNotes.txt
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/ReleaseNotes.txt?rev=1389155&r1=1389154&r2=1389155&view=diff
==============================================================================
--- jena/trunk/jena-arq/ReleaseNotes.txt (original)
+++ jena/trunk/jena-arq/ReleaseNotes.txt Sun Sep 23 22:20:24 2012
@@ -11,6 +11,7 @@ ChangeLog for ARQ
 + JENA-294 : improved optimization of sequeneces of OPTIONALs where the grouois only OPTIONAL and an equality filter
 + JENA-302 Add URIs for all XQuery/Xpath F&O functions for duration accessors
 + JENA-303 Add URIs for all XQuery/Xpath F&O functions where there are SPARQL functions
++ JENA-328 : implement OSGi friendly DatatypeFactory initialisation in NodeValue
 
 ==== ARQ 2.9.3
 

Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java?rev=1389155&r1=1389154&r2=1389155&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/NodeValue.java Sun Sep 23 22:20:24 2012
@@ -87,6 +87,15 @@ import com.hp.hpl.jena.sparql.graph.Node
 import com.hp.hpl.jena.sparql.graph.NodeTransform ;
 import com.hp.hpl.jena.sparql.serializer.SerializationContext ;
 import com.hp.hpl.jena.sparql.util.* ;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public abstract class NodeValue extends ExprNode
 {
@@ -137,6 +146,8 @@ public abstract class NodeValue extends 
      * 
      */
     
+    private static Logger log = LoggerFactory.getLogger(NodeValue.class) ;
+    
     // ---- Constants and initializers / public
     
     public static boolean VerboseWarnings = true ;
@@ -172,9 +183,63 @@ public abstract class NodeValue extends 
     public static DatatypeFactory xmlDatatypeFactory = null ;
     static
     {
-        try { xmlDatatypeFactory = DatatypeFactory.newInstance() ; }
+        try { xmlDatatypeFactory = getDatatypeFactory() ; }
         catch (DatatypeConfigurationException ex)
-        { throw new ARQInternalErrorException("Can't create a javax.xml DatatypeFactory") ; }
+        { throw new ARQInternalErrorException("Can't create a javax.xml DatatypeFactory", ex) ; }
+    }
+    
+    /**
+     * Get a datatype factory using the correct classloader
+     * 
+     * See JENA-328. DatatypeFactory.newInstance() clashes with OSGi
+     * This is clearly crazy, but DatatypeFactory is missing a very obvious
+     * method newInstance(Classloader). The method that was added is very
+     * hard to use correctly, as we shall see...
+     * @return 
+     */
+    private static DatatypeFactory getDatatypeFactory() 
+            throws DatatypeConfigurationException {
+        ClassLoader cl = NodeValue.class.getClassLoader();
+        File jaxpPropFile = new File(
+            System.getProperty("java.home") + File.pathSeparator + 
+            "lib" + File.pathSeparator + 
+            "jaxp.properties");
+        
+        // Step 1. Try the system property
+        String dtfClass = System.getProperty(DatatypeFactory.DATATYPEFACTORY_PROPERTY);
+        
+        // Step 2. Otherwise, try property in jaxp.properties
+        if (dtfClass == null && jaxpPropFile.exists() && jaxpPropFile.canRead()) {
+            Properties jaxp = new Properties();
+            InputStream in = null;
+            try {
+                in = new FileInputStream(jaxpPropFile);
+                jaxp.load(in);
+                dtfClass = jaxp.getProperty(DatatypeFactory.DATATYPEFACTORY_PROPERTY);
+            } catch (Exception e) {
+                log.warn("Issue loading jaxp.properties", e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException ex) {
+                        log.warn("Issue closing jaxp.properties ", ex);
+                    }
+                }
+            }
+        }
+        
+        // Step 3. Otherwise try the service approach
+        if (dtfClass == null) {
+            Iterator<DatatypeFactory> factoryIterator = 
+                ServiceLoader.load(DatatypeFactory.class, cl).iterator();
+            if (factoryIterator.hasNext()) return factoryIterator.next();
+        }
+        
+        // Step 4. Use the default
+        if (dtfClass == null) dtfClass = DatatypeFactory.DATATYPEFACTORY_IMPLEMENTATION_CLASS;
+        
+        return DatatypeFactory.newInstance(dtfClass, NodeValue.class.getClassLoader()) ;
     }
     
     // Use NodeValue.toNode(NodeValue)