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 2012/12/08 08:40:18 UTC
svn commit: r1418613 [1/2] - in
/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util: ./
collection/ resources/ type/
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