sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1478840 - in /sis/branches/JDK7: sis-metadata/src/main/java/org/apache/sis/metadata/ sis-metadata/src/test/java/org/apache/sis/metadata/ sis-utility/src/main/java/org/apache/sis/util/ sis-utility/src/main/java/org/apache/sis/util/collectio...
Date Fri, 03 May 2013 15:30:16 GMT
Author: desruisseaux
Date: Fri May  3 15:30:15 2013
New Revision: 1478840

URL: http://svn.apache.org/r1478840
Log:
Implemented MetadataTreeNode.newChild().

Modified:
    sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeChildren.java
    sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
    sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeNodeTest.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ObjectConverters.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
    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

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeChildren.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeChildren.java?rev=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeChildren.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeChildren.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -85,7 +85,7 @@ final class MetadataTreeChildren extends
      *     accessor = parent.table.standard.getAccessor(metadata.getClass(), true);
      * }
      */
-    private final PropertyAccessor accessor;
+    final PropertyAccessor accessor;
 
     /**
      * The children to be returned by this collection. All elements in this collection are
@@ -482,24 +482,36 @@ final class MetadataTreeChildren extends
      * @throws IllegalArgumentException if this list does not have a property for the node
identifier.
      * @throws IllegalStateException if a value already exists and no more value can be added
for the node identifier.
      * @throws UnmodifiableMetadataException if the property for the node identifier is read-only.
-     * @throws ClassCastException if the node value is not of the expected type.
+     * @throws ClassCastException if the node value can not be converted to the expected
type.
      * @throws BackingStoreException if the metadata implementation threw a checked exception.
      */
     @Override
-    public boolean add(final TreeTable.Node node) {
+    public boolean add(final TreeTable.Node node) throws IllegalStateException {
         final String identifier = node.getValue(TableColumn.IDENTIFIER);
         if (identifier == null) {
             throw new IllegalArgumentException(Errors.format(
                     Errors.Keys.MissingValueInColumn_1, TableColumn.IDENTIFIER.getHeader()));
         }
-        final Object value = node.getValue(TableColumn.VALUE);
+        return add(accessor.indexOf(identifier, true), node.getValue(TableColumn.VALUE));
+    }
+
+    /**
+     * Implementation of {@link #add(TreeTable.Node)}, also invoked by {@link MetadataTreeNode.NewChild}.
+     * This method will attempt to convert the given {@code value} to the expected type.
+     *
+     * @param  index The index in the accessor (<em>not</em> the index in this
collection).
+     * @param  value The property value to add.
+     * @return {@code true} if the metadata changed as a result of this method call.
+     */
+    final boolean add(final int index, final Object value) throws IllegalStateException {
         if (ValueExistencePolicy.isNullOrEmpty(value)) {
             return false;
         }
-        final int index = accessor.indexOf(identifier, true);
+        // Conversion attempt happen in the PropertyAccessor.set(…) method.
         final Boolean changed = (Boolean) accessor.set(index, metadata, value, PropertyAccessor.APPEND);
         if (changed == null) {
-            throw new IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1,
identifier));
+            throw new IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1,
+                    accessor.name(index, KeyNamePolicy.UML_IDENTIFIER)));
         }
         if (changed) {
             modCount++;

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java?rev=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -28,8 +28,10 @@ import org.apache.sis.util.Classes;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.TreeTable.Node;
+import org.apache.sis.util.collection.CheckedContainer;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
 
@@ -45,12 +47,16 @@ import org.apache.sis.util.resources.Voc
  * If a metadata property is a collection, then there is an instance of the {@link CollectionElement}
  * subclass for each element in the collection.</p>
  *
+ * <p>The {@link #newChild()} operation is supported if the node is not a leaf. The
user shall
+ * set the identifier and the value, in that order, before any other operation on the new
child.
+ * See {@code newChild()} javadpc for an example.</p>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
  * @version 0.3
  * @module
  */
-class MetadataTreeNode implements TreeTable.Node, Serializable {
+class MetadataTreeNode implements Node, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -64,7 +70,7 @@ class MetadataTreeNode implements TreeTa
      * does not implement the {@link List} interface. So we are better to never give to the
user
      * a collection implementing {@code List} in order to signal incorrect casts sooner.</p>
      */
-    private static final Collection<TreeTable.Node> LEAF = Collections.emptySet();
+    private static final Collection<Node> LEAF = Collections.emptySet();
 
     /**
      * A sentinel value meaning that the node is known to allow {@linkplain #children}, but
@@ -74,7 +80,7 @@ class MetadataTreeNode implements TreeTa
      * <p>Any value distinct than {@link #LEAF} is okay. This value will never be visible
      * to the user.</p>
      */
-    private static final Collection<TreeTable.Node> PENDING = Collections.emptyList();
+    private static final Collection<Node> PENDING = Collections.emptyList();
 
     /**
      * The table for which this node is an element. Contains information like
@@ -126,7 +132,7 @@ class MetadataTreeNode implements TreeTa
      *
      * @see #getChildren()
      */
-    private transient Collection<TreeTable.Node> children;
+    private transient Collection<Node> children;
 
     /**
      * Creates the root node of a new metadata tree table.
@@ -310,7 +316,7 @@ class MetadataTreeNode implements TreeTa
         }
 
         /**
-         * Sets the metadata value for this node.
+         * Sets the property value for this node.
          */
         @Override
         void setUserObject(final Object value) {
@@ -419,6 +425,41 @@ class MetadataTreeNode implements TreeTa
                 throw new ConcurrentModificationException(e);
             }
         }
+
+        /**
+         * Sets the property value for this node.
+         */
+        @Override
+        void setUserObject(Object value) {
+            final Collection<?> values = (Collection<?>) super.getUserObject();
+            if (!(values instanceof List<?>)) {
+                // 'setValue' is the public method which invoked this one.
+                throw new UnsupportedOperationException(Errors.format(
+                        Errors.Keys.UnsupportedOperation_1, "setValue"));
+            }
+            final Class<?> targetType;
+            if (values instanceof CheckedContainer<?>) {
+                // Typically the same than getElementType(), but let be safe
+                // in case some implementations have stricter requirements.
+                targetType = ((CheckedContainer<?>) values).getElementType();
+            } else {
+                targetType = getElementType();
+            }
+            value = ObjectConverters.convert(value, targetType);
+            try {
+                /*
+                 * Unsafe addition into a collection. In SIS implementation, the collection
is
+                 * actually an instance of CheckedCollection, so the check will be performed
at
+                 * runtime. However other implementations could use unchecked collection.
We have
+                 * done our best for converting the type above, there is not much more we
can do...
+                 */
+                // No @SuppressWarnings because this is a real hole.
+                ((List) values).set(indexInList, value);
+            } catch (IndexOutOfBoundsException e) {
+                // Same rational than in the getUserObject() method.
+                throw new ConcurrentModificationException(e);
+            }
+        }
     }
 
 
@@ -429,7 +470,7 @@ class MetadataTreeNode implements TreeTa
      * Returns the parent node, or {@code null} if this node is the root of the tree.
      */
     @Override
-    public final TreeTable.Node getParent() {
+    public final Node getParent() {
         return parent;
     }
 
@@ -457,7 +498,7 @@ class MetadataTreeNode implements TreeTa
      * Only metadata object can have children.
      */
     @Override
-    public final Collection<TreeTable.Node> getChildren() {
+    public final Collection<Node> getChildren() {
         /*
          * 'children' is set to LEAF if an only if the node *can not* have children,
          * in which case we do not need to check for changes in the underlying metadata.
@@ -492,12 +533,127 @@ class MetadataTreeNode implements TreeTa
     }
 
     /**
-     * Unconditionally throws {@link UnsupportedOperationException}, because there is no
-     * way we can safely determine which metadata property a new child would be for.
+     * Returns a proxy for a new property to be defined in the metadata object.
+     * The user shall set the identifier and the value, in that order, before
+     * any other operation on the new child. Example:
+     *
+     * {@preformat java
+     *     TreeTable.Node node = ...;
+     *     TreeTable.Node child = node.newChild();
+     *     child.setValue(TableColumn.IDENTIFIER, "title");
+     *     child.setValue(TableColumn.VALUE, "Le petit prince");
+     *     // Nothing else to do - node has been added.
+     * }
+     *
+     * Do not keep a reference to the returned node for a long time, since it is only
+     * a proxy toward the real node to be created once the identifier is known.
+     *
+     * @throws UnsupportedOperationException If this node {@linkplain #isLeaf() is a leaf}.
      */
     @Override
-    public final TreeTable.Node newChild() {
-        throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnsupportedOperation_1,
"newChild"));
+    public final Node newChild() throws UnsupportedOperationException {
+        if (isLeaf()) {
+            throw new UnsupportedOperationException(Errors.format(Errors.Keys.NodeIsLeaf_1,
this));
+        }
+        return new NewChild();
+    }
+
+    /**
+     * The proxy to be returned by {@link MetadataTreeNode#newChild()}.
+     * User shall not keep a reference to this proxy for a long time.
+     */
+    private final class NewChild implements Node {
+        /**
+         * Index in the {@link PropertyAccessor} for the property to be set.
+         * This index is known only after a value has been specified for the
+         * {@link TableColumn#IDENTIFIER}.
+         */
+        private int indexInData = -1;
+
+        /**
+         * The real node created after the identifier and the value have been specified.
+         * All operations will be delegated to that node after it has been determined.
+         */
+        private MetadataTreeNode delegate;
+
+        /**
+         * Returns the {@link #delegate} node if non-null, or throw an exception otherwise.
+         *
+         * @throws IllegalStateException if the identifier and value columns have not yet
been defined.
+         */
+        private MetadataTreeNode delegate() throws IllegalStateException {
+            if (delegate != null) {
+                return delegate;
+            }
+            throw new IllegalStateException(Errors.format(Errors.Keys.MissingValueInColumn_1,
+                    (indexInData < 0 ? TableColumn.IDENTIFIER : TableColumn.VALUE).getHeader()));
+        }
+
+        /**
+         * Returns all children of the parent node. The new child will be added to that list.
+         */
+        private MetadataTreeChildren getSiblings() {
+            return (MetadataTreeChildren) MetadataTreeNode.this.getChildren();
+        }
+
+        /**
+         * If the {@link #delegate} is not yet known, set the identifier or the value.
+         * After the identifier and value have been specified, delegates to the real node.
+         */
+        @Override
+        public <V> void setValue(final TableColumn<V> column, final V value)
{
+            if (delegate == null) {
+                /*
+                 * For the given identifier, get the index in the property accessor.
+                 * This can be done only before the 'delegate' is found - after that
+                 * point, the identifier will become unmodifiable.
+                 */
+                if (column == TableColumn.IDENTIFIER) {
+                    ArgumentChecks.ensureNonNull("value", value);
+                    indexInData = getSiblings().accessor.indexOf((String) value, true);
+                    return;
+                }
+                /*
+                 * Set the value for the property specified by the above identifier,
+                 * then get the 'delegate' on the assumption that the new value will
+                 * be added at the end of collection (if the property is a collection).
+                 */
+                if (column == TableColumn.VALUE) {
+                    ArgumentChecks.ensureNonNull("value", value);
+                    if (indexInData < 0) {
+                        throw new IllegalStateException(Errors.format(Errors.Keys.MissingValueInColumn_1,
+                                TableColumn.IDENTIFIER.getHeader()));
+                    }
+                    final MetadataTreeChildren siblings = getSiblings();
+                    final int indexInList;
+                    if (siblings.isCollection(indexInData)) {
+                        indexInList = ((Collection<?>) siblings.valueAt(indexInData)).size();
+                    } else {
+                        indexInList = -1;
+                    }
+                    if (!siblings.add(indexInData, value)) {
+                        throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1,
value));
+                    }
+                    delegate = siblings.childAt(indexInData, indexInList);
+                    return;
+                }
+            }
+            delegate().setValue(column, value);
+        }
+
+        /**
+         * For all operations other than {@code setValue(…)}, delegates to the {@link #delegate}
node
+         * or to some code functionally equivalent.
+         *
+         * @throws IllegalStateException if the identifier and value columns have not yet
been defined.
+         */
+        @Override public Node             getParent()                       {return MetadataTreeNode.this;}
+        @Override public boolean          isLeaf()                          {return delegate().isLeaf();}
+        @Override public Collection<Node> getChildren()                     {return
delegate().getChildren();}
+        @Override public Node             newChild()                        {return delegate().newChild();}
+        @Override public <V> V            getValue(TableColumn<V> column)   {return
delegate().getValue(column);}
+        @Override public boolean          isEditable(TableColumn<?> column) {return
delegate().isEditable(column);}
+        @Override public Object           getUserObject()                   {return delegate().getUserObject();}
     }
 
     /**
@@ -529,11 +685,17 @@ class MetadataTreeNode implements TreeTa
     /**
      * Sets the value if the given column is {@link TableColumn#VALUE}. This method verifies
      * the {@code column} argument, then delegates to {@link #setUserObject(Object)}.
+     *
+     * <p>This method does not accept null value, because setting a singleton property
to null
+     * with {@link ValueExistencePolicy#NON_EMPTY} is equivalent to removing the property,
and
+     * setting a collection element to null is not allowed. Those various behavior are at
risk
+     * of causing confusion, so we are better to never allow null.</p>
      */
     @Override
     public final <V> void setValue(final TableColumn<V> column, final V value)
throws UnsupportedOperationException {
         ArgumentChecks.ensureNonNull("column", column);
         if (column == TableColumn.VALUE) {
+            ArgumentChecks.ensureNonNull("value", value);
             setUserObject(value);
         } else if (MetadataTreeTable.COLUMNS.contains(column)) {
             throw new UnsupportedOperationException(unmodifiableCellValue(column));

Modified: sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeNodeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeNodeTest.java?rev=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeNodeTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeNodeTest.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -130,7 +130,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testRootNode") // Because tested more basic methods than 'getValue(TableColumn)'.
     public void testGetNameForSingleton() {
         final DefaultCitation citation = MetadataTreeChildrenTest.metadataWithSingletonInCollections();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
             "DefaultCitation",
               "Title",
               "Alternate title",
@@ -147,7 +147,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testGetNameForSingleton")
     public void testGetNameForMultiOccurrences() {
         final DefaultCitation citation = MetadataTreeChildrenTest.metadataWithMultiOccurrences();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
             "DefaultCitation",
               "Title",
               "Alternate title (1 of 2)",
@@ -165,7 +165,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testGetNameForMultiOccurrences")
     public void testGetNameForHierarchy() {
         final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
             "DefaultCitation",
               "Title",
               "Alternate title (1 of 2)",
@@ -195,7 +195,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testGetNameForMultiOccurrences") // Because similar to names, which
were tested progressively.
     public void testGetIdentifier() {
         final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.IDENTIFIER,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.IDENTIFIER,
             "CI_Citation",
               "title",
               "alternateTitle",
@@ -222,7 +222,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testGetIdentifier") // Because if identifiers are wrong, we are looking
at wrong properties.
     public void testGetElementType() {
         final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.TYPE,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.TYPE,
             Citation.class,
               InternationalString.class,
               InternationalString.class,
@@ -249,7 +249,7 @@ public final strictfp class MetadataTree
     @DependsOnMethod("testGetIdentifier") // Because if identifiers are wrong, we are looking
at wrong properties.
     public void testGetValue() {
         final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.VALUE,
+        assertColumnContentEquals(create(citation, ValueExistencePolicy.NON_EMPTY), TableColumn.VALUE,
             null, // Citation
               "Some title",
               "First alternate title",
@@ -270,6 +270,45 @@ public final strictfp class MetadataTree
     }
 
     /**
+     * Tests {@link MetadataTreeNode#newChild()}.
+     */
+    @Test
+    @DependsOnMethod("testGetValue")
+    public void testNewChild() {
+        final DefaultCitation citation = metadataWithHierarchy();
+        final MetadataTreeNode node = create(citation, ValueExistencePolicy.NON_EMPTY);
+        /*
+         * Ensure that we can not overwrite existing nodes.
+         */
+        TreeTable.Node child = node.newChild();
+        child.setValue(TableColumn.IDENTIFIER, "title");
+        try {
+            child.setValue(TableColumn.VALUE, "A new title");
+            fail("Attemps to overwrite an existing value shall fail.");
+        } catch (IllegalStateException e) {
+            assertTrue(e.getMessage().contains("title"));
+        }
+        /*
+         * Clear the title and try again. This time, it shall work.
+         */
+        citation.setTitle(null);
+        child = node.newChild();
+        child.setValue(TableColumn.IDENTIFIER, "title");
+        child.setValue(TableColumn.VALUE, "A new title");
+        assertEquals("A new title", citation.getTitle().toString());
+        assertSame(citation.getTitle(), child.getValue(TableColumn.VALUE));
+        /*
+         * Try adding a new element in a collection.
+         * Note that the code below imply a conversion from String to InternationalString.
+         */
+        child = node.newChild();
+        child.setValue(TableColumn.IDENTIFIER, "alternateTitle");
+        child.setValue(TableColumn.VALUE, "Third alternate title");
+        assertEquals(3, citation.getAlternateTitles().size());
+        assertEquals("Third alternate title", child.getValue(TableColumn.VALUE).toString());
+    }
+
+    /**
      * Compares the result of the given getter method invoked on the given node, then invoked
      * on all children of that given. In the particular case of the {@link #NAME} method,
      * international strings are replaced by unlocalized strings before comparisons.
@@ -280,17 +319,17 @@ public final strictfp class MetadataTree
      *                 applied on the given node, and all other values are the result of
the
      *                 getter method applied on the children, in iteration order.
      */
-    private static void assertColumnEquals(final MetadataTreeNode node,
+    private static void assertColumnContentEquals(final MetadataTreeNode node,
             final TableColumn<?> column, final Object... values)
     {
         assertEquals("Missing values in the tested metadata.", values.length,
-                assertColumnEquals(node, column, values, 0));
+                assertColumnContentEquals(node, column, values, 0));
     }
 
     /**
      * Implementation of the above {@code assertGetterReturns}, to be invoked recursively.
      */
-    private static int assertColumnEquals(final TreeTable.Node node, final TableColumn<?>
column,
+    private static int assertColumnContentEquals(final TreeTable.Node node, final TableColumn<?>
column,
             final Object[] values, int index)
     {
         Object actual = node.getValue(column);
@@ -299,7 +338,7 @@ public final strictfp class MetadataTree
         }
         assertEquals("values[" + index + ']', values[index++], actual);
         for (final TreeTable.Node child : node.getChildren()) {
-            index = assertColumnEquals(child, column, values, index);
+            index = assertColumnContentEquals(child, column, values, index);
         }
         return index;
     }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ObjectConverters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ObjectConverters.java?rev=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ObjectConverters.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ObjectConverters.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -94,10 +94,33 @@ public final class ObjectConverters exte
     public static <S,T> ObjectConverter<? super S, ? extends T> find(final Class<S>
source, final Class<T> target)
             throws UnconvertibleObjectException
     {
+        ArgumentChecks.ensureNonNull("source", source);
+        ArgumentChecks.ensureNonNull("target", target);
         return SystemRegistry.INSTANCE.find(source, target);
     }
 
     /**
+     * Converts the given value to the given type. This convenience method shall be used
only for
+     * rare conversions. For converting many instances between the same source and target
classes,
+     * consider invoking {@link #find(Class, Class)} instead in order to reuse the same converter
+     * for all values to convert.
+     *
+     * @param  <T>    The type of the {@code target} class.
+     * @param  value  The value to convert, or {@code null}.
+     * @param  target The target class.
+     * @return The converted value (may be {@code null}).
+     * @throws UnconvertibleObjectException if the given value can not be converted.
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static <T> T convert(Object value, final Class<T> target) throws UnconvertibleObjectException
{
+        ArgumentChecks.ensureNonNull("target", target);
+        if (!target.isInstance(value) && value != null) {
+            value = ((ObjectConverter) SystemRegistry.INSTANCE.find(value.getClass(), target)).convert(value);
+        }
+        return (T) value;
+    }
+
+    /**
      * Returns a set whose elements are derived <cite>on-the-fly</cite> from
the given set.
      * Conversions from the original elements to the derived elements are performed when
needed
      * by invoking the {@link ObjectConverter#convert(Object)} method on the given converter.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java?rev=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -543,8 +543,9 @@ public class DefaultTreeTable implements
 
         /**
          * Adds a new child in the {@linkplain #getChildren() children list}.
-         * The default implementation delegates to {@code Node(Node)} constructor,
-         * which has the following implications:
+         * The default implementation first checks that this node is not a leaf,
+         * then delegates to the {@code Node(Node)} constructor.
+         * That constructor call has the following implications:
          *
          * <ul>
          *   <li>The new node inherits the columns of this node, on the assumption
that
@@ -553,9 +554,14 @@ public class DefaultTreeTable implements
          * </ul>
          *
          * Subclasses may override this method with different behavior.
+         *
+         * @throws UnsupportedOperationException If this node {@linkplain #isLeaf() is a
leaf}.
          */
         @Override
         public Node newChild() {
+            if (isLeaf()) {
+                throw new UnsupportedOperationException(Errors.format(Errors.Keys.NodeIsLeaf_1,
this));
+            }
             return new Node(this);
         }
 

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=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] Fri May  3 15:30:15 2013
@@ -331,6 +331,11 @@ public final class Errors extends Indexe
         public static final int NodeHasNoParent_1 = 34;
 
         /**
+         * Node “{0}” is a leaf.
+         */
+        public static final int NodeIsLeaf_1 = 90;
+
+        /**
          * No “{0}” node found.
          */
         public static final int NodeNotFound_1 = 39;

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=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] Fri May  3 15:30:15 2013
@@ -75,6 +75,7 @@ NegativeArgument_2              = Argume
 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.
+NodeIsLeaf_1                    = Node \u201c{0}\u201d is a leaf.
 NodeNotFound_1                  = No \u201c{0}\u201d node found.
 NonEquilibratedParenthesis_2    = Missing a \u2018{1}\u2019 parenthesis in \u201c{0}\u201d.
 NonInvertibleConversion         = Conversion is not invertible.

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=1478840&r1=1478839&r2=1478840&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] Fri May  3 15:30:15 2013
@@ -65,6 +65,7 @@ NegativeArgument_2              = L\u201
 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.
+NodeIsLeaf_1                    = Le n\u0153ud \u201c{0}\u201d est une feuille.
 NodeNotFound_1                  = Aucun n\u0153ud \u201c{0}\u201d n\u2019a \u00e9t\u00e9
trouv\u00e9.
 NonEquilibratedParenthesis_2    = Il manque une parenth\u00e8se \u2018{1}\u2019 dans \u201c{0}\u201d.
 NonInvertibleConversion         = La conversion n\u2019est pas inversible.



Mime
View raw message