[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xindice-dev
Subject:    XUpdateImpl.java bug fixes B
From:       byrne () cns ! montana ! edu
Date:       2004-08-03 16:20:12
Message-ID: Pine.LNX.4.44.0408031014400.4094-200000 () finn ! cns ! montana ! edu
[Download RAW message or body]

Mainly a bug fix for bug 25892. I also found a temporary solution to fix 
corrupted XML files from invalid selects being passed into lexus. 

Bug 25892 is caused when more then one xupdate selects the same document 
causing the update commands to be ran multiple times. 

I attached the patch file in diff -u format. 


Sincerely,


Todd Byrne 	

["XUpdateImpl.java.patch" (TEXT/PLAIN)]

--- XUpdateImpl.java	2004-08-03 10:37:45.000000000 -0600
+++ /home/byrne/jbproject/xindice-cvs-src/xml-xindice/java/src/org/apache/xindice/core/xupdate/XUpdateImpl.java	2004-08-03 \
10:39:03.000000000 -0600 @@ -27,6 +27,7 @@
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 import org.xmldb.xupdate.lexus.XUpdateQueryImpl;
 import org.xmldb.xupdate.lexus.commands.CommandConstants;
@@ -35,6 +36,7 @@
 
 import java.util.Enumeration;
 import java.util.Hashtable;
+import org.apache.xindice.core.data.Key;
 
 /**
  * Provides Collection and document based XUpdate capabilities.
@@ -44,148 +46,198 @@
  *
  * @version CVS $Revision: 1.12 $, $Date: 2004/02/08 02:50:54 $
  */
-public class XUpdateImpl extends XUpdateQueryImpl {
+public class XUpdateImpl
+    extends XUpdateQueryImpl {
 
-    protected int nodesModified = 0;
-    protected NamespaceMap nsMap;
+  protected int nodesModified = 0;
+  protected NamespaceMap nsMap;
 
-    /**
-     * If set to true, then namespaces set explicitly via an API call will take \
                precendence.
-     * If set to false, then namespaces set implicitly within query string will take \
                precedence.
-     */
-    private static final boolean API_NS_PRECEDENCE = true;
-
-    /**
-     * Set the namespace map to be used when resolving queries
-     */
-    public void setNamespaceMap(NamespaceMap nsMap) {
-        if (nsMap == null) {
-            return;
-        }
-
-        if (this.nsMap == null) {
-            this.nsMap = nsMap;
-        } else {
-            this.nsMap.includeNamespaces(nsMap, API_NS_PRECEDENCE);
-        }
+  /**
+   * If set to true, then namespaces set explicitly via an API call will take \
precendence. +   * If set to false, then namespaces set implicitly within query \
string will take precedence. +   */
+  private static final boolean API_NS_PRECEDENCE = true;
+
+  /**
+   * Set the namespace map to be used when resolving queries
+   */
+  public void setNamespaceMap(NamespaceMap nsMap) {
+    if (nsMap == null) {
+      return;
     }
 
-
-    /**
-     * Sets the query string to be used when executing update
-     */
-    public void setQString(String query) throws SAXException {
-        super.setQString(query);
-        if (nsMap == null) {
-            nsMap = new NamespaceMap();
-        }
-        nsMap.includeNamespaces(super.namespaces, !API_NS_PRECEDENCE);
+    if (this.nsMap == null) {
+      this.nsMap = nsMap;
+    }
+    else {
+      this.nsMap.includeNamespaces(nsMap, API_NS_PRECEDENCE);
     }
+  }
 
+  /**
+   * Sets the query string to be used when executing update
+   */
+  public void setQString(String query) throws SAXException {
+    super.setQString(query);
+    if (nsMap == null) {
+      nsMap = new NamespaceMap();
+    }
+    nsMap.includeNamespaces(super.namespaces, !API_NS_PRECEDENCE);
+  }
 
-    /**
-     * Execute the XUpdate commands against a document.
-     */
-    public void execute(Node contextNode) throws Exception {
-        CommandObject currentCommand = new DefaultCommand(contextNode);
-        Enumeration commands = super.query[0].elements();
-        Enumeration attributes = super.query[1].elements();
-        Enumeration characters = super.query[2].elements();
-        Node origNode = contextNode;
-        CommandObject.getXPath().setNamespace(nsMap.getContextNode());
-
-        while (commands.hasMoreElements()) {
-            int id = ((Integer) commands.nextElement()).intValue();
-
-            if (id == CommandConstants.ATTRIBUTES) {
-                currentCommand.submitAttributes((Hashtable) \
                attributes.nextElement());
-            } else if (id == CommandConstants.CHARACTERS) {
-                currentCommand.submitCharacters((String) characters.nextElement());
-            } else if (id > 0) {
-                if (!currentCommand.submitInstruction(id)) {
-                    super.commandConstants.setContextNode(contextNode);
-                    currentCommand = super.commandConstants.commandForID(id);
-                    if (currentCommand == null) {
-                        throw new Exception("Operation can not have any \
                XUpdate-instruction!");
-                    }
-                    currentCommand.reset();
-                }
-            } else {
-                if (!currentCommand.executeInstruction()) {
-                    try {
-                        contextNode = currentCommand.execute();
-                    } catch (Exception e) {
-                        // While not ideal, CommandObject.execute throws
-                        // Exception("no nodes selected !") if nothing is
-                        // selected for modification we trap that case
-                        // and ignore allowing continued processing
-                        // of remaining xupdate instructions that may be present
-                        if (!"no nodes selected !".equals(e.getMessage())) {
-                            throw e;
-                        }
-                    }
-                    // Default do-nothing command will soak up anything
-                    // (characters, attributes, etc.) encountered until we
-                    // come across the next xupdate instruction
-                    // (e.g. remove, append, insert, etc.)
-                    currentCommand = new DefaultCommand(contextNode);
-                }
+  /**
+   * Execute the XUpdate commands against a document.
+   */
+  public void execute(Node contextNode) throws Exception {
+    CommandObject currentCommand = new DefaultCommand(contextNode);
+    Enumeration commands = super.query[0].elements();
+    Enumeration attributes = super.query[1].elements();
+    Enumeration characters = super.query[2].elements();
+    Node origNode = contextNode;
+    CommandObject.getXPath().setNamespace(nsMap.getContextNode());
+    boolean contextNodeNeedsCleaning = false;
+
+    while (commands.hasMoreElements()) {
+      int id = ( (Integer) commands.nextElement()).intValue();
+
+      if (id == CommandConstants.ATTRIBUTES) {
+        currentCommand.submitAttributes( (Hashtable) attributes.nextElement());
+      }
+      else if (id == CommandConstants.CHARACTERS) {
+        currentCommand.submitCharacters( (String) characters.nextElement());
+      }
+      else if (id > 0) {
+        if (!currentCommand.submitInstruction(id)) {
+          super.commandConstants.setContextNode(contextNode);
+          currentCommand = super.commandConstants.commandForID(id);
+          if (currentCommand == null) {
+            throw new Exception(
+                "Operation can not have any XUpdate-instruction!");
+          }
+          currentCommand.reset();
+        }
+      }
+      else {
+        if (!currentCommand.executeInstruction()) {
+          try {
+            contextNode = currentCommand.execute();
+          }
+          catch (Exception e) {
+            // While not ideal, CommandObject.execute throws
+            // Exception("no nodes selected !") if nothing is
+            // selected for modification we trap that case
+            // and ignore allowing continued processing
+            // of remaining xupdate instructions that may be present
+            if (!"no nodes selected !".equals(e.getMessage())) {
+              throw e;
             }
-        }
-
-        if (origNode instanceof CompressedNode) {
-            CompressedNode cn = (CompressedNode) origNode;
-            if (cn.isDirty()) {
-                nodesModified++;
+            // from my tests I figure it adds one temporary node per
+            // command, but when the exception gets thrown it never cleans it self \
up +            // this one node is always at the end
+            String lastNodeName = origNode.getLastChild().getNodeName();
+            System.err.println(lastNodeName);
+            if (lastNodeName.equals("temporaryXUpdateTree")) {
+              // assuming that one command one temporary site.
+              origNode.removeChild(origNode.getLastChild());
             }
+            else { // search for it?
+              contextNodeNeedsCleaning = true;
+            }
+
+          }
+          // Default do-nothing command will soak up anything
+          // (characters, attributes, etc.) encountered until we
+          // come across the next xupdate instruction
+          // (e.g. remove, append, insert, etc.)
+          currentCommand = new DefaultCommand(contextNode);
         }
+      }
     }
+    if (contextNodeNeedsCleaning) {
+      // search entire tree and to verify no extra nodes where left around.
+      cleanUpNode(origNode);
+    }
+    if (origNode instanceof CompressedNode) {
+      CompressedNode cn = (CompressedNode) origNode;
+      if (cn.isDirty()) {
+        nodesModified++;
+      }
+    }
+  }
+
+  /**
+   * Execute the set of XUpdate commands against a collection.
+   *
+   * @param col The collection against which the command will be executed
+   * @exception Exception Description of Exception
+   */
+  public void execute(Collection col) throws Exception {
+
+    int attribIndex = 0;
+    int temp = 0;
+    Hashtable docsUpdated = new Hashtable();
+
+    for (int i = 0; i < super.query[0].size(); i++) {
+      int cmdID = ( (Integer)super.query[0].elementAt(i)).intValue();
+
+      if (cmdID == CommandConstants.ATTRIBUTES) {
+        Hashtable attribs = (Hashtable)super.query[1].elementAt(attribIndex);
+        attribIndex++;
+        String selector = (String) attribs.get("select");
+
+        // If we found an XPath selector we need to execute the commands.
+        // save to skip variable because at this point we have already run the \
commands on the +        // files.
+        if (selector != null && !selector.startsWith("$")) {
+          NodeSet ns = col.queryCollection("XPath", selector, nsMap);
+
+          while (ns != null && ns.hasMoreNodes()) {
+            DBNode node = (DBNode) ns.getNextNode();
+            Document doc = node.getOwnerDocument();
+            NodeSource source = node.getSource();
+            Node contextNode = doc.getDocumentElement();
 
-    /**
-     * Execute the set of XUpdate commands against a collection.
-     *
-     * @param col The collection against which the command will be executed
-     * @exception Exception Description of Exception
-     */
-    public void execute(Collection col) throws Exception {
-
-        int attribIndex = 0;
-        for (int i = 0; i < super.query[0].size(); i++) {
-            int cmdID = ((Integer) super.query[0].elementAt(i)).intValue();
-
-            if (cmdID == CommandConstants.ATTRIBUTES) {
-                Hashtable attribs = (Hashtable) \
                super.query[1].elementAt(attribIndex);
-                attribIndex++;
-                String selector = (String) attribs.get("select");
-
-                // If we found an XPath selector we need to execute the commands.
-                if (selector != null) {
-                    NodeSet ns = col.queryCollection("XPath", selector, nsMap);
-                    Document lastDoc = null;
-                    while (ns != null && ns.hasMoreNodes()) {
-                        DBNode node = (DBNode) ns.getNextNode();
-                        Document doc = node.getOwnerDocument();
-
-                        if (doc == lastDoc) {
-                            continue; // We only have to process it once
-                        } else {
-                            lastDoc = doc;
-                        }
-
-                        NodeSource source = node.getSource();
-
-                        Node contextNode = doc.getDocumentElement();
-                        execute(contextNode);
-
-                        col.setDocument(source.getKey(), doc);
-                    }
-                }
+            if (docsUpdated.containsKey(source.getKey())) {
+              continue; // We only have to process it once
             }
+            else {
+              docsUpdated.put(source.getKey(), doc);
+            }
+
+            execute(contextNode);
+
+          }
         }
+      }
     }
+    Enumeration keys = docsUpdated.keys();
+    while (keys.hasMoreElements()) {
+      Key docID = (Key) keys.nextElement();
+      col.setDocument(docID, (Document) docsUpdated.get(docID));
+    }
+  }
+
+  public int getModifiedCount() {
+    return nodesModified;
+  }
+/**
+ * Search the document tree for nodes left around from the xupdate commands.
+ *
+ */
 
-    public int getModifiedCount() {
-        return nodesModified;
+  private void cleanUpNode(Node n) {
+    NodeList list = n.getChildNodes();
+    int listLength = list.getLength();
+
+    for (int i = listLength - 1; i >= 0; i--) {
+      Node currentNode = list.item(i);
+      if (currentNode.getNodeName().equals("temporaryXUpdateTree")) {
+        n.removeChild(currentNode);
+      }
+      else {
+        cleanUpNode(currentNode);
+      }
     }
-}
 
+  }
+}
\ No newline at end of file



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic