[ 
http://issues.apache.org/jira/browse/XERCESJ-727?page=comments#action_60359 ]
     
Michael Glavassevich commented on XERCESJ-727:
----------------------------------------------

I still believe this is a threading problem. A cloned node has the same owner 
document as the original node, so they're part of the same DOM even though the 
new node doesn't have a parent yet. 

In DOM, there are two ways of traversing a node's children. One is to walk to 
the child/sibling chain with getFirstChild()/getNextSibling(). The other is to 
iterate over the node list returned from getChildNodes(). In Xerces DOM 
implementation, siblings are stored as a linked list. So to get from node 1 to 
n, you have to walk through all the nodes in between.

To improve the performance of sequential lookups as well as getting the length, 
Xerces uses a cache. These caches which keep track of the last position 
accessed are managed by the owner document and get redistributed to other nodes 
when needed. If you're multi-threading with node lists, the cache could get 
swiped away from one and given to another while the first one is still using 
it, hence the NullPointerException.

> cloneNode(true) Element are still linked to original Element
> ------------------------------------------------------------
>
>          Key: XERCESJ-727
>          URL: http://issues.apache.org/jira/browse/XERCESJ-727
>      Project: Xerces2-J
>         Type: Bug
>   Components: DOM
>     Versions: 2.4.0
>  Environment: Operating System: Windows NT/2K
> Platform: PC
>     Reporter: Francois Abot
>     Assignee: Xerces-J Developers Mailing List

>
> NB : tested only under Windows 2000/ jdk 1.4.1_02
> -------
> - Create a DOM Element.
> - Create many threads, giving each of them a cloneNode(true) copy of the 
> Element.
> - Start all the threads.
> - Each thread just finds the Element's embedded sub-Elements.
> The following Exceptions occur many times (but not always) :
> java.lang.NullPointerException
>         at org.apache.xerces.dom.ParentNode.nodeListItem(Unknown Source)
>         at org.apache.xerces.dom.ParentNode.item(Unknown Source)
>         at Tst2Threads.run(Tst2Threads.java:40)
> java.lang.NullPointerException
>         at org.apache.xerces.dom.ParentNode.nodeListItem(Unknown Source)
>         at org.apache.xerces.dom.ParentNode.item(Unknown Source)
>         at Tst2Threads.run(Tst2Threads.java:41)
> where lines 40 and 41 are :
>         if ( lesNoeuds.item(i).getNodeType() != Element.ELEMENT_NODE ) 
> continue;
>         noeud = (Element)(lesNoeuds.item( i ));
> in the following example.
> NB : if I create an different Element from file for each thread creation 
> (different Element instances, not created from cloneNode) then no Exception 
> occurs
> This seems a wrong behaviour, keeping Xerces from being used in 
> multi-threading 
> environment.
> I understand that Xerces is not thread safe, but how can I use same data in 
> different threads if the cloning fails this way ?
> How can I write correct thread safe code using DOM data ?
> These symptoms seem close to bug #6885 but are NOT DUPLICATE at first sight : 
> there is no concurrent access on the same instance in my example.
> Thanks to tell me if there is any error in my code. I am interested in any 
> workaround for that behaviour...
> Francois.
> ***************************************
> Here follows a code example (sorry for poor comments ;-).
> Usage :
> - just run it from command line,
> - enter a XML file name, Element used will be the first one read from file (I 
> suggest a consequent Element), 
> - enter a number of threads,
> ==> with 200 threads the Exception occurs almost immediately.
> ***************************************
> import org.w3c.dom.*;
> public class Tst2Threads extends Thread
> {
>   static protected Document readDOM( String nomFichier ) throws Exception
>   {
>     java.net.URL url= new java.net.URL( nomFichier );
>     java.io.InputStream inputXML =  url.openStream();
>     
>     javax.xml.parsers.DocumentBuilderFactory factory =
>           javax.xml.parsers.DocumentBuilderFactory.newInstance();
>     factory.setValidating( false );
>     factory.setNamespaceAware( false );
>     factory.setIgnoringComments( true );
>     
>     javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder();
>     
>     Document document = builder.parse( inputXML );
>     
>     return document;
>   }
> /*******************************************************/   
>   Element element = null;
>   
>   public Tst2Threads(ThreadGroup gp, Element elt, String _nom)
>   {
>     super( gp, _nom);
>     element = elt;
>   }
>   
>   public void run()
>   {
>     NodeList lesNoeuds = element.getChildNodes();
>     Element noeud;
>     while (true)
>     {
>       for (int i=0, max=lesNoeuds.getLength(); i<max ; i++)
>       {
>         if ( lesNoeuds.item(i).getNodeType() != Element.ELEMENT_NODE ) 
> continue;
>         noeud = (Element)(lesNoeuds.item( i ));
>       }
>     }
>   }
>   // get first Element
>   static Element readElmt(String nomFic) throws Exception
>   {
>     Document doc = readDOM( "file://"+nomFic );
>     NodeList liste = doc.getChildNodes();
>     boolean done = false;
>     Element elmt = null;
>     if (liste != null)
>     {
>       for(int i=0, max=liste.getLength(); (i<max) && (! done); i++)
>       {
>         if ( liste.item(i).getNodeType() != Element.ELEMENT_NODE ) continue;
>         elmt = (Element)(liste.item( i ));
>         done = true ;
>       }
>     }
>     return elmt;
>   }
>   
> /*******************************************************/  
>   public static void main( java.lang.String[] args)
>   {
>     try
>     {
>       java.io.BufferedReader br=new java.io.BufferedReader( new 
> java.io.InputStreamReader( System.in));
>       System.out.print("XML file name for Element description 
> [d:/tmp/menu.xml] :");
>       String nomFic= br.readLine();
>       if ("".equals(nomFic)) nomFic = "d:/tmp/menu.xml";
>       Element elmt = readElmt(nomFic);
>       System.out.print("Nb of threads [200] :");
>       String s= br.readLine();
>       if ("".equals(s)) s="200";
>       int nbThreads = Integer.valueOf(s).intValue() - 1;
>       System.out.println(" Starting for :\n  file="+nomFic+"\n  nb 
> threads="+nbThreads);
>       
>       ThreadGroup groupe = new ThreadGroup("TEST");
>       Tst2Threads t;
>       for (int i=0; i<nbThreads; i++)
>       {
>         //    Element cloned here (from main thread --v)
>         t = new Tst2Threads(groupe, (Element)(elmt.cloneNode(true)), "Th"+i);
>         t.start();
>       }
>     }
>     catch (Throwable t)
>     {
>       t.printStackTrace();
>     }
>   }
> }

-- 
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
-
If you want more information on JIRA, or have a bug to report see:
   http://www.atlassian.com/software/jira


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to