You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/03/23 21:37:12 UTC

svn commit: r1580606 - in /commons/proper/configuration/branches/immutableNodes/src: main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java

Author: oheger
Date: Sun Mar 23 20:37:12 2014
New Revision: 1580606

URL: http://svn.apache.org/r1580606
Log:
Added a close() method to TrackedNodeModel.

This method releases the tracked node used as root for the model. It allows
freeing resources explicitly if they are no longer needed.

Modified:
    commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java
    commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java

Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java?rev=1580606&r1=1580605&r2=1580606&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/TrackedNodeModel.java Sun Mar 23 20:37:12 2014
@@ -17,6 +17,7 @@
 package org.apache.commons.configuration.tree;
 
 import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * <p>
@@ -38,6 +39,14 @@ import java.util.Collection;
  * the implementation of {@code InMemoryNodeModel}.
  * </p>
  * <p>
+ * If the tracked node acting as root node is exclusively used by this model, it
+ * should be released when this model is no longer needed. This can be done
+ * manually by calling the {@link #close()} method. It is also possible to pass
+ * a value of <strong>true</strong> to the {@code untrackOnFinalize} argument of
+ * the constructor. This causes {@code close()} to be called automatically if
+ * this object gets claimed by the garbage collector.
+ * </p>
+ * <p>
  * As {@code InMemoryNodeModel}, this class is thread-safe.
  * </p>
  *
@@ -58,6 +67,9 @@ public class TrackedNodeModel implements
      */
     private final boolean releaseTrackedNodeOnFinalize;
 
+    /** A flag whether this model has already been closed. */
+    private final AtomicBoolean closed;
+
     /**
      * Creates a new instance of {@code TrackedNodeModel} and initializes it
      * with the given underlying model and the selector to the root node. The
@@ -92,6 +104,7 @@ public class TrackedNodeModel implements
         parentModel = model;
         selector = sel;
         releaseTrackedNodeOnFinalize = untrackOnFinalize;
+        closed = new AtomicBoolean();
     }
 
     /**
@@ -184,18 +197,39 @@ public class TrackedNodeModel implements
     }
 
     /**
-     * {@inheritDoc} This implementation calls
-     * {@link InMemoryNodeModel#untrackNode(NodeSelector)} on the underlying
-     * model if the corresponding flag has been set at construction time. While
-     * this is not 100 percent reliable, it is better than keeping the tracked
-     * node hanging around.
+     * Closes this model. This causes the tracked node this model is based upon
+     * to be released (i.e. {@link InMemoryNodeModel#untrackNode(NodeSelector)}
+     * is called). This method should be called when this model is no longer
+     * needed. This implementation is idempotent; it is safe to call
+     * {@code close()} multiple times - only the first invocation has an effect.
+     * After this method has been called this model can no longer be used
+     * because there is no guarantee that the node can still be accessed from
+     * the parent model.
+     */
+    public void close()
+    {
+        if (closed.compareAndSet(false, true))
+        {
+            getParentModel().untrackNode(getSelector());
+        }
+    }
+
+    /**
+     * {@inheritDoc} This implementation calls {@code close()} if the
+     * {@code untrackOnFinalize} flag was set when this instance was
+     * constructed. While this is not 100 percent reliable, it is better than
+     * keeping the tracked node hanging around. Note that it is not a problem if
+     * {@code close()} already had been invoked manually because this method is
+     * idempotent.
+     *
+     * @see #close()
      */
     @Override
     protected void finalize() throws Throwable
     {
         if (isReleaseTrackedNodeOnFinalize())
         {
-            getParentModel().untrackNode(getSelector());
+            close();
         }
         super.finalize();
     }

Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java?rev=1580606&r1=1580605&r2=1580606&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestTrackedNodeModel.java Sun Mar 23 20:37:12 2014
@@ -204,4 +204,32 @@ public class TestTrackedNodeModel
         setUpModel().clear(resolver);
         EasyMock.verify(parentModel);
     }
+
+    /**
+     * Tests whether the model can be closed.
+     */
+    @Test
+    public void testClose()
+    {
+        parentModel.untrackNode(selector);
+        EasyMock.replay(parentModel);
+
+        setUpModel().close();
+        EasyMock.verify(parentModel);
+    }
+
+    /**
+     * Tests whether close can be called multiple times.
+     */
+    @Test
+    public void testCloseMultipleTimes()
+    {
+        parentModel.untrackNode(selector);
+        EasyMock.replay(parentModel);
+
+        TrackedNodeModel model = setUpModel();
+        model.close();
+        model.close();
+        EasyMock.verify(parentModel);
+    }
 }