Dear Sirs and Madams.
For some unknown reason I receive an "502 - Bad Gateway" error when trying
to access the jira bug reporting system.
So please forgive me for "spamming" this mailing list.
Consider the following piece of code:
private Node cloneOfTarget;
public static void main(String[] args) {
Document doc = loadDocument();
((EventTarget)doc).addEventListener( MutationEventImpl.DOM_NODE_REMOVED,
this, true );
((EventTarget)doc).addEventListener(
MutationEventImpl.DOM_SUBTREE_MODIFIED, this, true );
removeFirstNodeWithAttributes(doc);
}
public void handleEvent( Event event ) {
if ( event.getType().equals( MutationEventImpl.DOM_NODE_REMOVED ) ) {
cloneOfTarget = ((Node)event.getTarget()).cloneNode(true);
}
else if ( event.getType().equals( MutationEventImpl.DOM_SUBTREE_MODIFIED
) ) {
if ( cloneOfTarget.getAttributes() != null ) {
System.out.println("This line of code is never executed");
}
}
}
The "loadDocument()" method does only load a given document.
The "removeFirstNodeWithAttributes(doc)" method does only remove the first
found dom node containing an attribute node (however removing any dom node
containing one or more attributes is sufficent to demonstrate the problem).
The issue (using Xerces 2.7.0) is the following:
Since we registered ourself upon the DOM_SUBTREE_MODIFIED event and the
DOM_NODE_REMOVED event the program should output "This line of code is never
executed".
But as the content of the line suggests this does not happen.
A closer analysis reveals:
The reason is: Xerces 2.7.0 uses a variable 'EnclosingAttr
savedEnclosingAttr' inside each DocumentImpl to store whether an attribute
has been modified.
The cloneNode(true) inside the handleEvent method does a deep clone of the
removed node and thus sets this global variable while the
ParentNode.internalRemoveChild method assumes it to be null.
Now in DocumentImpl.dispatchAggregateEvents we find the following piece of
code:
if (enclosingAttr != null) {
dispatchEvent(enclosingAttr, me);
if (owner != null)
dispatchEvent(owner, me);
}
else
dispatchEvent(node, me);
since enclosingAttr is not null anymore the DOM_SUBTREE_MODIFIED event is
dispatched to the attributes owner node instead of the parent node of the
removed node.
But since the owner node is already removed and thus does not belong to the
document anymore at this time of being no DOM_SUBTREE_MODIFIED event is
dispatched to the document.
The question I have now is:
Is this allowed usage of the cloneNode method (inside an event)?
I.e. am I allowed to call methods dispatching subevents inside an event
handler like the cloneNode operation does?
I assume mutation of the dom inside an event is allowed usage (even though
we do not mutate the dom but merely clone it in this scenario) since the
following comment (inside DocumentImpl.dispatchEvent suggests so:
// Capture pre-event parentage chain, not including target;
// use pre-event-dispatch ancestors even if event handlers mutate
// document and change the target's context.
If this is accepted usage a possible solution could be to store the
document's "savedEnclosingAttr" variable locally inside the mutation
methods.
However I am not able to oversee whether this is an acceptable solution or
any unexpected side effects might occur.
The following patch does however solve the problem for me but might not be
an appropriate solution.
Thank you.
--
GMX DSL = Maximale Leistung zum minimalen Preis!
2000 MB nur 2,99, Flatrate ab 4,99 Euro/Monat: http://www.gmx.net/de/go/dslIndex: AttrImpl.java
===================================================================
RCS file:
/home/cvspublic/xml-xerces/java/src/org/apache/xerces/dom/AttrImpl.java,v
retrieving revision 1.64
diff -u -r1.64 AttrImpl.java
--- AttrImpl.java 2 May 2005 22:02:22 -0000 1.64
+++ AttrImpl.java 25 Jul 2005 16:32:03 -0000
@@ -20,6 +20,7 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import org.apache.xerces.dom.DocumentImpl.EnclosingAttr;
import org.w3c.dom.TypeInfo;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
@@ -796,7 +797,7 @@
makeChildNode(); // make sure we have a node and not a string
// notify document
- ownerDocument.insertingNode(this, replace);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.insertingNode(this,
replace);
// Convert to internal type, to avoid repeated casting
ChildNode newInternal = (ChildNode)newChild;
@@ -855,7 +856,7 @@
changed();
// notify document
- ownerDocument.insertedNode(this, newInternal, replace);
+ ownerDocument.insertedNode(this, newInternal, replace,
savedEnclosingAttr);
checkNormalizationAfterInsert(newInternal);
@@ -909,7 +910,7 @@
ChildNode oldInternal = (ChildNode) oldChild;
// notify document
- ownerDocument.removingNode(this, oldInternal, replace);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.removingNode(this,
oldInternal, replace);
// Patch linked list around oldChild
// Note: lastChild == firstChild.previousSibling
@@ -949,7 +950,7 @@
changed();
// notify document
- ownerDocument.removedNode(this, replace);
+ ownerDocument.removedNode(this, replace, savedEnclosingAttr);
checkNormalizationAfterRemove(oldPreviousSibling);
@@ -991,7 +992,7 @@
// notify document
CoreDocumentImpl ownerDocument = ownerDocument();
- ownerDocument.replacingNode(this);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.replacingNode(this);
internalInsertBefore(newChild, oldChild, true);
if (newChild != oldChild) {
@@ -999,7 +1000,7 @@
}
// notify document
- ownerDocument.replacedNode(this);
+ ownerDocument.replacedNode(this, savedEnclosingAttr);
return oldChild;
}
Index: CharacterDataImpl.java
===================================================================
RCS file:
/home/cvspublic/xml-xerces/java/src/org/apache/xerces/dom/CharacterDataImpl.java,v
retrieving revision 1.24
diff -u -r1.24 CharacterDataImpl.java
--- CharacterDataImpl.java 4 Nov 2004 20:42:20 -0000 1.24
+++ CharacterDataImpl.java 25 Jul 2005 16:32:03 -0000
@@ -16,6 +16,7 @@
package org.apache.xerces.dom;
+import org.apache.xerces.dom.DocumentImpl.EnclosingAttr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -123,12 +124,12 @@
String oldvalue = this.data;
// notify document
- ownerDocument.modifyingCharacterData(this, replace);
+ EnclosingAttr savedEnclosingAttr =
ownerDocument.modifyingCharacterData(this, replace);
this.data = value;
// notify document
- ownerDocument.modifiedCharacterData(this, oldvalue, value, replace);
+ ownerDocument.modifiedCharacterData(this, oldvalue, value, replace,
savedEnclosingAttr);
}
/**
Index: CoreDocumentImpl.java
===================================================================
RCS file:
/home/cvspublic/xml-xerces/java/src/org/apache/xerces/dom/CoreDocumentImpl.java,v
retrieving revision 1.86
diff -u -r1.86 CoreDocumentImpl.java
--- CoreDocumentImpl.java 13 Jun 2005 21:08:07 -0000 1.86
+++ CoreDocumentImpl.java 25 Jul 2005 16:32:04 -0000
@@ -19,6 +19,8 @@
import java.lang.reflect.Constructor;
import java.util.Enumeration;
import java.util.Hashtable;
+
+import org.apache.xerces.dom.DocumentImpl.EnclosingAttr;
import org.apache.xerces.util.URI;
import org.w3c.dom.DOMConfiguration;
@@ -2652,49 +2654,53 @@
/**
* A method to be called when a character data node is about to be modified
*/
- void modifyingCharacterData(NodeImpl node, boolean replace) {
+ EnclosingAttr modifyingCharacterData(NodeImpl node, boolean replace) {
+ return null;
}
/**
* A method to be called when a character data node has been modified
*/
- void modifiedCharacterData(NodeImpl node, String oldvalue, String value,
boolean replace) {
+ void modifiedCharacterData(NodeImpl node, String oldvalue, String value,
boolean replace, EnclosingAttr savedEnclosedAttr) {
}
/**
* A method to be called when a node is about to be inserted in the tree.
*/
- void insertingNode(NodeImpl node, boolean replace) {
+ EnclosingAttr insertingNode(NodeImpl node, boolean replace) {
+ return null;
}
/**
* A method to be called when a node has been inserted in the tree.
*/
- void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
+ void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace,
EnclosingAttr savedEnclosedAttr) {
}
/**
* A method to be called when a node is about to be removed from the tree.
*/
- void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
+ EnclosingAttr removingNode(NodeImpl node, NodeImpl oldChild, boolean
replace) {
+ return null;
}
/**
* A method to be called when a node has been removed from the tree.
*/
- void removedNode(NodeImpl node, boolean replace) {
+ void removedNode(NodeImpl node, boolean replace, EnclosingAttr
savedEnclosedAttr) {
}
/**
* A method to be called when a node is about to be replaced in the tree.
*/
- void replacingNode(NodeImpl node) {
+ EnclosingAttr replacingNode(NodeImpl node) {
+ return null;
}
/**
* A method to be called when a node has been replaced in the tree.
*/
- void replacedNode(NodeImpl node) {
+ void replacedNode(NodeImpl node, EnclosingAttr savedEnclosedAttr) {
}
/**
Index: DocumentImpl.java
===================================================================
RCS file:
/home/cvspublic/xml-xerces/java/src/org/apache/xerces/dom/DocumentImpl.java,v
retrieving revision 1.85
diff -u -r1.85 DocumentImpl.java
--- DocumentImpl.java 2 May 2005 22:02:22 -0000 1.85
+++ DocumentImpl.java 25 Jul 2005 16:32:05 -0000
@@ -869,8 +869,6 @@
String oldvalue;
}
- EnclosingAttr savedEnclosingAttr;
-
/**
* NON-DOM INTERNAL: Convenience wrapper for calling
* dispatchAggregateEvents when the context was established
@@ -963,8 +961,7 @@
* @param node node to get enclosing attribute for
* @return either a description of that Attr, or null if none such.
*/
- protected void saveEnclosingAttr(NodeImpl node) {
- savedEnclosingAttr = null;
+ protected EnclosingAttr saveEnclosingAttr(NodeImpl node) {
// MUTATION PREPROCESSING AND PRE-EVENTS:
// If we're within the scope of an Attr and DOMAttrModified
// was requested, we need to preserve its previous value for
@@ -974,41 +971,42 @@
NodeImpl eventAncestor = node;
while (true) {
if (eventAncestor == null)
- return;
+ return null;
int type = eventAncestor.getNodeType();
if (type == Node.ATTRIBUTE_NODE) {
EnclosingAttr retval = new EnclosingAttr();
retval.node = (AttrImpl) eventAncestor;
retval.oldvalue = retval.node.getNodeValue();
- savedEnclosingAttr = retval;
- return;
+ return retval;
}
else if (type == Node.ENTITY_REFERENCE_NODE)
eventAncestor = eventAncestor.parentNode();
else if (type == Node.TEXT_NODE)
eventAncestor = eventAncestor.parentNode();
else
- return;
+ return null;
// Any other parent means we're not in an Attr
}
}
+ return null;
} // saveEnclosingAttr(NodeImpl) :void
/**
* A method to be called when a character data node has been modified
*/
- void modifyingCharacterData(NodeImpl node, boolean replace) {
+ EnclosingAttr modifyingCharacterData(NodeImpl node, boolean replace) {
if (mutationEvents) {
if (!replace) {
- saveEnclosingAttr(node);
+ return saveEnclosingAttr(node);
}
}
+ return null;
}
/**
* A method to be called when a character data node has been modified
*/
- void modifiedCharacterData(NodeImpl node, String oldvalue, String value,
boolean replace) {
+ void modifiedCharacterData(NodeImpl node, String oldvalue, String value,
boolean replace, EnclosingAttr savedEnclosingAttr) {
if (mutationEvents) {
if (!replace) {
// MUTATION POST-EVENTS:
@@ -1033,12 +1031,12 @@
/**
* A method to be called when a character data node has been replaced
*/
- void replacedCharacterData(NodeImpl node, String oldvalue, String value) {
+ void replacedCharacterData(NodeImpl node, String oldvalue, String value,
EnclosingAttr savedEnclosingAttr) {
//now that we have finished replacing data, we need to perform the same
actions
//that are required after a character data node has been modified
//send the value of false for replace parameter so that mutation
//events if appropriate will be initiated
- modifiedCharacterData(node, oldvalue, value, false);
+ modifiedCharacterData(node, oldvalue, value, false, savedEnclosingAttr);
}
@@ -1046,18 +1044,19 @@
/**
* A method to be called when a node is about to be inserted in the tree.
*/
- void insertingNode(NodeImpl node, boolean replace) {
+ EnclosingAttr insertingNode(NodeImpl node, boolean replace) {
if (mutationEvents) {
if (!replace) {
- saveEnclosingAttr(node);
+ return saveEnclosingAttr(node);
}
}
+ return null;
}
/**
* A method to be called when a node has been inserted in the tree.
*/
- void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
+ void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace,
EnclosingAttr savedEnclosingAttr) {
if (mutationEvents) {
// MUTATION POST-EVENTS:
// "Local" events (non-aggregated)
@@ -1122,7 +1121,9 @@
/**
* A method to be called when a node is about to be removed from the tree.
*/
- void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
+ EnclosingAttr removingNode(NodeImpl node, NodeImpl oldChild, boolean
replace) {
+
+ EnclosingAttr savedEnclosingAttr = null;
// notify iterators
if (iterators != null) {
@@ -1147,7 +1148,7 @@
// was requested, we need to preserve its previous value for
// that event.
if (!replace) {
- saveEnclosingAttr(node);
+ savedEnclosingAttr = saveEnclosingAttr(node);
}
// Child is told that it is about to be removed
LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_REMOVED);
@@ -1184,12 +1185,13 @@
}
}
} // End mutation preprocessing
+ return savedEnclosingAttr;
}
/**
* A method to be called when a node has been removed from the tree.
*/
- void removedNode(NodeImpl node, boolean replace) {
+ void removedNode(NodeImpl node, boolean replace, EnclosingAttr
savedEnclosingAttr) {
if (mutationEvents) {
// MUTATION POST-EVENTS:
// Subroutine: Transmit DOMAttrModified and DOMSubtreeModified,
@@ -1203,25 +1205,23 @@
/**
* A method to be called when a node is about to be replaced in the tree.
*/
- void replacingNode(NodeImpl node) {
+ EnclosingAttr replacingNode(NodeImpl node) {
if (mutationEvents) {
- saveEnclosingAttr(node);
+ return saveEnclosingAttr(node);
}
+ return null;
}
/**
* A method to be called when character data is about to be replaced in
the tree.
*/
void replacingData (NodeImpl node) {
- if (mutationEvents) {
- saveEnclosingAttr(node);
- }
}
/**
* A method to be called when a node has been replaced in the tree.
*/
- void replacedNode(NodeImpl node) {
+ void replacedNode(NodeImpl node, EnclosingAttr savedEnclosingAttr) {
if (mutationEvents) {
dispatchAggregateEvents(node, savedEnclosingAttr);
}
Index: ParentNode.java
===================================================================
RCS file:
/home/cvspublic/xml-xerces/java/src/org/apache/xerces/dom/ParentNode.java,v
retrieving revision 1.50
diff -u -r1.50 ParentNode.java
--- ParentNode.java 2 May 2005 22:02:22 -0000 1.50
+++ ParentNode.java 25 Jul 2005 16:32:05 -0000
@@ -21,6 +21,7 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import org.apache.xerces.dom.DocumentImpl.EnclosingAttr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -375,7 +376,7 @@
}
// notify document
- ownerDocument.insertingNode(this, replace);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.insertingNode(this,
replace);
// Convert to internal type, to avoid repeated casting
ChildNode newInternal = (ChildNode)newChild;
@@ -450,7 +451,7 @@
}
// notify document
- ownerDocument.insertedNode(this, newInternal, replace);
+ ownerDocument.insertedNode(this, newInternal, replace,
savedEnclosingAttr);
checkNormalizationAfterInsert(newInternal);
@@ -500,7 +501,7 @@
ChildNode oldInternal = (ChildNode) oldChild;
// notify document
- ownerDocument.removingNode(this, oldInternal, replace);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.removingNode(this,
oldInternal, replace);
// update cached length if we have any
if (fNodeListCache != null) {
@@ -555,7 +556,7 @@
changed();
// notify document
- ownerDocument.removedNode(this, replace);
+ ownerDocument.removedNode(this, replace, savedEnclosingAttr);
checkNormalizationAfterRemove(oldPreviousSibling);
@@ -593,7 +594,7 @@
// aggregations should be issued only once per user request.
// notify document
- ownerDocument.replacingNode(this);
+ EnclosingAttr savedEnclosingAttr = ownerDocument.replacingNode(this);
internalInsertBefore(newChild, oldChild, true);
if (newChild != oldChild) {
@@ -601,7 +602,7 @@
}
// notify document
- ownerDocument.replacedNode(this);
+ ownerDocument.replacedNode(this, savedEnclosingAttr);
return oldChild;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]