You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2016/11/23 13:56:17 UTC

svn commit: r1770970 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/CharacteristicTypeMap.java main/java/org/apache/sis/feature/DefaultFeatureType.java test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java

Author: desruisseaux
Date: Wed Nov 23 13:56:17 2016
New Revision: 1770970

URL: http://svn.apache.org/viewvc?rev=1770970&view=rev
Log:
Attribute.characteristics().get(String) should accept short names (i.e. allow the scope to be omitted when there is no ambiguity).
This is the same mechanism than the one already used by FeatureType. Opportunistically generalize the search for shorter names.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java?rev=1770970&r1=1770969&r2=1770970&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] Wed Nov 23 13:56:17 2016
@@ -18,6 +18,8 @@ package org.apache.sis.feature;
 
 import java.util.Map;
 import java.util.HashMap;
+import org.opengis.util.ScopedName;
+import org.opengis.util.GenericName;
 import org.apache.sis.internal.util.AbstractMap;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.collection.Containers;
@@ -45,7 +47,7 @@ import org.opengis.feature.AttributeType
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.8
  * @module
  */
 final class CharacteristicTypeMap extends AbstractMap<String,AttributeType<?>> {
@@ -81,9 +83,9 @@ final class CharacteristicTypeMap extend
      * <p>This method does not clone the {@code characterizedBy} array. If that array
      * is a user-provided argument, then cloning that array is caller responsibility.</p>
      *
-     * @param  source The attribute which is characterized by {@code characterizedBy}.
-     * @param  characterizedBy Characteristics of {@code source}. Should not be empty.
-     * @return A map for this given characteristics.
+     * @param  source  the attribute which is characterized by {@code characterizedBy}.
+     * @param  characterizedBy  characteristics of {@code source}. Should not be empty.
+     * @return a map for this given characteristics.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
     static CharacteristicTypeMap create(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
@@ -104,20 +106,47 @@ final class CharacteristicTypeMap extend
      * <p>This constructor does not clone the {@code characterizedBy} array. If that array
      * is a user-provided argument, then cloning that array is caller responsibility.</p>
      *
-     * @param  source The attribute which is characterized by {@code characterizedBy}.
-     * @param  characterizedBy Characteristics of {@code source}. Should not be empty.
+     * @param  source  the attribute which is characterized by {@code characterizedBy}.
+     * @param  characterizedBy  characteristics of {@code source}. Should not be empty.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
     private CharacteristicTypeMap(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
         this.characterizedBy = characterizedBy;
         int index = 0;
         final Map<String,Integer> indices = new HashMap<>(Containers.hashMapCapacity(characterizedBy.length));
+        final Map<String,Integer> aliases = new HashMap<>();
         for (int i=0; i<characterizedBy.length; i++) {
             final AttributeType<?> attribute = characterizedBy[i];
             ensureNonNullElement("characterizedBy", i, attribute);
-            final String name = AbstractIdentifiedType.toString(attribute.getName(), source, "characterizedBy", i);
-            if (indices.put(name, index++) != null) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedIdentifier_1, name));
+            GenericName name = attribute.getName();
+            String key = AbstractIdentifiedType.toString(name, source, "characterizedBy", i);
+            final Integer value = index++;
+            if (indices.put(key, value) != null) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedIdentifier_1, key));
+            }
+            /*
+             * If some characteristics use long name of the form "head:tip", creates short aliases containing
+             * only the "tip" name for convenience, provided that it does not create ambiguity. If an alias
+             * could map to two or more characteristics, then that alias is not added. Those ambiguous aliases
+             * are identified by the -1 value in the 'aliases' map.
+             */
+            while (name instanceof ScopedName) {
+                if (name == (name = ((ScopedName) name).tail())) break;   // Safety against broken implementations.
+                key = name.toString();
+                if (key == null || (key = key.trim()).isEmpty()) break;   // Safety against broken implementations.
+                if (aliases.put(key, value) != null) {
+                    aliases.put(key, -1);
+                }
+            }
+        }
+        /*
+         * Copy the aliases only after we finished to create the list of all fully-qualified names.
+         * The copy operation shall exclude all ambiguous names.
+         */
+        for (final Map.Entry<String,Integer> entry : aliases.entrySet()) {
+            final Integer value = entry.getValue();
+            if (value >= 0) {
+                indices.putIfAbsent(entry.getKey(), value);
             }
         }
         this.indices = CollectionsExt.compact(indices);

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=1770970&r1=1770969&r2=1770970&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] Wed Nov 23 13:56:17 2016
@@ -26,10 +26,11 @@ import java.util.IdentityHashMap;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.Objects;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import org.opengis.util.NameFactory;
-import org.opengis.util.LocalName;
+import org.opengis.util.ScopedName;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.parameter.ParameterDescriptorGroup;
@@ -40,7 +41,6 @@ import org.apache.sis.internal.util.Unmo
 import org.apache.sis.internal.feature.Resources;
 
 // Branch-dependent imports
-import java.util.Objects;
 import org.opengis.feature.IdentifiedType;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.AttributeType;
@@ -387,19 +387,18 @@ public class DefaultFeatureType extends
         /*
          * If some properties use long name of the form "head:tip", creates short aliases containing only the "tip"
          * name for convenience, provided that it does not create ambiguity.  If a short alias could map to two or
-         * more properties, then this alias is not added.
+         * more properties, then that alias is not added.
          *
          * In the 'aliases' map below, null values will be assigned to ambiguous short names.
          */
         final Map<String, PropertyType> aliases = new LinkedHashMap<>();
         for (final PropertyType property : allProperties) {
-            final GenericName name = property.getName();
-            final LocalName tip = name.tip();
-            if (tip != name) {                                          // Slight optimization for a common case.
-                final String key = tip.toString();
-                if (key != null && !key.isEmpty() && !key.equals(name.toString())) {
-                    aliases.put(key, aliases.containsKey(key) ? null : property);
-                }
+            GenericName name = property.getName();
+            while (name instanceof ScopedName) {
+                if (name == (name = ((ScopedName) name).tail())) break;   // Safety against broken implementations.
+                String key = name.toString();
+                if (key == null || (key = key.trim()).isEmpty()) break;   // Safety against broken implementations.
+                aliases.put(key, aliases.containsKey(key) ? null : property);
             }
         }
         for (final Map.Entry<String,PropertyType> entry : aliases.entrySet()) {
@@ -411,7 +410,7 @@ public class DefaultFeatureType extends
                     // The 'indices' value may be null if the property is an operation.
                     final Integer value = indices.get(property.getName().toString());
                     if (value != null && indices.put(tip, value) != null) {
-                        throw new AssertionError(tip);  // Should never happen.
+                        throw new AssertionError(tip);                                  // Should never happen.
                     }
                 }
             }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java?rev=1770970&r1=1770969&r2=1770970&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java [UTF-8] Wed Nov 23 13:56:17 2016
@@ -28,6 +28,7 @@ import static org.apache.sis.test.Assert
 
 // Branch-dependent imports
 import org.opengis.feature.AttributeType;
+import org.apache.sis.util.iso.Names;
 
 
 /**
@@ -35,7 +36,7 @@ import org.opengis.feature.AttributeType
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.8
  * @module
  */
 @DependsOn(DefaultAttributeTypeTest.class)
@@ -109,4 +110,24 @@ public final strictfp class Characterist
         assertNotSame(temperature, unserialized);
         assertSame(temperature.characteristics(), unserialized.characteristics());
     }
+
+    /**
+     * Tests usage of names in namespaces.
+     */
+    @Test
+    public void testQualifiedNames() {
+        final DefaultAttributeType<?> a1, a2, a3, tp;
+        a1 = new DefaultAttributeType<>(singletonMap(NAME_KEY, Names.parseGenericName(null, null, "ns1:accuracy")), Float.class, 1, 1, 0.1f);
+        a2 = new DefaultAttributeType<>(singletonMap(NAME_KEY, Names.parseGenericName(null, null, "ns2:accuracy")), Float.class, 1, 1, 0.1f);
+        a3 = new DefaultAttributeType<>(singletonMap(NAME_KEY, Names.parseGenericName(null, null, "ns2:s3:units")), String.class, 1, 1, "�C");
+        tp = new DefaultAttributeType<>(singletonMap(NAME_KEY, "temperature"), Float.class, 1, 1, null, a1, a2, a3);
+
+        final Map<String, AttributeType<?>> characteristics = tp.characteristics();
+        assertSame("ns1:accuracy", a1, characteristics.get("ns1:accuracy"));
+        assertSame("ns2:accuracy", a2, characteristics.get("ns2:accuracy"));
+        assertSame("ns2:s3:units", a3, characteristics.get("ns2:s3:units"));
+        assertSame(    "s3:units", a3, characteristics.get(    "s3:units"));
+        assertSame(       "units", a3, characteristics.get(       "units"));
+        assertNull("    accuracy",     characteristics.get("    accuracy"));        // Because ambiguous.
+    }
 }