sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1598371 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/ test/java/org/apache/sis/feature/
Date Thu, 29 May 2014 19:03:15 GMT
Author: desruisseaux
Date: Thu May 29 19:03:14 2014
New Revision: 1598371

URL: http://svn.apache.org/r1598371
Log:
DefaultFeatureType now implements FeatureType.
We had to disable the check against infinite recursivity in 'isAssignableFrom'.
The previous check was wrong anyway (we need to compare feature pairs, not only
the base feature type). We will implement a new recursivity check later.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.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/DefaultFeatureType.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/MultiValuedAssociation.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/Validator.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/feature/DefaultFeatureTypeTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1598371&r1=1598370&r2=1598371&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] Thu May 29 19:03:14 2014
@@ -25,6 +25,9 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
+// Branch-dependent imports
+import org.opengis.feature.FeatureType;
+
 
 /**
  * Indicates the role played by the association between two features.
@@ -185,8 +188,8 @@ public abstract class AbstractAssociatio
      * Ensures that storing a feature of the given type is valid for an association
      * expecting the given base type.
      */
-    final void ensureValid(final DefaultFeatureType base, final DefaultFeatureType type) {
-        if (base != type && !base.maybeAssignableFrom(type)) {
+    final void ensureValid(final FeatureType base, final FeatureType type) {
+        if (base != type && !DefaultFeatureType.maybeAssignableFrom(base, type)) {
             throw new IllegalArgumentException(
                     Errors.format(Errors.Keys.IllegalArgumentClass_3, getName(), base.getName(), type.getName()));
         }

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -31,6 +31,7 @@ import org.apache.sis.internal.util.Chec
 // Branch-dependent imports
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -79,7 +80,7 @@ public abstract class AbstractFeature im
     /**
      * Information about the feature (name, characteristics, <i>etc.</i>).
      */
-    final DefaultFeatureType type;
+    final FeatureType type;
 
     /**
      * Creates a new feature of the given type.
@@ -88,7 +89,7 @@ public abstract class AbstractFeature im
      *
      * @see DefaultFeatureType#newInstance()
      */
-    protected AbstractFeature(final DefaultFeatureType type) {
+    protected AbstractFeature(final FeatureType type) {
         ArgumentChecks.ensureNonNull("type", type);
         this.type = type;
     }
@@ -109,26 +110,11 @@ public abstract class AbstractFeature im
      *
      * @return Information about the feature.
      */
-    public DefaultFeatureType getType() {
+    public FeatureType getType() {
         return type;
     }
 
     /**
-     * Returns the type for the property of the given name.
-     *
-     * @param  name The property name.
-     * @return The type for the property of the given name (never {@code null}).
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
-     */
-    final PropertyType getPropertyType(final String name) throws IllegalArgumentException {
-        final PropertyType pt = type.getProperty(name);
-        if (pt != null) {
-            return pt;
-        }
-        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
-    }
-
-    /**
      * Returns the property (attribute, operation or association) of the given name.
      *
      * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
@@ -153,13 +139,13 @@ public abstract class AbstractFeature im
      * <ul>
      *   <li>It must be non-null.</li>
      *   <li>Its {@linkplain Property#getName() name} shall be the name of the property to set in this feature.</li>
-     *   <li>Its type shall be the same instance than the {@linkplain AbstractFeature#getPropertyType(String)
+     *   <li>Its type shall be the same instance than the {@linkplain DefaultFeatureType#getProperty(String)
      *       property type} defined by the feature type for the above name.
      *       In other words, the following condition shall hold:</li>
      * </ul>
      *
      * {@preformat java
-     *     assert property.getType() == getType().getPropertyType(property.getName());
+     *     assert property.getType() == getType().getProperty(property.getName());
      * }
      *
      * <div class="note"><b>Note:</b> This method is useful for storing non-default {@code Attribute} or
@@ -186,7 +172,7 @@ public abstract class AbstractFeature im
      * @return A {@code Property} wrapping the given value.
      */
     final Property createProperty(final String name, final Object value) {
-        final PropertyType pt = getPropertyType(name);
+        final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             return AbstractAttribute.create((AttributeType<?>) pt, value);
         } else if (pt instanceof DefaultAssociationRole) {
@@ -205,7 +191,7 @@ public abstract class AbstractFeature im
      * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
      */
     final Property createProperty(final String name) throws IllegalArgumentException {
-        final PropertyType pt = getPropertyType(name);
+        final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             return AbstractAttribute.create((AttributeType<?>) pt);
         } else if (pt instanceof DefaultAssociationRole) {
@@ -224,7 +210,7 @@ public abstract class AbstractFeature im
      * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
      */
     final Object getDefaultValue(final String name) throws IllegalArgumentException {
-        final PropertyType pt = getPropertyType(name);
+        final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             return getDefaultValue((AttributeType<?>) pt);
         } else if (pt instanceof DefaultAssociationRole) {
@@ -358,10 +344,10 @@ public abstract class AbstractFeature im
     private static void setAssociationValue(final AbstractAssociation association, final Object value) {
         if (value != null) {
             final DefaultAssociationRole role = association.getRole();
-            final DefaultFeatureType base = role.getValueType();
+            final FeatureType base = role.getValueType();
             if (value instanceof AbstractFeature) {
-                final DefaultFeatureType actual = ((AbstractFeature) value).getType();
-                if (!base.maybeAssignableFrom(actual)) {
+                final FeatureType actual = ((AbstractFeature) value).getType();
+                if (base != actual && !DefaultFeatureType.maybeAssignableFrom(base, actual)) {
                     throw illegalPropertyType(role.getName(), actual.getName());
                 }
             } else if (value instanceof Collection<?>) {
@@ -404,15 +390,15 @@ public abstract class AbstractFeature im
      * @param property The property to verify.
      */
     final void verifyPropertyType(final String name, final Property property) {
-        final PropertyType type, base = getPropertyType(name);
+        final PropertyType pt, base = type.getProperty(name);
         if (property instanceof AbstractAttribute<?>) {
-            type = ((AbstractAttribute<?>) property).getType();
+            pt = ((AbstractAttribute<?>) property).getType();
         } else if (property instanceof AbstractAssociation) {
-            type = ((AbstractAssociation) property).getRole();
+            pt = ((AbstractAssociation) property).getRole();
         } else {
             throw illegalPropertyType(base.getName(), property.getClass());
         }
-        if (type != base) {
+        if (pt != base) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
         }
     }
@@ -422,7 +408,7 @@ public abstract class AbstractFeature im
      * to store. The returned value is usually the same than the given one, except in the case of collections.
      */
     final Object verifyPropertyValue(final String name, final Object value) {
-        final PropertyType pt = getPropertyType(name);
+        final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             if (value != null) {
                 return verifyAttributeValue((AttributeType<?>) pt, value);
@@ -476,8 +462,9 @@ public abstract class AbstractFeature im
              * If the user gave us a single value, first verify its validity.
              * Then wrap it in a list of 1 element if this property is multi-valued.
              */
-            final DefaultFeatureType valueType = ((AbstractFeature) value).getType();
-            if (role.getValueType().maybeAssignableFrom(valueType)) {
+            final FeatureType valueType = ((AbstractFeature) value).getType();
+            final FeatureType base = role.getValueType();
+            if (base != valueType && DefaultFeatureType.maybeAssignableFrom(base, valueType)) {
                 return isSingleton ? value : singletonList(AbstractFeature.class, role.getMinimumOccurs(), value);
             } else {
                 throw illegalPropertyType(role.getName(), valueType.getName());
@@ -494,15 +481,15 @@ public abstract class AbstractFeature im
      * Verifies if all values in the given collection are valid instances of feature for the given association role.
      */
     private static void verifyAssociationValues(final DefaultAssociationRole role, final Collection<?> values) {
-        final DefaultFeatureType base = role.getValueType();
+        final FeatureType base = role.getValueType();
         int index = 0;
         for (final Object value : values) {
             ArgumentChecks.ensureNonNullElement("values", index, value);
             if (!(value instanceof AbstractFeature)) {
                 throw illegalValueClass(role.getName(), value);
             }
-            final DefaultFeatureType type = ((AbstractFeature) value).getType();
-            if (!base.maybeAssignableFrom(type)) {
+            final FeatureType type = ((AbstractFeature) value).getType();
+            if (base != type && !DefaultFeatureType.maybeAssignableFrom(base, type)) {
                 throw illegalPropertyType(role.getName(), type.getName());
             }
             index++;
@@ -595,8 +582,8 @@ public abstract class AbstractFeature im
      */
     public DataQuality quality() {
         final Validator v = new Validator(ScopeCode.FEATURE);
-        for (final String name : type.indices().keySet()) {
-            final Property property = (Property) getProperty(name);
+        for (final PropertyType pt : type.getProperties(true)) {
+            final Property property = (Property) getProperty(pt.getName().toString());
             final DataQuality quality;
             if (property instanceof AbstractAttribute<?>) {
                 quality = ((AbstractAttribute<?>) property).quality();

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -26,6 +26,7 @@ import static org.apache.sis.util.Argume
 // Branch-dependent imports
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -63,7 +64,7 @@ public class DefaultAssociationRole exte
      *
      * @see #getValueType()
      */
-    private final DefaultFeatureType valueType;
+    private final FeatureType valueType;
 
     /**
      * The name of the property to use as a title for the associated feature, or an empty string if none.
@@ -114,7 +115,7 @@ public class DefaultAssociationRole exte
      * @param maximumOccurs  The maximum number of occurrences of the association within its containing entity,
      *                       or {@link Integer#MAX_VALUE} if there is no restriction.
      */
-    public DefaultAssociationRole(final Map<String,?> identification, final DefaultFeatureType valueType,
+    public DefaultAssociationRole(final Map<String,?> identification, final FeatureType valueType,
             final int minimumOccurs, final int maximumOccurs)
     {
         super(identification, minimumOccurs, maximumOccurs);
@@ -130,7 +131,7 @@ public class DefaultAssociationRole exte
      *
      * @return The type of feature values.
      */
-    public final DefaultFeatureType getValueType() {
+    public final FeatureType getValueType() {
         return valueType;
     }
 
@@ -142,7 +143,7 @@ public class DefaultAssociationRole exte
         String p = titleProperty; // No synchronization - not a big deal if computed twice.
         if (p == null) {
             p = "";
-            for (final PropertyType type : valueType.getPropertyTypes(true)) {
+            for (final PropertyType type : valueType.getProperties(true)) {
                 if (type instanceof AttributeType<?>) {
                     final AttributeType<?> pt = (AttributeType<?>) type;
                     if (pt.getMaximumOccurs() != 0 && CharSequence.class.isAssignableFrom(pt.getValueClass())) {

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -23,7 +23,6 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.IdentityHashMap;
 import java.util.Collection;
 import java.util.Collections;
 import java.io.IOException;
@@ -37,8 +36,10 @@ import org.apache.sis.internal.util.Coll
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 // Branch-dependent imports
+import java.util.Objects;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -49,18 +50,13 @@ import org.opengis.feature.AttributeType
  * compared to the Java language, {@code FeatureType} is equivalent to {@link Class} while
  * {@code Feature} instances are equivalent to {@link Object} instances of that class.</div>
  *
- * <div class="warning"><b>Warning:</b>
- * This class is expected to implement a GeoAPI {@code FeatureType} interface in a future version.
- * When such interface will be available, most references to {@code DefaultFeatureType} in the API
- * will be replaced by references to the {@code FeatureType} interface.</div>
- *
  * {@section Naming}
  * The feature type {@linkplain #getName() name} is mandatory and should be unique. Those names are the main
  * criterion used for deciding if a feature type {@linkplain #isAssignableFrom is assignable from} another type.
  * Names can be {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped} for avoiding name collision.
  *
  * {@section Properties and inheritance}
- * Each feature type can provide descriptions for the following {@linkplain #getPropertyTypes(boolean) properties}:
+ * Each feature type can provide descriptions for the following {@linkplain #getProperties(boolean) properties}:
  *
  * <ul>
  *   <li>{@linkplain DefaultAttributeType    Attributes}</li>
@@ -91,7 +87,7 @@ import org.opengis.feature.AttributeType
  *
  * @see AbstractFeature
  */
-public class DefaultFeatureType extends AbstractIdentifiedType {
+public class DefaultFeatureType extends AbstractIdentifiedType implements FeatureType {
     /**
      * For cross-version compatibility.
      */
@@ -123,13 +119,13 @@ public class DefaultFeatureType extends 
      *
      * @see #getSuperTypes()
      */
-    private final Set<DefaultFeatureType> superTypes;
+    private final Set<FeatureType> superTypes;
 
     /**
-     * The names of all parents of this feature type, including parents of parents. This is used
-     * for a more efficient implementation of {@link #isAssignableFrom(DefaultFeatureType)}.
+     * The names of all parents of this feature type, including parents of parents.
+     * This is used for a more efficient implementation of {@link #isAssignableFrom(FeatureType)}.
      *
-     * @see #isAssignableFrom(DefaultFeatureType)
+     * @see #isAssignableFrom(FeatureType)
      */
     private transient Set<GenericName> assignableTo;
 
@@ -137,7 +133,7 @@ public class DefaultFeatureType extends 
      * Any feature operation, any feature attribute type and any feature association role
      * that carries characteristics of a feature type.
      *
-     * @see #getPropertyTypes(boolean)
+     * @see #getProperties(boolean)
      */
     private final List<PropertyType> properties;
 
@@ -145,7 +141,7 @@ public class DefaultFeatureType extends 
      * All properties, including the ones declared in the super-types.
      * This is an unmodifiable view of the {@link #byName} values.
      *
-     * @see #getPropertyTypes(boolean)
+     * @see #getProperties(boolean)
      */
     private transient Collection<PropertyType> allProperties;
 
@@ -207,13 +203,13 @@ public class DefaultFeatureType extends 
      *                       association role that carries characteristics of a feature type.
      */
     public DefaultFeatureType(final Map<String,?> identification, final boolean isAbstract,
-            final DefaultFeatureType[] superTypes, final PropertyType... properties)
+            final FeatureType[] superTypes, final PropertyType... properties)
     {
         super(identification);
         ArgumentChecks.ensureNonNull("properties", properties);
         this.isAbstract = isAbstract;
-        this.superTypes = (superTypes == null) ? Collections.<DefaultFeatureType>emptySet() :
-                          CollectionsExt.<DefaultFeatureType>immutableSet(true, superTypes);
+        this.superTypes = (superTypes == null) ? Collections.<FeatureType>emptySet() :
+                          CollectionsExt.<FeatureType>immutableSet(true, superTypes);
         switch (properties.length) {
             case 0:  this.properties = Collections.emptyList(); break;
             case 1:  this.properties = Collections.singletonList(properties[0]); break;
@@ -318,28 +314,23 @@ public class DefaultFeatureType extends 
      * This method invokes itself recursively in order to use the information provided in super-types.
      * This method also performs an opportunist verification of argument validity.
      */
-    private void scanPropertiesFrom(final DefaultFeatureType source) {
-        for (final DefaultFeatureType parent : source.getSuperTypes()) {
+    private void scanPropertiesFrom(final FeatureType source) {
+        for (final FeatureType parent : source.getSuperTypes()) {
             if (assignableTo.add(parent.getName())) {
                 scanPropertiesFrom(parent);
             }
         }
         int index = -1;
-        Map<DefaultFeatureType,Boolean> done = null;
-        for (final PropertyType property : source.properties) {
+        for (final PropertyType property : source.getProperties(false)) {
             ArgumentChecks.ensureNonNullElement("properties", ++index, property);
             final String name = toString(property.getName(), source, index);
             final PropertyType previous = byName.put(name, property);
             if (previous != null) {
-                if (done == null) {
-                    done = new IdentityHashMap<>(4); // Guard against infinite recursivity.
-                }
-                if (!isAssignableIgnoreName(previous, property, done)) {
-                    final GenericName owner = ownerOf(previous);
+                if (!isAssignableIgnoreName(previous, property)) {
+                    final GenericName owner = ownerOf(this, previous);
                     throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyAlreadyExists_2,
                             (owner != null) ? owner : "?", name));
                 }
-                done.clear();
             }
         }
     }
@@ -349,12 +340,12 @@ public class DefaultFeatureType extends 
      * This method is for information purpose when producing an error message - its implementation does
      * not need to be efficient.
      */
-    private GenericName ownerOf(final PropertyType property) {
-        if (properties.contains(property)) {
-            return getName();
+    private static GenericName ownerOf(final FeatureType type, final PropertyType property) {
+        if (type.getProperties(false).contains(property)) {
+            return type.getName();
         }
-        for (final DefaultFeatureType type : superTypes) {
-            final GenericName owner = type.ownerOf(property);
+        for (final FeatureType superType : type.getSuperTypes()) {
+            final GenericName owner = ownerOf(superType, property);
             if (owner != null) {
                 return owner;
             }
@@ -370,7 +361,7 @@ public class DefaultFeatureType extends 
      * @param source The feature which contains the property (typically {@code this}).
      * @param index  Index of the property having the given name.
      */
-    private String toString(final GenericName name, final DefaultFeatureType source, final int index) {
+    private String toString(final GenericName name, final FeatureType source, final int index) {
         short key = Errors.Keys.MissingValueForProperty_1;
         if (name != null) {
             final String s = name.toString();
@@ -397,6 +388,7 @@ public class DefaultFeatureType extends 
      *
      * @return {@code true} if the feature type acts as an abstract super-type.
      */
+    @Override
     public final boolean isAbstract() {
         return isAbstract;
     }
@@ -415,16 +407,31 @@ public class DefaultFeatureType extends 
      *
      * @return {@code true} if this feature type contains only simple attributes or operations.
      */
+    @Override
     public boolean isSimple() {
         return isSimple;
     }
 
     /**
-     * Returns {@code true} if this type may be the same or a super-type of the given type, using only
-     * the name as a criterion. This is a faster check than {@link #isAssignableFrom(DefaultFeatureType)}
+     * Returns {@code true} if the given base type may be the same or a super-type of the given type, using only
+     * the name as a criterion. This is a faster check than {@link #isAssignableFrom(FeatureType)}.
+     *
+     * <p>Performance note: callers should verify that {@code base != type} before to invoke this method.</p>
      */
-    final boolean maybeAssignableFrom(final DefaultFeatureType type) {
-        return type.assignableTo.contains(getName());
+    static boolean maybeAssignableFrom(final FeatureType base, final FeatureType type) {
+        if (type instanceof DefaultFeatureType) {
+            return ((DefaultFeatureType) type).assignableTo.contains(base.getName());
+        }
+        // Slower path for non-SIS implementations.
+        if (Objects.equals(base.getName(), type.getName())) {
+            return true;
+        }
+        for (final FeatureType superType : type.getSuperTypes()) {
+            if (base == superType || maybeAssignableFrom(base, superType)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -440,32 +447,35 @@ public class DefaultFeatureType extends 
      * @param  type The type to be checked.
      * @return {@code true} if instances of the given type can be assigned to association of this type.
      */
-    public boolean isAssignableFrom(final DefaultFeatureType type) {
+    @Override
+    public boolean isAssignableFrom(final FeatureType type) {
         if (type == this) {
             return true; // Optimization for a common case.
         }
         ArgumentChecks.ensureNonNull("type", type);
-        return maybeAssignableFrom(type) && isAssignableIgnoreName(type, new IdentityHashMap<>(4));
-    }
-
-    /**
-     * Return {@code true} if all properties in this type are also properties in the given type.
-     * This method does not compare the names — this verification is presumed already done by the caller.
-     *
-     * @param type The type to check.
-     * @param done An initially empty map to be used for avoiding infinite recursivity.
-     */
-    private boolean isAssignableIgnoreName(final DefaultFeatureType type, final Map<DefaultFeatureType,Boolean> done) {
-        if (done.put(this, Boolean.TRUE) == null) {
-            /*
-             * Ensures that all properties defined in this feature type is also defined
-             * in the given property, and that the former is assignable from the later.
-             */
-            for (final Map.Entry<String, PropertyType> entry : byName.entrySet()) {
-                final PropertyType other = type.getProperty(entry.getKey());
-                if (other == null || !isAssignableIgnoreName(entry.getValue(), other, done)) {
-                    return false;
-                }
+        if (!maybeAssignableFrom(this, type)) {
+            return false;
+        }
+        /*
+         * Ensures that all properties defined in this feature type is also defined
+         * in the given property, and that the former is assignable from the later.
+         */
+        for (final Map.Entry<String, PropertyType> entry : byName.entrySet()) {
+            final PropertyType other;
+            try {
+                other = type.getProperty(entry.getKey());
+            } catch (IllegalArgumentException e) {
+                /*
+                 * A property in this FeatureType does not exist in the given FeatureType.
+                 * Catching exceptions is not an efficient way to perform this check, but
+                 * actually this case should be rare because we verified before this loop
+                 * that the names match. If the names are unique (as recommended), then
+                 * this exception should never happen.
+                 */
+                return false;
+            }
+            if (!isAssignableIgnoreName(entry.getValue(), other)) {
+                return false;
             }
         }
         return true;
@@ -475,14 +485,8 @@ public class DefaultFeatureType extends 
      * Returns {@code true} if instances of the {@code other} type are assignable to the given {@code base} type.
      * This method does not compare the names — this verification is presumed already done by the caller.
      */
-    private static boolean isAssignableIgnoreName(final PropertyType base, final PropertyType other,
-            final Map<DefaultFeatureType,Boolean> done)
-    {
+    private static boolean isAssignableIgnoreName(final PropertyType base, final PropertyType other) {
         if (base != other) {
-            /*
-             * TODO: DefaultAssociationRole to be replaced by GeoAPI interfaces
-             *       (pending GeoAPI review).
-             */
             if (base instanceof AttributeType<?>) {
                 if (!(other instanceof AttributeType<?>)) {
                     return false;
@@ -507,10 +511,12 @@ public class DefaultFeatureType extends 
                 {
                     return false;
                 }
-                final DefaultFeatureType f0 = p0.getValueType();
-                final DefaultFeatureType f1 = p1.getValueType();
-                if (!f0.maybeAssignableFrom(f1) || !f0.isAssignableIgnoreName(f1, done)) {
-                    return false;
+                final FeatureType f0 = p0.getValueType();
+                final FeatureType f1 = p1.getValueType();
+                if (f0 != f1) {
+                    if (!f0.isAssignableFrom(f1)) {
+                        return false;
+                    }
                 }
             }
         }
@@ -530,7 +536,8 @@ public class DefaultFeatureType extends 
      *
      * @return The parents of this feature type, or an empty set if none.
      */
-    public Set<DefaultFeatureType> getSuperTypes() {
+    @Override
+    public Set<FeatureType> getSuperTypes() {
         return superTypes;
     }
 
@@ -545,7 +552,8 @@ public class DefaultFeatureType extends 
      * @return Feature operation, attribute type and association role that carries characteristics of this
      *         feature type (not including parent types).
      */
-    public Collection<PropertyType> getPropertyTypes(final boolean includeSuperTypes) {
+    @Override
+    public Collection<PropertyType> getProperties(final boolean includeSuperTypes) {
         return includeSuperTypes ? allProperties : properties;
     }
 
@@ -554,9 +562,15 @@ public class DefaultFeatureType extends 
      *
      * @param  name The name of the property to search.
      * @return The property for the given name, or {@code null} if none.
+     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
      */
-    final PropertyType getProperty(final String name) {
-        return byName.get(name);
+    @Override
+    public PropertyType getProperty(final String name) throws IllegalArgumentException {
+        final PropertyType pt = byName.get(name);
+        if (pt != null) {
+            return pt;
+        }
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -219,7 +219,7 @@ final class DenseFeature extends Abstrac
         if (properties != null && !(properties instanceof Property[])) {
             final Validator v = new Validator(ScopeCode.FEATURE);
             for (final Map.Entry<String, Integer> entry : indices.entrySet()) {
-                v.validateAny(getPropertyType(entry.getKey()), properties[entry.getValue()]);
+                v.validateAny(type.getProperty(entry.getKey()), properties[entry.getValue()]);
             }
             return v.quality;
         }

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -36,6 +36,7 @@ import org.apache.sis.util.resources.Voc
 import org.opengis.feature.IdentifiedType;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -153,13 +154,13 @@ public class FeatureFormat extends Tabul
     public void format(final Object object, final Appendable toAppendTo) throws IOException {
         ArgumentChecks.ensureNonNull("object",     object);
         ArgumentChecks.ensureNonNull("toAppendTo", toAppendTo);
-        final DefaultFeatureType featureType;
-        final AbstractFeature     feature;
+        final FeatureType featureType;
+        final AbstractFeature feature;
         if (object instanceof AbstractFeature) {
             feature     = (AbstractFeature) object;
             featureType = feature.getType();
-        } else if (object instanceof DefaultFeatureType) {
-            featureType = (DefaultFeatureType) object;
+        } else if (object instanceof FeatureType) {
+            featureType = (FeatureType) object;
             feature     = null;
         } else {
             throw new IllegalArgumentException(Errors.getResources(displayLocale)
@@ -189,7 +190,7 @@ header: for (int i=0; ; i++) {
          * Done writing the header. Now write all property rows.
          * Rows without value will be skipped only if optional.
          */
-        for (final PropertyType propertyType : featureType.getPropertyTypes(true)) {
+        for (final PropertyType propertyType : featureType.getProperties(true)) {
             Object value;
             if (feature != null) {
                 value = feature.getPropertyValue(propertyType.getName().toString());

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?rev=1598371&r1=1598370&r2=1598371&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] Thu May 29 19:03:14 2014
@@ -21,6 +21,9 @@ import org.apache.sis.internal.util.Chec
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
+// Branch-dependent imports
+import org.opengis.feature.FeatureType;
+
 
 /**
  * An instance of an {@linkplain DefaultAssociationRole association role} containing an arbitrary amount of values.
@@ -129,7 +132,7 @@ final class MultiValuedAssociation exten
     @Override
     public void setValues(final Collection<? extends AbstractFeature> values) {
         ArgumentChecks.ensureNonNull("values", values);
-        final DefaultFeatureType base = role.getValueType();
+        final FeatureType base = role.getValueType();
         this.values.clear();
         for (final AbstractFeature value : values) {
             ensureValid(base, value.getType());

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -25,6 +25,10 @@ import org.apache.sis.internal.util.Clon
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CorruptedObjectException;
 
+// Branch-dependent imports
+import org.opengis.feature.PropertyType;
+import org.opengis.feature.FeatureType;
+
 
 /**
  * A feature in which only a small fraction of properties are expected to be provided. This implementation uses
@@ -89,7 +93,7 @@ final class SparseFeature extends Abstra
      *
      * @param type Information about the feature (name, characteristics, <i>etc.</i>).
      */
-    public SparseFeature(final DefaultFeatureType type) {
+    public SparseFeature(final FeatureType type) {
         super(type);
         properties = new HashMap<>();
     }
@@ -248,8 +252,8 @@ final class SparseFeature extends Abstra
     public DataQuality quality() {
         if (valuesKind == VALUES) {
             final Validator v = new Validator(ScopeCode.FEATURE);
-            for (final String name : type.indices().keySet()) {
-                v.validateAny(getPropertyType(name), properties.get(name));
+            for (final PropertyType pt : type.getProperties(true)) {
+                v.validateAny(pt, properties.get(pt.getName().toString()));
             }
             return v.quality;
         }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java?rev=1598371&r1=1598370&r2=1598371&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java [UTF-8] Thu May 29 19:03:14 2014
@@ -34,6 +34,7 @@ import org.apache.sis.util.resources.Err
 // Branch-dependent imports
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -147,7 +148,7 @@ final class Validator {
     void validate(final DefaultAssociationRole role, final Collection<?> values) {
         AbstractElement report = null;
         for (final Object value : values) {
-            final DefaultFeatureType type = ((AbstractFeature) value).getType();
+            final FeatureType type = ((AbstractFeature) value).getType();
             if (!role.getValueType().isAssignableFrom(type)) {
                 report = addViolationReport(report, role, Errors.formatInternational(
                         Errors.Keys.IllegalPropertyClass_2, role.getName(), type.getName()));

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=1598371&r1=1598370&r2=1598371&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] Thu May 29 19:03:14 2014
@@ -26,7 +26,7 @@
  *       {@linkplain org.apache.sis.feature.DefaultAttributeType attributes},
  *       {@linkplain org.apache.sis.feature.DefaultOperation operations} or
  *       {@linkplain org.apache.sis.feature.DefaultAssociationRole associations to other features}
- *       (collectively called “{@linkplain org.apache.sis.feature.DefaultFeatureType#getPropertyTypes(boolean) properties}”
+ *       (collectively called “{@linkplain org.apache.sis.feature.DefaultFeatureType#getProperties(boolean) properties}”
  *       or “characteristics”) that a feature can have.</p>
  *
  *       <div class="note"><b>Analogy:</b> a {@code FeatureType} in a Spatial Information System is equivalent to a

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java?rev=1598371&r1=1598370&r2=1598371&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java [UTF-8] Thu May 29 19:03:14 2014
@@ -152,8 +152,8 @@ public final strictfp class DefaultFeatu
      */
     private static void assertUnmodifiable(final DefaultFeatureType feature) {
         final Collection<?> superTypes         = feature.getSuperTypes();
-        final Collection<?> declaredProperties = feature.getPropertyTypes(false);
-        final Collection<?> allProperties      = feature.getPropertyTypes(true);
+        final Collection<?> declaredProperties = feature.getProperties(false);
+        final Collection<?> allProperties      = feature.getProperties(true);
         if (!superTypes.isEmpty()) try {
             superTypes.clear();
             fail("Super-types collection shall not be modifiable.");
@@ -182,7 +182,7 @@ public final strictfp class DefaultFeatu
      * This method tests the following {@code FeatureType} methods:
      *
      * <ul>
-     *   <li>{@link DefaultFeatureType#getPropertyTypes(boolean)}</li>
+     *   <li>{@link DefaultFeatureType#getProperties(boolean)}</li>
      *   <li>{@link DefaultFeatureType#getProperty(String)}</li>
      * </ul>
      *
@@ -195,7 +195,7 @@ public final strictfp class DefaultFeatu
             final String... expected)
     {
         int index = 0;
-        for (final PropertyType property : feature.getPropertyTypes(includeSuperTypes)) {
+        for (final PropertyType property : feature.getProperties(includeSuperTypes)) {
             assertTrue("Found more properties than expected.", index < expected.length);
             final String name = expected[index++];
             assertNotNull(name, property);
@@ -203,7 +203,14 @@ public final strictfp class DefaultFeatu
             assertSame   (name, property, feature.getProperty(name));
         }
         assertEquals("Unexpected number of properties.", expected.length, index);
-        assertNull("Shall not found a non-existent property.", feature.getProperty("apple"));
+        try {
+            feature.getProperty("apple");
+            fail("Shall not found a non-existent property.");
+        } catch (IllegalArgumentException e) {
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("apple"));
+            assertTrue(message, message.contains(feature.getName().toString()));
+        }
     }
 
     /**
@@ -261,7 +268,7 @@ public final strictfp class DefaultFeatu
                 false, null, city, population, festival);
 
         assertUnmodifiable(complex);
-        final Collection<PropertyType> properties = complex.getPropertyTypes(false);
+        final Collection<PropertyType> properties = complex.getProperties(false);
         final Iterator<PropertyType> it = properties.iterator();
 
         assertEquals("name",            "Festival",                     complex.getName().toString());
@@ -327,8 +334,8 @@ public final strictfp class DefaultFeatu
         assertPropertiesEquals(capital, true,  "city", "population", "parliament");
 
         // Check based only on name.
-        assertTrue ("maybeAssignableFrom", city.maybeAssignableFrom(capital));
-        assertFalse("maybeAssignableFrom", capital.maybeAssignableFrom(city));
+        assertTrue ("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(city, capital));
+        assertFalse("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(capital, city));
 
         // Public API.
         assertTrue ("isAssignableFrom", city.isAssignableFrom(capital));
@@ -363,10 +370,10 @@ public final strictfp class DefaultFeatu
                 ((DefaultAttributeType) metroCapital.getProperty("region")).getValueClass());
 
         // Check based only on name.
-        assertTrue ("maybeAssignableFrom", capital.maybeAssignableFrom(metroCapital));
-        assertFalse("maybeAssignableFrom", metroCapital.maybeAssignableFrom(capital));
-        assertTrue ("maybeAssignableFrom", metropolis.maybeAssignableFrom(metroCapital));
-        assertFalse("maybeAssignableFrom", metroCapital.maybeAssignableFrom(metropolis));
+        assertTrue ("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(capital, metroCapital));
+        assertFalse("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(metroCapital, capital));
+        assertTrue ("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(metropolis, metroCapital));
+        assertFalse("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(metroCapital, metropolis));
 
         // Public API.
         assertTrue ("isAssignableFrom", capital.isAssignableFrom(metroCapital));
@@ -406,8 +413,8 @@ public final strictfp class DefaultFeatu
                 ((DefaultAttributeType) worldMetropolis.getProperty("region")).getValueClass());
 
         // Check based only on name.
-        assertTrue ("maybeAssignableFrom", metropolis.maybeAssignableFrom(worldMetropolis));
-        assertFalse("maybeAssignableFrom", worldMetropolis.maybeAssignableFrom(metropolis));
+        assertTrue ("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(metropolis, worldMetropolis));
+        assertFalse("maybeAssignableFrom", DefaultFeatureType.maybeAssignableFrom(worldMetropolis, metropolis));
 
         // Public API.
         assertTrue ("isAssignableFrom", metropolis.isAssignableFrom(worldMetropolis));

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java?rev=1598371&r1=1598370&r2=1598371&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] Thu May 29 19:03:14 2014
@@ -32,6 +32,9 @@ import org.junit.Test;
 import static org.apache.sis.test.Assert.*;
 import static java.util.Collections.singletonMap;
 
+// Branch-dependent imports
+import org.opengis.feature.FeatureType;
+
 
 /**
  * Tests common to {@link DenseFeatureTest} and {@link SparseFeatureTest}.
@@ -64,10 +67,10 @@ public abstract strictfp class FeatureTe
      */
     static AbstractFeature twinTown(final boolean isSparse) {
         final DefaultAssociationRole twinTown = DefaultAssociationRoleTest.twinTown();
-        final DefaultFeatureType     city     = twinTown.getValueType();
+        final FeatureType            city     = twinTown.getValueType();
         final DefaultFeatureType     type     = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Twin town"), false,
-                new DefaultFeatureType[] {city}, twinTown);
+                new FeatureType[] {city}, twinTown);
 
         final AbstractFeature leMans = isSparse ? new SparseFeature(type) : new DenseFeature(type);
         leMans.setPropertyValue("city", "Le Mans");



Mime
View raw message