axis-java-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Johan Andersson (JIRA)" <j...@apache.org>
Subject [jira] Commented: (AXIS2-1570) Rampart/Axiom is not thread safe
Date Thu, 02 Nov 2006 09:48:30 GMT
    [ http://issues.apache.org/jira/browse/AXIS2-1570?page=comments#action_12446519 ] 
            
Johan Andersson commented on AXIS2-1570:
----------------------------------------

Thanks for the quick response to this issue Ruchith but I'm afraid the fix in 
http://svn.apache.org/viewvc?view=rev&rev=469841 will not solve the problem.

Let me try to break it down in two parts: 
1. The source of the NullPointer
2. The reason I cannot allow code like the one inside setDOOMRequired() to run in our application
server.

1) The source of the NullPointer
--------------------------------

If we look at setDOOMRequired() and newDocumentBuilder() methods again (http://svn.apache.org/viewvc?view=rev&rev=469841)

   public static void setDOOMRequired(boolean isDOOMRequired) {
        String systemKey = DocumentBuilderFactory.class.getName();
        if (isDOOMRequired) {
            if (!isDOOMRequired()) {
                originalDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
                originalDocumentBuilderFactoryClassName = originalDocumentBuilderFactory.getClass().getName();
                documentBuilderFactoryTracker.set(Boolean.TRUE);
                System.setProperty(systemKey, DocumentBuilderFactoryImpl.class.getName());
            }
        } else {
            String currentFactoryClassName = DocumentBuilderFactory.newInstance().getClass().getName();
            if (currentFactoryClassName != null && currentFactoryClassName.equals(DocumentBuilderFactoryImpl.class.getName()))
{
                System.getProperties().remove(systemKey);
                if (originalDocumentBuilderFactoryClassName != null) {
                    System.setProperty(DocumentBuilderFactory.class.getName(), originalDocumentBuilderFactoryClassName);
                }
            }
            documentBuilderFactoryTracker.set(null);
            originalDocumentBuilderFactory = null;
        }
    }

    public DocumentBuilder newDocumentBuilder()
            throws ParserConfigurationException {
        /**
         * Determine which DocumentBuilder implementation should be returned
         */
        return isDOOMRequired()
                ? new DocumentBuilderImpl()
                : originalDocumentBuilderFactory.newDocumentBuilder();
    }

And then assume this is executing in a number of active threads.

Thread 1 runs setDOOMRequired(true) which will set the threadlocal flag,
change the System property for the entire JVM and also manipulate static 
objects in the DocumentBuilderFactoryImpl class.

Thread 2 simultaneously is trying to get hold of a DocumentBuilderFactory (jaxp)
If Thread 2 does this right after the line where the system property is changed:
  System.setProperty(systemKey, DocumentBuilderFactoryImpl.class.getName());
Thread 2 will get the DocumentBuilderFactoryImpl as the DocumentBuilderFactory.
Thread 2 then yeilds.

Thread 1 then runs setDOOMRequired(false) which will try to revert the 
settings and make set the default DocumentBuilderFactory to 
javax.xml.parsers.DocumentBuilderFactory and also sets the static object
originalDocumentBuilderFactory to null.

Right after this Thread 2 picks up and asks the DocumentBuilderFactory 
it previously retrieved (while the system property still pointed at the 
org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl)
for a new DocumentBuilder through running the newDocumentBuilder() method.
The threadlocal flag returns that no doom is required so the code in 
the newDocumentBuilder() will call originalDocumentBuilderFactory.newDocumentBuilder()
As Thread 1 has set the static originalDocumentBuilderFactory to null this will cause a
nullpointer exception.

This is one example why the NPE occurs I'm guessing there are a couple of more ways it can
happen.


2) The reason, in my humble opinion, I cannot let this code run on my server
============================================================================

If we look at an application server, say Websphere, the web applications are
isolated through the classloader tree.

Say that I have Axis2 and another ApplicationX running in my Websphere.
Both of these applications parse XML documents using DocumentBuilders they retrieve
through DocumentBuilderFactory.newInstance() (standard JAXP).

The javadoc for javax.xml.parsers.DocumentBuilderFactory.newInstance() says:

 Obtain a new instance of a DocumentBuilderFactory. 
 This static method creates a new factory instance. 
 This method uses the following ordered lookup procedure to determine the DocumentBuilderFactory
implementation class to load: 
  * Use the javax.xml.parsers.DocumentBuilderFactory system property. 
  * 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. 
  * 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. 
  * Platform default DocumentBuilderFactory instance. 
 Once an application has obtained a reference to a DocumentBuilderFactory it can use the factory
to configure and obtain parser instances. 

As I understand the javax.xml.parsers.DocumentBuilderFactory system property overrides everything.

If the Axis2 application changes this property, even for just a split second, 
javax.xml.parsers.DocumentBuilderFactory.newInstance() will try to instantiate 
org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl if executed.

If another application, isolated from Axis2 through different classloaders, 
calls javax.xml.parsers.DocumentBuilderFactory.newInstance() during this split second
a ClassNotFound exception will occur as that applications classloader has no knowledge
about the org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl.

This could lead to potential troubleshooting nightmares in large server installations.

=============================================================================

I don't have a good suggestion to help resolve this, I understand (correct me if I'm wrong)
that the reason the default document builder is switched around is because you want WSS4J
to use DOOM
instead of the default/user defined DOM.

One possible way to do it is to make it possible to configure the DocumentBuilderFactory for
WSS4J
as an alternative to using JAXP.

As a final note I have tried to disable the use of DOOM through the useDOOM property in the
MessageContext
but it seems to give me other problems.


> Rampart/Axiom is not thread safe
> --------------------------------
>
>                 Key: AXIS2-1570
>                 URL: http://issues.apache.org/jira/browse/AXIS2-1570
>             Project: Apache Axis 2.0 (Axis2)
>          Issue Type: Bug
>          Components: modules
>    Affects Versions: 1.0
>         Environment: WinXP, Tomcat 4/5, Websphere 5/6
>            Reporter: Johan Andersson
>
> The Axiom DOM (distributed with Axis 1.0) implementation seems to have some threading
issues.
> The problem manifests itself as a nullpointer exception in org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl
> If I apply a moderate amount of load on the server so the number of http processor threads
start increase the NPE will 
> happen all of the time whenever a piece of code tries to create a DocumentBuilder (for
instance the WSDL parsing during deployment).
> I can reproduce this problem quite reliably.
> Nullpointer is caused by the originalDocumentBuilderFactory being null 
> --- snip ---
>     public DocumentBuilder newDocumentBuilder()
>             throws ParserConfigurationException {
>         /**
>          * Determine which DocumentBuilder implementation should be returned
>          */
>         return isDOOMRequired()
>                 ? new DocumentBuilderImpl()
>                 : originalDocumentBuilderFactory.newDocumentBuilder();
>     }
> --- snip ---
> I've tracked the problem to this piece of code in the org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl
> --- snip ---
>    public static void setDOOMRequired(boolean isDOOMRequired) {
>         String systemKey = DocumentBuilderFactory.class.getName();
>         if (isDOOMRequired) {
>             if (!isDOOMRequired()) {
>                 originalDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
>                 originalDocumentBuilderFactoryClassName = originalDocumentBuilderFactory.getClass().getName();
>                 documentBuilderFactoryTracker.set(Boolean.TRUE);
>                 System.setProperty(systemKey, DocumentBuilderFactoryImpl.class.getName());
>             }
>         } else {
>             String currentFactoryClassName = DocumentBuilderFactory.newInstance().getClass().getName();
>             if (currentFactoryClassName != null && currentFactoryClassName.equals(DocumentBuilderFactoryImpl.class.getName()))
{
>                 System.getProperties().remove(systemKey);
>                 if (originalDocumentBuilderFactoryClassName != null) {
>                     System.setProperty(DocumentBuilderFactory.class.getName(), originalDocumentBuilderFactoryClassName);
>                 }
>             }
>             documentBuilderFactoryTracker.set(null);
>             originalDocumentBuilderFactory = null;
>         }
>     }
> --- snip ---
> Trying to find away to resolve this I realise that the DOOM document builder factory
implementation is in fact manipulating a JVM-wide
> system property in a multi-threaded environment (!) which besides the problem I am currently
experiencing could lead to all sorts 
> of unwanted side-effects.
> As I don't want to allow this to happen I simply commented out the contents of the setDoomRequired()
method hoping that Rampart could work
> with my default DOM instead and that I would only suffer some performance loss.
> I was wrong in that assumption as I encountered another problem: 
> StAXOMBuilder CHARACTERS: [org.apache.axis2.AxisFault: WSDoAllReceiver: security processing
failed; nested exception is: 
> 	org.apache.ws.security.WSSecurityException: Cannot encrypt/decrypt data; nested exception
is: 
> 	org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node
where it is not permitted. 
> 	at org.apache.axis2.security.WSDoAllReceiver.processMessage(WSDoAllReceiver.java:183)
> 	at org.apache.axis2.security.handler.WSDoAllHandler.invoke(WSDoAllHandler.java:82)
> 	at org.apache.axis2.engine.Phase.invoke(Phase.java:381)
> 	at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:473)
> 	at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:445)
> 	at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:284)
> 	at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:157)
> 	at javax.servlet.http.HttpServlet.service(HttpServlet.java:716)
> I compared the source of org.apache.axiom.om.impl.dom.jaxp.DocumentBuilderFactoryImpl
in Axis 1.0 release and the latest in SVN
> http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderFactoryImpl.java?view=markup
> and can see no changes in how this is handled.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

---------------------------------------------------------------------
To unsubscribe, e-mail: axis-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-dev-help@ws.apache.org


Mime
View raw message