sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1406953 - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util: collection/TreeNodeList.java resources/Errors.java resources/Errors.properties resources/Errors_fr.properties
Date Thu, 08 Nov 2012 08:39:04 GMT
Author: desruisseaux
Date: Thu Nov  8 08:39:04 2012
New Revision: 1406953

URL: http://svn.apache.org/viewvc?rev=1406953&view=rev
Log:
Added a private list implementation for managing TreeTable.Node children.
Adding or removing elements to/from this list shall update the parent node accordingly.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
  (with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java?rev=1406953&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
Thu Nov  8 08:39:04 2012
@@ -0,0 +1,359 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.collection;
+
+import java.util.Arrays;
+import java.util.AbstractList;
+import java.io.Serializable;
+import net.jcip.annotations.NotThreadSafe;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * A list of children in a {@link TreeTable.Node}. This list accepts only nodes that either
have no
+ * {@link TreeTable.Node#getParent() parent} at addition time, or already have the parent
for which
+ * this list manages the children. The {@link #add add} and {@link #remove remove} operations
shall
+ * update the parent when needed.
+ *
+ * <p>This list does not support duplicated elements. Attempts to add a node which
is already an
+ * element of another {@code TreeNodeList} will cause an {@link IllegalArgumentException}
to be
+ * thrown.</p>
+ *
+ * <p>Operations receiving a single {@code TreeTable.Node} argument are <cite>all
or nothing</cite>
+ * operations: in case of failure, the list will be left in the same state as if no operation
were
+ * attempted. If a failure occurs during a bulk operations, then the list may be left in
a state
+ * where some elements where processed and others not.</p>
+ *
+ * <p>Subclasses need to define the {@link #setParentOf(TreeTable.Node, int)} method
+ * because the way to set the parent is specific to the node implementation:</p>
+ *
+ * {@section Implementation note}
+ * We do not extend {@link java.util.ArrayList} because:
+ * <ul>
+ *   <li>We want to use identity comparisons rather than {@link Object#equals(Object)}.</li>
+ *   <li>We don't want this list to be cloneable, because it would complexify the management
+ *       of references to the parent node.</li>
+ *   <li>Extending {@link AbstractList} reduce the number of methods to override, since
+ *       {@code ArrayList} overrides bulk operations with optimized code which are not suitable
+ *       to {@code TreeNodeList} (we need the slower path implemented in {@code AbstractList}).</li>
+ * </ul>
+ *
+ * {@note Being serializable may seem contradictory with the non-cloneable requirement.
+ *        But serializating {@code TreeNodeList} will also serialize the parent, thus
+ *        creating new copy on deserialization. So the parents should not be mixed.}
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+@NotThreadSafe
+abstract class TreeNodeList extends AbstractList<TreeTable.Node>
+        implements CheckedContainer<TreeTable.Node>, Serializable
+{
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 9210230622796007350L;
+
+    /**
+     * Enumeration constant for {@link #setParentOf(TreeTable.Node, int)}.
+     */
+    protected static final int NULL=0, THIS=1, DRY_RUN=2;
+
+    /**
+     * The parent of all children managed by this list.
+     */
+    protected final TreeTable.Node parent;
+
+    /**
+     * The children, or {@code null} if none.
+     * This array will be created when first needed.
+     */
+    private TreeTable.Node[] children;
+
+    /**
+     * Number of valid elements in the {@link #children} array.
+     */
+    private int size;
+
+    /**
+     * Creates an initially empty list.
+     */
+    protected TreeNodeList(final TreeTable.Node parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Returns {@code true} if the node associated to this list is already the parent of
the given
+     * node, {@code false} if the given node has no parent, or throws an exception otherwise.
+     *
+     * @param  node The node for which to check the parent.
+     * @return {@code true} if the given node already has its parent set, or {@code false}
otherwise.
+     * @throws IllegalArgumentException If the given node is the children of another list.
+     */
+    private boolean isParentOf(final TreeTable.Node node) throws IllegalArgumentException
{
+        if (node == parent) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.NodeChildOfItself_1,
node));
+        }
+        final TreeTable.Node p = node.getParent();
+        if (p == null)   return false;
+        if (p == parent) return true;
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.NodeHasAnotherParent_1,
node));
+    }
+
+    /**
+     * Sets or clears the parent of the given node. This method doesn't need to care about
the
+     * current node parent, since {@code TreeNodeList} will take care of removing the
tree node
+     * from its previous parent before to invoke this method.
+     *
+     * <p>The {@code mode} argument specifies the parent value to set, as one of the
following
+     * values:</p>
+     * <ul>
+     *   <li>{@link #NULL} - set the node parent to {@code null}.</li>
+     *   <li>{@link #THIS} - set the node parent to {@link #parent}.</li>
+     *   <li>{@link #DRY_RUN} - only check if this method can set the parent of the
given node;
+     *       do not change the node parent yet.</li>
+     * </ul>
+     *
+     * @param  node The node on which to set the parent (never {@code null}).
+     * @param  mode One of the {@link #NULL}, {@link #THIS} or {@link #DRY_RUN} constants.
+     * @throws IllegalArgumentException If this method can not set the parent of the given
node.
+     */
+    protected abstract void setParentOf(TreeTable.Node node, int mode) throws IllegalArgumentException;
+
+    /**
+     * Returns the type of elements in this list.
+     *
+     * @return Fixed to {@code TreeTable.Node}.
+     */
+    @Override
+    public final Class<TreeTable.Node> getElementType() {
+        return TreeTable.Node.class;
+    }
+
+    /**
+     * Returns the number of nodes in this list.
+     *
+     * @return The number of nodes.
+     */
+    @Override
+    public final int size() {
+        return size;
+    }
+
+    /**
+     * Returns the node at the specified index in this list.
+     *
+     * @param  index The index of the node to fetch.
+     * @return The node at the given index (never {@code null}).
+     */
+    @Override
+    public TreeTable.Node get(final int index) {
+        ArgumentChecks.ensureValidIndex(size, index);
+        return children[index];
+    }
+
+    /**
+     * Sets the node at the specified index in this list.
+     *
+     * @param  index The index of the node to set.
+     * @param  node The node to store at the given index (can not be {@code null}).
+     * @return The node which was previously stored at the given index (never {@code null}).
+     * @throws IllegalArgumentException If this list can not add the given node, for example
+     *         if the node is already an element of another {@code TreeNodeList}.
+     */
+    @Override
+    public TreeTable.Node set(final int index, final TreeTable.Node node) throws IllegalArgumentException
{
+        ArgumentChecks.ensureValidIndex(size, index);
+        ArgumentChecks.ensureNonNull("node", node);
+        final TreeTable.Node old = children[index];
+        if (old != node) {
+            if (isParentOf(node)) {
+                ensureNotPresent(node);
+                setParentOf(old, NULL);
+            } else {
+                setParentOf(node, DRY_RUN);
+                setParentOf(old,  NULL);
+                setParentOf(node, THIS);
+            }
+            children[index] = node;
+            modCount++;
+        }
+        return old;
+    }
+
+    /**
+     * Adds the given node at the given index in this list, shifting all nodes currently
at
+     * and after the given index.
+     *
+     * @param  index The index where to insert the node.
+     * @param  node The node to store at the given index (can not be {@code null}).
+     * @throws IllegalArgumentException If this list can not add the given node, for example
+     *         if the node is already an element of another {@code TreeNodeList}.
+     */
+    @Override
+    public void add(final int index, final TreeTable.Node node) throws IllegalArgumentException
{
+        ArgumentChecks.ensureValidIndex(size + 1, index);
+        ArgumentChecks.ensureNonNull("node", node);
+        if (isParentOf(node)) {
+            ensureNotPresent(node);
+        } else {
+            setParentOf(node, THIS);
+        }
+        if (children == null) {
+            children = new TreeTable.Node[4];
+        } else if (size == children.length) {
+            children = Arrays.copyOf(children, size*2);
+        }
+        System.arraycopy(children, index, children, index+1, size - index);
+        children[index] = node;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Ensures the the given node is not already present in this list. This checks is performed
+     * only if a newly added node declares to have this list {@linkplain #parent}. Such case
may
+     * occur either because the node is a custom user implementation with pre-set parent,
or
+     * because the node is already presents in this list.
+     *
+     * @param  node The node to check.
+     * @throws IllegalArgumentException If the given node is already present in this list.
+     */
+    private void ensureNotPresent(final TreeTable.Node node) throws IllegalArgumentException
{
+        for (int i=size; --i>=0;) {
+            if (children[i] == node) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1));
+            }
+        }
+    }
+
+    /**
+     * Removes all children in the given range of this list. This method removes the nodes
in
+     * reverse order (last added nodes are removed first). If this method failed to remove
a
+     * node, then that node and all nodes at lower index will be left in the list.
+     *
+     * @throws IllegalArgumentException If this method failed to remove a node in the given
range.
+     */
+    @Override
+    protected void removeRange(final int lower, final int upper) throws IllegalArgumentException
{
+        int i = upper;
+        try {
+            while (i != lower) {
+                setParentOf(children[i-1], NULL);
+                i--; // Must be decremented only after 'setParentOf' returned successfully.
+            }
+        } finally {
+            modCount++;
+            System.arraycopy(children, upper, children, i, size - upper);
+            Arrays.fill(children, upper, size, null);
+            size -= (upper - i);
+        }
+    }
+
+    /**
+     * Removes from this list the node at the given index.
+     * All nodes after the given index will be shifted by one.
+     *
+     * @param  index The index of the node to remove.
+     * @return The node which was previously at the given index (never {@code null}).
+     */
+    @Override
+    public final TreeTable.Node remove(final int index) throws IllegalArgumentException {
+        ArgumentChecks.ensureValidIndex(size, index);
+        final TreeTable.Node old = children[index];
+        setParentOf(old, NULL);
+        System.arraycopy(children, index+1, children, index, --size - index);
+        children[size] = null;
+        modCount++;
+        return old;
+    }
+
+    /**
+     * Removes the first occurrence of the given node from this list, if presents.
+     * The default implementation searches the node using the {@link #indexOf(Object)},
+     * then removes it (if the node has been found) using the {@link #remove(int)} method.
+     *
+     * @param  node The node to remove. {@code null} values are ignored.
+     * @return {@code true} if the node has been removed, or {@code false} if this list doesn't
+     *         contain the given node.
+     * @throws IllegalArgumentException If the node has been found but this list can not
remove it.
+     */
+    @Override
+    public boolean remove(final Object node) throws IllegalArgumentException {
+        final int index = indexOf(node);
+        if (index >= 0) {
+            remove(index);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this list contains the given node. This implementation only
checks
+     * if the {@linkplain TreeTable.Node#getParent() node parent} is the {@link #parent}
instance.
+     * This implementation does not iterate over the children.
+     *
+     * @param  node The node to check (can be {@code null}).
+     * @return {@code true} if this list contains the given node.
+     */
+    @Override
+    public final boolean contains(final Object node) {
+        return (node instanceof TreeTable.Node) && ((TreeTable.Node) node).getParent()
== parent;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified node in this list.
+     * This method delegates to {@link #lastIndexOf(Object)} because the list is not
+     * expected to contain duplicated values.
+     *
+     * @param  node The node to search (can be {@code null}).
+     * @return Index of the given node, or -1 if not found.
+     */
+    @Override
+    public final int indexOf(final Object node) {
+        return lastIndexOf(node);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified node in this list.
+     *
+     * @param  node The node to search (can be {@code null}).
+     * @return Index of the given node, or -1 if not found.
+     */
+    @Override
+    public final int lastIndexOf(final Object node) {
+        if (contains(node)) {
+            for (int i=size; --i>=0;) {
+                if (children[i] == node) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns an array containing all the children in this list.
+     */
+    @Override
+    public Object[] toArray() {
+        return Arrays.copyOf(children, size);
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeNodeList.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1406953&r1=1406952&r2=1406953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
Thu Nov  8 08:39:04 2012
@@ -46,6 +46,11 @@ public final class Errors extends Indexe
         }
 
         /**
+         * Element “{0}” is already present.
+         */
+        public static final int ElementAlreadyPresent_1 = 36;
+
+        /**
          * Argument ‘{0}’ shall not be empty.
          */
         public static final int EmptyArgument_1 = 1;
@@ -127,6 +132,16 @@ public final class Errors extends Indexe
         public static final int NegativeArgument_2 = 8;
 
         /**
+         * Node “{0}” can not be a child of itself.
+         */
+        public static final int NodeChildOfItself_1 = 37;
+
+        /**
+         * Node “{0}” already has another parent.
+         */
+        public static final int NodeHasAnotherParent_1 = 35;
+
+        /**
          * Node “{0}” has no parent.
          */
         public static final int NodeHasNoParent_1 = 34;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1406953&r1=1406952&r2=1406953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
Thu Nov  8 08:39:04 2012
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+ElementAlreadyPresent_1         = Element \u201c{0}\u201d is already present.
 EmptyArgument_1                 = Argument \u2018{0}\u2019 shall not be empty.
 ForbiddenAttribute_2            = Attribute \u201c{0}\u201d is not allowed for an object
of type \u2018{1}\u2019.
 IllegalArgument_1               = Illegal value for argument \u2018{0}\u2019.
@@ -30,6 +31,8 @@ IndexOutOfBounds_1              = Index 
 KeyCollision_1                  = A different value is already associated to the \u201c{0}\u201d
key.
 MandatoryAttribute_2            = Attribute \u201c{0}\u201d is mandatory for an object of
type \u2018{1}\u2019.
 NegativeArgument_2              = Argument \u2018{0}\u2019 shall not be negative. The given
value was {1}.
+NodeChildOfItself_1             = Node \u201c{0}\u201d can not be a child of itself.
+NodeHasAnotherParent_1          = Node \u201c{0}\u201d already has another parent.
 NodeHasNoParent_1               = Node \u201c{0}\u201d has no parent.
 NotANumber_1                    = Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number).
 NotAPrimitiveWrapper_1          = Class \u2018{0}\u2019 is not a primitive type wrapper.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1406953&r1=1406952&r2=1406953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
Thu Nov  8 08:39:04 2012
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+ElementAlreadyPresent_1         = L\u2019\u00e9lement \u201c{0}\u201d est d\u00e9j\u00e0
pr\u00e9sent.
 EmptyArgument_1                 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide.
 ForbiddenAttribute_2            = L\u2019attribut \u201c{0}\u201d n\u2019est pas autoris\u00e9
pour un objet de type \u2018{1}\u2019.
 IllegalArgument_1               = Valeur ill\u00e9gale pour l\u2019argument \u2018{0}\u2019.
@@ -30,6 +31,8 @@ IndexOutOfBounds_1              = L\u201
 KeyCollision_1                  = Une valeur diff\u00e9rente est d\u00e9j\u00e0 associ\u00e9e
\u00e0 la cl\u00e9 \u201c{0}\u201d.
 MandatoryAttribute_2            = L\u2019attribut \u201c{0}\u201d est obligatoire pour un
objet de type \u2018{1}\u2019.
 NegativeArgument_2              = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre n\u00e9gatif.
La valeur donn\u00e9e \u00e9tait {1}.
+NodeChildOfItself_1             = Le n\u0153ud \u201c{0}\u201d ne peut pas \u00eatre un enfant
de lui-m\u00eame.
+NodeHasAnotherParent_1          = Le n\u0153ud \u201c{0}\u201d a d\u00e9j\u00e0 un autre
parent.
 NodeHasNoParent_1               = Le n\u0153ud \u201c{0}\u201d n\u2019a pas de parent.
 NotANumber_1                    = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN
(Not-a-Number).
 NotAPrimitiveWrapper_1          = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur
d\u2019un type primitif.



Mime
View raw message