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");


Reply via email to