sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1592633 - in /sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature: DefaultAttribute.java DefaultAttributeType.java DefaultFeature.java DefaultFeatureType.java
Date Mon, 05 May 2014 21:13:18 GMT
Author: desruisseaux
Date: Mon May  5 21:13:17 2014
New Revision: 1592633

URL: http://svn.apache.org/r1592633
Log:
Initial support of Attribute in Feature, for now only in the case of [0...1] cardinality.
This cover the vast majority of cases and is handled in a special way for lower memory consumption.
We still need to implement the multi-values case (cardinality [0...n]) and add test and documentation.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java?rev=1592633&r1=1592632&r2=1592633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
[UTF-8] Mon May  5 21:13:17 2014
@@ -25,9 +25,18 @@ import java.util.Objects;
 
 
 /**
- * Holds the value of an attribute in a feature. The value can be an arbitrary Java object.
- * Constraints like the base Java class and domain of values are specified by the
- * {@linkplain DefaultAttributeType attribute type} associated to each attribute instance.
+ * Holds the value of an attribute in a feature.
+ * {@code Attribute} holds two main information:
+ *
+ * <ul>
+ *   <li>A reference to an {@linkplain DefaultAttributeType attribute type}
+ *       which define the base Java type and domain of valid values.</li>
+ *   <li>A value.</li>
+ * </ul>
+ *
+ * {@section Usage in multi-thread environment}
+ * {@code DefaultAttribute} are <strong>not</strong> thread-safe.
+ * Synchronization, if needed, shall be done externally by the caller.
  *
  * @param <T> The type of attribute values.
  *

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java?rev=1592633&r1=1592632&r2=1592633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
[UTF-8] Mon May  5 21:13:17 2014
@@ -46,9 +46,13 @@ import java.util.Objects;
  * will be replaced by references to the {@code AttributeType} interface.</div>
  *
  * {@section Immutability and thread safety}
- * This class is immutable if the {@link GenericName} and {@link InternationalString} instances
given to the
- * constructor are also immutable. Such immutable instances can be shared by many objects
and passed between
- * threads without synchronization.
+ * Instances of this class are immutable if all properties ({@link GenericName} and {@link
InternationalString}
+ * instances) and all arguments (default value, cardinality) given to the constructor are
also immutable.
+ * Such immutable instances can be shared by many objects and passed between threads without
synchronization.
+ *
+ * <p>In particular, the {@link #getDefaultValue()} method does <strong>not</strong>
clone the returned value.
+ * This means that the same {@code defaultValue} instance may be shared by many {@link DefaultAttribute}
instances.
+ * Consequently the default value should be immutable for avoiding unexpected behavior.</p>
  *
  * @param <T> The type of attribute values.
  *

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeature.java?rev=1592633&r1=1592632&r2=1592633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeature.java
[UTF-8] Mon May  5 21:13:17 2014
@@ -25,6 +25,7 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.Containers;
+import org.apache.sis.measure.NumberRange;
 
 // Related to JDK7
 import java.util.Objects;
@@ -33,6 +34,10 @@ import java.util.Objects;
 /**
  * An instance of {@linkplain DefaultFeatureType feature type} containing values for a real-world
phenomena.
  *
+ * {@section Usage in multi-thread environment}
+ * {@code DefaultFeature} are <strong>not</strong> thread-safe.
+ * Synchronization, if needed, shall be done externally by the caller.
+ *
  * @author  Travis L. Pinney
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -53,8 +58,19 @@ public class DefaultFeature implements S
 
     /**
      * The properties (attributes, operations, feature associations) of this feature.
+     * Each value can be one of the following types (from most generic to most specific):
+     *
+     * <ul>
+     *   <li>A {@link MultiValues}, which is a list of {@code Attribute}.</li>
+     *   <li>An {@code Attribute} in the common case of [0…1] cardinality.</li>
+     *   <li>An object in the common case of [0…1] cardinality when only the value
+     *       (not the {@code Attribute} object) is requested.</li>
+     * </ul>
+     *
+     * The intend is to reduce the amount of allocate objects as much as possible,
+     * because typical SIS applications may create a very large amount of features.
      */
-    private final Map<String, DefaultAttribute<?>> properties;
+    private final Map<String, Object> properties;
 
     /**
      * Creates a new features.
@@ -77,33 +93,96 @@ public class DefaultFeature implements S
     }
 
     /**
-     * Returns all attributes of the given name.
-     *
-     * @param  name The attribute name.
-     * @return All attributes of the given name, or an empty list if none.
+     * Returns {@code true} if the given cardinality is for a singleton property.
      */
-    public List<DefaultAttribute<?>> getAttributes(final String name) {
-        return null;
+    private static boolean isSingleton(final NumberRange<Integer> cardinality) {
+        switch (cardinality.getMaxValue()) {
+            case 0:
+            case 1:  return true;
+            case 2:  return !cardinality.isMaxIncluded();
+            default: return false;
+        }
     }
 
     /**
-     * Returns the value(s) of the attribute of the given name.
+     * Returns all properties (attributes, operations or associations) of the given name.
+     * The returned list is <em>live</em>: change in that list will be immediately
reflected
+     * in this {@code DefaultFeature}, and conversely.
+     *
+     * <div class="warning">In a future SIS version, the type of list elements may
be changed
+     * to {@code org.opengis.feature.Property}. This change is pending GeoAPI revision.</div>
+     *
+     * @param  name The property name.
+     * @return All properties of the given name, or an empty list if none.
+     * @throws IllegalArgumentException If the given argument is not a property name of this
feature.
+     */
+    public List<DefaultAttribute<?>> getProperties(final String name) throws
IllegalArgumentException {
+        ArgumentChecks.ensureNonNull("name", name);
+        final DefaultAttributeType<?> at = type.getProperty(name);
+        if (at == null) {
+            throw new IllegalArgumentException(propertyNotFound(name));
+        }
+        /*
+         * If the majority of cases, the feature allows at most one attribute for the given
name.
+         * In order to save a little bit of space (because SIS applications may have a very
large
+         * amount of features), we will not store the list in this DefaultFeature. Instead,
we use
+         * a temporary object which will read and write the Attribute instance directly in
the map.
+         */
+        if (isSingleton(at.getCardinality())) {
+            return new SingletonValue(properties, name);
+        }
+        /*
+         * If the property allow more than one feature, then we need a real List implementation.
+         */
+        final Object element = properties.get(name);
+        if (element == null) {
+            // TODO: create MultiValues list here.
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the value(s) of all attribute of the given name.
+     * This convenience method combines a call to {@link #getProperties(String)} followed
by calls to
+     * {@link DefaultAttribute#getValue()} for each attribute, but may potentially be more
efficient.
+     *
+     * <p>Special cases:</p>
+     * <ul>
+     *   <li>If the {@linkplain DefaultAttributeType#getCardinality() attribute cardinality}
allows
+     *       more than one occurrence, then this method will always return a {@link List}.
+     *       That list may be empty but never {@code null}.</li>
+     *   <li>Otherwise (if the attribute cardinality allows at most one occurrence),
+     *       this method returns either the singleton value or {@code null}.</li>
+     * </ul>
      *
      * @param  name The attribute name.
-     * @return The value for the given attribute, or {@code null} if none.
+     * @return The value or list of values for the given attribute(s), or {@code null} if
none.
+     * @throws IllegalArgumentException If the given argument is not an attribute name of
this feature.
      *
      * @see DefaultAttribute#getValue()
      */
-    public Object getAttributeValue(final String name) {
-        final DefaultAttribute<?> attribute = properties.get(name);
-        if (attribute == null) {
+    public Object getAttributeValue(final String name) throws IllegalArgumentException {
+        ArgumentChecks.ensureNonNull("name", name);
+        final Object element = properties.get(name);
+        /*
+         * If there is no value for the given name, first ensure that the name is valid,
+         * then return the default value without storing any object in this DefaultFeature.
+         */
+        if (element == null) {
             final DefaultAttributeType<?> at = type.getProperty(name);
             if (at == null) {
                 throw new IllegalArgumentException(propertyNotFound(name));
             }
-            return at.getDefaultValue();
+            if (isSingleton(at.getCardinality())) {
+                return at.getDefaultValue();
+            }
+            // TODO
         }
-        return attribute.getValue();
+        // TODO: test MultiValues list here.
+        if (element instanceof DefaultAttribute<?>) {
+            return ((DefaultAttribute<?>) element).getValue();
+        }
+        return element;
     }
 
     /**
@@ -111,18 +190,20 @@ public class DefaultFeature implements S
      *
      * {@section Validation}
      * The amount of validation performed by this method is implementation dependent.
-     * The current {@code DefaultFeature} implementation performs only very cheap (if any)
validations.
+     * The current {@code DefaultFeature} implementation performs only minimal validations.
      * A more exhaustive verification can be performed by invoking the {@link #validate()}
method.
      *
-     * @param name  The attribute name.
-     * @param value The new value for the given attribute (may be {@code null}).
+     * @param  name  The attribute name.
+     * @param  value The new value for the given attribute (may be {@code null}).
+     * @throws IllegalArgumentException If the given argument is not an attribute name of
this feature.
+     * @throws RuntimeException If this method performs validation and the given value does
not meet the conditions.
+     *         <em>This exception will be changed to {@code IllegalAttributeException}
in a future SIS version.</em>
      *
      * @see DefaultAttribute#setValue(Object)
      */
-    @SuppressWarnings("unchecked")
-    public void setAttributeValue(final String name, final Object value) {
-        DefaultAttribute<?> attribute = properties.get(name);
-        if (attribute == null) {
+    public void setAttributeValue(final String name, final Object value) throws IllegalArgumentException
{
+        Object element = properties.get(name);
+        if (element == null) {
             final DefaultAttributeType<?> at = type.getProperty(name);
             if (at == null) {
                 throw new IllegalArgumentException(propertyNotFound(name));
@@ -130,12 +211,35 @@ public class DefaultFeature implements S
             if (Objects.equals(value, at.getDefaultValue())) {
                 return; // Avoid creating the attribute if not necessary.
             }
-            attribute = new DefaultAttribute<>(at);
+            final DefaultAttribute<?> attribute = new DefaultAttribute<>(at);
+            setAttributeValue(attribute, value);
             if (properties.put(name, attribute) != null) {
                 throw new ConcurrentModificationException();
             }
+        } else {
+            // TODO: check for MultiValues list here.
+            if (element instanceof DefaultAttribute<?>) {
+                setAttributeValue((DefaultAttribute<?>) element, value);
+            } else {
+                if (properties.put(name, value) != element) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the attribute value after verification of its type.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> void setAttributeValue(final DefaultAttribute<T> attribute,
final Object value) {
+        if (value != null) {
+            final DefaultAttributeType<T> at = attribute.getType();
+            if (!at.getValueClass().isInstance(value)) {
+                throw new RuntimeException( // TODO: use IllegalAttributeException after
GeoAPI revision.
+                        Errors.format(Errors.Keys.IllegalPropertyClass_2, at.getName(), value.getClass()));
+            }
         }
-        ArgumentChecks.ensureCanCast(name, attribute.getType().getValueClass(), value);
         ((DefaultAttribute) attribute).setValue(value);
     }
 
@@ -198,8 +302,17 @@ public class DefaultFeature implements S
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         final String lineSeparator = System.lineSeparator();
-        for (final DefaultAttribute<?> attribute : properties.values()) {
-            sb.append(attribute.getType().getName()).append(": ").append(attribute.getValue()).append(lineSeparator);
+        for (final Map.Entry<String,Object> entry : properties.entrySet()) {
+            final DefaultAttributeType<?> at;
+            Object element = entry.getValue();
+            // TODO: check for MultiValues list here.
+            if (element instanceof DefaultAttribute<?>) {
+                at = ((DefaultAttribute<?>) element).getType();
+                element = ((DefaultAttribute<?>) element).getValue();
+            } else {
+                at = type.getProperty(entry.getKey());
+            }
+            sb.append(at.getName()).append(": ").append(element).append(lineSeparator);
         }
         return sb.toString();
     }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1592633&r1=1592632&r2=1592633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
[UTF-8] Mon May  5 21:13:17 2014
@@ -47,7 +47,8 @@ import org.apache.sis.internal.util.Unmo
  * will be replaced by references to the {@code FeatureType} interface.</div>
  *
  * {@section Immutability and thread safety}
- * This class is immutable if the {@link AttributeType} instances given to the constructor
are also immutable.
+ * Instances of this class are immutable if all properties ({@link GenericName} and {@link
InternationalString}
+ * instances) and all arguments ({@link AttributeType} instances) given to the constructor
are also immutable.
  * Such immutable instances can be shared by many objects and passed between threads without
synchronization.
  *
  * @author  Johann Sorel (Geomatys)



Mime
View raw message