[jbossws-commits] JBossWS SVN: r11354 - in common/branches/jbossws-common-1.1.0/src: test/java/org/jboss/test/ws/common/utils and 1 other directory.

jbossws-commits at lists.jboss.org jbossws-commits at lists.jboss.org
Wed Dec 23 08:39:00 EST 2009


Author: alessio.soldano at jboss.com
Date: 2009-12-23 08:39:00 -0500 (Wed, 23 Dec 2009)
New Revision: 11354

Added:
   common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/JBossWSDocumentBuilderFactory.java
   common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/SecurityActions.java
   common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/DummyDocumentBuilderFactory.java
   common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/JBossWSDocumentBuilderFactoryTestCase.java
Modified:
   common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/DOMUtils.java
Log:
[JBPAPP-3303] Porting changes from trunk + adding SecurityActions utility class


Modified: common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/DOMUtils.java
===================================================================
--- common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/DOMUtils.java	2009-12-23 13:20:16 UTC (rev 11353)
+++ common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/DOMUtils.java	2009-12-23 13:39:00 UTC (rev 11354)
@@ -1,6 +1,6 @@
 /*
  * JBoss, Home of Professional Open Source.
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
  * as indicated by the @author tags. See the copyright.txt file in the
  * distribution for a full listing of individual contributors.
  *
@@ -80,7 +80,7 @@
          DocumentBuilderFactory factory = null;
          try
          {
-            factory = DocumentBuilderFactory.newInstance();
+            factory = JBossWSDocumentBuilderFactory.newInstance();
             factory.setValidating(false);
             factory.setNamespaceAware(true);
 

Copied: common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/JBossWSDocumentBuilderFactory.java (from rev 11350, common/trunk/src/main/java/org/jboss/wsf/common/JBossWSDocumentBuilderFactory.java)
===================================================================
--- common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/JBossWSDocumentBuilderFactory.java	                        (rev 0)
+++ common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/JBossWSDocumentBuilderFactory.java	2009-12-23 13:39:00 UTC (rev 11354)
@@ -0,0 +1,492 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.wsf.common;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.WeakHashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+
+import org.jboss.logging.Logger;
+
+/**
+ * A thread-safe {@link DocumentBuilderFactory} that also adds a caching system
+ * for preventing useless access to the filesystem due to the Service API when
+ * the same context classloader is in place.
+ * 
+ * @author alessio.soldano at jboss.com
+ * @since 22-Dec-2009
+ *
+ */
+public class JBossWSDocumentBuilderFactory extends DocumentBuilderFactory
+{
+   private static Logger log = Logger.getLogger(JBossWSDocumentBuilderFactory.class);
+   private static final String PROPERTY_NAME = "javax.xml.parsers.DocumentBuilderFactory";
+   private static final boolean useJaxpProperty;
+   /**
+    * A weak hash map that keeps DocumentBuilderFactory instances for each classloader.
+    * Weak keys are used to remove entries when classloaders are garbage collected.
+    * 
+    * No need for a synchronized map as this accessed from the
+    * static synchronized newInstance newInstance method.
+    */
+   private static Map<ClassLoader, JBossWSDocumentBuilderFactory> factoryMap = new WeakHashMap<ClassLoader, JBossWSDocumentBuilderFactory>();
+   
+   private final DocumentBuilderFactory delegate;
+   
+   //ThreadLocal attributes and features maps required to achieve thread safety
+   private ThreadLocal<DocumentBuilderFactoryFields> fields = new ThreadLocal<DocumentBuilderFactoryFields>() {
+      @Override
+      protected DocumentBuilderFactoryFields initialValue()
+      {
+         return new DocumentBuilderFactoryFields();
+      }
+   };
+   
+   static
+   {
+      // Use the properties file "lib/jaxp.properties" in the JRE directory.
+      // This configuration file is in standard java.util.Properties format and contains the fully
+      // qualified name of the implementation class with the key being the system property defined above.
+      PrivilegedAction<Object> action = new PropertyAccessAction("java.home");
+      String javaHome = (String)AccessController.doPrivileged(action);
+      File jaxmFile = new File(javaHome + "/lib/jaxp.properties");
+      if ((Boolean)AccessController.doPrivileged(new PropertyFileExistAction(jaxmFile)))
+      {
+         String factoryName = null;
+         boolean error = false;
+         try
+         {
+            action = new PropertyFileAccessAction(jaxmFile.getCanonicalPath());
+            Properties jaxmProperties = (Properties)AccessController.doPrivileged(action);
+            factoryName = jaxmProperties.getProperty(PROPERTY_NAME);
+         }
+         catch (IOException e)
+         {
+            log.warn("Can't read " + jaxmFile);
+            error = true;
+         }
+         finally
+         {
+            useJaxpProperty = (error || (factoryName != null));
+         }
+      }
+      else
+      {
+         useJaxpProperty = false;
+      }
+   }
+   
+   private JBossWSDocumentBuilderFactory(DocumentBuilderFactory delegate)
+   {
+      this.delegate = delegate;
+   }
+
+   @Override
+   public Object getAttribute(String name) throws IllegalArgumentException
+   {
+      return fields.get().getAttribute(name);
+   }
+
+   @Override
+   public boolean getFeature(String name) throws ParserConfigurationException
+   {
+      return fields.get().getFeature(name);
+   }
+
+   /**
+    * The creation method for the document builder; it's synchronized to allow us configuring the underlying
+    * DocumentBuilderFactory and delegate to it in a thread safe way.
+    * 
+    */
+   @Override
+   public synchronized DocumentBuilder newDocumentBuilder() throws ParserConfigurationException
+   {
+      DocumentBuilderFactoryFields currentFields = fields.get();
+      currentFields.copyTo(delegate);
+      return delegate.newDocumentBuilder();
+   }
+
+   @Override
+   public void setAttribute(String name, Object value) throws IllegalArgumentException
+   {
+      fields.get().setAttribute(name, value);
+   }
+
+   @Override
+   public void setFeature(String name, boolean value) throws ParserConfigurationException
+   {
+      fields.get().setFeature(name, value);
+   }
+   
+   @Override
+   public boolean isCoalescing()
+   {
+      return fields.get().isCoalescing();
+   }
+
+   @Override
+   public void setCoalescing(boolean coalescing)
+   {
+      fields.get().setCoalescing(coalescing);
+   }
+
+   @Override
+   public boolean isExpandEntityReferences()
+   {
+      return fields.get().isExpandEntityReferences();
+   }
+
+   @Override
+   public void setExpandEntityReferences(boolean expandEntityReferences)
+   {
+      fields.get().setExpandEntityReferences(expandEntityReferences);
+   }
+
+   @Override
+   public boolean isIgnoringComments()
+   {
+      return fields.get().isIgnoringComments();
+   }
+
+   @Override
+   public void setIgnoringComments(boolean ignoringComments)
+   {
+      fields.get().setIgnoringComments(ignoringComments);
+   }
+
+   @Override
+   public boolean isIgnoringElementContentWhitespace()
+   {
+      return fields.get().isIgnoringElementContentWhitespace();
+   }
+
+   @Override
+   public void setIgnoringElementContentWhitespace(boolean ignoringElementContentWhitespace)
+   {
+      fields.get().setIgnoringElementContentWhitespace(ignoringElementContentWhitespace);
+   }
+
+   @Override
+   public boolean isNamespaceAware()
+   {
+      return fields.get().isNamespaceAware();
+   }
+
+   @Override
+   public void setNamespaceAware(boolean namespaceAware)
+   {
+      fields.get().setNamespaceAware(namespaceAware);
+   }
+
+   @Override
+   public Schema getSchema()
+   {
+      return fields.get().getSchema();
+   }
+
+   @Override
+   public void setSchema(Schema schema)
+   {
+      fields.get().setSchema(schema);
+   }
+
+   @Override
+   public boolean isValidating()
+   {
+      return fields.get().isValidating();
+   }
+
+   @Override
+   public void setValidating(boolean validating)
+   {
+      fields.get().setValidating(validating);
+   }
+
+   @Override
+   public boolean isXIncludeAware()
+   {
+      return fields.get().isXIncludeAware();
+   }
+
+   @Override
+   public void setXIncludeAware(boolean includeAware)
+   {
+      fields.get().setXIncludeAware(includeAware);
+   }
+   
+   /**
+    * The {@link DocumentBuilderFactory#newInstance()} documentation defines the retrieval algorithm:
+    * 
+    * 1) Use the javax.xml.parsers.DocumentBuilderFactory system property.
+    * 2) Use the properties file "lib/jaxp.properties" in the JRE directory. This configuration file is in standard java.util.Properties format
+    *    and contains the fully qualified name of the implementation class with the key being the system property defined above. The jaxp.properties
+    *    file is read only once by the JAXP implementation and it's values are then cached for future use. If the file does not exist when the first
+    *    attempt is made to read from it, no further attempts are made to check for its existence. It is not possible to change the value of any
+    *    property in jaxp.properties after it has been read for the first time.
+    * 3) Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API will look for a
+    *    classname in the file META-INF/services/javax.xml.parsers.DocumentBuilderFactory in jars available to the runtime.
+    * 4) Platform default DocumentBuilderFactory instance.
+    * 
+    * So we basically check if 1) or 2) applies: if yes, we simply delegate to the DocumentBuilderFactory, otherwise we first try using our classloader
+    * cache and delegate to the DocumentBuilderFactory only in case of a miss in the cache. Then we wrap up the result into a JBossWSDocumentBuilderFactory
+    * instance.
+    * 
+    * @return a DocumentBuilderFactoryInstance
+    */
+   public static synchronized JBossWSDocumentBuilderFactory newInstance()
+   {
+      if (useJaxpProperty || getFactoryNameFromSystemProperty() != null)
+      {
+         return new JBossWSDocumentBuilderFactory(DocumentBuilderFactory.newInstance());
+      }
+      ClassLoader classLoader = SecurityActions.getContextClassLoader();
+      JBossWSDocumentBuilderFactory factory = factoryMap.get(classLoader);
+      if (factory == null)
+      {
+         factory = new JBossWSDocumentBuilderFactory(DocumentBuilderFactory.newInstance());
+         factoryMap.put(classLoader, factory);
+      }
+      return factory;
+   }
+   
+   private static String getFactoryNameFromSystemProperty()
+   {
+      PrivilegedAction<Object> action = new PropertyAccessAction(PROPERTY_NAME);
+      return (String)AccessController.doPrivileged(action);
+   }
+   
+   
+   //--------------------------------- Utility privileged actions
+   
+   private static class PropertyAccessAction implements PrivilegedAction<Object>
+   {
+      private String name;
+
+      PropertyAccessAction(String name)
+      {
+         this.name = name;
+      }
+
+      public Object run()
+      {
+         return System.getProperty(name);
+      }
+   }
+
+   private static class PropertyFileAccessAction implements PrivilegedAction<Object>
+   {
+      private String filename;
+
+      PropertyFileAccessAction(String filename)
+      {
+         this.filename = filename;
+      }
+
+      public Object run()
+      {
+         InputStream inStream = null;
+         try
+         {
+            inStream = new FileInputStream(filename);
+            Properties props = new Properties();
+            props.load(inStream);
+            return props;
+         }
+         catch (IOException ex)
+         {
+            throw new SecurityException("Cannot load properties: " + filename, ex);
+         }
+         finally
+         {
+            try
+            {
+               inStream.close();
+            }
+            catch (Exception e) {} //ignore
+         }
+      }
+   }
+   
+   private static class PropertyFileExistAction implements PrivilegedAction<Object>
+   {
+      private File file;
+
+      PropertyFileExistAction(File file)
+      {
+         this.file = file;
+      }
+
+      public Object run()
+      {
+         return file.exists();
+      }
+   }
+   
+   /**
+    * A utility class for storing the document builder factory fields in the ThreadLocal
+    */
+   private static class DocumentBuilderFactoryFields {
+      private boolean coalescing = false;
+      private boolean expandEntityReferences = true;
+      private boolean ignoringComments = false;
+      private boolean ignoringElementContentWhitespace = false;
+      private boolean namespaceAware = false;
+      private Schema schema = null;
+      private boolean validating = false;
+      private boolean XIncludeAware = false;
+      private Map<String, Object> attributes = new HashMap<String, Object>();
+      private Map<String, Boolean> features = new HashMap<String, Boolean>();
+      
+      public void copyTo(DocumentBuilderFactory target) throws ParserConfigurationException
+      {
+         target.setCoalescing(coalescing);
+         target.setExpandEntityReferences(expandEntityReferences);
+         target.setIgnoringComments(ignoringComments);
+         target.setIgnoringElementContentWhitespace(ignoringElementContentWhitespace);
+         target.setNamespaceAware(namespaceAware);
+         target.setSchema(schema);
+         target.setValidating(validating);
+         target.setXIncludeAware(XIncludeAware);
+         for (String key : attributes.keySet())
+         {
+            target.setAttribute(key, attributes.get(key));
+         }
+         for (String key : features.keySet())
+         {
+            target.setFeature(key, features.get(key));
+         }
+      }
+      
+      public Object getAttribute(String name)
+      {
+         return attributes.get(name);
+      }
+      
+      public Boolean getFeature(String name)
+      {
+         return features.get(name);
+      }
+      
+      public void setAttribute(String key, Object value)
+      {
+         this.attributes.put(key, value);
+      }
+      
+      public void setFeature(String key, Boolean value)
+      {
+         this.features.put(key, value);
+      }
+
+      public boolean isCoalescing()
+      {
+         return coalescing;
+      }
+
+      public void setCoalescing(boolean coalescing)
+      {
+         this.coalescing = coalescing;
+      }
+
+      public boolean isExpandEntityReferences()
+      {
+         return expandEntityReferences;
+      }
+
+      public void setExpandEntityReferences(boolean expandEntityReferences)
+      {
+         this.expandEntityReferences = expandEntityReferences;
+      }
+
+      public boolean isIgnoringComments()
+      {
+         return ignoringComments;
+      }
+
+      public void setIgnoringComments(boolean ignoringComments)
+      {
+         this.ignoringComments = ignoringComments;
+      }
+
+      public boolean isIgnoringElementContentWhitespace()
+      {
+         return ignoringElementContentWhitespace;
+      }
+
+      public void setIgnoringElementContentWhitespace(boolean ignoringElementContentWhitespace)
+      {
+         this.ignoringElementContentWhitespace = ignoringElementContentWhitespace;
+      }
+
+      public boolean isNamespaceAware()
+      {
+         return namespaceAware;
+      }
+
+      public void setNamespaceAware(boolean namespaceAware)
+      {
+         this.namespaceAware = namespaceAware;
+      }
+
+      public Schema getSchema()
+      {
+         return schema;
+      }
+
+      public void setSchema(Schema schema)
+      {
+         this.schema = schema;
+      }
+
+      public boolean isValidating()
+      {
+         return validating;
+      }
+
+      public void setValidating(boolean validating)
+      {
+         this.validating = validating;
+      }
+
+      public boolean isXIncludeAware()
+      {
+         return XIncludeAware;
+      }
+
+      public void setXIncludeAware(boolean includeAware)
+      {
+         XIncludeAware = includeAware;
+      }
+   }
+
+}

Added: common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/SecurityActions.java
===================================================================
--- common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/SecurityActions.java	                        (rev 0)
+++ common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/SecurityActions.java	2009-12-23 13:39:00 UTC (rev 11354)
@@ -0,0 +1,92 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.wsf.common;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Security actions for this package
+ * 
+ * @author alessio.soldano at jboss.com
+ * @since 19-Jun-2009
+ *
+ */
+class SecurityActions
+{
+   /**
+    * Get context classloader.
+    * 
+    * @return the current context classloader
+    */
+   static ClassLoader getContextClassLoader()
+   {
+      SecurityManager sm = System.getSecurityManager();
+      if (sm == null)
+      {
+         return Thread.currentThread().getContextClassLoader();
+      }
+      else
+      {
+         return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+            public ClassLoader run()
+            {
+               return Thread.currentThread().getContextClassLoader();
+            }
+         });
+      }
+   }
+   
+   /**
+    * Load a class using the provided classloader
+    * 
+    * @param name
+    * @return
+    * @throws PrivilegedActionException
+    */
+   static Class<?> loadClass(final ClassLoader cl, final String name) throws PrivilegedActionException, ClassNotFoundException
+   {
+      SecurityManager sm = System.getSecurityManager();
+      if (sm == null)
+      {
+         return cl.loadClass(name);
+      }
+      else
+      {
+         return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+            public Class<?> run() throws PrivilegedActionException
+            {
+               try
+               {
+                  return cl.loadClass(name);
+               }
+               catch (Exception e)
+               {
+                  throw new PrivilegedActionException(e);
+               }
+            }
+         });
+      }
+   }
+}
\ No newline at end of file


Property changes on: common/branches/jbossws-common-1.1.0/src/main/java/org/jboss/wsf/common/SecurityActions.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Copied: common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/DummyDocumentBuilderFactory.java (from rev 11350, common/trunk/src/test/java/org/jboss/test/ws/common/utils/DummyDocumentBuilderFactory.java)
===================================================================
--- common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/DummyDocumentBuilderFactory.java	                        (rev 0)
+++ common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/DummyDocumentBuilderFactory.java	2009-12-23 13:39:00 UTC (rev 11354)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.ws.common.utils;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * A dummy document builder factory just for testing in {@link JBossWSDocumentBuilderFactoryTestCase}.
+ * 
+ * @author alessio.soldano at jboss.com
+ * @since 23-Dec-2009
+ *
+ */
+public class DummyDocumentBuilderFactory extends DocumentBuilderFactory
+{
+   @Override
+   public Object getAttribute(String name) throws IllegalArgumentException
+   {
+      return null;
+   }
+
+   @Override
+   public boolean getFeature(String name) throws ParserConfigurationException
+   {
+      return false;
+   }
+
+   @Override
+   public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException
+   {
+      return null;
+   }
+
+   @Override
+   public void setAttribute(String name, Object value) throws IllegalArgumentException
+   {
+   }
+
+   @Override
+   public void setFeature(String name, boolean value) throws ParserConfigurationException
+   {
+   }
+}

Copied: common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/JBossWSDocumentBuilderFactoryTestCase.java (from rev 11350, common/trunk/src/test/java/org/jboss/test/ws/common/utils/JBossWSDocumentBuilderFactoryTestCase.java)
===================================================================
--- common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/JBossWSDocumentBuilderFactoryTestCase.java	                        (rev 0)
+++ common/branches/jbossws-common-1.1.0/src/test/java/org/jboss/test/ws/common/utils/JBossWSDocumentBuilderFactoryTestCase.java	2009-12-23 13:39:00 UTC (rev 11354)
@@ -0,0 +1,191 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.ws.common.utils;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.TestCase;
+
+import org.jboss.wsf.common.JBossWSDocumentBuilderFactory;
+
+/**
+ * Tests for the JBossWSDocumentBuilderFactory
+ * 
+ * @author alessio.soldano at jboss.com
+ * @since 23-Dec-2009
+ *
+ */
+public class JBossWSDocumentBuilderFactoryTestCase extends TestCase
+{
+   public void testCaching() throws Exception
+   {
+      final String propName = "javax.xml.parsers.DocumentBuilderFactory";
+      String origValue = System.getProperty(propName);
+      try
+      {
+         //remove system prop if any, to get the same factory for a given classloader
+         System.getProperties().remove(propName);
+         DocumentBuilderFactory factory1 = JBossWSDocumentBuilderFactory.newInstance();
+         DocumentBuilderFactory factory2 = JBossWSDocumentBuilderFactory.newInstance();
+         assertTrue("Expected the same factory", factory1.equals(factory2));
+         
+         //set the system prop, we should get different factories every time as the classloader based cache is by-passed
+         System.setProperty(propName, DummyDocumentBuilderFactory.class.getCanonicalName());
+         DocumentBuilderFactory factory3 = JBossWSDocumentBuilderFactory.newInstance();
+         assertTrue("Expected different factories", !factory3.equals(factory1));
+         assertTrue("Expected different factories", !factory3.equals(factory2));
+         DocumentBuilderFactory factory4 = JBossWSDocumentBuilderFactory.newInstance();
+         assertTrue("Expected different factories", !factory4.equals(factory1));
+         assertTrue("Expected different factories", !factory4.equals(factory2));
+         assertTrue("Expected different factories", !factory4.equals(factory3));
+         
+         //remove the prop again, we should get the first factory
+         System.getProperties().remove(propName);
+         DocumentBuilderFactory factory5 = JBossWSDocumentBuilderFactory.newInstance();
+         assertTrue("Expected the same factory", factory5.equals(factory1));
+         
+         ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
+         try
+         {
+            //change context classloader
+            Thread.currentThread().setContextClassLoader(new TestClassLoader(origLoader));
+            DocumentBuilderFactory factory6 = JBossWSDocumentBuilderFactory.newInstance();
+            assertTrue("Expected different factories", !factory6.equals(factory1));
+            DocumentBuilderFactory factory7 = JBossWSDocumentBuilderFactory.newInstance();
+            assertTrue("Expected the same factory", factory7.equals(factory6));
+         }
+         finally
+         {
+            Thread.currentThread().setContextClassLoader(origLoader);
+         }
+      }
+      finally
+      {
+         if (origValue == null)
+         {
+            System.getProperties().remove(propName);
+         }
+         else
+         {
+            System.setProperty(propName, origValue);
+         }
+      }
+   }
+   
+   public void testThreadSafety() throws Exception
+   {
+      DocumentBuilderFactory factory = JBossWSDocumentBuilderFactory.newInstance();
+      List<Callable<Boolean>> callables = new LinkedList<Callable<Boolean>>();
+      for (int j = 0; j < 3; j++)
+      {
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, true, true, true));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, true, true, false));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, true, false, false));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, false, false, false));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, false, false, true));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, false, true, true));
+         }
+         for (int i = 0; i < 10; i++)
+         {
+            callables.add(new TestCallable(factory, false, true, false));
+         }
+      }
+      ExecutorService es = Executors.newFixedThreadPool(210);
+      List<Future<Boolean>> futures = es.invokeAll(callables);
+      for (Future<Boolean> f : futures)
+      {
+         assertTrue(f.get());
+      }
+   }
+   
+   /**
+    * A Callable that use the provided thread safe factory to create a document builder and verifies it has the required configuration
+    */
+   public static class TestCallable implements Callable<Boolean>
+   {
+      private final DocumentBuilderFactory factory;
+      private final Boolean namespaceAware;
+      private final Boolean validating;
+      private final Boolean XIncludeAware;
+      
+      public TestCallable(DocumentBuilderFactory factory, boolean namespaceAware, boolean validating, boolean includeAware)
+      {
+         this.factory = factory;
+         this.namespaceAware = namespaceAware;
+         this.validating = validating;
+         this.XIncludeAware = includeAware;
+      }
+
+      public Boolean call() throws Exception
+      {
+         factory.setNamespaceAware(namespaceAware);
+         factory.setValidating(validating);
+         factory.setXIncludeAware(XIncludeAware);
+         DocumentBuilder builder = factory.newDocumentBuilder();
+         if (!namespaceAware.equals(builder.isNamespaceAware()))
+            return false;
+         if (!validating.equals(builder.isValidating()))
+            return false;
+         if (!XIncludeAware.equals(builder.isXIncludeAware()))
+            return false;
+         return true;
+      }
+      
+   }
+   
+   /**
+    * A ClassLoader doing nothing except falling back to its parent
+    */
+   public static class TestClassLoader extends ClassLoader
+   {
+      public TestClassLoader(ClassLoader parent)
+      {
+         super(parent);
+      }
+   }
+   
+}



More information about the jbossws-commits mailing list