Hi Michael, thanks for your quick answer.

Ok, Here I send a first proposal for changes as a patch regarding Ranges and 
weak references.
It should not be difficult to apply similar changes to NodeIterators.

A more optimized implementation would likely make use of reference queues 
removing the need to actively check the weak reference's content upon each 
range update by DocumentImpl.

Since I am not proficient regarding java.io.Serialization at all someone more 
competent in this matter has to check whether something like this would break 
serializability.


Internally we were also thinking about EventListeners to use WeakReferences 
however I think that references to objects provided by an external application 
should not be weak (which I think applies to EventListener and user data).

However classes xerces provides to the application where xerces stores an 
reference in order to be able to update it's content can be weak and thus 
garbage collectable (which I think applies to Ranges and NodeIterators).


The following is a use case where a weak reference to an EventListener could 
cause undesired behaviour.

Imagine an EventListener implementation that solely logs all events to 
System.out or a file:

node.addEventListener(MutationEventImpl.DOM_SUBTREE_MODIFIED,
            new EventListener() {
                public void handleEvent( Event evt ) {
                    System.out.println( "Subtree Modification Event occured" );
                }
            }, true );


The only reference to this EventListener resides inside the DOM implementation.
If I am not mistaken usage of WeakReferences inside the DOM implementation here 
would result in the logging EventListener eventually being garbage-collected 
and thus cease event logging, right?

Same applies to user data: It might happen, that an application provides user 
data and relies upon the node implementation to hold on to it until the 
application retrieves the user data from the node again.


Thanks,

Ludger Bünger
--
Dipl.Inf. Ludger Bünger
RealObjects GmbH

> -----Original Message-----
> From: Michael Glavassevich [mailto:[EMAIL PROTECTED]
> Sent: Wednesday, March 07, 2007 9:11 PM
> To: [email protected]
> Cc: Ludger Buenger
> Subject: Re: xerces Range unnecessarily not garbage-collectable if not
> detached...
> 
> 
> Hi Ludger,
> 
> Oddly enough I was thinking about this (again) yesterday while I was 
> fixing some bugs in the Range implementation. 
> 
> Definitely interested in moving to WeakReferences. NodeIterators, 
> EventListeners, user data and probably a few other things in the DOM 
> implementation which hold on to objects which could otherwise 
> be garbage 
> collected would also benefit from this. It's been on my TODO 
> list since we 
> dropped JDK 1.1 support, though I first wanted to check what 
> impact it 
> would have on performance and serialization compatibility (i.e. 
> java.io.Serializable) if any before committing these 
> improvements. Just 
> haven't gotten around to it yet.
> 
> Thanks.
> 
> Michael Glavassevich
> XML Parser Development
> IBM Toronto Lab
> E-mail: [EMAIL PROTECTED]
> E-mail: [EMAIL PROTECTED]
> 
> "Ludger Buenger" <[EMAIL PROTECTED]> wrote on 03/07/2007 
> 11:12:54 AM:
> 
> > Hello Mr. Glavassevich,
> > 
> > Since I am not actively registered to the xerces-mailinglist and 
> > unsure whether this is an issue with regards to the xerces 
> > philosophy, I write to you as the one most involved with 
> this project.
> > 
> > During development we discovered that DOM ranges always have to be 
> > detached as defined by the DOM Range specification.
> > 
> > This sure is a useful behaviour for a general API but since Java has
> > an inbuild-garbage-collector there is no need to have to rely upon 
> > external developers allways actively detaching a range (however it 
> > still might be desirable).
> > 
> > Since I patched xerces for our own product to use garbage-
> > collectable ranges, I'd like to ask whether you or the community is 
> > interested to add this 'feature'?
> > 
> > Sincerely yours,
> > 
> > Ludger Bünger
> > 
> > --
> > Ludger Bünger
> > RealObjects GmbH 
> 
Index: C:/Lokal/Eigene 
Dateien/Programming/Xerces/src/org/apache/xerces/dom/DocumentImpl.java
===================================================================
--- C:/Lokal/Eigene 
Dateien/Programming/Xerces/src/org/apache/xerces/dom/DocumentImpl.java      
(revision 478532)
+++ C:/Lokal/Eigene 
Dateien/Programming/Xerces/src/org/apache/xerces/dom/DocumentImpl.java      
(working copy)
@@ -18,6 +18,7 @@
 package org.apache.xerces.dom;
 
 import java.io.Serializable;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Vector;
@@ -301,7 +302,7 @@
 
         Range range = new RangeImpl(this);
 
-        ranges.addElement(range);
+        ranges.addElement(new WeakReference(range));
 
         return range;
 
@@ -316,7 +317,21 @@
         if (range == null) return;
         if (ranges == null) return;
 
-        ranges.removeElement(range);
+        Object ref;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            ref = ((WeakReference)ranges.elementAt(i)).get();
+            if ( ref == null ) {
+                ranges.remove(i);
+                size--;
+            } else if (ref == range) {
+                ranges.remove(i);
+                break;
+            } else {
+                i++;
+            }
+        }
     }
 
     /**
@@ -331,9 +346,18 @@
     }
     
     private void notifyRangesReplacedText(NodeImpl node) {
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).receiveReplacedText(node);
+        RangeImpl r;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            r = (RangeImpl)((WeakReference)ranges.elementAt(i)).get();
+            if ( r == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                r.receiveReplacedText(node);
+                i++;
+            }
         }
     }
 
@@ -349,9 +373,18 @@
     }
     
     private void notifyRangesDeletedText(NodeImpl node, int offset, int count) 
{
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).receiveDeletedText(node, offset, 
count);
+        Object ref;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            ref = ((WeakReference)ranges.elementAt(i)).get();
+            if ( ref == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                ((RangeImpl)ref).receiveDeletedText(node, offset, count);
+                i++;
+            }
         }
     }
 
@@ -367,9 +400,18 @@
     }
     
     private void notifyRangesInsertedText(NodeImpl node, int offset, int 
count) {
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).receiveInsertedText(node, offset, 
count);
+        Object ref;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            ref = ((WeakReference)ranges.elementAt(i)).get();
+            if ( ref == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                ((RangeImpl)ref).receiveInsertedText(node, offset, count);
+                i++;
+            }
         }
     }
 
@@ -385,9 +427,18 @@
     }
     
     private void notifyRangesSplitData(Node node, Node newNode, int offset) {
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).receiveSplitData(node, newNode, 
offset);
+        Object ref;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            ref = ((WeakReference)ranges.elementAt(i)).get();
+            if ( ref == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                ((RangeImpl)ref).receiveSplitData(node, newNode, offset);
+                i++;
+            }
         }
     }
 
@@ -1137,9 +1188,18 @@
     }
     
     private void notifyRangesInsertedNode(NodeImpl newInternal) {
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).insertedNodeFromDOM(newInternal);
+        Object ref;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            ref = ((WeakReference)ranges.elementAt(i)).get();
+            if ( ref == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                ((RangeImpl)ref).insertedNodeFromDOM(newInternal);
+                i++;
+            }
         }
     }
 
@@ -1172,9 +1232,18 @@
     }
     
     private void notifyRangesRemovingNode(NodeImpl oldChild) {
-        final int size = ranges.size();
-        for (int i = 0; i != size; i++) {
-            ((RangeImpl)ranges.elementAt(i)).removeNode(oldChild);
+        RangeImpl r;
+        int size = ranges.size();
+        int i = 0;
+        while ( i < size ) {
+            r = (RangeImpl)((WeakReference)ranges.elementAt(i)).get();
+            if ( r == null ) {
+                ranges.remove(i);
+                size--;
+            } else {
+                r.removeNode(oldChild);
+                i++;
+            }
         }
     }
     
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to