sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1478546 - in /sis/branches/JDK7/sis-metadata/src: main/java/org/apache/sis/metadata/ test/java/org/apache/sis/metadata/
Date Thu, 02 May 2013 21:06:19 GMT
Author: desruisseaux
Date: Thu May  2 21:06:17 2013
New Revision: 1478546

URL: http://svn.apache.org/r1478546
Log:
Implemented MetadataTreeChildren.add(TreeTable.Node).

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/main/java/org/apache/sis/metadata/PropertyAccessor.java
    sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java
    sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
    sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeChildrenTest.java
    sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java

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=1478546&r1=1478545&r2=1478546&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] Thu May  2 21:06:17 2013
@@ -21,7 +21,9 @@ import java.util.Collections;
 import java.util.AbstractCollection;
 import java.util.NoSuchElementException;
 import java.util.ConcurrentModificationException;
+import org.apache.sis.util.collection.TableColumn;
 import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.Debug;
 
 
@@ -133,7 +135,7 @@ final class MetadataTreeChildren extends
      * @param index The index in the accessor (<em>not</em> the index in this
collection).
      */
     final void clearAt(final int index) {
-        accessor.set(index, metadata, null, false);
+        accessor.set(index, metadata, null, PropertyAccessor.RETURN_NULL);
     }
 
     /**
@@ -464,6 +466,44 @@ final class MetadataTreeChildren extends
     }
 
     /**
+     * Adds the given node to this list. This method fetches the object from {@link TableColumn#VALUE}
+     * and assigns it to the property identified by {@link TableColumn#IDENTIFIER}. All other
columns
+     * are ignored.
+     *
+     * <p>If the identified property is a collection, then this method adds the value
to that collection.
+     * Otherwise the new value will overwrite the value that existed prior this method call.</p>
+     *
+     * <p>This method does not iterate explicitly through the children list, because
adding a metadata
+     * object implicitly adds all its children.</p>
+     *
+     * @param  node The node from which to get the values.
+     * @return {@code true} if the metadata changed as a result of this method call.
+     * @throws NullPointerException if the given node is null.
+     * @throws IllegalArgumentException if this list does not have a property 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 BackingStoreException if the metadata implementation threw a checked exception.
+     */
+    @Override
+    public boolean add(final TreeTable.Node node) {
+        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);
+        if (ValueExistencePolicy.isNullOrEmpty(value)) {
+            return false;
+        }
+        final int index = accessor.indexOf(identifier, true);
+        if ((Boolean) accessor.set(index, metadata, value, PropertyAccessor.RETURN_CHANGED))
{
+            modCount++;
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Returns a string representation of this collection for debugging purpose.
      * This string representation uses one line per element instead of formatting
      * everything on a single line.

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=1478546&r1=1478545&r2=1478546&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] Thu May  2 21:06:17 2013
@@ -314,7 +314,7 @@ class MetadataTreeNode implements TreeTa
          */
         @Override
         void setUserObject(final Object value) {
-            accessor.set(indexInData, metadata, value, false);
+            accessor.set(indexInData, metadata, value, PropertyAccessor.RETURN_NULL);
         }
 
         /**

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java?rev=1478546&r1=1478545&r2=1478546&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
[UTF-8] Thu May  2 21:06:17 2013
@@ -104,6 +104,12 @@ final class PropertyAccessor {
     static final int COUNT_FIRST=0, COUNT_SHALLOW=1, COUNT_DEEP=2;
 
     /**
+     * Enumeration constants for the {@code mode} argument
+     * in the {@link #set(int, Object, Object, int)} method.
+     */
+    static final int RETURN_NULL=0, RETURN_CHANGED=1, RETURN_PREVIOUS=2;
+
+    /**
      * Additional getter to declare in every list of getter methods that do not already provide
      * their own {@code getIdentifiers()} method. We handle this method specially because
it is
      * needed for XML marshalling in ISO 19139 compliant document, while not part of abstract
@@ -663,10 +669,23 @@ final class PropertyAccessor {
     }
 
     /**
-     * Sets a value for the specified metadata and returns the old value if {@code getOld}
is
-     * {@code true}. If the old value was a collection or a map, then this value is copied
in
-     * a new collection or map before the new value is set, because the setter methods typically
-     * copy the new collection in their existing instance.
+     * Sets a value for the specified metadata and returns the old value if {@code mode}
is
+     * {@link #RETURN_PREVIOUS}. The {@code mode} argument can be one of the following, from
+     * cheapest to more expensive mode:
+     *
+     * <ul>
+     *   <li>RETURN_NULL:     Set the value and returns {@code null}.</li>
+     *   <li>RETURN_CHANGED:  Set the value and returns {@link Boolean#TRUE} if the
metadata changed
+     *                        as a result of this method call, or {@code Boolean#FALSE} otherwise.</li>
+     *   <li>RETURN_PREVIOUS: Set the value and returns the previous value. If the
previous value was a
+     *                        collection or a map, then that value is copied in a new collection
or map
+     *                        before the new value is set because the setter methods typically
copy the
+     *                        new collection in their existing instance.</li>
+     * </ul>
+     *
+     * <p>The {@code RETURN_CHANGED} mode has an additional side effect: it sets the
{@code append} argument
+     * to {@code true} in the call to the {@link #convert(Method, Object, Object, Object[],
Class, boolean)}
+     * method. See the {@code convert} javadoc for more information.</p>
      *
      * <p>If the given index is out of bounds, then this method does nothing and return
{@code null}.
      * We do that because the {@link ValueMap#remove(Object)} method may invoke this method
with
@@ -674,16 +693,17 @@ final class PropertyAccessor {
      * However the given value will be silently discarded, so index out-of-bounds shall be
used only
      * in the context of {@code remove} operations (this is not verified).</p>
      *
-     * @param  index    The index of the property to set.
-     * @param  metadata The metadata object on which to set the value.
-     * @param  value    The new value.
-     * @param  getOld   {@code true} if this method should first fetches the old value.
-     * @return The old value, or {@code null} if {@code getOld} was {@code false}.
+     * @param  index       The index of the property to set.
+     * @param  metadata    The metadata object on which to set the value.
+     * @param  value       The new value.
+     * @param  mode Whether this method should first fetches the old value,
+     *                     as one of the {@code RETURN_*} constants.
+     * @return The old value, or {@code null} if {@code returnValue} was {@code RETURN_NULL}.
      * @throws UnmodifiableMetadataException if the property for the given key is read-only.
      * @throws ClassCastException if the given value is not of the expected type.
      * @throws BackingStoreException if the implementation threw a checked exception.
      */
-    final Object set(final int index, final Object metadata, final Object value, final boolean
getOld)
+    final Object set(final int index, final Object metadata, final Object value, final int
mode)
             throws UnmodifiableMetadataException, ClassCastException, BackingStoreException
     {
         if (index < 0 || index >= standardCount) {
@@ -693,27 +713,32 @@ final class PropertyAccessor {
             final Method getter = getters[index];
             final Method setter = setters[index];
             if (setter != null) {
-                final Object old;
-                final Object copy;
-                if (getOld) {
-                    old = get(getter, metadata);
-                    if (old instanceof Collection<?>) {
-                        if (old instanceof List<?>) {
-                            copy = snapshot((List<?>) old);
-                        } else {
-                            copy = modifiableCopy((Collection<?>) old);
+                Object old  = null;
+                Object copy = null;
+                if (mode != RETURN_NULL) {
+                    old  = get(getter, metadata);
+                    copy = old;
+                    if (mode == RETURN_PREVIOUS) {
+                        if (old instanceof Collection<?>) {
+                            if (old instanceof List<?>) {
+                                copy = snapshot((List<?>) old);
+                            } else {
+                                copy = modifiableCopy((Collection<?>) old);
+                            }
+                        } else if (old instanceof Map<?,?>) {
+                            copy = modifiableCopy((Map<?,?>) old);
                         }
-                    } else if (old instanceof Map<?,?>) {
-                        copy = modifiableCopy((Map<?,?>) old);
-                    } else {
-                        copy = old;
                     }
-                } else {
-                    copy = old = null;
                 }
                 final Object[] newValues = new Object[] {value};
-                convert(getter, metadata, old, newValues, elementTypes[index], false);
+                Boolean changed = convert(getter, metadata, old, newValues, elementTypes[index],
mode == RETURN_CHANGED);
                 set(setter, metadata, newValues);
+                if (mode == RETURN_CHANGED) {
+                    if (changed == null) {
+                        changed = (newValues[0] != old);
+                    }
+                    return changed;
+                }
                 return copy;
             }
         }
@@ -792,10 +817,12 @@ final class PropertyAccessor {
      * @param elementType The target type (if singleton) or the type of elements in the collection.
      * @param append      If {@code true} and the value is a collection, then that collection
will be added
      *                    to any previously existing collection instead of replacing it.
+     * @return If the given value has been added to an existing collection, then whether
that existing
+     *         collection has been modified as a result of this method call. Otherwise {@code
null}.
      * @throws ClassCastException if the element of the {@code arguments} array is not of
the expected type.
      * @throws BackingStoreException If the implementation threw a checked exception.
      */
-    private void convert(final Method getter, final Object metadata, Object oldValue, final
Object[] newValues,
+    private Boolean convert(final Method getter, final Object metadata, Object oldValue,
final Object[] newValues,
             Class<?> elementType, final boolean append) throws ClassCastException,
BackingStoreException
     {
         assert newValues.length == 1;
@@ -806,8 +833,9 @@ final class PropertyAccessor {
             if (targetType.isPrimitive()) {
                 newValues[0] = Numbers.valueOfNil(targetType);
             }
-            return;
+            return null;
         }
+        Boolean changed = null;
         if (!Collection.class.isAssignableFrom(targetType)) {
             /*
              * We do not expect a collection. The provided argument should not be a
@@ -821,7 +849,7 @@ final class PropertyAccessor {
                 final Iterator<?> it = ((Collection<?>) newValue).iterator();
                 if (!it.hasNext()) { // If empty, process like null argument.
                     newValues[0] = null;
-                    return;
+                    return null;
                 }
                 final Object next = it.next();
                 if (!it.hasNext()) { // Singleton
@@ -886,7 +914,7 @@ final class PropertyAccessor {
                  * There is not much we can do...
                  */
                 // No @SuppressWarnings because this is a real hole.
-                ((Collection) addTo).addAll(elementList);
+                changed = ((Collection) addTo).addAll(elementList);
             }
         }
         /*
@@ -895,6 +923,7 @@ final class PropertyAccessor {
          */
         newValues[0] = newValue;
         convert(newValues, targetType);
+        return changed;
     }
 
     /**

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java?rev=1478546&r1=1478545&r2=1478546&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java [UTF-8]
(original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java [UTF-8]
Thu May  2 21:06:17 2013
@@ -22,6 +22,9 @@ import java.util.Iterator;
 import java.util.NoSuchElementException;
 import org.apache.sis.util.CharSequences;
 
+import static org.apache.sis.metadata.PropertyAccessor.RETURN_NULL;
+import static org.apache.sis.metadata.PropertyAccessor.RETURN_PREVIOUS;
+
 // Related to JDK7
 import java.util.Objects;
 
@@ -112,7 +115,7 @@ final class ValueMap extends PropertyMap
      */
     @Override
     public Object put(final String key, final Object value) {
-        final Object old = accessor.set(accessor.indexOf(key, true), metadata, value, true);
+        final Object old = accessor.set(accessor.indexOf(key, true), metadata, value, RETURN_PREVIOUS);
         return valuePolicy.isSkipped(old) ? null : old;
     }
 
@@ -127,7 +130,7 @@ final class ValueMap extends PropertyMap
     @Override
     public void putAll(final Map<? extends String, ?> map) {
         for (final Map.Entry<? extends String, ?> e : map.entrySet()) {
-            accessor.set(accessor.indexOf(e.getKey(), true), metadata, e.getValue(), false);
+            accessor.set(accessor.indexOf(e.getKey(), true), metadata, e.getValue(), RETURN_NULL);
         }
     }
 
@@ -139,7 +142,7 @@ final class ValueMap extends PropertyMap
     @Override
     public Object remove(final Object key) throws UnsupportedOperationException {
         if (key instanceof String) {
-            final Object old = accessor.set(accessor.indexOf((String) key, false), metadata,
null, true);
+            final Object old = accessor.set(accessor.indexOf((String) key, false), metadata,
null, RETURN_PREVIOUS);
             if (!valuePolicy.isSkipped(old)) {
                 return old;
             }
@@ -223,7 +226,7 @@ final class ValueMap extends PropertyMap
          */
         @Override
         public Object setValue(final Object value) {
-            return accessor.set(index, metadata, value, true);
+            return accessor.set(index, metadata, value, RETURN_PREVIOUS);
         }
 
         /**

Modified: sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java?rev=1478546&r1=1478545&r2=1478546&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
[UTF-8] Thu May  2 21:06:17 2013
@@ -251,7 +251,7 @@ public abstract strictfp class MetadataT
             assertEquals("isWritable", isWritable, accessor.isWritable(i));
             if (isWritable) {
                 final Object newValue = valueFor(property, elementType);
-                final Object oldValue = accessor.set(i, instance, newValue, true);
+                final Object oldValue = accessor.set(i, instance, newValue, PropertyAccessor.RETURN_PREVIOUS);
                 assertEquals("PropertyAccessor.set(…) shall return the value previously
returned by get(…).", value, oldValue);
                 value = accessor.get(i, instance);
                 if (isCollection) {

Modified: sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeChildrenTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeChildrenTest.java?rev=1478546&r1=1478545&r2=1478546&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeChildrenTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTreeChildrenTest.java
[UTF-8] Thu May  2 21:06:17 2013
@@ -23,6 +23,8 @@ import java.util.ArrayList;
 import org.opengis.metadata.citation.PresentationForm;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.util.collection.DefaultTreeTable;
+import org.apache.sis.util.collection.TableColumn;
 import org.apache.sis.util.collection.TreeTable;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -182,6 +184,48 @@ public final strictfp class MetadataTree
     }
 
     /**
+     * Tests the {@link MetadataTreeChildren#add(TreeTable.Node)} method.
+     */
+    @Test
+    @DependsOnMethod("testReadOnlyWithMultiOccurrences")
+    public void testAdd() {
+        final DefaultCitation      citation = metadataWithMultiOccurrences();
+        final MetadataTreeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
+        final DefaultTreeTable.Node   toAdd = new DefaultTreeTable.Node(new DefaultTreeTable(
+                TableColumn.IDENTIFIER,
+                TableColumn.VALUE));
+        final String[] expected = {
+            "Some title",
+            "First alternate title",
+            "Second alternate title",
+            "Third alternate title",  // After addition
+            "New edition", // After "addition" (actually change).
+            "PresentationForm[MAP_DIGITAL]",
+            "PresentationForm[MAP_HARDCOPY]",
+            "PresentationForm[IMAGE_DIGITAL]", // After addition
+            "Some other details"
+        };
+        toAdd.setValue(TableColumn.IDENTIFIER, "edition");
+        toAdd.setValue(TableColumn.VALUE, citation.getEdition());
+        assertFalse("Adding the same value shall be a no-op.", children.add(toAdd));
+        toAdd.setValue(TableColumn.VALUE, "New edition");
+        assertTrue("Setting a different value shall be a change.", children.add(toAdd));
+
+        toAdd.setValue(TableColumn.IDENTIFIER, "presentationForm");
+        toAdd.setValue(TableColumn.VALUE, PresentationForm.MAP_DIGITAL);
+        assertFalse("Adding the same value shall be a no-op.", children.add(toAdd));
+        toAdd.setValue(TableColumn.VALUE, PresentationForm.IMAGE_DIGITAL);
+        assertTrue("Adding a new value shall be a change.", children.add(toAdd));
+
+        toAdd.setValue(TableColumn.IDENTIFIER, "alternateTitle");
+        toAdd.setValue(TableColumn.VALUE, "Third alternate title");
+        assertTrue("Adding a new value shall be a change.", children.add(toAdd));
+
+        assertEquals("size()", expected.length, children.size());
+        assertAllNextEqual(expected, children.iterator());
+    }
+
+    /**
      * Tests the {@link Iterator#remove()} operation on a list of properties without collections.
      */
     @Test

Modified: sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java?rev=1478546&r1=1478545&r2=1478546&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
[UTF-8] Thu May  2 21:06:17 2013
@@ -19,6 +19,7 @@ package org.apache.sis.metadata;
 import java.util.Set;
 import java.util.List;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Date;
@@ -52,6 +53,8 @@ import org.junit.Test;
 import static java.util.Collections.singleton;
 import static org.opengis.test.Assert.*;
 import static org.apache.sis.test.TestUtilities.getSingleton;
+import static org.apache.sis.metadata.PropertyAccessor.RETURN_CHANGED;
+import static org.apache.sis.metadata.PropertyAccessor.RETURN_PREVIOUS;
 
 
 /**
@@ -194,6 +197,7 @@ public final strictfp class PropertyAcce
 
     /**
      * Tests the {@link PropertyAccessor#descriptor(int)} method.
+     * This method delegates to some {@link PropertyInformationTest} methods.
      */
     @Test
     @DependsOnMethod("testConstructor")
@@ -204,7 +208,17 @@ public final strictfp class PropertyAcce
     }
 
     /**
-     * Tests the {@link PropertyAccessor#get(int, Object)} method.
+     * Tests the {@link PropertyAccessor#get(int, Object)} method on the {@link HardCodedCitations#ISO}
+     * constant. The metadata object read by this test is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title…………………………………… International Organization
for Standardization
+     *     ├─Alternate title………… ISO
+     *     ├─Identifier
+     *     │   └─Code…………………………… ISO
+     *     └─Presentation form…… Document digital
+     * }
      */
     @Test
     @DependsOnMethod("testConstructor")
@@ -229,8 +243,19 @@ public final strictfp class PropertyAcce
     }
 
     /**
-     * Tests the {@link PropertyAccessor#set(int, Object, Object, boolean)} method
-     * with a value to be stored <cite>as-is</cite>.
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method
+     * with a value to be stored <cite>as-is</cite> (without conversion).
+     * The metadata object created by this test is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title………………………… Some title
+     *     ├─Identifier
+     *     │   ├─Code………………… Some ISBN code
+     *     │   └─Authority
+     *     │       └─Title…… ISBN
+     *     └─ISBN…………………………… Some ISBN code
+     * }
      */
     @Test
     @DependsOnMethod("testGet")
@@ -242,21 +267,26 @@ public final strictfp class PropertyAcce
 
         newValue = new SimpleInternationalString("Some title");
         index = accessor.indexOf("title", true);
-        assertNull("title", accessor.set(index, instance, newValue, true));
+        assertNull("title", accessor.set(index, instance, newValue, RETURN_PREVIOUS));
         assertSame("title", newValue, accessor.get(index, instance));
         assertSame("title", newValue, instance.getTitle());
 
         newValue = "Some ISBN code";
         index = accessor.indexOf("ISBN", true);
-        assertNull("ISBN", accessor.set(index, instance, newValue, true));
+        assertNull("ISBN", accessor.set(index, instance, newValue, RETURN_PREVIOUS));
         assertSame("ISBN", newValue, accessor.get(index, instance));
         assertSame("ISBN", newValue, instance.getISBN());
     }
 
     /**
-     * Tests the {@link PropertyAccessor#set(int, Object, Object, boolean)} method
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method
      * with a value that will need to be converted. The conversion will be from
-     * {@link String} to {@link InternationalString}.
+     * {@link String} to {@link InternationalString}. The created metadata object is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     └─Title……………… Some title
+     * }
      */
     @Test
     @DependsOnMethod("testSet")
@@ -265,55 +295,110 @@ public final strictfp class PropertyAcce
         final DefaultCitation  instance = new DefaultCitation();
         final PropertyAccessor accessor = createPropertyAccessor();
         final int              index    = accessor.indexOf("title", true);
-        final Object           oldValue = accessor.set(index, instance, expected, true);
+        final Object           oldValue = accessor.set(index, instance, expected, RETURN_PREVIOUS);
         final Object           value    = accessor.get(index, instance);
 
-        assertNull("title", oldValue);
+        assertNull      ("title", oldValue);
         assertInstanceOf("title", InternationalString.class, value);
-        assertSame("title", expected, value.toString());
-        assertSame("title", value, instance.getTitle());
+        assertSame      ("title", expected, value.toString());
+        assertSame      ("title", value, instance.getTitle());
+    }
+
+    /**
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method when the value
+     * is a collection. The new collection shall replace the previous one (no merge expected).
+     * The metadata object created by this test after the replacement is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title……………………………………………………… Ignored
title
+     *     ├─Alternate title (1 of 2)…… New title 1
+     *     └─Alternate title (2 of 2)…… New title 2
+     * }
+     *
+     * @see #testSetInAppendMode()
+     */
+    @Test
+    @DependsOnMethod("testSet")
+    public void testSetCollection() {
+        final DefaultCitation instance = new DefaultCitation("Ignored title");
+        final List<InternationalString> oldTitles = Arrays.<InternationalString>asList(
+                new SimpleInternationalString("Old title 1"),
+                new SimpleInternationalString("Old title 2"));
+        final List<InternationalString> newTitles = Arrays.<InternationalString>asList(
+                new SimpleInternationalString("New title 1"),
+                new SimpleInternationalString("New title 2"));
+
+        // Set the alternate titles.
+        instance.setAlternateTitles(oldTitles);
+        final PropertyAccessor accessor = createPropertyAccessor();
+        final int              index    = accessor.indexOf("alternateTitles", true);
+        final Object           oldValue = accessor.set(index, instance, newTitles, RETURN_PREVIOUS);
+        final Object           newValue = accessor.get(index, instance);
+
+        // Verify the values.
+        assertEquals("set(…, RETURN_PREVIOUS)", oldTitles, oldValue);
+        assertEquals("get(…)",                  newTitles, newValue);
+        assertSame  ("alternateTitles",         newValue, instance.getAlternateTitles());
+        assertEquals("title",                   "Ignored title", instance.getTitle().toString());
     }
 
     /**
-     * Tests the {@link PropertyAccessor#set(int, Object, Object, boolean)} method
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method
      * when adding elements in a collection, without conversion of type.
+     * The metadata object created by this test is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title……………………………………………………… Ignored
title
+     *     ├─Alternate title (1 of 2)…… An other title
+     *     └─Alternate title (2 of 2)…… Yet an other title
+     * }
      */
     @Test
     @DependsOnMethod("testSet")
-    public void testSetInCollection() {
-        testSetInCollection(false);
+    public void testSetIntoCollection() {
+        testSetIntoCollection(false);
     }
 
     /**
-     * Tests the {@link PropertyAccessor#set(int, Object, Object, boolean)} method
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method
      * when adding elements in a collection, with conversion of type.
+     * The metadata object created by this test is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title……………………………………………………… Ignored
title
+     *     ├─Alternate title (1 of 2)…… An other title
+     *     └─Alternate title (2 of 2)…… Yet an other title
+     * }
      */
     @Test
-    @DependsOnMethod("testSet")
-    public void testSetInCollectionWithConversion() {
-        testSetInCollection(true);
+    @DependsOnMethod("testSetIntoCollection")
+    public void testSetIntoCollectionWithConversion() {
+        testSetIntoCollection(true);
     }
 
     /**
-     * Tests the {@link PropertyAccessor#set(int, Object, Object, boolean)} method
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method
      * when adding elements in a collection, with or without conversion of type.
      */
-    private void testSetInCollection(final boolean conversion) {
+    private static void testSetIntoCollection(final boolean conversion) {
         final String              text1    = "An other title";
         final String              text2    = "Yet an other title";
         final InternationalString title1   = new SimpleInternationalString(text1);
         final InternationalString title2   = new SimpleInternationalString(text2);
-        final DefaultCitation     instance = new DefaultCitation();
+        final DefaultCitation     instance = new DefaultCitation("Ignored title");
         final PropertyAccessor    accessor = createPropertyAccessor();
         final int                 index    = accessor.indexOf("alternateTitles", true);
 
         // Insert the first value. Old collection shall be empty.
-        Object oldValue = accessor.set(index, instance, conversion ? text1 : title1, true);
+        Object oldValue = accessor.set(index, instance, conversion ? text1 : title1, RETURN_PREVIOUS);
         assertInstanceOf("alternateTitles", Collection.class, oldValue);
         assertTrue("alternateTitles", ((Collection<?>) oldValue).isEmpty());
 
         // Insert the second value. Old collection shall contains the first value.
-        oldValue = accessor.set(index, instance, conversion ? text2 : title2, true);
+        oldValue = accessor.set(index, instance, conversion ? text2 : title2, RETURN_PREVIOUS);
         assertInstanceOf("alternateTitles", Collection.class, oldValue);
         oldValue = getSingleton((Collection<?>) oldValue);
         assertSame("alternateTitles", text1, oldValue.toString());
@@ -324,6 +409,58 @@ public final strictfp class PropertyAcce
         // Check final collection content.
         final List<InternationalString> expected = Arrays.asList(title1, title2);
         assertEquals("alternateTitles", expected, accessor.get(index, instance));
+        assertEquals("title", "Ignored title", instance.getTitle().toString());
+    }
+
+    /**
+     * Tests the {@link PropertyAccessor#set(int, Object, Object, int)} method in
+     * {@link PropertyAccessor#RETURN_CHANGED} mode. In this mode, new collections
+     * are added into existing collections instead than replacing them.
+     * The metadata object created by this test after the merge is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     ├─Title……………………………………………………… Added
title
+     *     ├─Alternate title (1 of 4)…… Old title 1
+     *     ├─Alternate title (2 of 4)…… Old title 2
+     *     ├─Alternate title (3 of 4)…… New title 1
+     *     └─Alternate title (4 of 4)…… New title 2
+     * }
+     *
+     * @see #testSetCollection()
+     */
+    public void testSetInAppendMode() {
+        final DefaultCitation instance = new DefaultCitation();
+        final List<InternationalString> oldTitles = Arrays.<InternationalString>asList(
+                new SimpleInternationalString("Old title 1"),
+                new SimpleInternationalString("Old title 2"));
+        final List<InternationalString> newTitles = Arrays.<InternationalString>asList(
+                new SimpleInternationalString("New title 1"),
+                new SimpleInternationalString("New title 2"));
+        final List<InternationalString> merged = new ArrayList<>(oldTitles);
+        assertTrue(merged.addAll(newTitles));
+
+        // Set the title.
+        instance.setAlternateTitles(oldTitles);
+        final PropertyAccessor accessor = createPropertyAccessor();
+        final int titleIndex = accessor.indexOf("title", true);
+        Object titleChanged = accessor.set(titleIndex, instance, "Added title", RETURN_CHANGED);
+
+        // Set the alternate titles.
+        final int    index    = accessor.indexOf("alternateTitles", true);
+        final Object changed  = accessor.set(index, instance, newTitles, RETURN_CHANGED);
+        final Object newValue = accessor.get(index, instance);
+
+        // Verify the values.
+        assertEquals("set(…, RETURN_CHANGED)", Boolean.TRUE, titleChanged);
+        assertEquals("set(…, RETURN_CHANGED)", Boolean.TRUE, changed);
+        assertEquals("get(…)",                 merged, newValue);
+        assertSame  ("alternateTitles",        newValue, instance.getAlternateTitles());
+        assertEquals("title", "Added title", instance.getTitle().toString());
+
+        // Test setting again the title to the same value.
+        titleChanged = accessor.set(titleIndex, instance, "Added title", RETURN_CHANGED);
+        assertEquals("set(…, RETURN_CHANGED)", Boolean.FALSE, titleChanged);
     }
 
     /**
@@ -352,7 +489,7 @@ public final strictfp class PropertyAcce
         HardCodedCitations.assertIdentifiersFor("EPSG", (Collection<?>) target);
 
         // Set the identifiers to null, which should clear the collection.
-        assertEquals("Expected the previous value.", source, accessor.set(index, citation,
null, true));
+        assertEquals("Expected the previous value.", source, accessor.set(index, citation,
null, RETURN_PREVIOUS));
         final Object value = accessor.get(index, citation);
         assertNotNull("Should have replaced null by an empty collection.", value);
         assertTrue("Should have replaced null by an empty collection.", ((Collection<?>)
value).isEmpty());



Mime
View raw message