sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1418613 [1/2] - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util: ./ collection/ resources/ type/
Date Sat, 08 Dec 2012 07:40:18 GMT
Author: desruisseaux
Date: Sat Dec  8 07:40:17 2012
New Revision: 1418613

URL: http://svn.apache.org/viewvc?rev=1418613&view=rev
Log:
Ported AbstractName and sub-classes.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameSpace.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultScopedName.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultTypeName.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/GlobalNameSpace.java   (with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java Sat Dec  8 07:40:17 2012
@@ -43,6 +43,7 @@ import org.apache.sis.util.resources.Err
  *     {@link #ensurePositive(String, int) ensurePositive},
  *     {@link #ensureStrictlyPositive(String, int) ensureStrictlyPositive},
  *     {@link #ensureBetween(String, int, int, int) ensureBetween},
+ *     {@link #ensureSizeBetween(String, int, int, int) ensureBetween},
  *     {@link #ensureCanCast(String, Class, Object) ensureCanCast}.
  *   </td>
  * </tr><tr>
@@ -89,7 +90,7 @@ public final class ArgumentChecks extend
      * Makes sure that an argument is non-null. If the given {@code object} is null, then a
      * {@link NullArgumentException} is thrown with a localized message containing the given name.
      *
-     * @param  name The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name The name of the argument to be checked. Used only if an exception is thrown.
      * @param  object The user argument to check against null value.
      * @throws NullArgumentException if {@code object} is null.
      */
@@ -102,21 +103,19 @@ public final class ArgumentChecks extend
     }
 
     /**
-     * Makes sure that an array element is non-null. If {@code array[index]} is null, then a
-     * {@link NullArgumentException} is thrown with a localized message containing the given name.
-     *
-     * @param  name The name of the argument to be checked. Used only in case an exception is thrown.
-     * @param  index Index of the element to check.
-     * @param  array The user argument to check against null element.
-     * @throws NullArgumentException if {@code array} or {@code array[index]} is null.
+     * Makes sure that an array element is non-null. If {@code element} is null, then a
+     * {@link NullArgumentException} is thrown with a localized message containing the
+     * given name and index.
+     *
+     * @param  name    The name of the argument to be checked. Used only if an exception is thrown.
+     * @param  index   The Index of the element to check in an array or a list. Used only if an exception is thrown.
+     * @param  element The array or list element to check against null null.
+     * @throws NullArgumentException if {@code element} is null.
      */
-    public static void ensureNonNull(final String name, final int index, final Object[] array)
+    public static void ensureNonNullElement(final String name, final int index, final Object element)
             throws NullArgumentException
     {
-        if (array == null) {
-            throw new NullArgumentException(Errors.format(Errors.Keys.NullArgument_1, name));
-        }
-        if (array[index] == null) {
+        if (element == null) {
             throw new NullArgumentException(Errors.format(
                     Errors.Keys.NullArgument_1, name + '[' + index + ']'));
         }
@@ -128,7 +127,7 @@ public final class ArgumentChecks extend
      * a {@linkplain CharSequence#length() length} equals to 0, then an {@link IllegalArgumentException}
      * is thrown.
      *
-     * @param  name The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name The name of the argument to be checked. Used only if an exception is thrown.
      * @param  text The user argument to check against null value and empty sequences.
      * @throws NullArgumentException if {@code text} is null.
      * @throws IllegalArgumentException if {@code text} is empty.
@@ -210,7 +209,7 @@ public final class ArgumentChecks extend
      * @throws IndexOutOfBoundsException If the given [{@code lower} … {@code upper}]
      *         range is out of the sequence index range.
      *
-     * @see #ensureBetween(String, int, int, int)
+     * @see #ensureSizeBetween(String, int, int, int)
      */
     public static void ensureValidIndexRange(final int length, final int lower, final int upper) throws IndexOutOfBoundsException {
         if (lower < 0 || upper < lower || upper > length) {
@@ -413,13 +412,25 @@ public final class ArgumentChecks extend
 
     /**
      * Ensures that the given integer value is between the given bounds, inclusive.
+     * This is a general-purpose method for checking integer arguments.
+     * Note that the following specialized methods are provided for common kinds
+     * of integer range checks:
+     *
+     * <ul>
+     *   <li>{@link #ensureSizeBetween(String, int, int, int) ensureSizeBetween(…)}
+     *       if the {@code value} argument is a collection size or an array length.</li>
+     *   <li>{@link #ensureValidIndex(int, int) ensureValidIndex(…)} if the {@code value}
+     *       argument is an index in a list or an array.</li>
+     * </ul>
      *
-     * @param  name  The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name  The name of the argument to be checked. Used only if an exception is thrown.
      * @param  min   The minimal value, inclusive.
      * @param  max   The maximal value, inclusive.
-     * @param  value The value to be tested.
+     * @param  value The user argument to check.
      * @throws IllegalArgumentException if the given value is not in the given range.
      *
+     * @see #ensureSizeBetween(String, int, int, int)
+     * @see #ensureValidIndex(int, int)
      * @see #ensureValidIndexRange(int, int, int)
      */
     public static void ensureBetween(final String name, final int min, final int max, final int value)
@@ -434,10 +445,10 @@ public final class ArgumentChecks extend
     /**
      * Ensures that the given long value is between the given bounds, inclusive.
      *
-     * @param  name  The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name  The name of the argument to be checked. Used only if an exception is thrown.
      * @param  min   The minimal value, inclusive.
      * @param  max   The maximal value, inclusive.
-     * @param  value The value to be tested.
+     * @param  value The user argument to check.
      * @throws IllegalArgumentException if the given value is not in the given range.
      */
     public static void ensureBetween(final String name, final long min, final long max, final long value)
@@ -452,10 +463,10 @@ public final class ArgumentChecks extend
     /**
      * Ensures that the given floating point value is between the given bounds, inclusive.
      *
-     * @param  name  The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name  The name of the argument to be checked. Used only if an exception is thrown.
      * @param  min   The minimal value, inclusive.
      * @param  max   The maximal value, inclusive.
-     * @param  value The value to be tested.
+     * @param  value The user argument to check.
      * @throws IllegalArgumentException if the given value is NaN or not in the given range.
      */
     public static void ensureBetween(final String name, final float min, final float max, final float value)
@@ -471,10 +482,10 @@ public final class ArgumentChecks extend
     /**
      * Ensures that the given floating point value is between the given bounds, inclusive.
      *
-     * @param  name  The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name  The name of the argument to be checked. Used only if an exception is thrown.
      * @param  min   The minimal value, inclusive.
      * @param  max   The maximal value, inclusive.
-     * @param  value The value to be tested.
+     * @param  value The user argument to check.
      * @throws IllegalArgumentException if the given value is NaN or not in the given range.
      */
     public static void ensureBetween(final String name, final double min, final double max, final double value)
@@ -488,10 +499,42 @@ public final class ArgumentChecks extend
     }
 
     /**
+     * Ensures that the given collection size of array length is between the given bounds, inclusive.
+     * This method performs the same check than {@link #ensureBetween(String, int, int, int)
+     * ensureBetween(…)}, but the error message is different in case of failure.
+     *
+     * @param  name  The name of the argument to be checked. Used only if an exception is thrown.
+     * @param  min   The minimal size (inclusive), or 0 if none.
+     * @param  max   The maximal size (inclusive), or {@link Integer#MAX_VALUE} if none.
+     * @param  size  The user collection size or array length to be checked.
+     * @throws IllegalArgumentException if the given value is not in the given range.
+     *
+     * @see #ensureBetween(String, int, int, int)
+     * @see #ensureValidIndexRange(int, int, int)
+     */
+    public static void ensureSizeBetween(final String name, final int min, final int max, final int size)
+            throws IllegalArgumentException
+    {
+        final String message;
+        if (size < min) {
+            if (min == 1) {
+                message = Errors.format(Errors.Keys.EmptyArgument_1, name);
+            } else {
+                message = Errors.format(Errors.Keys.InsufficientArgumentSize_3, name, min, size);
+            }
+        } else if (size > max) {
+            message = Errors.format(Errors.Keys.ExcessiveArgumentSize_3, name, max, size);
+        } else {
+            return;
+        }
+        throw new IllegalArgumentException(message);
+    }
+
+    /**
      * Ensures that the given direct position has the expected number of dimensions.
      * This method does nothing if the given direct position is null.
      *
-     * @param  name     The name of the argument to be checked. Used only in case an exception is thrown.
+     * @param  name     The name of the argument to be checked. Used only if an exception is thrown.
      * @param  expected The expected number of dimensions.
      * @param  position The direct position to check for its dimension, or {@code null}.
      * @throws MismatchedDimensionException If the given direct position is non-null and does

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java Sat Dec  8 07:40:17 2012
@@ -163,8 +163,8 @@ public class DefaultTreeTable implements
             default: map = new LinkedHashMap<>(hashMapCapacity(columns.length)); break;
         }
         for (int i=0; i<columns.length; i++) {
-            ArgumentChecks.ensureNonNull("columns", i, columns);
             final TableColumn<?> column = columns[i];
+            ArgumentChecks.ensureNonNullElement("columns", i, column);
             final Integer pos = i;
             if (map == null) {
                 map = Collections.<TableColumn<?>,Integer>singletonMap(column, pos);

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java Sat Dec  8 07:40:17 2012
@@ -142,6 +142,23 @@ public class UnmodifiableArrayList<E> ex
     }
 
     /**
+     * Returns the size of the array backing this list. This is the length of the array
+     * given to the constructor. It is equal to {@link #size()} except if this instance
+     * is a {@linkplain #subList(int,int) sublist}, in which case the value returned by
+     * this method is greater than {@code size()}.
+     *
+     * <p>This method can be used as a hint for choosing a {@code UnmodifiableArrayList}
+     * instance to keep when there is a choice between many equal instances. Note that a
+     * greater value is not necessarily more memory consuming, since the backing array
+     * may be shared by many sublists.</p>
+     *
+     * @return The length of the backing array.
+     */
+    public final int arraySize() {
+        return array.length;
+    }
+
+    /**
      * Returns the element at the specified index.
      */
     @Override

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java Sat Dec  8 07:40:17 2012
@@ -84,6 +84,21 @@ public final class Errors extends Indexe
         public static final int EmptyArgument_1 = 1;
 
         /**
+         * The dictionary shall contains at least one entry.
+         */
+        public static final int EmptyDictionary = 54;
+
+        /**
+         * Property named “{0}” shall not be empty.
+         */
+        public static final int EmptyProperty_1 = 55;
+
+        /**
+         * Argument ‘{0}’ shall not contain more than {1} elements. A number of {2} is excessive.
+         */
+        public static final int ExcessiveArgumentSize_3 = 52;
+
+        /**
          * Attribute “{0}” is not allowed for an object of type ‘{1}’.
          */
         public static final int ForbiddenAttribute_2 = 21;
@@ -161,6 +176,16 @@ public final class Errors extends Indexe
         public static final int InfiniteArgumentValue_1 = 45;
 
         /**
+         * Infinite recursivity.
+         */
+        public static final int InfiniteRecursivity = 51;
+
+        /**
+         * Argument ‘{0}’ shall contain at least {1} elements. A number of {2} is insufficient.
+         */
+        public static final int InsufficientArgumentSize_3 = 53;
+
+        /**
          * A different value is already associated to the “{0}” key.
          */
         public static final int KeyCollision_1 = 19;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties Sat Dec  8 07:40:17 2012
@@ -20,6 +20,9 @@ DeadThread_1                    = Thread
 DuplicatedValue_1               = Value \u201c{0}\u201d is duplicated.
 ElementAlreadyPresent_1         = Element \u201c{0}\u201d is already present.
 EmptyArgument_1                 = Argument \u2018{0}\u2019 shall not be empty.
+EmptyDictionary                 = The dictionary shall contains at least one entry.
+EmptyProperty_1                 = Property named \u201c{0}\u201d shall not be empty.
+ExcessiveArgumentSize_3         = Argument \u2018{0}\u2019 shall not contain more than {1} elements. A number of {2} is excessive.
 ForbiddenAttribute_2            = Attribute \u201c{0}\u201d is not allowed for an object of type \u2018{1}\u2019.
 IllegalArgumentClass_2          = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019.
 IllegalArgumentClass_3          = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019. Expected an instance of \u2018{2}\u2019 or derived type.
@@ -35,6 +38,8 @@ InconsistentTableColumns        = Incons
 IdentifierAlreadyBound_1        = Identifier \u201c{0}\u201d is already associated to another object.
 IndexOutOfBounds_1              = Index {0} is out of bounds.
 InfiniteArgumentValue_1         = Argument \u2018{0}\u2019 can not take an infinite value.
+InfiniteRecursivity             = Infinite recursivity.
+InsufficientArgumentSize_3      = Argument \u2018{0}\u2019 shall contain at least {1} elements. A number of {2} is insufficient.
 KeyCollision_1                  = A different value is already associated to the \u201c{0}\u201d key.
 MandatoryAttribute_2            = Attribute \u201c{0}\u201d is mandatory for an object of type \u2018{1}\u2019.
 NegativeArgument_2              = Argument \u2018{0}\u2019 shall not be negative. The given value was {1}.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1418613&r1=1418612&r2=1418613&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties Sat Dec  8 07:40:17 2012
@@ -20,6 +20,9 @@ DeadThread_1                    = La t\u
 DuplicatedValue_1               = La valeur \u201c{0}\u201d est dupliqu\u00e9e.
 ElementAlreadyPresent_1         = L\u2019\u00e9lement \u201c{0}\u201d est d\u00e9j\u00e0 pr\u00e9sent.
 EmptyArgument_1                 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide.
+EmptyDictionary                 = Le dictionnaire doit contenir au moins une entr\u00e9e.
+EmptyProperty_1                 = La propri\u00e9t\u00e9 nomm\u00e9e \u201c{0}\u201d ne doit pas \u00eatre vide.
+ExcessiveArgumentSize_3         = L\u2019argument \u2018{0}\u2019 ne peut pas contenir plus de {1} \u00e9l\u00e9ments. Un nombre de {2} est excessif.
 ForbiddenAttribute_2            = L\u2019attribut \u201c{0}\u201d n\u2019est pas autoris\u00e9 pour un objet de type \u2018{1}\u2019.
 IllegalArgumentClass_2          = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019.
 IllegalArgumentClass_3          = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019. Une instance de \u2018{2}\u2019 ou d\u2019un type d\u00e9riv\u00e9 \u00e9tait attendue.
@@ -35,6 +38,8 @@ InconsistentTableColumns        = Les co
 IdentifierAlreadyBound_1        = L\u2019identifiant \u201c{0}\u201d est d\u00e9j\u00e0 associ\u00e9 \u00e0 un autre objet.
 IndexOutOfBounds_1              = L\u2019index {0} est en dehors des limites permises.
 InfiniteArgumentValue_1         = L\u2019argument \u2018{0}\u2019 ne peut pas prendre une valeur infinie.
+InfiniteRecursivity             = R\u00e9cursivit\u00e9 infinie.
+InsufficientArgumentSize_3      = L\u2019argument \u2018{0}\u2019 doit contenir au moins {1} \u00e9l\u00e9ments. Un nombre de {2} est insuffisant.
 KeyCollision_1                  = Une valeur diff\u00e9rente est d\u00e9j\u00e0 associ\u00e9e \u00e0 la cl\u00e9 \u201c{0}\u201d.
 MandatoryAttribute_2            = L\u2019attribut \u201c{0}\u201d est obligatoire pour un objet de type \u2018{1}\u2019.
 NegativeArgument_2              = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre n\u00e9gatif. La valeur donn\u00e9e \u00e9tait {1}.

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java?rev=1418613&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java Sat Dec  8 07:40:17 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.type;
+
+import org.opengis.util.Factory;
+import org.opengis.metadata.citation.Citation;
+import org.apache.sis.internal.simple.SimpleCitation;
+
+
+/**
+ * Base class of factories provided in the Apache SIS library.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+public abstract class AbstractFactory implements Factory {
+    /**
+     * Creates a new factory.
+     */
+    protected AbstractFactory() {
+    }
+
+    /**
+     * Returns the implementor of this factory, or {@code null} if unknown.
+     * The default implementation tries to fetch this information from the
+     * manifest associated to the package of this class.
+     */
+    @Override
+    public Citation getVendor() {
+        final Package p = getClass().getPackage();
+        if (p != null) {
+            final String vendor = p.getImplementationVendor();
+            if (vendor != null) {
+                return new SimpleCitation(vendor);
+            }
+        }
+        return null;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java?rev=1418613&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java Sat Dec  8 07:40:17 2012
@@ -0,0 +1,406 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.type;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Iterator;
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlType;
+import net.jcip.annotations.Immutable;
+import org.opengis.util.NameSpace;
+import org.opengis.util.LocalName;
+import org.opengis.util.ScopedName;
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.apache.sis.util.resources.Errors;
+
+// Related to JDK7
+import java.util.Objects;
+
+
+/**
+ * A sequence of identifiers rooted within the context of a {@linkplain DefaultNameSpace namespace}.
+ * Names are <em>immutable</em>. They may be {@linkplain #toFullyQualifiedName() fully qualified}
+ * like {@code "org.opengis.util.Record"}, or they may be relative to a {@linkplain #scope() scope}
+ * like {@code "util.Record"} in the {@code "org.opengis"} scope.
+ * See the {@linkplain GenericName GeoAPI javadoc} for an illustration.
+ *
+ * <p>Subclasses need only to implement the following methods:</p>
+ * <ul>
+ *   <li>{@link #scope()}</li>
+ *   <li>{@link #getParsedNames()}</li>
+ * </ul>
+ *
+ * {@section <code>Comparable</code> ordering}
+ * This class has a natural ordering that is inconsistent with {@link #equals(Object)}.
+ * The natural ordering is case-insensitive and ignores the character separator between
+ * name elements.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+@XmlType(name = "GenericName")
+public abstract class AbstractName implements GenericName, Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 3362498790089164525L;
+
+    /**
+     * A view of this name as a fully-qualified one.
+     * Will be created only when first needed.
+     */
+    transient GenericName fullyQualified;
+
+    /**
+     * The string representation of this name, to be returned by {@link #toString()} or
+     * {@link #toInternationalString()}. This field will initially references a {@link String}
+     * object when first needed, and may be replaced by a {@link InternationalString} object
+     * later if such object is asked for.
+     */
+    transient CharSequence asString;
+
+    /**
+     * The cached hash code, or {@code 0} if not yet computed.
+     */
+    private transient int hash;
+
+    /**
+     * Creates a new instance of generic name.
+     */
+    protected AbstractName() {
+    }
+
+    /**
+     * Returns the scope (name space) in which this name is local. For example if a
+     * {@linkplain #toFullyQualifiedName() fully qualified name} is {@code "org.opengis.util.Record"}
+     * and if this instance is the {@code "util.Record"} part, then its scope is
+     * {@linkplain DefaultNameSpace#name() named} {@code "org.opengis"}.
+     *
+     * <p>Continuing with the above example, the full {@code "org.opengis.util.Record"} name has
+     * no scope. If this method is invoked on such name, then the SIS implementation returns a
+     * global scope instance (i.e. an instance for which {@link DefaultNameSpace#isGlobal()}
+     * returns {@code true}) which is unique and named {@code "global"}.</p>
+     */
+    @Override
+    public abstract NameSpace scope();
+
+    /**
+     * Indicates the number of levels specified by this name. The default implementation returns
+     * the size of the list returned by the {@link #getParsedNames()} method.
+     */
+    @Override
+    public int depth() {
+        return getParsedNames().size();
+    }
+
+    /**
+     * Returns the size of the backing array. This is used only has a hint for optimizations
+     * in attempts to share internal arrays. The {@link DefaultScopedName} class is the only
+     * one to override this method. For other classes, the {@link #depth()} can be assumed.
+     */
+    int arraySize() {
+        return depth();
+    }
+
+    /**
+     * Returns the sequence of {@linkplain DefaultLocalName local names} making this generic name.
+     * The length of this sequence is the {@linkplain #depth() depth}. It does not include the
+     * {@linkplain #scope() scope}.
+     */
+    @Override
+    public abstract List<? extends LocalName> getParsedNames();
+
+    /**
+     * Returns the first element in the sequence of {@linkplain #getParsedNames() parsed names}.
+     * For any {@code LocalName}, this is always {@code this}.
+     *
+     * <p><b>Example</b>:
+     * If {@code this} name is {@code "org.opengis.util.Record"} (no matter its
+     * {@linkplain #scope() scope}), then this method returns {@code "org"}.</p>
+     */
+    @Override
+    public LocalName head() {
+        return getParsedNames().get(0);
+    }
+
+    /**
+     * Returns the last element in the sequence of {@linkplain #getParsedNames() parsed names}.
+     * For any {@code LocalName}, this is always {@code this}.
+     *
+     * <p><b>Example</b>:
+     * If {@code this} name is {@code "org.opengis.util.Record"} (no matter its
+     * {@linkplain #scope() scope}), then this method returns {@code "Record"}.</p>
+     */
+    @Override
+    public LocalName tip() {
+        final List<? extends LocalName> names = getParsedNames();
+        return names.get(names.size() - 1);
+    }
+
+    /**
+     * Returns a view of this name as a fully-qualified name. The {@linkplain #scope() scope}
+     * of a fully qualified name is {@linkplain DefaultNameSpace#isGlobal() global}.
+     * If the scope of this name is already global, then this method returns {@code this}.
+     */
+    @Override
+    public synchronized GenericName toFullyQualifiedName() {
+        if (fullyQualified == null) {
+            final NameSpace scope = scope();
+            if (scope.isGlobal()) {
+                fullyQualified = this;
+            } else {
+                final GenericName prefix = scope.name();
+                assert prefix.scope().isGlobal() : prefix;
+                fullyQualified = new DefaultScopedName(prefix, this);
+            }
+        }
+        return fullyQualified;
+    }
+
+    /**
+     * Returns this name expanded with the specified scope. One may represent this operation
+     * as a concatenation of the specified {@code scope} with {@code this}. For example if
+     * {@code this} name is {@code "util.Record"} and the given {@code scope} argument is
+     * {@code "org.opengis"}, then {@code this.push(scope)} shall return
+     * {@code "org.opengis.util.Record"}.
+     */
+    @Override
+    public ScopedName push(final GenericName scope) {
+        return new DefaultScopedName(scope, this);
+    }
+
+    /**
+     * Returns the separator to write before the given name. If the scope of the given name
+     * is a {@link DefaultNameSpace} instance, then this method returns its head separator.
+     * We really want {@link DefaultNameSpace#headSeparator}, not {@link DefaultNameSpace#separator}.
+     * See {@link DefaultNameSpace#child(CharSequence)} for details.
+     *
+     * @param  name The name after which to write a separator.
+     * @return The separator to write after the given name.
+     */
+    static String separator(final GenericName name) {
+        if (name != null) {
+            final NameSpace scope = name.scope();
+            if (scope instanceof DefaultNameSpace) {
+                return ((DefaultNameSpace) scope).headSeparator;
+            }
+        }
+        return DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
+    }
+
+    /**
+     * Returns a string representation of this generic name. This string representation
+     * is local-independent. It contains all elements listed by {@link #getParsedNames()}
+     * separated by a namespace-dependent character (usually {@code ':'} or {@code '/'}).
+     * This rule implies that the result may or may not be fully qualified.
+     * Special cases:
+     *
+     * <ul>
+     *   <li><code>{@linkplain #toFullyQualifiedName()}.toString()</code> is guaranteed to
+     *       contain the {@linkplain #scope() scope} (if any).</li>
+     *   <li><code>{@linkplain #tip()}.toString()</code> is guaranteed to not contain
+     *       any scope.</li>
+     * </ul>
+     */
+    @Override
+    public synchronized String toString() {
+        if (asString == null) {
+            boolean insertSeparator = false;
+            final StringBuilder buffer = new StringBuilder();
+            for (final LocalName name : getParsedNames()) {
+                if (insertSeparator) {
+                    buffer.append(separator(name));
+                }
+                insertSeparator = true;
+                buffer.append(name);
+            }
+            asString = buffer.toString();
+        }
+        // Note: there is no need to invoke InternationalString.toString(null) for the
+        // unlocalized version, because our International inner class is implemented in
+        // such a way that InternationalString.toString() returns AbstractName.toString().
+        return asString.toString();
+    }
+
+    /**
+     * Returns a local-dependent string representation of this generic name.
+     * This string is similar to the one returned by {@link #toString()} except that each element
+     * has been localized in the {@linkplain InternationalString#toString(Locale) specified locale}.
+     * If no international string is available, then this method returns an implementation mapping
+     * to {@link #toString()} for all locales.
+     */
+    @Override
+    public synchronized InternationalString toInternationalString() {
+        if (!(asString instanceof InternationalString)) {
+            asString = new International(toString(), getParsedNames());
+        }
+        return (InternationalString) asString;
+    }
+
+    /**
+     * An international string built from a snapshot of {@link GenericName}.
+     *
+     * @author  Martin Desruisseaux (IRD, Geomatys)
+     * @since   0.3 (derived from geotk-2.1)
+     * @version 0.3
+     * @module
+     */
+    @Immutable
+    private static final class International extends SimpleInternationalString {
+        /**
+         * Serial number for inter-operability with different versions.
+         */
+        private static final long serialVersionUID = -6422809765366372062L;
+
+        /**
+         * The sequence of {@linkplain DefaultLocalName local names} making this generic name.
+         * This is the value returned by {@link AbstractName#getParsedNames()}.
+         */
+        private final List<? extends LocalName> parsedNames;
+
+        /**
+         * Constructs a new international string from the specified {@link AbstractName} fields.
+         *
+         * @param asString The string representation of the enclosing abstract name.
+         * @param parsedNames The value returned by {@link AbstractName#getParsedNames()}.
+         */
+        public International(final String asString, final List<? extends LocalName> parsedNames) {
+            super(asString);
+            this.parsedNames = parsedNames;
+        }
+
+        /**
+         * Returns a string representation for the specified locale.
+         */
+        @Override
+        public String toString(final Locale locale) {
+            boolean insertSeparator = false;
+            final StringBuilder buffer = new StringBuilder();
+            for (final LocalName name : parsedNames) {
+                if (insertSeparator) {
+                    buffer.append(separator(name));
+                }
+                insertSeparator = true;
+                buffer.append(name.toInternationalString().toString(locale));
+            }
+            return buffer.toString();
+        }
+
+        /**
+         * Compares this international string with the specified object for equality.
+         */
+        @Override
+        public boolean equals(final Object object) {
+            if (object == this) {
+                return true;
+            }
+            if (super.equals(object)) {
+                final International that = (International) object;
+                return Objects.equals(parsedNames, that.parsedNames);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Compares this name with the specified name for order. Returns a negative integer,
+     * zero, or a positive integer as this name lexicographically precedes, is equal to,
+     * or follows the specified name. The comparison is performed in the following way:
+     *
+     * <ul>
+     *   <li>For each element of the {@linkplain #getParsedNames() list of parsed names} taken
+     *       in iteration order, compare the {@link LocalName}. If a name lexicographically
+     *       precedes or follows the corresponding element of the specified name, returns
+     *       a negative or a positive integer respectively.</li>
+     *   <li>If all elements in both names are lexicographically equal, then if this name has less
+     *       or more elements than the specified name, returns a negative or a positive integer
+     *       respectively.</li>
+     *   <li>Otherwise, returns 0.</li>
+     * </ul>
+     *
+     * @param name The other name to compare with this name.
+     * @return -1 if this name precedes the given one, +1 if it follows, 0 if equals.
+     */
+    @Override
+    public int compareTo(final GenericName name) {
+        final Iterator<? extends LocalName> thisNames = this.getParsedNames().iterator();
+        final Iterator<? extends LocalName> thatNames = name.getParsedNames().iterator();
+        while (thisNames.hasNext()) {
+            if (!thatNames.hasNext()) {
+                return +1;
+            }
+            final LocalName thisNext = thisNames.next();
+            final LocalName thatNext = thatNames.next();
+            if (thisNext == this && thatNext == name) {
+                // Never-ending loop: usually an implementation error
+                throw new IllegalStateException(Errors.format(Errors.Keys.InfiniteRecursivity));
+            }
+            final int compare = thisNext.compareTo(thatNext);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+        return thatNames.hasNext() ? -1 : 0;
+    }
+
+    /**
+     * Compares this generic name with the specified object for equality.
+     * The default implementation returns {@code true} if the {@linkplain #scope() scopes}
+     * and the lists of {@linkplain #getParsedNames() parsed names} are equal.
+     *
+     * @param object The object to compare with this name for equality.
+     * @return {@code true} if the given object is equal to this name.
+     */
+    @Override
+    public boolean equals(final Object object) {
+        if (object == this) {
+            return true;
+        }
+        if (object != null && object.getClass() == getClass()) {
+            final AbstractName that = (AbstractName) object;
+            return Objects.equals(scope(), that.scope()) &&
+                   Objects.equals(getParsedNames(), that.getParsedNames());
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this generic name.
+     */
+    @Override
+    public int hashCode() {
+        if (hash == 0) {
+            int code = computeHashCode();
+            if (code == 0) {
+                code = -1;
+            }
+            hash = code;
+        }
+        return hash;
+    }
+
+    /**
+     * Invoked by {@link #hashCode()} for computing the hash code value when first needed.
+     */
+    int computeHashCode() {
+        return Objects.hash(scope(), getParsedNames()) ^ (int) serialVersionUID;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractName.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java?rev=1418613&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java Sat Dec  8 07:40:17 2012
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.type;
+
+import java.util.List;
+import java.util.Collections;
+import java.io.ObjectStreamException;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import net.jcip.annotations.Immutable;
+import org.opengis.util.NameSpace;
+import org.opengis.util.LocalName;
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.apache.sis.xml.Namespaces;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
+
+// Related to JDK7
+import java.util.Objects;
+
+
+/**
+ * Identifier within a {@linkplain DefaultNameSpace name space} for a local object.
+ * Local names are names which are directly accessible to and maintained by a name space.
+ * Names are local to one and only one name space.
+ * The name space within which they are local is indicated by the {@linkplain #scope() scope}.
+ *
+ * <p>{@code DefaultLocalName} can be instantiated by any of the following methods:</p>
+ * <ul>
+ *   <li>{@link DefaultNameFactory#createLocalName(NameSpace, CharSequence)}</li>
+ *   <li>{@link DefaultNameFactory#createGenericName(NameSpace, CharSequence[])} with an array of length 1</li>
+ *   <li>{@link DefaultNameFactory#parseGenericName(NameSpace, CharSequence)} without separator</li>
+ * </ul>
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+@Immutable
+@XmlRootElement(name = "LocalName")
+public class DefaultLocalName extends AbstractName implements LocalName {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 8747478206456790138L;
+
+    /**
+     * The scope of this name, or {@code null} if the scope is the unique {@code GLOBAL} instance.
+     * We don't use direct reference to {@code GLOBAL} because {@code null} is used as a sentinel
+     * value for stopping iterative searches (using GLOBAL would have higher risk of never-ending
+     * loops in case of bug), and in order to reduce the stream size during serialization.
+     */
+    final NameSpace scope;
+
+    /**
+     * The name, either as a {@link String} or an {@link InternationalString}.
+     */
+    @XmlJavaTypeAdapter(CharSequenceAdapter.class)
+    @XmlElement(name = "aName", namespace = Namespaces.GCO)
+    final CharSequence name;
+
+    /**
+     * Empty constructor to be used by JAXB only, or by sub-classes empty constructors
+     * themselves used only by JAXB. Despite its "final" declaration, the {@link #name}
+     * field will be set by JAXB during unmarshalling.
+     */
+    DefaultLocalName() {
+        scope = null;
+        name  = null;
+    }
+
+    /**
+     * Constructs a local name from the given character sequence.
+     * If the character sequence is an instance of {@link InternationalString},
+     * then its {@link InternationalString#toString(java.util.Locale) toString(null)}
+     * method will be invoked for fetching an unlocalized name.
+     * Otherwise the {@link CharSequence#toString()} method will be used.
+     *
+     * @param scope The scope of this name, or {@code null} for a global scope.
+     * @param name The local name (never {@code null}).
+     */
+    protected DefaultLocalName(NameSpace scope, final CharSequence name) {
+        ArgumentChecks.ensureNonNull("name", name);
+        if (scope == GlobalNameSpace.GLOBAL) {
+            scope = null; // Handled specially by scope().
+        }
+        this.scope = scope;
+        if (name instanceof InternationalString) {
+            if (name.getClass() == SimpleInternationalString.class) {
+                /*
+                 * In the special case of SimpleInternationalString, we will retain the String
+                 * flavor instead than InternationalString (this is done by name.toString() at
+                 * the end of this constructor). It will not cause any lost of information since
+                 * SimpleInternationalString contains only one String. This simplification allows
+                 * the equals(Object) method to return "true" for DefaultLocalName that would
+                 * otherwise be considered different.
+                 *
+                 * In order to reduce the amount of objects created, we retain the full
+                 * InternationalString in the "asString" field, which is NOT considered
+                 * by equals(Object). This is the value returned by toInternationalString().
+                 */
+                asString = name;
+            } else {
+                /*
+                 * For any InternationalString that are not SimpleInternationalString, we retain
+                 * the given name and we do NOT set the "asString" field. It will be computed on
+                 * the fly when first needed.
+                 */
+                this.name = name;
+                return;
+            }
+        }
+        this.name = name.toString();
+    }
+
+    /**
+     * Returns the scope (name space) in which this name is local. This method returns a
+     * non-null value in all cases, even when the scope given to the constructor was null.
+     */
+    @Override
+    public NameSpace scope() {
+        return (scope != null) ? scope : GlobalNameSpace.GLOBAL;
+    }
+
+    /**
+     * Returns the depth, which is always 1 for a local name.
+     */
+    @Override
+    public final int depth() {
+        return 1;
+    }
+
+    /**
+     * Returns the sequence of local name for this name.
+     * Since this object is itself a local name, this method always returns a singleton
+     * containing only {@code this}.
+     */
+    @Override
+    public final List<DefaultLocalName> getParsedNames() {
+        return Collections.singletonList(this);
+    }
+
+    /**
+     * Returns {@code this} since this object is already a local name.
+     */
+    @Override
+    public final LocalName head() {
+        return this;
+    }
+
+    /**
+     * Returns {@code this} since this object is already a local name.
+     */
+    @Override
+    public final LocalName tip() {
+        return this;
+    }
+
+    /**
+     * Returns a locale-independent string representation of this local name.
+     * This string does not include the scope, which is consistent with the
+     * {@linkplain #getParsedNames() parsed names} definition.
+     */
+    @Override
+    public synchronized String toString() {
+        if (asString == null) {
+            if (name instanceof InternationalString) {
+                // We really want the 'null' locale, not the system default one.
+                asString = ((InternationalString) name).toString(null);
+            } else {
+                asString = name.toString();
+            }
+        } else if (asString instanceof InternationalString) {
+            return ((InternationalString) asString).toString(null);
+        }
+        return asString.toString();
+    }
+
+    /**
+     * Returns a local-dependent string representation of this locale name.
+     */
+    @Override
+    public synchronized InternationalString toInternationalString() {
+        if (!(asString instanceof InternationalString)) {
+            asString = Types.toInternationalString(name);
+        }
+        return (InternationalString) asString;
+    }
+
+    /**
+     * Compares this name with the specified object for order. Returns a negative integer,
+     * zero, or a positive integer as this name lexicographically precedes, is equal to,
+     * or follows the specified object. The comparison is case-insensitive.
+     *
+     * @param name The other name to compare with this name.
+     * @return -1 if this name precedes the given one, +1 if it follows, 0 if equals.
+     */
+    @Override
+    public int compareTo(final GenericName name) {
+        if (name instanceof LocalName) {
+            return toString().compareToIgnoreCase(name.toString());
+        } else {
+            return super.compareTo(name);
+        }
+    }
+
+    /**
+     * Compares this local name with the specified object for equality.
+     *
+     * @param object The object to compare with this name for equality.
+     * @return {@code true} if the given object is equal to this name.
+     */
+    @Override
+    public boolean equals(final Object object) {
+        if (object == this) {
+            return true;
+        }
+        if (object != null && object.getClass() == getClass()) {
+            final DefaultLocalName that = (DefaultLocalName) object;
+            return Objects.equals(this.scope, that.scope) &&
+                   Objects.equals(this.name,  that.name);
+        }
+        return false;
+    }
+
+    /**
+     * Invoked by {@link #hashCode()} for computing the hash code value when first needed.
+     */
+    @Override
+    final int computeHashCode() {
+        return Objects.hash(scope, name) ^ (int) serialVersionUID;
+    }
+
+    /**
+     * If an instance already exists for the deserialized name, returns that instance.
+     *
+     * <p>Because of its private access, this method is <strong>not</strong> invoked if the
+     * deserialized class is a subclass. This is the intended behavior since we don't want
+     * to replace an instance of a user-defined class.</p>
+     *
+     * @return The unique instance.
+     * @throws ObjectStreamException Should never happen.
+     */
+    private Object readResolve() throws ObjectStreamException {
+        final DefaultNameSpace ns;
+        if (scope == null) { // Not a bug: readResolve() is intentionally private.
+            ns = GlobalNameSpace.GLOBAL;
+        } else if (scope instanceof DefaultNameSpace) {
+            ns = (DefaultNameSpace) scope;
+        } else {
+            return this;
+        }
+        return ns.local(name, this);
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultLocalName.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java?rev=1418613&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java Sat Dec  8 07:40:17 2012
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.type;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import net.jcip.annotations.Immutable;
+import org.opengis.util.MemberName;
+import org.opengis.util.NameSpace;
+import org.opengis.util.TypeName;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
+
+/**
+ * The name to identify a member of a {@linkplain org.opengis.util.Record record}.
+ * {@code DefaultMemberName} can be instantiated by any of the following methods:
+ *
+ * <ul>
+ *   <li>{@link DefaultNameFactory#createMemberName(NameSpace, CharSequence, TypeName)}</li>
+ * </ul>
+ *
+ * @author  Guilhem Legal (Geomatys)
+ * @since   0.3 (derived from geotk-3.17)
+ * @version 0.3
+ * @module
+ */
+@Immutable
+@XmlRootElement(name = "MemberName")
+public class DefaultMemberName extends DefaultLocalName implements MemberName {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 6252686806895124457L;
+
+    /**
+     * The type of the data associated with the record member.
+     */
+    @XmlElement(required = true)
+    private final TypeName attributeType;
+
+    /**
+     * Empty constructor to be used by JAXB only. Despite its "final" declaration,
+     * the {@link #attributeType} field will be set by JAXB during unmarshalling.
+     */
+    private DefaultMemberName() {
+        attributeType = null;
+    }
+
+    /**
+     * Constructs a member name from the given character sequence and attribute type.
+     *
+     * @param scope The scope of this name, or {@code null} for a global scope.
+     * @param name  The local name (never {@code null}).
+     * @param attributeType The type of the data associated with the record member (can not be {@code null}).
+     */
+    protected DefaultMemberName(final NameSpace scope, final CharSequence name, final TypeName attributeType) {
+        super(scope, name);
+        ensureNonNull("attributeType", attributeType);
+        this.attributeType = attributeType;
+    }
+
+    /**
+     * Returns the type of the data associated with the record member.
+     */
+    @Override
+    public TypeName getAttributeType() {
+        return attributeType;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultMemberName.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java?rev=1418613&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java Sat Dec  8 07:40:17 2012
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.type;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.Collection;
+import net.jcip.annotations.ThreadSafe;
+
+import org.opengis.util.TypeName;
+import org.opengis.util.NameSpace;
+import org.opengis.util.LocalName;
+import org.opengis.util.MemberName;
+import org.opengis.util.GenericName;
+import org.opengis.util.NameFactory;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.Identifier;
+
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.NullArgumentException;
+import org.apache.sis.util.collection.WeakHashSet;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+import static org.apache.sis.util.type.DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
+
+
+/**
+ * A factory for creating {@link AbstractName} objects.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+@ThreadSafe
+public class DefaultNameFactory extends AbstractFactory implements NameFactory {
+    /**
+     * Weak references to the name created by this factory.
+     */
+    private final WeakHashSet<GenericName> pool;
+
+    /**
+     * Creates a new factory.
+     */
+    public DefaultNameFactory() {
+        pool = new WeakHashSet<>(GenericName.class);
+    }
+
+    /**
+     * Creates an international string from a set of strings in different locales.
+     */
+    @Override
+    public InternationalString createInternationalString(final Map<Locale,String> strings) {
+        ensureNonNull("strings", strings);
+        switch (strings.size()) {
+            case 0:  throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyDictionary));
+            case 1:  return new SimpleInternationalString(strings.values().iterator().next());
+            default: return new DefaultInternationalString(strings);
+        }
+        // Do not cache in the pool, because not all instances are immutable.
+    }
+
+    /**
+     * Returns the value for the given key in the given properties map, or {@code null} if none.
+     */
+    private static String getString(final Map<String,?> properties, final String key) {
+        if (properties != null) {
+            final Object value = properties.get(key);
+            if (value != null) {
+                return value.toString();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates a namespace having the given name. Despite the "create" name, this method tries
+     * to returns an existing instance when possible.
+     *
+     * <p>This method can receive an optional map of properties. Recognized entries are:</p>
+     * <table class="sis">
+     *   <tr>
+     *     <th nowrap>Property name</th>
+     *     <th nowrap>Purpose</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code "separator"}</td>
+     *     <td>The separator to insert between
+     *     {@linkplain AbstractName#getParsedNames() parsed names} in that namespace.
+     *     For HTTP namespace, it is {@code "."}.
+     *     For URN namespace, it is typically {@code ":"}.</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code "separator.head"}</td>
+     *     <td>The separator to insert between the namespace and the
+     *     {@linkplain AbstractName#head() head}. For HTTP namespace, it is {@code "://"}.
+     *     For URN namespace, it is typically {@code ":"}. If this entry is omitted, then
+     *     the default is the same value than the {@code "separator"} entry.</td>
+     *   </tr>
+     * </table>
+     *
+     * @param name
+     *          The name of the namespace to be returned. This argument can be created using
+     *          <code>{@linkplain #createGenericName(NameSpace, CharSequence[]) createGenericName}(null, parsedNames)</code>.
+     * @param properties
+     *          An optional map of properties to be assigned to the namespace, or {@code null} if none.
+     *
+     * @return A namespace having the given name and separator.
+     */
+    @Override
+    public NameSpace createNameSpace(final GenericName name, final Map<String,?> properties) {
+        ensureNonNull("name", name);
+        String separator = getString(properties, "separator");
+        if (separator == null) {
+            separator = DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
+        }
+        String headSeparator = getString(properties, "separator.head");
+        if (headSeparator == null) {
+            headSeparator = separator;
+        }
+        final boolean isEmpty = separator.isEmpty();
+        if (isEmpty || headSeparator.isEmpty()) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.EmptyProperty_1, isEmpty ? "separator" : "separator.head"));
+        }
+        return DefaultNameSpace.forName(name.toFullyQualifiedName(), headSeparator, separator);
+    }
+
+    /**
+     * Creates a type name from the given character sequence.
+     * The default implementation returns a new or an existing {@link DefaultTypeName} instance.
+     *
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the type
+     *         name to be created, or {@code null} for a global namespace.
+     * @param  name The type name as a string or an international string.
+     * @return The type name for the given character sequence.
+     * @throws NullArgumentException If the {@code name} argument is null.
+     */
+    @Override
+    public TypeName createTypeName(final NameSpace scope, final CharSequence name) {
+        return pool.unique(new DefaultTypeName(scope, name));
+    }
+
+    /**
+     * Creates a member name from the given character sequence and attribute type.
+     * The default implementation returns a new or an existing {@link DefaultMemberName}
+     * instance.
+     *
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the member
+     *         name to be created, or {@code null} for a global namespace.
+     * @param  name The member name as a string or an international string.
+     * @param  attributeType The type of the data associated with the record member.
+     * @return The member name for the given character sequence.
+     * @throws NullArgumentException If the {@code name} or {@code attributeType} argument is null.
+     */
+    @Override
+    public MemberName createMemberName(final NameSpace scope, final CharSequence name, final TypeName attributeType) {
+        return pool.unique(new DefaultMemberName(scope, name, attributeType));
+    }
+
+    /**
+     * Creates a local name from the given character sequence.
+     * The default implementation returns a new or an existing {@link DefaultLocalName} instance.
+     *
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the local
+     *         name to be created, or {@code null} for a global namespace.
+     * @param  name The local name as a string or an international string.
+     * @return The local name for the given character sequence.
+     * @throws NullArgumentException If the {@code name} argument is null.
+     */
+    @Override
+    public LocalName createLocalName(final NameSpace scope, final CharSequence name) {
+        if (scope instanceof DefaultNameSpace) {
+            // Following may return a cached instance.
+            return ((DefaultNameSpace) scope).local(name, null);
+        }
+        return pool.unique(new DefaultLocalName(scope, name));
+    }
+
+    /**
+     * Creates a local or scoped name from an array of parsed names. The default implementation
+     * returns an instance of {@link DefaultLocalName} if the length of the {@code parsedNames}
+     * array is 1, or an instance of {@link DefaultScopedName} if the length of the array is 2
+     * or more.
+     *
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the generic name to
+     *         be created, or {@code null} for a global namespace.
+     * @param  parsedNames The local names as an array of {@link String} or {@link InternationalString}
+     *         instances. This array shall contains at least one element.
+     * @return The generic name for the given parsed names.
+     * @throws NullArgumentException If the given array is empty.
+     */
+    @Override
+    public GenericName createGenericName(final NameSpace scope, final CharSequence... parsedNames) {
+        ensureNonNull("parsedNames", parsedNames);
+        switch (parsedNames.length) {
+            default: return pool.unique(new DefaultScopedName(scope, Arrays.asList(parsedNames)));
+            case 1:  return createLocalName(scope, parsedNames[0]); // User may override.
+            case 0:  throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "parsedNames"));
+        }
+    }
+
+    /**
+     * Constructs a generic name from a qualified name.
+     * This method splits the given name around a separator inferred from the given scope, or the
+     * {@value org.apache.sis.util.typeDefaultNameSpace#DEFAULT_SEPARATOR} separator if the given
+     * scope is null.
+     *
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the generic name to
+     *         be created, or {@code null} for a global namespace.
+     * @param  name The qualified name, as a sequence of names separated by a scope-dependent
+     *         separator.
+     * @return A name parsed from the given string.
+     */
+    @Override
+    public GenericName parseGenericName(final NameSpace scope, final CharSequence name) {
+        final String separator;
+        if (scope instanceof DefaultNameSpace) {
+            separator = ((DefaultNameSpace) scope).separator;
+        } else {
+            separator = DEFAULT_SEPARATOR_STRING;
+        }
+        final int s = separator.length();
+        final List<String> names = new ArrayList<>();
+        int lower = 0;
+        final String string = name.toString();
+        while (true) {
+            final int upper = string.indexOf(separator, lower);
+            if (upper >= 0) {
+                names.add(string.substring(lower, upper));
+                lower = upper + s;
+            } else {
+                names.add(string.substring(lower));
+                break;
+            }
+        }
+        if (names.size() == 1) {
+            // Preserves the InternationalString (current implementation of
+            // the parsing code above has lost the internationalization).
+            return createLocalName(scope, name);
+        }
+        return createGenericName(scope, names.toArray(new String[names.size()]));
+    }
+
+    /**
+     * Creates a generic name from the given value. The value may be an instance of
+     * {@link GenericName}, {@link Identifier} or {@link CharSequence}. If the given
+     * object is not recognized, then this method returns {@code null}.
+     *
+     * @param  value The object to convert.
+     * @return The converted object, or {@code null} if {@code value} is not convertible.
+     */
+    private GenericName createFromObject(final Object value) {
+        ensureNonNull("value", value);
+        if (value instanceof GenericName) {
+            return (GenericName) value;
+        }
+        if (value instanceof Identifier) {
+            return parseGenericName(null, ((Identifier) value).getCode());
+        }
+        if (value instanceof CharSequence) {
+            return parseGenericName(null, (CharSequence) value);
+        }
+        return null;
+    }
+
+    /**
+     * Converts the given value to an array of generic names. If the given value is an instance of
+     * {@link GenericName}, {@link String} or any other type enumerated below, then it is converted
+     * and returned in an array of length 1. If the given value is an array or a collection, then an
+     * array of same length is returned where each element has been converted.
+     *
+     * <p>Allowed types or element types are:</p>
+     * <ul>
+     *   <li>{@link GenericName}, to be casted and returned as-is.</li>
+     *   <li>{@link CharSequence} (usually a {@link String} or an {@link InternationalString}), to
+     *       be parsed as a generic name using the {@linkplain DefaultNameSpace#DEFAULT_SEPARATOR
+     *       default separator}.</li>
+     *   <li>{@link Identifier}, its {@linkplain Identifier#getCode() code} to be parsed as a generic name
+     *       using the {@value org.apache.sis.util.typeDefaultNameSpace#DEFAULT_SEPARATOR} separator.</li>
+     * </ul>
+     *
+     * @param  value The object to cast into an array of generic names.
+     * @return The generic names. May be a direct reference to {@code value}.
+     * @throws NullArgumentException if {@code value} is null.
+     * @throws ClassCastException if {@code value} can't be casted.
+     */
+    public GenericName[] toArray(Object value) throws ClassCastException {
+        GenericName name = createFromObject(value);
+        if (name != null) {
+            return new GenericName[] {
+                name
+            };
+        }
+        /*
+         * Above code checked for a singleton. Now check for a collection or an array.
+         */
+        final Object[] values;
+        if (value instanceof Collection<?>) {
+            values = ((Collection<?>) value).toArray();
+        } else if (value instanceof Object[]) {
+            values = (Object[]) value;
+        } else {
+            throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_2,
+                    "value", value.getClass()));
+        }
+        if (values instanceof GenericName[]) {
+            return (GenericName[]) values;
+        }
+        final GenericName[] names = new GenericName[values.length];
+        for (int i=0; i<values.length; i++) {
+            value = values[i];
+            name = createFromObject(value);
+            if (name == null) {
+                throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_2,
+                        "value[" + i + ']', value.getClass()));
+            }
+            names[i] = name;
+        }
+        return names;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultNameFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message