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);
+ }
}