sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1597037 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/ test/java/org/apache/sis/feature/ test/java/org/apache/sis/test/suite/
Date Fri, 23 May 2014 09:07:19 GMT
Author: desruisseaux
Date: Fri May 23 09:07:19 2014
New Revision: 1597037

URL: http://svn.apache.org/r1597037
Log:
Apply to association the same pattern than for attribute (1/2): renamed DefaultAssociation
as AbstractAssociation, and implement as SingletonAssociation.

Added:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
      - copied, changed from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java   (with
props)
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
      - copied, changed from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
      - copied, changed from r1596663, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
Removed:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
(from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java&r1=1596975&r2=1597037&rev=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Collection;
+import java.util.Iterator;
 import java.io.Serializable;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.quality.DataQuality;
@@ -23,16 +25,18 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Related to JDK7
-import java.util.Objects;
-
 
 /**
  * Indicates the role played by the association between two features.
  *
- * {@section Usage in multi-thread environment}
- * {@code DefaultAssociation} are <strong>not</strong> thread-safe.
- * Synchronization, if needed, shall be done externally by the caller.
+ * {@section Limitations}
+ * <ul>
+ *   <li><b>Multi-threading:</b> {@code AbstractAssociation} instances
are <strong>not</strong> thread-safe.
+ *       Synchronization, if needed, shall be done externally by the caller.</li>
+ *   <li><b>Serialization:</b> serialized objects of this class are not
guaranteed to be compatible with future
+ *       versions. Serialization should be used only for short term storage or RMI between
applications running
+ *       the same SIS version.</li>
+ * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -41,48 +45,28 @@ import java.util.Objects;
  *
  * @see DefaultAssociationRole
  */
-public class DefaultAssociation extends Property implements Cloneable, Serializable {
+public abstract class AbstractAssociation extends Field<AbstractFeature> implements
Serializable {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -1175014792131253528L;
+    private static final long serialVersionUID = 5992169056331267867L;
 
     /**
      * Information about the association.
      */
-    private final DefaultAssociationRole role;
-
-    /**
-     * The associated feature.
-     */
-    private AbstractFeature value;
+    final DefaultAssociationRole role;
 
     /**
      * Creates a new association of the given type.
      *
      * @param role Information about the association.
      */
-    public DefaultAssociation(final DefaultAssociationRole role) {
+    public AbstractAssociation(final DefaultAssociationRole role) {
         ArgumentChecks.ensureNonNull("role", role);
         this.role = role;
     }
 
     /**
-     * Creates a new association of the given type initialized to the given value.
-     *
-     * @param role  Information about the association.
-     * @param value The initial value (may be {@code null}).
-     */
-    DefaultAssociation(final DefaultAssociationRole role, final AbstractFeature value) {
-        ArgumentChecks.ensureNonNull("role", role);
-        this.role  = role;
-        this.value = value;
-        if (value != null) {
-            ensureValid(role.getValueType(), value.getType());
-        }
-    }
-
-    /**
      * Returns the name of this association as defined by its {@linkplain #getRole() role}.
      * This convenience method delegates to {@link DefaultAssociationRole#getName()}.
      *
@@ -106,23 +90,34 @@ public class DefaultAssociation extends 
     }
 
     /**
-     * Returns the associated feature.
+     * Returns the associated feature, or {@code null} if none. This convenience method can
be invoked in
+     * the common case where the {@linkplain DefaultAssociationRole#getMaximumOccurs() maximum
number} of
+     * features is restricted to 1 or 0.
      *
      * <div class="warning"><b>Warning:</b> In a future SIS version, the
return type may be changed
      * to {@code org.opengis.feature.Feature}. This change is pending GeoAPI revision.</div>
      *
      * @return The associated feature (may be {@code null}).
+     * @throws IllegalStateException if this association contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
-    public AbstractFeature getValue() {
-        return value;
-    }
+    @Override
+    public abstract AbstractFeature getValue();
 
-    final java.util.Collection<AbstractFeature> getValues() {
-        return (value == null)
-               ? java.util.Collections.emptyList()
-               : java.util.Collections.singletonList(value);
+    /**
+     * Returns all features, or an empty collection if none.
+     * The returned collection is <cite>live</cite>: changes in the returned
collection
+     * will be reflected immediately in this {@code Association} instance, and conversely.
+     *
+     * <p>The default implementation returns a collection which will delegate its work
to
+     * {@link #getValue()} and {@link #setValue(Object)}.</p>
+     *
+     * @return The features in a <cite>live</cite> collection.
+     */
+    @Override
+    public Collection<AbstractFeature> getValues() {
+        return super.getValues();
     }
 
     /**
@@ -142,18 +137,27 @@ public class DefaultAssociation extends 
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
-    public void setValue(final AbstractFeature value) {
-        if (value != null) {
-            ensureValid(role.getValueType(), value.getType());
-        }
-        this.value = value;
+    @Override
+    public abstract void setValue(final AbstractFeature value);
+
+    /**
+     * Set the features. All previous values are replaced by the given collection.
+     *
+     * <p>The default implementation ensures that the given collection contains at
most one element,
+     * then delegates to {@link #setValue(AbstractFeature)}.</p>
+     *
+     * @param values The new values.
+     */
+    @Override
+    public void setValues(final Collection<? extends AbstractFeature> values) {
+        super.setValues(values);
     }
 
     /**
      * Ensures that storing a feature of the given type is valid for an association
      * expecting the given base type.
      */
-    private void ensureValid(final DefaultFeatureType base, final DefaultFeatureType type)
{
+    final void ensureValid(final DefaultFeatureType base, final DefaultFeatureType type)
{
         if (base != type && !base.maybeAssignableFrom(type)) {
             throw new IllegalArgumentException(
                     Errors.format(Errors.Keys.IllegalArgumentClass_3, getName(), base.getName(),
type.getName()));
@@ -182,49 +186,6 @@ public class DefaultAssociation extends 
     }
 
     /**
-     * Returns a copy of this association.
-     * The default implementation returns a <em>shallow</em> copy:
-     * the association {@linkplain #getValue() value} is <strong>not</strong>
cloned.
-     * However subclasses may choose to do otherwise.
-     *
-     * @return A clone of this association.
-     * @throws CloneNotSupportedException if this association can not be cloned.
-     *         The default implementation never throw this exception. However subclasses
may throw it.
-     */
-    @Override
-    public DefaultAssociation clone() throws CloneNotSupportedException {
-        return (DefaultAssociation) super.clone();
-    }
-
-    /**
-     * Returns a hash code value for this association.
-     *
-     * @return A hash code value.
-     */
-    @Override
-    public int hashCode() {
-        return role.hashCode() + Objects.hashCode(value);
-    }
-
-    /**
-     * Compares this association with the given object for equality.
-     *
-     * @return {@code true} if both objects are equal.
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj != null && obj.getClass() == getClass()) {
-            final DefaultAssociation that = (DefaultAssociation) obj;
-            return role.equals(that.role) &&
-                   Objects.equals(value, that.value);
-        }
-        return false;
-    }
-
-    /**
      * Returns a string representation of this association.
      * The returned string is for debugging purpose and may change in any future SIS version.
      *
@@ -233,13 +194,16 @@ public class DefaultAssociation extends 
     @Debug
     @Override
     public String toString() {
-        final StringBuilder buffer = role.toString("FeatureAssociation", role.getValueType().getName());
-        if (value != null) {
-            final String pt = role.getTitleProperty();
-            if (pt != null) {
-                buffer.append(" = ").append(value.getPropertyValue(pt));
+        final String pt = role.getTitleProperty();
+        final Iterator<AbstractFeature> it = getValues().iterator();
+        return role.toString("FeatureAssociation", role.getValueType().getName(), new Iterator<Object>()
{
+            @Override public boolean hasNext() {
+                return it.hasNext();
             }
-        }
-        return buffer.toString();
+
+            @Override public Object next() {
+                return it.next().getPropertyValue(pt);
+            }
+        });
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -17,7 +17,6 @@
 package org.apache.sis.feature;
 
 import java.util.Collection;
-import java.util.Iterator;
 import java.io.Serializable;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.quality.DataQuality;
@@ -25,7 +24,6 @@ import org.opengis.metadata.maintenance.
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -57,7 +55,7 @@ import org.apache.sis.util.resources.Err
  *
  * @see DefaultAttributeType
  */
-public abstract class AbstractAttribute<V> extends Property implements Serializable
{
+public abstract class AbstractAttribute<V> extends Field<V> implements Serializable
{
     /**
      * For cross-version compatibility.
      */
@@ -141,6 +139,7 @@ public abstract class AbstractAttribute<
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
+    @Override
     public abstract V getValue() throws IllegalStateException;
 
     /**
@@ -153,8 +152,9 @@ public abstract class AbstractAttribute<
      *
      * @return The attribute values in a <cite>live</cite> collection.
      */
+    @Override
     public Collection<V> getValues() {
-        return new PropertySingleton<>(this);
+        return super.getValues();
     }
 
     /**
@@ -170,6 +170,7 @@ public abstract class AbstractAttribute<
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
+    @Override
     public abstract void setValue(final V value);
 
     /**
@@ -180,17 +181,9 @@ public abstract class AbstractAttribute<
      *
      * @param values The new values.
      */
+    @Override
     public void setValues(final Collection<? extends V> values) {
-        V value = null;
-        ArgumentChecks.ensureNonNull("values", values);
-        final Iterator<? extends V> it = values.iterator();
-        if (it.hasNext()) {
-            value = it.next();
-            if (it.hasNext()) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.TooManyOccurrences_2,
1, getName()));
-            }
-        }
-        setValue(value);
+        super.setValues(values);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -35,7 +35,7 @@ import org.apache.sis.internal.util.Chec
  *
  * <ul>
  *   <li>{@linkplain AbstractAttribute  Attributes}</li>
- *   <li>{@linkplain DefaultAssociation Associations to other features}</li>
+ *   <li>{@link AbstractAssociation Associations to other features}</li>
  *   <li>{@linkplain DefaultOperation   Operations}</li>
  * </ul>
  *
@@ -130,7 +130,7 @@ public abstract class AbstractFeature im
      *
      * <div class="note"><b>Tip:</b> This method returns the property <em>instance</em>.
If only the property
      * <em>value</em> is desired, then {@link #getPropertyValue(String)} is preferred
since it gives to SIS a
-     * chance to avoid the creation of {@link AbstractAttribute} or {@link DefaultAssociation}
instances.</div>
+     * chance to avoid the creation of {@link AbstractAttribute} or {@link AbstractAssociation}
instances.</div>
      *
      * @param  name The property name.
      * @return The property of the given name (never {@code null}).
@@ -184,7 +184,7 @@ public abstract class AbstractFeature im
         if (pt instanceof DefaultAttributeType<?>) {
             return AbstractAttribute.create((DefaultAttributeType<?>) pt, value);
         } else if (pt instanceof DefaultAssociationRole) {
-            return new DefaultAssociation((DefaultAssociationRole) pt, (AbstractFeature)
value);
+            return new SingletonAssociation((DefaultAssociationRole) pt, (AbstractFeature)
value);
         } else {
             // Should never happen, unless the user gave us some mutable FeatureType.
             throw new CorruptedObjectException(Errors.format(Errors.Keys.UnknownType_1, pt));
@@ -203,7 +203,7 @@ public abstract class AbstractFeature im
         if (pt instanceof DefaultAttributeType<?>) {
             return AbstractAttribute.create((DefaultAttributeType<?>) pt);
         } else if (pt instanceof DefaultAssociationRole) {
-            return new DefaultAssociation((DefaultAssociationRole) pt);
+            return new SingletonAssociation((DefaultAssociationRole) pt);
         } else {
             throw new IllegalArgumentException(unsupportedPropertyType(pt.getName()));
         }
@@ -299,9 +299,9 @@ public abstract class AbstractFeature im
     static void setPropertyValue(final Property property, final Object value) {
         if (property instanceof AbstractAttribute<?>) {
             setAttributeValue((AbstractAttribute<?>) property, value);
-        } else if (property instanceof DefaultAssociation) {
+        } else if (property instanceof AbstractAssociation) {
             ArgumentChecks.ensureCanCast("value", AbstractFeature.class, value);
-            setAssociationValue((DefaultAssociation) property, (AbstractFeature) value);
+            setAssociationValue((AbstractAssociation) property, (AbstractFeature) value);
         } else {
             throw new IllegalArgumentException(unsupportedPropertyType(property.getName()));
         }
@@ -342,7 +342,7 @@ public abstract class AbstractFeature im
      * Sets the association value after verification of its type.
      * For a more exhaustive validation, use {@link Validator} instead.
      */
-    private static void setAssociationValue(final DefaultAssociation association, final AbstractFeature
value) {
+    private static void setAssociationValue(final AbstractAssociation association, final
AbstractFeature value) {
         if (value != null) {
             final DefaultAssociationRole pt = association.getRole();
             final DefaultFeatureType base = pt.getValueType();
@@ -387,8 +387,8 @@ public abstract class AbstractFeature im
         final PropertyType type;
         if (property instanceof AbstractAttribute<?>) {
             type = ((AbstractAttribute<?>) property).getType();
-        } else if (property instanceof DefaultAssociation) {
-            type = ((DefaultAssociation) property).getRole();
+        } else if (property instanceof AbstractAssociation) {
+            type = ((AbstractAssociation) property).getRole();
         } else {
             throw new IllegalArgumentException(Errors.format(
                     Errors.Keys.IllegalArgumentClass_2, "property", property.getClass()));
@@ -527,7 +527,7 @@ public abstract class AbstractFeature im
      * @return Reports on all constraint violations found.
      *
      * @see AbstractAttribute#quality()
-     * @see DefaultAssociation#quality()
+     * @see AbstractAssociation#quality()
      */
     public DataQuality quality() {
         final Validator v = new Validator(ScopeCode.FEATURE);
@@ -536,8 +536,8 @@ public abstract class AbstractFeature im
             final DataQuality quality;
             if (property instanceof AbstractAttribute<?>) {
                 quality = ((AbstractAttribute<?>) property).quality();
-            } else if (property instanceof DefaultAssociation) {
-                quality = ((DefaultAssociation) property).quality();
+            } else if (property instanceof AbstractAssociation) {
+                quality = ((AbstractAssociation) property).quality();
             } else {
                 continue;
             }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -46,7 +46,7 @@ import static org.apache.sis.util.Argume
  * @version 0.5
  * @module
  *
- * @see DefaultAssociation
+ * @see AbstractAssociation
  */
 public class DefaultAssociationRole extends FieldType {
     /**
@@ -64,7 +64,7 @@ public class DefaultAssociationRole exte
     /**
      * The name of the property to use as a title for the associated feature, or an empty
string if none.
      * This field is initially null, then computed when first needed.
-     * This field is used only by {@link DefaultAssociation#toString()} implementation.
+     * This information is used only by {@link AbstractAssociation#toString()} implementation.
      *
      * @see #getTitleProperty()
      */

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -164,8 +164,8 @@ final class DenseFeature extends Abstrac
                     return element; // Most common case.
                 } else if (element instanceof AbstractAttribute<?>) {
                     return getAttributeValue((AbstractAttribute<?>) element);
-                } else if (element instanceof DefaultAssociation) {
-                    return ((DefaultAssociation) element).getValue();
+                } else if (element instanceof AbstractAssociation) {
+                    return ((AbstractAssociation) element).getValue();
                 } else {
                     throw new IllegalArgumentException(unsupportedPropertyType(((Property)
element).getName()));
                 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -39,7 +39,7 @@ import org.apache.sis.util.resources.Voc
  *
  * <div class="note"><b>Example:</b> a feature named “City” and containing
3 properties (“name”, “population” and
  * “twin town”) may be formatted like below. The two first properties are {@linkplain
AbstractAttribute attributes}
- * while the last property is an {@linkplain DefaultAssociation association} to an other
feature.
+ * while the last property is an {@linkplain AbstractAssociation association} to an other
feature.
  *
  * {@preformat text
  *   City

Added: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java?rev=1597037&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java (added)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8]
Fri May 23 09:07:19 2014
@@ -0,0 +1,91 @@
+/*
+ * 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.feature;
+
+import java.util.Collection;
+import java.util.Iterator;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * Base class of property that can be stored in a {@link AbstractFeature} instance.
+ * This include {@code Attribute} and {@code Association}, but not {@code Operation}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+abstract class Field<V> extends Property {
+    /**
+     * For subclass constructors.
+     */
+    Field() {
+    }
+
+    /**
+     * Returns the field feature or attribute value, or {@code null} if none.
+     *
+     * @return The feature or attribute value (may be {@code null}).
+     * @throws IllegalStateException if this field contains more than one value.
+     *
+     * @see AbstractFeature#getPropertyValue(String)
+     */
+    public abstract V getValue() throws IllegalStateException;
+
+    /**
+     * Returns all features or attribute values, or an empty collection if none.
+     * The returned collection is <cite>live</cite>: changes in the returned
collection
+     * will be reflected immediately in this {@code Field} instance, and conversely.
+     *
+     * @return The features or attribute values in a <cite>live</cite> collection.
+     */
+    public Collection<V> getValues() {
+        return new PropertySingleton<>(this);
+    }
+
+    /**
+     * Sets the feature or attribute value. All previous values are replaced by the given
singleton.
+     *
+     * @param value The new value, or {@code null} for removing all values from this field.
+     *
+     * @see AbstractFeature#setPropertyValue(String, Object)
+     */
+    public abstract void setValue(final V value);
+
+    /**
+     * Set the features or attribute values. All previous values are replaced by the given
collection.
+     *
+     * <p>The default implementation ensures that the given collection contains at
most one element,
+     * then delegates to {@link #setValue(Object)}.</p>
+     *
+     * @param values The new values.
+     */
+    public void setValues(final Collection<? extends V> values) {
+        V value = null;
+        ArgumentChecks.ensureNonNull("values", values);
+        final Iterator<? extends V> it = values.iterator();
+        if (it.hasNext()) {
+            value = it.next();
+            if (it.hasNext()) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.TooManyOccurrences_2,
1, getName()));
+            }
+        }
+        setValue(value);
+    }
+}

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -42,12 +42,12 @@ final class PropertySingleton<V> extends
     /**
      * The property where to read and write the value.
      */
-    private final AbstractAttribute<V> property;
+    private final Field<V> property;
 
     /**
      * Creates a new list for the value of the given property.
      */
-    PropertySingleton(final AbstractAttribute<V> property) {
+    PropertySingleton(final Field<V> property) {
         this.property = property;
     }
 

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
(from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java&r1=1596975&r2=1597037&rev=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -16,23 +16,21 @@
  */
 package org.apache.sis.feature;
 
-import java.io.Serializable;
-import org.opengis.util.GenericName;
-import org.opengis.metadata.quality.DataQuality;
-import org.apache.sis.util.Debug;
-import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.resources.Errors;
-
 // Related to JDK7
 import java.util.Objects;
 
 
 /**
- * Indicates the role played by the association between two features.
+ * An instance of an {@linkplain DefaultAssociationRole association role} containing at most
one value.
+ * The majority of features types contain associations restricted to such [0 … 1] cardinality.
+ * While {@link MultiValuedAssociation} would be suitable to all cases, this {@code SingletonAssociation}
+ * consumes less memory.
  *
- * {@section Usage in multi-thread environment}
- * {@code DefaultAssociation} are <strong>not</strong> thread-safe.
- * Synchronization, if needed, shall be done externally by the caller.
+ * {@section Limitations}
+ * <ul>
+ *   <li><b>Multi-threading:</b> {@code SingletonAssociation} instances
are <strong>not</strong> thread-safe.
+ *       Synchronization, if needed, shall be done externally by the caller.</li>
+ * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -41,16 +39,11 @@ import java.util.Objects;
  *
  * @see DefaultAssociationRole
  */
-public class DefaultAssociation extends Property implements Cloneable, Serializable {
+final class SingletonAssociation extends AbstractAssociation implements Cloneable {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -1175014792131253528L;
-
-    /**
-     * Information about the association.
-     */
-    private final DefaultAssociationRole role;
+    private static final long serialVersionUID = -5247767277033831214L;
 
     /**
      * The associated feature.
@@ -62,9 +55,8 @@ public class DefaultAssociation extends 
      *
      * @param role Information about the association.
      */
-    public DefaultAssociation(final DefaultAssociationRole role) {
-        ArgumentChecks.ensureNonNull("role", role);
-        this.role = role;
+    public SingletonAssociation(final DefaultAssociationRole role) {
+        super(role);
     }
 
     /**
@@ -73,9 +65,8 @@ public class DefaultAssociation extends 
      * @param role  Information about the association.
      * @param value The initial value (may be {@code null}).
      */
-    DefaultAssociation(final DefaultAssociationRole role, final AbstractFeature value) {
-        ArgumentChecks.ensureNonNull("role", role);
-        this.role  = role;
+    SingletonAssociation(final DefaultAssociationRole role, final AbstractFeature value)
{
+        super(role);
         this.value = value;
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());
@@ -83,65 +74,22 @@ public class DefaultAssociation extends 
     }
 
     /**
-     * Returns the name of this association as defined by its {@linkplain #getRole() role}.
-     * This convenience method delegates to {@link DefaultAssociationRole#getName()}.
-     *
-     * @return The association name specified by its role.
-     */
-    @Override
-    public GenericName getName() {
-        return role.getName();
-    }
-
-    /**
-     * Returns information about the association.
-     *
-     * <div class="warning"><b>Warning:</b> In a future SIS version, the
return type may be changed
-     * to {@code org.opengis.feature.AssociationRole}. This change is pending GeoAPI revision.</div>
-     *
-     * @return Information about the association.
-     */
-    public DefaultAssociationRole getRole() {
-        return role;
-    }
-
-    /**
      * Returns the associated feature.
      *
-     * <div class="warning"><b>Warning:</b> In a future SIS version, the
return type may be changed
-     * to {@code org.opengis.feature.Feature}. This change is pending GeoAPI revision.</div>
-     *
      * @return The associated feature (may be {@code null}).
-     *
-     * @see AbstractFeature#getPropertyValue(String)
      */
+    @Override
     public AbstractFeature getValue() {
         return value;
     }
 
-    final java.util.Collection<AbstractFeature> getValues() {
-        return (value == null)
-               ? java.util.Collections.emptyList()
-               : java.util.Collections.singletonList(value);
-    }
-
     /**
      * Sets the associated feature.
      *
-     * <div class="warning"><b>Warning:</b> In a future SIS version, the
argument type may be changed
-     * to {@code org.opengis.feature.Feature}. This change is pending GeoAPI revision.</div>
-     *
-     * {@section Validation}
-     * The amount of validation performed by this method is implementation dependent.
-     * Usually, only the most basic constraints are verified. This is so for performance
reasons
-     * and also because some rules may be temporarily broken while constructing a feature.
-     * A more exhaustive verification can be performed by invoking the {@link #quality()}
method.
-     *
      * @param  value The new value, or {@code null}.
      * @throws IllegalArgumentException If the given feature is not valid for this association.
-     *
-     * @see AbstractFeature#setPropertyValue(String, Object)
      */
+    @Override
     public void setValue(final AbstractFeature value) {
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());
@@ -150,38 +98,6 @@ public class DefaultAssociation extends 
     }
 
     /**
-     * Ensures that storing a feature of the given type is valid for an association
-     * expecting the given base type.
-     */
-    private void ensureValid(final DefaultFeatureType base, final DefaultFeatureType type)
{
-        if (base != type && !base.maybeAssignableFrom(type)) {
-            throw new IllegalArgumentException(
-                    Errors.format(Errors.Keys.IllegalArgumentClass_3, getName(), base.getName(),
type.getName()));
-        }
-    }
-
-    /**
-     * Verifies if the current association value mets the constraints defined by the association
role.
-     * This method returns at most one {@linkplain org.apache.sis.metadata.iso.quality.DefaultDataQuality#getReports()
-     * report} with a {@linkplain org.apache.sis.metadata.iso.quality.DefaultDomainConsistency#getResults()
result} for
-     * each constraint violations found, if any.
-     * See {@link AbstractAttribute#quality()} for an example.
-     *
-     * <p>This association is valid if this method does not report any
-     * {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult conformance
result} having a
-     * {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult#pass() pass}
value of {@code false}.</p>
-     *
-     * @return Reports on all constraint violations found.
-     *
-     * @see AbstractFeature#quality()
-     */
-    public DataQuality quality() {
-        final Validator v = new Validator(null);
-        v.validate(role, getValues());
-        return v.quality;
-    }
-
-    /**
      * Returns a copy of this association.
      * The default implementation returns a <em>shallow</em> copy:
      * the association {@linkplain #getValue() value} is <strong>not</strong>
cloned.
@@ -192,8 +108,8 @@ public class DefaultAssociation extends 
      *         The default implementation never throw this exception. However subclasses
may throw it.
      */
     @Override
-    public DefaultAssociation clone() throws CloneNotSupportedException {
-        return (DefaultAssociation) super.clone();
+    public SingletonAssociation clone() throws CloneNotSupportedException {
+        return (SingletonAssociation) super.clone();
     }
 
     /**
@@ -216,30 +132,10 @@ public class DefaultAssociation extends 
         if (obj == this) {
             return true;
         }
-        if (obj != null && obj.getClass() == getClass()) {
-            final DefaultAssociation that = (DefaultAssociation) obj;
-            return role.equals(that.role) &&
-                   Objects.equals(value, that.value);
+        if (obj instanceof SingletonAssociation) {
+            final SingletonAssociation that = (SingletonAssociation) obj;
+            return role.equals(that.role) && Objects.equals(value, that.value);
         }
         return false;
     }
-
-    /**
-     * Returns a string representation of this association.
-     * The returned string is for debugging purpose and may change in any future SIS version.
-     *
-     * @return A string representation of this association for debugging purpose.
-     */
-    @Debug
-    @Override
-    public String toString() {
-        final StringBuilder buffer = role.toString("FeatureAssociation", role.getValueType().getName());
-        if (value != null) {
-            final String pt = role.getTitleProperty();
-            if (pt != null) {
-                buffer.append(" = ").append(value.getPropertyValue(pt));
-            }
-        }
-        return buffer.toString();
-    }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -82,8 +82,6 @@ final class SingletonAttribute<V> extend
      * Returns the attribute value.
      *
      * @return The attribute value (may be {@code null}).
-     *
-     * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
     public V getValue() {

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -178,8 +178,8 @@ final class SparseFeature extends Abstra
                 return element; // Most common case.
             } else if (element instanceof AbstractAttribute<?>) {
                 return getAttributeValue((AbstractAttribute<?>) element);
-            } else if (element instanceof DefaultAssociation) {
-                return ((DefaultAssociation) element).getValue();
+            } else if (element instanceof AbstractAssociation) {
+                return ((AbstractAssociation) element).getValue();
             } else if (valuesKind == PROPERTIES) {
                 throw new IllegalArgumentException(unsupportedPropertyType(((Property) element).getName()));
             } else {

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -72,10 +72,10 @@
  * {@code      ├─} {@linkplain org.apache.sis.feature.DefaultAssociationRole  Feature
association role}<br>
  * {@code      └─} {@linkplain org.apache.sis.feature.DefaultOperation        Operation}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
- *             {@linkplain org.apache.sis.feature.AbstractFeature    Feature}<br>
- *                                                                   Property<br>
- * {@code  ├─} {@linkplain org.apache.sis.feature.AbstractAttribute  Attribute}<br>
- * {@code  └─} {@linkplain org.apache.sis.feature.DefaultAssociation Feature association}<br>
+ *             {@linkplain org.apache.sis.feature.AbstractFeature     Feature}<br>
+ *                                                                    Property<br>
+ * {@code  ├─} {@linkplain org.apache.sis.feature.AbstractAttribute   Attribute}<br>
+ * {@code  └─} {@linkplain org.apache.sis.feature.AbstractAssociation Feature association}<br>
  * </td></tr></table>
  *
  * @author  Travis L. Pinney

Copied: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
(from r1596663, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java?p2=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java&p1=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java&r1=1596663&r2=1597037&rev=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -25,7 +25,7 @@ import static org.apache.sis.test.Assert
 
 
 /**
- * Tests {@link DefaultAssociation}.
+ * Tests {@link SingletonAssociation}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -36,18 +36,18 @@ import static org.apache.sis.test.Assert
     DefaultAssociationRoleTest.class,
     DenseFeatureTest.class
 })
-public final strictfp class DefaultAssociationTest extends TestCase {
+public final strictfp class SingletonAssociationTest extends TestCase {
     /**
      * Returns an association to use for testing purpose.
      *
      * <blockquote>“The earliest known town twinning in Europe was between Paderborn,
Germany
      * and Le Mans, France in 836.” — source: Wikipedia</blockquote>
      */
-    static DefaultAssociation twinTown() {
+    static AbstractAssociation twinTown() {
         final AbstractFeature twinTown = DefaultFeatureTypeTest.city().newInstance();
         twinTown.setPropertyValue("city", "Le Mans");
         twinTown.setPropertyValue("population", 143240); // In 2011.
-        final DefaultAssociation association = new DefaultAssociation(DefaultAssociationRoleTest.twinTown());
+        final AbstractAssociation association = new SingletonAssociation(DefaultAssociationRoleTest.twinTown());
         association.setValue(twinTown);
         return association;
     }
@@ -57,7 +57,7 @@ public final strictfp class DefaultAssoc
      */
     @Test
     public void testWrongValue() {
-        final DefaultAssociation association  = twinTown();
+        final AbstractAssociation association  = twinTown();
         final PropertyType       population   = association.getRole().getValueType().getProperty("population");
         final AbstractFeature    otherFeature = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Population"), false, null, population).newInstance();
@@ -76,16 +76,16 @@ public final strictfp class DefaultAssoc
      */
     @Test
     public void testSerialization() {
-        final DefaultAssociation twinTown = twinTown();
+        final AbstractAssociation twinTown = twinTown();
         assertNotSame(twinTown, assertSerializedEquals(twinTown));
     }
 
     /**
-     * Tests {@link DefaultAssociation#toString()}.
+     * Tests {@link SingletonAssociation#toString()}.
      */
     @Test
     public void testToString() {
-        final DefaultAssociation twinTown = twinTown();
+        final AbstractAssociation twinTown = twinTown();
         assertEquals("FeatureAssociation[“twin town” : City] = Le Mans", twinTown.toString());
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java?rev=1597037&r1=1597036&r2=1597037&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
[UTF-8] Fri May 23 09:07:19 2014
@@ -38,7 +38,7 @@ import org.junit.BeforeClass;
     org.apache.sis.feature.DenseFeatureTest.class,
     org.apache.sis.feature.SparseFeatureTest.class,
     org.apache.sis.feature.DefaultAssociationRoleTest.class,
-    org.apache.sis.feature.DefaultAssociationTest.class,
+    org.apache.sis.feature.SingletonAssociationTest.class,
     org.apache.sis.feature.DefaultOperationTest.class,
     org.apache.sis.feature.FeatureFormatTest.class,
     org.apache.sis.feature.FeaturesTest.class



Mime
View raw message