sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1626345 [12/14] - in /sis/trunk: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gml/ core/sis-metada...
Date Fri, 19 Sep 2014 21:46:44 GMT
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractName.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractName.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractName.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractName.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -21,7 +21,7 @@ import java.util.Locale;
 import java.util.Iterator;
 import java.util.ConcurrentModificationException;
 import java.io.Serializable;
-import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.NameSpace;
 import org.opengis.util.LocalName;
 import org.opengis.util.ScopedName;
@@ -61,10 +61,15 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
-@XmlType(name = "GenericName") // Actually 'gml:CodeType', but the later is used elsewhere.
+
+/*
+ * JAXB annotation would be @XmlType(name ="CodeType"), but this can not be used here
+ * since "CodeType" is used for various classes (including LocalName and ScopedName).
+ */
+@XmlTransient
 public abstract class AbstractName implements GenericName, Serializable {
     /**
      * Serial number for inter-operability with different versions.
@@ -102,10 +107,10 @@ public abstract class AbstractName imple
      *
      * <ul>
      *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of {@code AbstractName},
-     *       then it is returned unchanged.</li>
      *   <li>Otherwise if the given object is an instance of {@link LocalName}, then this
      *       method delegates to {@link DefaultLocalName#castOrCopy(LocalName)}.</li>
+     *   <li>Otherwise if the given object is already an instance of {@code AbstractName},
+     *       then it is returned unchanged.</li>
      *   <li>Otherwise a new instance of an {@code AbstractName} subclass is created using the
      *       {@link DefaultNameFactory#createGenericName(NameSpace, CharSequence[])} method.</li>
      * </ul>
@@ -115,12 +120,12 @@ public abstract class AbstractName imple
      *         given object itself), or {@code null} if the argument was null.
      */
     public static AbstractName castOrCopy(final GenericName object) {
-        if (object == null || object instanceof AbstractName) {
-            return (AbstractName) object;
-        }
         if (object instanceof LocalName) {
             return DefaultLocalName.castOrCopy((LocalName) object);
         }
+        if (object == null || object instanceof AbstractName) {
+            return (AbstractName) object;
+        }
         /*
          * Recreates a new name for the given name in order to get
          * a SIS implementation from an arbitrary implementation.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -19,9 +19,8 @@ package org.apache.sis.util.iso;
 import java.util.List;
 import java.util.Collections;
 import java.util.Locale;
-import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.NameSpace;
 import org.opengis.util.LocalName;
@@ -31,7 +30,6 @@ 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.system.DefaultFactories;
 import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
 
 // Branch-dependent imports
@@ -46,9 +44,10 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * <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>
+ *   <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)} with no occurrence of the separator in the path.</li>
+ *   <li>Similar static convenience methods in {@link Names}.</li>
  * </ul>
  *
  * {@section Immutability and thread safety}
@@ -58,11 +57,22 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
+ *
+ * @see DefaultNameSpace
+ * @see DefaultScopedName
+ */
+
+/*
+ * JAXB annotation would be @XmlType(name ="CodeType"), but this can not be used here
+ * since "CodeType" is used for various classes (including GenericName and ScopedName).
+ * (Un)marhalling of this class needs to be handled by a JAXB adapter.
  */
-@XmlType(name = "LocalName") // Actually 'gml:CodeType', but the later is used elsewhere.
-@XmlRootElement(name = "LocalName")
+@XmlSeeAlso({
+    DefaultTypeName.class,
+    DefaultMemberName.class
+})
 public class DefaultLocalName extends AbstractName implements LocalName {
     /**
      * Serial number for inter-operability with different versions.
@@ -150,12 +160,12 @@ public class DefaultLocalName extends Ab
      *
      * <ul>
      *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
+     *   <li>Otherwise if the given object is an instance of {@link MemberName} or {@link TypeName},
+     *       then this method delegates to {@code castOrCopy(…)} method of the corresponding subclass.</li>
      *   <li>Otherwise if the given object is already an instance of {@code DefaultLocalName},
      *       then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultLocalName} instance is created using the
-     *       {@link DefaultNameFactory#createLocalName(NameSpace, CharSequence)} method,
-     *       or the {@code createTypeName} or {@code createMemberName} variants if the
-     *       given object implements the corresponding interface.</li>
+     *   <li>Otherwise a new {@code DefaultLocalName} instance is created
+     *       with the same values than the given name.</li>
      * </ul>
      *
      * @param  object The object to get as a SIS implementation, or {@code null} if none.
@@ -163,24 +173,22 @@ public class DefaultLocalName extends Ab
      *         given object itself), or {@code null} if the argument was null.
      */
     public static DefaultLocalName castOrCopy(final LocalName object) {
+        if (object instanceof MemberName) {
+            return DefaultMemberName.castOrCopy((MemberName) object);
+        }
+        if (object instanceof TypeName) {
+            return DefaultTypeName.castOrCopy((TypeName) object);
+        }
         if (object == null || object instanceof DefaultLocalName) {
             return (DefaultLocalName) object;
         }
         final NameSpace scope = object.scope();
         final InternationalString name = object.toInternationalString();
-        final LocalName result;
-        if (object instanceof MemberName) {
-            result = DefaultFactories.SIS_NAMES.createMemberName(scope, name, ((MemberName) object).getAttributeType());
-        } else if (object instanceof TypeName) {
-            result = DefaultFactories.SIS_NAMES.createTypeName(scope, name);
+        if (scope instanceof DefaultNameSpace) {
+            return ((DefaultNameSpace) scope).local(name, null); // May return a cached instance.
         } else {
-            result = DefaultFactories.SIS_NAMES.createLocalName(scope, name);
+            return new DefaultLocalName(scope, name);
         }
-        /*
-         * Following cast should be safe because the SIS_NAMES factory is fixed to a
-         * DefaultNameFactory instance, which is known to create AbstractName instances.
-         */
-        return (DefaultLocalName) result;
     }
 
     /**
@@ -309,7 +317,7 @@ public class DefaultLocalName extends Ab
      * Invoked by {@link #hashCode()} for computing the hash code value when first needed.
      */
     @Override
-    final int computeHashCode() {
+    int computeHashCode() {
         return Objects.hash(scope, name) ^ (int) serialVersionUID;
     }
 

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.util.iso;
 
+import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.MemberName;
@@ -24,6 +25,9 @@ import org.opengis.util.TypeName;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk7.Objects;
+
 
 /**
  * The name to identify a member of a {@linkplain org.opengis.util.Record record}.
@@ -31,6 +35,7 @@ import static org.apache.sis.util.Argume
  *
  * <ul>
  *   <li>{@link DefaultNameFactory#createMemberName(NameSpace, CharSequence, TypeName)}</li>
+ *   <li>Similar static convenience method in {@link Names}.</li>
  * </ul>
  *
  * {@section Immutability and thread safety}
@@ -41,9 +46,14 @@ import static org.apache.sis.util.Argume
  *
  * @author  Guilhem Legal (Geomatys)
  * @since   0.3 (derived from geotk-3.17)
- * @version 0.3
+ * @version 0.5
  * @module
+ *
+ * @see DefaultTypeName
+ * @see DefaultNameFactory
+ * @see DefaultRecordType
  */
+@XmlType(name = "MemberName_Type")
 @XmlRootElement(name = "MemberName")
 public class DefaultMemberName extends DefaultLocalName implements MemberName {
     /**
@@ -79,6 +89,31 @@ public class DefaultMemberName extends D
     }
 
     /**
+     * Returns a SIS member name implementation with the values of the given arbitrary implementation.
+     * This method performs the first applicable action in the following choices:
+     *
+     * <ul>
+     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
+     *   <li>Otherwise if the given object is already an instance of {@code DefaultMemberName},
+     *       then it is returned unchanged.</li>
+     *   <li>Otherwise a new {@code DefaultMemberName} instance is created
+     *       with the same values than the given name.</li>
+     * </ul>
+     *
+     * @param  object The object to get as a SIS implementation, or {@code null} if none.
+     * @return A SIS implementation containing the values of the given object (may be the
+     *         given object itself), or {@code null} if the argument was null.
+     *
+     * @since 0.5
+     */
+    public static DefaultMemberName castOrCopy(final MemberName object) {
+        if (object == null || object instanceof DefaultMemberName) {
+            return (DefaultMemberName) object;
+        }
+        return new DefaultMemberName(object.scope(), object.toInternationalString(), object.getAttributeType());
+    }
+
+    /**
      * Returns the type of the data associated with the record member.
      *
      * @return The type of the data associated with the record member.
@@ -87,4 +122,23 @@ public class DefaultMemberName extends D
     public TypeName getAttributeType() {
         return attributeType;
     }
+
+    /**
+     * Compares this member 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) {
+        return super.equals(object) && Objects.equals(attributeType, ((DefaultMemberName) object).attributeType);
+    }
+
+    /**
+     * Invoked by {@link #hashCode()} for computing the hash code value when first needed.
+     */
+    @Override
+    final int computeHashCode() {
+        return super.computeHashCode() + Objects.hashCode(attributeType);
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -31,7 +31,6 @@ import org.opengis.util.GenericName;
 import org.opengis.util.NameFactory;
 import org.opengis.util.InternationalString;
 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;
@@ -61,6 +60,7 @@ import static org.apache.sis.util.iso.De
  * <ul>
  *   <li>{@link #parseGenericName(NameSpace, CharSequence)}</li>
  *   <li>{@link #toGenericNames(Object)}</li>
+ *   <li>{@link #toTypeName(Class)}</li>
  * </ul>
  *
  * {@section Thread safety}
@@ -72,14 +72,36 @@ import static org.apache.sis.util.iso.De
  * @since   0.3 (derived from geotk-2.1)
  * @version 0.5
  * @module
+ *
+ * @see Names
+ * @see DefaultNameSpace
+ * @see DefaultScopedName
+ * @see DefaultLocalName
+ * @see DefaultTypeName
+ * @see DefaultMemberName
  */
 public class DefaultNameFactory extends AbstractFactory implements NameFactory {
     /**
+     * The key for name separator.
+     */
+    static final String SEPARATOR_KEY = "separator";
+
+    /**
+     * The key or the separator after the first name.
+     */
+    static final String HEAD_SEPARATOR_KEY = "separator.head";
+
+    /**
      * Weak references to the name created by this factory.
      */
     private final WeakHashSet<GenericName> pool;
 
     /**
+     * Helper class for mapping {@link Class} to {@link TypeName}, created when first needed.
+     */
+    private transient volatile TypeNames typeNames;
+
+    /**
      * Creates a new factory.
      */
     public DefaultNameFactory() {
@@ -160,18 +182,18 @@ public class DefaultNameFactory extends 
     @Override
     public NameSpace createNameSpace(final GenericName name, final Map<String,?> properties) {
         ensureNonNull("name", name);
-        String separator = getString(properties, "separator");
+        String separator = getString(properties, SEPARATOR_KEY);
         if (separator == null) {
             separator = DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
         }
-        String headSeparator = getString(properties, "separator.head");
+        String headSeparator = getString(properties, HEAD_SEPARATOR_KEY);
         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"));
+                    Errors.Keys.EmptyProperty_1, isEmpty ? SEPARATOR_KEY : HEAD_SEPARATOR_KEY));
         }
         return DefaultNameSpace.forName(name.toFullyQualifiedName(), headSeparator, separator);
     }
@@ -184,7 +206,9 @@ public class DefaultNameFactory extends 
      *         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.
+     *
+     * @see #toTypeName(Class)
+     * @see Names#createTypeName(CharSequence, String, CharSequence)
      */
     @Override
     public TypeName createTypeName(final NameSpace scope, final CharSequence name) {
@@ -193,15 +217,13 @@ public class DefaultNameFactory extends 
 
     /**
      * Creates a member name from the given character sequence and attribute type.
-     * The default implementation returns a new or an existing {@link DefaultMemberName}
-     * instance.
+     * 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.
      */
     public MemberName createMemberName(final NameSpace scope, final CharSequence name, final TypeName attributeType) {
         return pool.unique(new DefaultMemberName(scope, name, attributeType));
@@ -215,12 +237,15 @@ public class DefaultNameFactory extends 
      *         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.
      *
      * @see Names#createLocalName(CharSequence, String, CharSequence)
      */
     @Override
     public LocalName createLocalName(final NameSpace scope, final CharSequence name) {
+        /*
+         * Maintenance note: if the body of this method is modified (except for the use of the cache),
+         * consider updating DefaultLocalName.castOrCopy(LocalName) method accordingly.
+         */
         if (scope instanceof DefaultNameSpace) {
             // Following may return a cached instance.
             return ((DefaultNameSpace) scope).local(name, null);
@@ -239,7 +264,8 @@ public class DefaultNameFactory extends 
      * @param  parsedNames The local names as an array of {@link String} or {@link InternationalString} instances.
      *         This array shall contain at least one element.
      * @return The generic name for the given parsed names.
-     * @throws NullArgumentException If the given array is empty.
+     *
+     * @see #parseGenericName(NameSpace, CharSequence)
      */
     @Override
     public GenericName createGenericName(final NameSpace scope, final CharSequence... parsedNames) {
@@ -261,6 +287,8 @@ public class DefaultNameFactory extends 
      * @param  name The qualified name, as a sequence of names separated by a scope-dependent
      *         separator.
      * @return A name parsed from the given string.
+     *
+     * @see Names#parseGenericName(CharSequence, String, CharSequence)
      */
     @Override
     public GenericName parseGenericName(final NameSpace scope, final CharSequence name) {
@@ -359,8 +387,8 @@ public class DefaultNameFactory extends 
 
     /**
      * 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}.
+     * {@link GenericName}, {@link Identifier}, {@link CharSequence} or {@link Class}.
+     * 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.
@@ -375,6 +403,56 @@ public class DefaultNameFactory extends 
         if (value instanceof CharSequence) {
             return parseGenericName(null, (CharSequence) value);
         }
+        if (value instanceof Class<?>) {
+            return toTypeName((Class<?>) value);
+        }
         return null;
     }
+
+    /**
+     * Suggests a type name for the given class. Apache SIS provides a mapping between {@code Class}
+     * and {@code TypeName} objects as documented in the {@link DefaultTypeName} javadoc.
+     *
+     * <p>In order to protect against potential changes in the {@code Class} ↔ {@code TypeName} mapping, users are
+     * encouraged to retrieve the {@code valueClass} by invoking the {@link Names#toClass(TypeName)} method instead
+     * than parsing the name.</p>
+     *
+     * @param  valueClass The Java class for which to get a type name, or {@code null}.
+     * @return A suggested type name, or {@code null} if the given class was null.
+     *
+     * @see DefaultTypeName#toClass()
+     * @see Names#toClass(TypeName)
+     *
+     * @since 0.5
+     */
+    public TypeName toTypeName(final Class<?> valueClass) {
+        if (!TypeNames.isValid(valueClass)) {
+            return null;
+        }
+        /*
+         * Note: we do not cache the TypeName for the valueClass argument because:
+         *
+         *  - It is not needed (at least in the default implementation) for getting unique instance.
+         *  - It is not the best place for performance improvement, since TypeName are usually only
+         *    a step in the creation of bigger object (typically AttributeType). Users are better to
+         *    cache the bigger object instead.
+         */
+        TypeNames t = typeNames;
+        if (t == null) {
+            /*
+             * Create TypeNames outide the synchronized block because the TypeNames constructor will call back
+             * methods from this class. Since those methods are overrideable, this could invoke user's code.
+             * Note also that methods in this class use the 'pool', which is itself synchronized, so we are
+             * better to avoid double synchronization for reducing the risk of dead-lock.
+             */
+            final TypeNames c = new TypeNames(this);
+            synchronized (this) { // Double-check strategy is ok if 'typeNames' is volatile.
+                t = typeNames;
+                if (t == null) {
+                    typeNames = t = c;
+                }
+            }
+        }
+        return t.toTypeName(this, valueClass);
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -55,6 +55,12 @@ import org.apache.sis.internal.jdk7.Obje
  * @since   0.3 (derived from geotk-3.00)
  * @version 0.3
  * @module
+ *
+ * @see DefaultScopedName
+ * @see DefaultLocalName
+ * @see DefaultTypeName
+ * @see DefaultMemberName
+ * @see DefaultNameFactory
  */
 public class DefaultNameSpace implements NameSpace, Serializable {
     /**
@@ -78,8 +84,10 @@ public class DefaultNameSpace implements
      * 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.
+     *
+     * @see #parent()
      */
-    final DefaultNameSpace parent;
+    private final DefaultNameSpace parent;
 
     /**
      * The name of this namespace, usually as a {@link String} or an {@link InternationalString}.
@@ -122,8 +130,7 @@ public class DefaultNameSpace implements
     private transient WeakValueHashMap<String,Object> childs;
 
     /**
-     * Creates the global namespace. This constructor can be invoked by {@link GlobalNameSpace}
-     * only.
+     * Creates the global namespace. This constructor can be invoked by {@link GlobalNameSpace} only.
      */
     DefaultNameSpace() {
         this.parent        = null;
@@ -151,7 +158,7 @@ public class DefaultNameSpace implements
     protected DefaultNameSpace(final DefaultNameSpace parent, CharSequence name,
                                final String headSeparator, final String separator)
     {
-        this.parent = parent;
+        this.parent = (parent != GlobalNameSpace.GLOBAL) ? parent : null;
         ensureNonNull("name",          name);
         ensureNonNull("headSeparator", headSeparator);
         ensureNonNull("separator",     separator);
@@ -248,6 +255,13 @@ public class DefaultNameSpace implements
     }
 
     /**
+     * Returns the parent namespace, replacing null parent by {@link GlobalNameSpace#GLOBAL}.
+     */
+    final DefaultNameSpace parent() {
+        return (parent != null) ? parent : GlobalNameSpace.GLOBAL;
+    }
+
+    /**
      * Returns the depth of the given namespace.
      *
      * @param ns The namespace for which to get the depth, or {@code null}.
@@ -398,7 +412,7 @@ public class DefaultNameSpace implements
                 }
             }
         }
-        assert child.parent == this;
+        assert child.parent() == this;
         return child;
     }
 
@@ -518,7 +532,7 @@ public class DefaultNameSpace implements
      * @return The unique instance.
      */
     Object readResolve() {
-        final DefaultNameSpace p = (parent != null) ? parent : GlobalNameSpace.GLOBAL;
+        final DefaultNameSpace p = parent();
         final String key = key(name);
         final WeakValueHashMap<String,Object> pool = p.childs;
         synchronized (pool) {

Copied: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java (from r1625241, sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java?p2=sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java&p1=sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java&r1=1625241&r2=1626345&rev=1626345&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -81,8 +81,13 @@ public class DefaultRecordSchema impleme
     /**
      * The factory to use for creating names.
      * This is the factory given at construction time.
+     *
+     * <div class="warning"><b>Upcoming API change</b> — generalization<br>
+     * This field type will be changed to the {@link NameFactory} interface when that interface
+     * will provide a {@code createMemberName(…)} method (tentatively in GeoAPI 3.1).
+     * </div>
      */
-    protected final NameFactory nameFactory;
+    protected final DefaultNameFactory nameFactory;
 
     /**
      * The helper class to use for mapping Java classes to {@code TypeName} instances, or {@code null} if not needed.
@@ -120,11 +125,16 @@ public class DefaultRecordSchema impleme
     /**
      * Creates a new schema of the given name.
      *
+     * <div class="warning"><b>Upcoming API change</b> — generalization<br>
+     * This type of the first argument will be changed to the {@link NameFactory} interface when
+     * that interface will provide a {@code createMemberName(…)} method (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param nameFactory The factory to use for creating names, or {@code null} for the default factory.
      * @param parent      The parent namespace, or {@code null} if none.
      * @param schemaName  The name of the new schema.
      */
-    public DefaultRecordSchema(NameFactory nameFactory, final NameSpace parent, final CharSequence schemaName) {
+    public DefaultRecordSchema(DefaultNameFactory nameFactory, final NameSpace parent, final CharSequence schemaName) {
         ArgumentChecks.ensureNonNull("schemaName", schemaName);
         if (nameFactory == null) {
             nameFactory = DefaultFactories.NAMES;
@@ -211,12 +221,7 @@ public class DefaultRecordSchema impleme
             if (valueClass == Void.TYPE) {
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "valueClass", "void"));
             }
-            final TypeName name;
-            if (nameFactory instanceof DefaultNameFactory) {
-                name = ((DefaultNameFactory) nameFactory).toTypeName(valueClass);
-            } else {
-                name = typeFactory.toTypeName(nameFactory, valueClass);
-            }
+            final TypeName name = nameFactory.toTypeName(valueClass);
             type = new SimpleAttributeType(name, valueClass);
             final Type old = attributeTypes.putIfAbsent(valueClass, type);
             if (old != null) { // May happen if the type has been computed concurrently.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -18,20 +18,28 @@ package org.apache.sis.util.iso;
 
 import java.util.Set;
 import java.util.Map;
-import java.util.Collections;
 import java.util.LinkedHashMap;
+import java.util.Arrays;
 import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.InvalidObjectException;
 import javax.xml.bind.annotation.XmlType;
 import org.opengis.util.Type;
 import org.opengis.util.TypeName;
+import org.opengis.util.LocalName;
 import org.opengis.util.MemberName;
+import org.opengis.util.GenericName;
+import org.opengis.util.NameSpace;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
 import org.opengis.util.RecordSchema;
-import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.ObjectConverters;
+import org.apache.sis.internal.converter.SurjectiveConverter;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
@@ -43,23 +51,52 @@ import org.apache.sis.internal.jdk7.Obje
  * arbitrary amount of {@linkplain #getMembers() members} as (<var>name</var>, <var>type</var>) pairs.
  * A {@code RecordType} may therefore contain another {@code RecordType} as a member.
  *
- * {@section Comparison with Java reflection}
+ * <div class="note"><b>Comparison with Java reflection:</b>
  * {@code RecordType} instances can be though as equivalent to instances of the Java {@link Class} class.
  * The set of members in a {@code RecordType} can be though as equivalent to the set of fields in a class.
+ * </div>
+ *
+ * {@section Instantiation}
+ * The easiest way to create {@code DefaultRecordType} instances is to use the
+ * {@link DefaultRecordSchema#createRecordType(CharSequence, Map)} method.
+ * Example:
+ *
+ * <div class="note">
+ * {@preformat java
+ *     DefaultRecordSchema schema = new DefaultRecordSchema(null, null, "MySchema");
+ *     // The same instance can be reused for all records to create in that schema.
+ *
+ *     Map<CharSequence,Class<?>> members = new LinkedHashMap<>();
+ *     members.put("city",        String .class);
+ *     members.put("latitude",    Double .class);
+ *     members.put("longitude",   Double .class);
+ *     members.put("population",  Integer.class);
+ *     RecordType record = schema.createRecordType("MyRecordType", members);
+ * }
+ * </div>
  *
  * {@section Immutability and thread safety}
- * This class is immutable and thus inherently thread-safe if the {@link TypeName} and {@link RecordSchema} arguments,
- * as well as all ({@link MemberName}, {@link Type}) entries in the map given to the constructor, are also immutable.
+ * This class is immutable and thus inherently thread-safe if the {@link TypeName}, the {@link RecordSchema}
+ * and all ({@link MemberName}, {@link Type}) entries in the map given to the constructor are also immutable.
  * Subclasses shall make sure that any overridden methods remain safe to call from multiple threads and do not change
  * any public {@code RecordType} state.
  *
+ * {@section Serialization}
+ * This class is serializable if all elements given to the constructor are also serializable.
+ * Note in particular that {@link DefaultRecordSchema} is currently <strong>not</strong> serializable,
+ * so users wanting serialization may need to provide their own schema.
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.5
  * @module
+ *
+ * @see DefaultRecord
+ * @see DefaultRecordSchema
+ * @see DefaultMemberName
  */
 @XmlType(name = "RecordType")
-public class DefaultRecordType implements RecordType, Serializable {
+public class DefaultRecordType extends RecordDefinition implements RecordType, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -80,20 +117,18 @@ public class DefaultRecordType implement
     private final RecordSchema container;
 
     /**
-     * The dictionary of (<var>name</var>, <var>type</var>) pairs.
+     * The type of each members.
      *
-     * @see #getMembers()
      * @see #getMemberTypes()
      */
-    private final Map<MemberName,Type> memberTypes;
+    private transient Type[] memberTypes;
 
     /**
      * Empty constructor only used by JAXB.
      */
     private DefaultRecordType() {
-        typeName    = null;
-        container   = null;
-        memberTypes = Collections.emptyMap();
+        typeName  = null;
+        container = null;
     }
 
     /**
@@ -104,32 +139,116 @@ public class DefaultRecordType implement
     public DefaultRecordType(final RecordType other) {
         typeName    = other.getTypeName();
         container   = other.getContainer();
-        memberTypes = other.getMemberTypes();
+        memberTypes = computeTransientFields(other.getMemberTypes());
+    }
+
+    /**
+     * Creates a new record in the given schema.
+     * It is caller responsibility to add the new {@code RecordType} in the container
+     * {@linkplain RecordSchema#getDescription() description} map, if desired.
+     *
+     * <p>This constructor is provided mostly for developers who want to create {@code DefaultRecordType}
+     * instances in their own {@code RecordSchema} implementation. Otherwise if the default record schema
+     * implementation is sufficient, the {@link DefaultRecordSchema#createRecordType(CharSequence, Map)}
+     * method provides an easier alternative.</p>
+     *
+     * @param typeName  The name that identifies this record type.
+     * @param container The schema that contains this record type.
+     * @param members   The name and type of the members to be included in this record type.
+     *
+     * @see DefaultRecordSchema#createRecordType(CharSequence, Map)
+     */
+    public DefaultRecordType(final TypeName typeName, final RecordSchema container,
+            final Map<? extends MemberName, ? extends Type> members)
+    {
+        ArgumentChecks.ensureNonNull("typeName",  typeName);
+        ArgumentChecks.ensureNonNull("container", container);
+        ArgumentChecks.ensureNonNull("members",   members);
+        this.typeName    = typeName;
+        this.container   = container;
+        this.memberTypes = computeTransientFields(members);
+        /*
+         * Ensure that the record namespace is equals to the schema name. For example if the schema
+         * name is "MyNameSpace", then the record type name can be "MyNameSpace:MyRecordType".
+         */
+        final LocalName   schemaName   = container.getSchemaName();
+        final GenericName fullTypeName = typeName.toFullyQualifiedName();
+        if (schemaName.compareTo(typeName.scope().name().tip()) != 0) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentNamespace_2, schemaName, fullTypeName));
+        }
+        final int size = size();
+        for (int i=0; i<size; i++) {
+            final MemberName name = getName(i);
+            final Type type = this.memberTypes[i];
+            if (type == null || name.getAttributeType().compareTo(type.getTypeName()) != 0) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalMemberType_2, name, type));
+            }
+            if (fullTypeName.compareTo(name.scope().name()) != 0) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentNamespace_2,
+                        fullTypeName, name.toFullyQualifiedName()));
+            }
+        }
     }
 
     /**
-     * Creates a new record.
+     * Creates a new record from member names specified as character sequence.
+     * This constructor builds the {@link MemberName} instance itself.
      *
      * @param typeName    The name that identifies this record type.
      * @param container   The schema that contains this record type.
-     * @param memberTypes The name of the members to be included in this record type.
+     * @param members     The name of the members to be included in this record type.
+     * @param nameFactory The factory to use for instantiating {@link MemberName}.
      */
-    public DefaultRecordType(final TypeName typeName, final RecordSchema container, Map<MemberName,Type> memberTypes) {
-        ArgumentChecks.ensureNonNull("typeName",    typeName);
-        ArgumentChecks.ensureNonNull("container",   container);
-        ArgumentChecks.ensureNonNull("memberTypes", memberTypes);
-        memberTypes = new LinkedHashMap<MemberName,Type>(memberTypes);
-        memberTypes.remove(null);
-        for (final Map.Entry<MemberName,Type> entry : memberTypes.entrySet()) {
-            final MemberName name = entry.getKey();
-            final Type type = entry.getValue();
-            if (type == null || !name.getAttributeType().equals(type.getTypeName())) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalMemberType_2, name, type));
+    DefaultRecordType(final TypeName typeName, final RecordSchema container,
+            final Map<? extends CharSequence, ? extends Type> members, final DefaultNameFactory nameFactory)
+    {
+        this.typeName  = typeName;
+        this.container = container;
+        final NameSpace namespace = nameFactory.createNameSpace(typeName, null);
+        final Map<MemberName,Type> memberTypes = new LinkedHashMap<MemberName,Type>(Containers.hashMapCapacity(members.size()));
+        for (final Map.Entry<? extends CharSequence, ? extends Type> entry : members.entrySet()) {
+            final Type         type   = entry.getValue();
+            final CharSequence name   = entry.getKey();
+            final MemberName   member = nameFactory.createMemberName(namespace, name, type.getTypeName());
+            if (memberTypes.put(member, type) != null) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedElement_1, member));
             }
         }
-        this.typeName    = typeName;
-        this.container   = container;
-        this.memberTypes = CollectionsExt.unmodifiableOrCopy(memberTypes);
+        this.memberTypes = computeTransientFields(memberTypes);
+    }
+
+    /**
+     * Invoked on deserialization for restoring the transient fields.
+     * See {@link #writeObject(ObjectOutputStream)} for the stream data description.
+     */
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        final int size = in.readInt();
+        final Map<MemberName,Type> members = new LinkedHashMap<MemberName,Type>(Containers.hashMapCapacity(size));
+        for (int i=0; i<size; i++) {
+            final MemberName member = (MemberName) in.readObject();
+            final Type type = (Type) in.readObject();
+            if (members.put(member, type) != null) {
+                throw new InvalidObjectException(Errors.format(Errors.Keys.DuplicatedElement_1, member));
+            }
+        }
+        memberTypes = computeTransientFields(members);
+    }
+
+    /**
+     * Invoked on serialization for writing the member names and their type.
+     *
+     * @serialData The number of members as an {@code int}, followed by a
+     *             ({@code MemberName}, {@code Type}) pair for each member.
+     */
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        final int size = size();
+        out.defaultWriteObject();
+        out.writeInt(size);
+        for (int i=0; i<size; i++) {
+            out.writeObject(getName(i));
+            out.writeObject(memberTypes[i]);
+        }
     }
 
     /**
@@ -159,6 +278,14 @@ public class DefaultRecordType implement
     }
 
     /**
+     * Returns {@code this} since {@link RecordDefinition} is the definition of this record type.
+     */
+    @Override
+    final RecordType getRecordType() {
+        return this;
+    }
+
+    /**
      * Returns the name that identifies this record type. If this {@code RecordType} is contained in a
      * {@linkplain DefaultRecordSchema record schema}, then the record type name shall be valid in the
      * {@linkplain DefaultNameSpace name space} of the record schema:
@@ -167,9 +294,10 @@ public class DefaultRecordType implement
      *     NameSpace namespace = getContainer().getSchemaName().scope()
      * }
      *
-     * {@section Comparison with Java reflection}
+     * <div class="note"><b>Comparison with Java reflection:</b>
      * If we think about this {@code RecordType} as equivalent to a {@code Class} instance,
      * then this method can be think as the equivalent of the Java {@link Class#getName()} method.
+     * </div>
      *
      * @return The name that identifies this record type.
      */
@@ -192,15 +320,20 @@ public class DefaultRecordType implement
      * Returns the dictionary of all (<var>name</var>, <var>type</var>) pairs in this record type.
      * The returned map is unmodifiable.
      *
-     * {@section Comparison with Java reflection}
+     * <div class="note"><b>Comparison with Java reflection:</b>
      * If we think about this {@code RecordType} as equivalent to a {@code Class} instance, then
      * this method can be though as the related to the Java {@link Class#getFields()} method.
+     * </div>
      *
      * @return The dictionary of (<var>name</var>, <var>type</var>) pairs, or an empty map if none.
      */
     @Override
-    public Map<MemberName, Type> getMemberTypes() {
-        return memberTypes;
+    public Map<MemberName,Type> getMemberTypes() {
+        return ObjectConverters.derivedValues(memberIndices(), MemberName.class, new SurjectiveConverter<Integer,Type>() {
+            @Override public Class<Integer> getSourceClass() {return Integer.class;}
+            @Override public Class<Type>    getTargetClass() {return Type.class;}
+            @Override public Type apply(final Integer index) {return getType(index);}
+        });
     }
 
     /**
@@ -215,7 +348,14 @@ public class DefaultRecordType implement
      */
     @Override
     public Set<MemberName> getMembers() {
-        return memberTypes.keySet();
+        return memberIndices().keySet();
+    }
+
+    /**
+     * Returns the type at the given index.
+     */
+    final Type getType(final int index) {
+        return memberTypes[index];
     }
 
     /**
@@ -226,17 +366,18 @@ public class DefaultRecordType implement
      *     getMemberTypes().get(memberName).getTypeName();
      * }
      *
-     * {@section Comparison with Java reflection}
+     * <div class="note"><b>Comparison with Java reflection:</b>
      * If we think about this {@code RecordType} as equivalent to a {@code Class} instance, then
      * this method can be though as related to the Java {@link Class#getField(String)} method.
+     * </div>
      *
      * @param  memberName The attribute name for which to get the associated type name.
      * @return The associated type name, or {@code null} if none.
      */
     @Override
     public TypeName locate(final MemberName memberName) {
-        final Type type = memberTypes.get(memberName);
-        return (type != null) ? type.getTypeName() : null;
+        final Integer index = indexOf(memberName);
+        return (index != null) ? getType(index).getTypeName() : null;
     }
 
     /**
@@ -273,9 +414,10 @@ public class DefaultRecordType implement
         }
         if (other != null && other.getClass() == getClass()) {
             final DefaultRecordType that = (DefaultRecordType) other;
-            return Objects.equals(typeName,    that.typeName)  &&
-                   Objects.equals(container,   that.container) &&
-                   Objects.equals(memberTypes, that.memberTypes);
+            return Objects.equals(typeName,    that.typeName)    &&
+                   Objects.equals(container,   that.container)   &&
+                   Arrays .equals(memberTypes, that.memberTypes) &&
+                   memberIndices().equals(that.memberIndices());
         }
         return false;
     }
@@ -285,19 +427,6 @@ public class DefaultRecordType implement
      */
     @Override
     public int hashCode() {
-        int code = memberTypes.hashCode();
-        if (typeName  != null) code = 31*code + typeName .hashCode();
-        if (container != null) code = 31*code + container.hashCode();
-        return code;
-    }
-
-    /**
-     * Returns a string representation of this {@code RecordType}.
-     * The string representation is for debugging purpose and may change in any future SIS version.
-     */
-    @Debug
-    @Override
-    public String toString() {
-        return "RecordType[\"" + typeName + "\"]";
+        return Objects.hashCode(typeName) + 31*(memberIndices().hashCode() + 31*Arrays.hashCode(memberTypes));
     }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -19,8 +19,7 @@ package org.apache.sis.util.iso;
 import java.util.List;
 import java.util.Iterator;
 import java.util.ConcurrentModificationException;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.NameSpace;
 import org.opengis.util.LocalName;
 import org.opengis.util.ScopedName;
@@ -38,8 +37,9 @@ import org.apache.sis.internal.util.Unmo
  *
  * <p>{@code DefaultScopedName} can be instantiated by any of the following methods:</p>
  * <ul>
- *   <li>{@link DefaultNameFactory#createGenericName(NameSpace, CharSequence[])} with an array of length 2 or more</li>
- *   <li>{@link DefaultNameFactory#parseGenericName(NameSpace, CharSequence)} with at least one separator</li>
+ *   <li>{@link DefaultNameFactory#createGenericName(NameSpace, CharSequence[])} with an array of length 2 or more.</li>
+ *   <li>{@link DefaultNameFactory#parseGenericName(NameSpace, CharSequence)} with at least one occurrence of the separator in the path.</li>
+ *   <li>Similar static convenience methods in {@link Names}.</li>
  * </ul>
  *
  * {@section Immutability and thread safety}
@@ -52,9 +52,17 @@ import org.apache.sis.internal.util.Unmo
  * @since   0.3 (derived from geotk-2.1)
  * @version 0.3
  * @module
+ *
+ * @see DefaultNameSpace
+ * @see DefaultLocalName
+ */
+
+/*
+ * JAXB annotation would be @XmlType(name ="CodeType"), but this can not be used here
+ * since "CodeType" is used for various classes (including GenericName and LocalName).
+ * (Un)marhalling of this class needs to be handled by a JAXB adapter.
  */
-@XmlType(name = "ScopedName") // Actually 'gml:CodeType', but the later is used elsewhere.
-@XmlRootElement(name = "ScopedName")
+@XmlTransient
 public class DefaultScopedName extends AbstractName implements ScopedName {
     /**
      * Serial number for inter-operability with different versions.
@@ -87,14 +95,6 @@ public class DefaultScopedName extends A
     }
 
     /**
-     * Empty constructor to be used by JAXB only. Despite its "final" declaration,
-     * the {@link #parsedNames} field will be set by JAXB during unmarshalling.
-     */
-    private DefaultScopedName() {
-        parsedNames = null;
-    }
-
-    /**
      * Creates a new scoped names from the given list of local names. This constructor is
      * not public because it does not check if the given local names have the proper scope.
      *
@@ -183,7 +183,7 @@ public class DefaultScopedName extends A
         final LocalName lastName  = locals[index-1];
         final NameSpace lastScope = lastName.scope();
         final NameSpace tailScope = name.scope();
-        if (tailScope instanceof DefaultNameSpace && ((DefaultNameSpace) tailScope).parent == lastScope) {
+        if (tailScope instanceof DefaultNameSpace && ((DefaultNameSpace) tailScope).parent() == lastScope) {
             /*
              * If the tail is actually the tip (a LocalName), remember the tail so we
              * don't need to create it again later. Then copy the tail after the path.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -16,9 +16,11 @@
  */
 package org.apache.sis.util.iso;
 
+import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.TypeName;
 import org.opengis.util.NameSpace;
+import org.apache.sis.util.UnknownNameException;
 
 
 /**
@@ -27,8 +29,38 @@ import org.opengis.util.NameSpace;
  *
  * <ul>
  *   <li>{@link DefaultNameFactory#createTypeName(NameSpace, CharSequence)}</li>
+ *   <li>{@link DefaultNameFactory#toTypeName(Class)}</li>
  * </ul>
  *
+ * {@section Mapping Java classes to type names}
+ * It is sometime useful to establish a mapping between {@link Class} and {@code TypeName}.
+ * When an UML identifier from an OGC standard exists for a given {@code Class}, Apache SIS
+ * uses that identifier prefixed by the {@code "OGC"} namespace.
+ * Note that this is <strong>not</strong> a standard practice.
+ * A more standard practice would be to use the <cite>definition identifiers in OGC namespace</cite>
+ * (last column in the table below), but the set of data type identifiers defined by OGC is currently
+ * small and is sometime not an exact match.
+ *
+ * <table class="sis">
+ *   <caption>Mapping from Java classes to type names (non-exhaustive list)</caption>
+ *   <tr><th>Java class</th>                                   <th>Type name (unofficial)</th>      <th>Definition identifier in OGC namespace</th></tr>
+ *   <tr><td>{@link org.opengis.util.InternationalString}</td> <td>{@code OGC:FreeText}</td>        <td></td></tr>
+ *   <tr><td>{@link java.lang.String}</td>                     <td>{@code OGC:CharacterString}</td> <td>urn:ogc:def:dataType:OGC::string</td></tr>
+ *   <tr><td>{@link java.net.URI}</td>                         <td>{@code OGC:URI}</td>             <td>urn:ogc:def:dataType:OGC::anyURI</td></tr>
+ *   <tr><td>{@link java.lang.Boolean}</td>                    <td>{@code OGC:Boolean}</td>         <td>urn:ogc:def:dataType:OGC::boolean</td></tr>
+ *   <tr><td>{@link java.lang.Integer}</td>                    <td>{@code OGC:Integer}</td>         <td>urn:ogc:def:dataType:OGC::nonNegativeInteger</td></tr>
+ *   <tr><td>{@link java.lang.Double}</td>                     <td>{@code OGC:Real}</td>            <td></td></tr>
+ *   <tr><td>{@link java.util.Date}</td>                       <td>{@code OGC:DateTime}</td>        <td></td></tr>
+ *   <tr><td>{@link java.util.Locale}</td>                     <td>{@code OGC:PT_Locale}</td>       <td></td></tr>
+ *   <tr><td>{@link org.opengis.metadata.Metadata}</td>        <td>{@code OGC:MD_Metadata}</td>     <td></td></tr>
+ *   <tr><td>Unknown Java class</td>                           <td>{@code class:}&lt;the class name&gt;</td><td></td></tr>
+ * </table>
+ *
+ * The mapping defined by Apache SIS may change in any future version depending on standardization progress.
+ * To protect against such changes, users are encouraged to rely on methods or constructors like
+ * {@link DefaultNameFactory#toTypeName(Class)} or {@link #toClass()} instead than parsing the name.
+ *
+ *
  * {@section Immutability and thread safety}
  * This class is immutable and thus inherently thread-safe if the {@link NameSpace} and {@link CharSequence}
  * arguments given to the constructor are also immutable. Subclasses shall make sure that any overridden methods
@@ -36,10 +68,15 @@ import org.opengis.util.NameSpace;
  *
  * @author  Guilhem Legal (Geomatys)
  * @author  Cédric Briançon (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.5
  * @module
+ *
+ * @see DefaultMemberName
+ * @see DefaultNameFactory
  */
+@XmlType(name = "TypeName_Type")
 @XmlRootElement(name = "TypeName")
 public class DefaultTypeName extends DefaultLocalName implements TypeName {
     /**
@@ -48,6 +85,20 @@ public class DefaultTypeName extends Def
     private static final long serialVersionUID = 7182126541436753582L;
 
     /**
+     * The value class to be returned by {@link #toClass()}, or {@code null} if not yet computed.
+     * {@link Void#TYPE} is used as a sentinel value meaning explicit {@code null}.
+     *
+     * <p>This value is only computed. We do not allow the user to explicitely specify it, because we
+     * need that {@code DefaultTypeName}s having identical name also have the same {@code valueClass}.
+     * This is necessary {@link DefaultNameFactory#pool} cache integrity. Users who want to explicitely
+     * specify their own value class can override {@link #toClass()} instead.</p>
+     *
+     * @see #setValueClass(NameSpace, String, Class)
+     * @see #toClass()
+     */
+    private transient Class<?> valueClass;
+
+    /**
      * Empty constructor to be used by JAXB only. Despite its "final" declaration,
      * the {@link #name} field will be set by JAXB during unmarshalling.
      */
@@ -55,14 +106,121 @@ public class DefaultTypeName extends Def
     }
 
     /**
-     * Constructs a type name from the given character sequence. The argument are given unchanged
-     * to the {@linkplain DefaultLocalName#DefaultLocalName(NameSpace,CharSequence) super-class
-     * constructor}.
+     * Constructs a type name from the given character sequence. The argument are given unchanged to the
+     * {@linkplain DefaultLocalName#DefaultLocalName(NameSpace,CharSequence) super-class constructor}.
      *
      * @param scope The scope of this name, or {@code null} for a global scope.
      * @param name  The local name (never {@code null}).
+     *
+     * @see DefaultNameFactory#createTypeName(NameSpace, CharSequence)
      */
     protected DefaultTypeName(final NameSpace scope, final CharSequence name) {
         super(scope, name);
     }
+
+    /**
+     * Returns a SIS type name implementation with the values of the given arbitrary implementation.
+     * This method performs the first applicable action in the following choices:
+     *
+     * <ul>
+     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
+     *   <li>Otherwise if the given object is already an instance of {@code DefaultTypeName},
+     *       then it is returned unchanged.</li>
+     *   <li>Otherwise a new {@code DefaultTypeName} instance is created
+     *       with the same values than the given name.</li>
+     * </ul>
+     *
+     * @param  object The object to get as a SIS implementation, or {@code null} if none.
+     * @return A SIS implementation containing the values of the given object (may be the
+     *         given object itself), or {@code null} if the argument was null.
+     *
+     * @since 0.5
+     */
+    public static DefaultTypeName castOrCopy(final TypeName object) {
+        if (object == null || object instanceof DefaultTypeName) {
+            return (DefaultTypeName) object;
+        }
+        return new DefaultTypeName(object.scope(), object.toInternationalString());
+    }
+
+    /**
+     * Sets {@link #valueClass} to the given value, only if the scope and the name of this {@code TypeName}
+     * are equal to the given values. The check for scope and name is a protection against renaming that user
+     * could apply if they subclass {@link DefaultNameFactory}. If the user performed such renaming, then the
+     * value class may be wrong, so we will ignore the given value class and let {@link #toClass()} computes
+     * the class itself.
+     */
+    final void setValueClass(final NameSpace scope, final String name, final Class<?> valueClass) {
+        if (scope == super.scope() && name.equals(super.toString())) {
+            this.valueClass = valueClass;
+        }
+    }
+
+    /**
+     * Returns the Java class associated to this type name.
+     * The default implementation parses this name in different ways depending on the {@linkplain #scope() scope}:
+     *
+     * <ul>
+     *   <li>If the scope is {@code "OGC"}, then:
+     *     <ul>
+     *       <li>If the name is {@code "CharacterString"}, {@code "Integer"}, {@code "Real"} or other recognized names
+     *           (see {@linkplain DefaultTypeName class javadoc}), then the corresponding class is returned.</li>
+     *       <li>Otherwise {@link UnknownNameException} is thrown.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Else if the scope is {@code "class"}, then:
+     *     <ul>
+     *       <li>If the name is accepted by {@link Class#forName(String)}, then that class is returned.</li>
+     *       <li>Otherwise {@link UnknownNameException} is thrown.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Else if the scope {@linkplain DefaultNameSpace#isGlobal() is global}, then:
+     *     <ul>
+     *       <li>If the name is one of the names recognized in {@code "OGC"} scope (see above),
+     *           then the corresponding class is returned.</li>
+     *       <li>Otherwise {@code null} is returned. No exception is thrown because names in the global namespace
+     *           could be anything, so we can not be sure that the given name was wrong.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Otherwise {@code null} is returned, since this method can not check the validity of names in other
+     *       namespaces.</li>
+     * </ul>
+     *
+     * @return The Java class associated to this {@code TypeName},
+     *         or {@code null} if there is no mapping from this name to a Java class.
+     * @throws UnknownNameException if a mapping from this name to a Java class was expected to exist
+     *         (typically because of the {@linkplain #scope() scope}) but the operation failed.
+     *
+     * @see Names#toClass(TypeName)
+     * @see DefaultNameFactory#toTypeName(Class)
+     *
+     * @since 0.5
+     */
+    public Class<?> toClass() throws UnknownNameException {
+        /*
+         * No synchronization, because it is not a problem if two threads compute the same value concurrently.
+         * No volatile field neither, because instances of Class are safely published (well, I presume...).
+         */
+        Class<?> c = valueClass;
+        if (c == Void.TYPE) {
+            return null;
+        }
+        if (c == null) {
+            /*
+             * Invoke super.foo() instead than this.foo() because we do not want to invoke any overridden method.
+             * This is for ensuring that two TypeNames constructed with the same name will map to the same class.
+             * See 'valueClass' javadoc for more information.
+             */
+            try {
+                c = TypeNames.toClass(TypeNames.namespace(super.scope()), super.toString());
+            } catch (ClassNotFoundException e) {
+                throw new UnknownNameException(TypeNames.unknown(super.toFullyQualifiedName()), e);
+            }
+            if (c == null) {
+                throw new UnknownNameException(TypeNames.unknown(super.toFullyQualifiedName()));
+            }
+            valueClass = c;
+        }
+        return (c != Void.TYPE) ? c : null;
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -17,12 +17,15 @@
 package org.apache.sis.util.iso;
 
 import java.util.Collections;
+import org.opengis.util.TypeName;
 import org.opengis.util.LocalName;
+import org.opengis.util.MemberName;
 import org.opengis.util.GenericName;
 import org.opengis.util.NameSpace;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.Static;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.util.UnknownNameException;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
@@ -70,6 +73,13 @@ import static org.apache.sis.util.Argume
  * @since   0.5
  * @version 0.5
  * @module
+ *
+ * @see DefaultNameFactory
+ * @see DefaultNameSpace
+ * @see DefaultScopedName
+ * @see DefaultLocalName
+ * @see DefaultTypeName
+ * @see DefaultMemberName
  */
 public final class Names extends Static {
     /**
@@ -86,7 +96,7 @@ public final class Names extends Static 
      * @return The namespace object.
      */
     private static NameSpace createNameSpace(final CharSequence namespace, final String separator) {
-        if (namespace == null) {
+        if (namespace == null || namespace.length() == 0) {
             return null;
         }
         return DefaultFactories.NAMES.createNameSpace(
@@ -95,17 +105,30 @@ public final class Names extends Static 
     }
 
     /**
+     * Creates a local or scoped name in the given namespace.
+     * The character sequences can be either {@link String} or {@link InternationalString} instances.
+     * The {@code namespace} character sequences is taken verbatim, while {@code scopedName} is parsed
+     * as described in {@linkplain DefaultNameFactory#createGenericName(NameSpace, CharSequence...) name factory}.
+     *
+     * @param  namespace  The namespace, or {@code null} for the global namespace.
+     * @param  separator  The separator between the namespace and the scoped name.
+     * @param  scopedName The name to parse.
+     * @return A local or scoped name in the given namespace.
+     */
+    public static GenericName parseGenericName(final CharSequence namespace, final String separator, final CharSequence scopedName) {
+        ensureNonNull("localPart", scopedName);
+        ensureNonNull("separator", separator);
+        return DefaultFactories.NAMES.parseGenericName(createNameSpace(namespace, separator), scopedName);
+    }
+
+    /**
      * Creates a name which is local in the given namespace.
      * The character sequences can be either {@link String} or {@link InternationalString} instances.
      * Those character sequences are taken verbatim; they are <em>not</em> parsed into their components.
      *
      * <div class="note"><b>Note:</b> it is possible to split the {@code namespace} and {@code localPart}
-     * strings into smaller name components. If such finer grain control is desired, one can use
-     * {@link DefaultNameFactory} instead of this {@code Names} class.</div>
-     *
-     * <div class="note"><b>Performance note:</b> this method is okay for <em>casual</em> use. If many names need
-     * to be created in the same namespace, then {@link DefaultNameFactory#createLocalName(NameSpace, CharSequence)}
-     * is more efficient since it allows to create the {@code NameSpace} object only once.</div>
+     * strings into smaller name components (e.g. namespaces contained in other namespaces). If such finer
+     * grain control is desired, one can use {@link DefaultNameFactory} instead of this {@code Names} class.</div>
      *
      * The following table shows where the strings given in argument will go:
      *
@@ -117,7 +140,7 @@ public final class Names extends Static 
      * </table></blockquote>
      *
      * <div class="note"><b>Example:</b>
-     * for a name created by {@code create("http://www.opengis.net/gml/srs/epsg.xml", "#", "4326")}:
+     * for a name created by {@code createLocalName("http://www.opengis.net/gml/srs/epsg.xml", "#", "4326")}:
      * <blockquote><table class="compact" summary="Examples of return values for a name built by this method.">
      *   <tr><td>• <code>name.{@linkplain DefaultLocalName#toString() toString()}</code></td>
      *       <td>returns the {@code "4326"} string.</td></tr>
@@ -129,6 +152,10 @@ public final class Names extends Static 
      *       <td>returns the {@code "{http://www.opengis.net/gml/srs/epsg.xml}4326"} string.</td></tr>
      * </table></blockquote></div>
      *
+     * <div class="note"><b>Performance note:</b> this method is okay for <em>casual</em> use. If many names need
+     * to be created in the same namespace, then {@link DefaultNameFactory#createLocalName(NameSpace, CharSequence)}
+     * is more efficient since it allows to create the {@code NameSpace} object only once.</div>
+     *
      * @param  namespace The namespace, or {@code null} for the global namespace.
      * @param  separator The separator between the namespace and the local part.
      * @param  localPart The name which is locale in the given namespace.
@@ -141,6 +168,121 @@ public final class Names extends Static 
     }
 
     /**
+     * Creates a type name which is local in the given namespace.
+     * The character sequences can be either {@link String} or {@link InternationalString} instances.
+     * Those character sequences are taken verbatim; they are <em>not</em> parsed into their components.
+     *
+     * <div class="note"><b>Example:</b> {@code createTypeName("gco", ":", "Integer")} returns a name
+     * which can be used for representing the type of {@code <gco:Integer>} elements in XML files.</div>
+     *
+     * <div class="note"><b>Performance note:</b> this method is okay for <em>casual</em> use. If many names need
+     * to be created in the same namespace, then {@link DefaultNameFactory#createTypeName(NameSpace, CharSequence)}
+     * is more efficient since it allows to create the {@code NameSpace} object only once.</div>
+     *
+     * @param  namespace The namespace, or {@code null} for the global namespace.
+     * @param  separator The separator between the namespace and the local part.
+     * @param  localPart The name which is locale in the given namespace.
+     * @return A local name in the given namespace.
+     */
+    public static TypeName createTypeName(final CharSequence namespace, final String separator, final CharSequence localPart) {
+        ensureNonNull("localPart", localPart);
+        ensureNonNull("separator", separator);
+        return DefaultFactories.NAMES.createTypeName(createNameSpace(namespace, separator), localPart);
+    }
+
+    /**
+     * Creates a member name for values of the given class. A {@link TypeName} will be inferred
+     * from the given {@code valueClass} as documented in the {@link DefaultTypeName} javadoc.
+     *
+     * <div class="note"><b>Performance note:</b> this method is okay for <em>casual</em> use. If many names
+     * need to be created, then {@link DefaultNameFactory#createMemberName(NameSpace, CharSequence, TypeName)}
+     * is more efficient since it allows to create the {@code NameSpace} and {@code TypeName} objects only once.</div>
+     *
+     * @param  namespace  The namespace, or {@code null} for the global namespace.
+     * @param  separator  The separator between the namespace and the local part.
+     * @param  localPart  The name which is locale in the given namespace.
+     * @param  valueClass The type of values, used for inferring a {@link TypeName} instance.
+     * @return A member name in the given namespace for values of the given type.
+     */
+    public static MemberName createMemberName(final CharSequence namespace, final String separator,
+            final CharSequence localPart, final Class<?> valueClass)
+    {
+        ensureNonNull("localPart",  localPart);
+        ensureNonNull("separator",  separator);
+        ensureNonNull("valueClass", valueClass);
+        return DefaultFactories.NAMES.createMemberName(
+                createNameSpace(namespace, separator), localPart,
+                DefaultFactories.SIS_NAMES.toTypeName(valueClass));
+    }
+
+    /**
+     * Returns the Java class associated to the given type name.
+     * The method performs the following choices:
+     *
+     * <ul>
+     *   <li>If the given type name is {@code null}, then this method returns {@code null}.</li>
+     *   <li>Else if the given type name is an instance of {@code DefaultTypeName},
+     *       then this method delegates to {@link DefaultTypeName#toClass()}.</li>
+     *   <li>Else if the type name {@linkplain DefaultTypeName#scope() scope} is {@code "OGC"}, then:
+     *     <ul>
+     *       <li>If the name is {@code "CharacterString"}, {@code "Integer"}, {@code "Real"} or other recognized names
+     *           (see {@link DefaultTypeName} javadoc), then the corresponding class is returned.</li>
+     *       <li>Otherwise {@link UnknownNameException} is thrown.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Else if the scope is {@code "class"}, then:
+     *     <ul>
+     *       <li>If the name is accepted by {@link Class#forName(String)}, then that class is returned.</li>
+     *       <li>Otherwise {@link UnknownNameException} is thrown.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Else if the scope {@linkplain DefaultNameSpace#isGlobal() is global}, then:
+     *     <ul>
+     *       <li>If the name is one of the names recognized in {@code "OGC"} scope (see above),
+     *           then the corresponding class is returned.</li>
+     *       <li>Otherwise {@code null} is returned. No exception is thrown because names in the global namespace
+     *           could be anything, so we can not be sure that the given name was wrong.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Otherwise {@code null} is returned, since this method can not check the validity of names in other
+     *       namespaces.</li>
+     * </ul>
+     *
+     * @param  type The type name from which to infer a Java class.
+     * @return The Java class associated to the given {@code TypeName},
+     *         or {@code null} if there is no mapping from the given name to a Java class.
+     * @throws UnknownNameException if a mapping from the given name to a Java class was expected to exist
+     *         (typically because of the {@linkplain DefaultTypeName#scope() scope}) but the operation failed.
+     *
+     * @see DefaultTypeName#toClass()
+     * @see DefaultNameFactory#toTypeName(Class)
+     *
+     * @since 0.5
+     */
+    public static Class<?> toClass(final TypeName type) throws UnknownNameException {
+        if (type == null) {
+            return null;
+        }
+        Class<?> c;
+        if (type instanceof DefaultTypeName) {
+            c = ((DefaultTypeName) type).toClass();
+        } else {
+            try {
+                c = TypeNames.toClass(TypeNames.namespace(type.scope()), type.toString());
+            } catch (ClassNotFoundException e) {
+                throw new UnknownNameException(TypeNames.unknown(type), e);
+            }
+            if (c == null) {
+                throw new UnknownNameException(TypeNames.unknown(type));
+            }
+            if (c == Void.TYPE) {
+                c = null;
+            }
+        }
+        return c;
+    }
+
+    /**
      * Formats the given name in <cite>expanded form</cite> close to the Java Content Repository (JCR) definition.
      * The expanded form is defined as below:
      *
@@ -148,13 +290,15 @@ public final class Names extends Static 
      * NameSpace    ::= name.{@linkplain AbstractName#scope() scope()}.{@linkplain DefaultNameSpace#name() name()}.toString()
      * LocalPart    ::= name.{@linkplain AbstractName#toString() toString()}</pre></blockquote>
      *
-     * @param  name The generic name to format in expanded form.
-     * @return Expanded form of the given generic name.
+     * @param  name The generic name to format in expanded form, or {@code null}.
+     * @return Expanded form of the given generic name, or {@code null} if the given name was null.
      *
      * @see DefaultNameSpace#toString()
      */
     public static String toExpandedString(final GenericName name) {
-        ensureNonNull("name", name);
+        if (name == null) {
+            return null;
+        }
         final String localPart = name.toString();
         final NameSpace scope = name.scope();
         if (scope == null || scope.isGlobal()) {

Copied: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java (from r1625241, sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java?p2=sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java&p1=sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java&r1=1625241&r2=1626345&rev=1626345&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -26,7 +26,6 @@ import javax.xml.bind.annotation.XmlTran
 import org.opengis.util.Type;
 import org.opengis.util.RecordType;
 import org.opengis.util.MemberName;
-import org.opengis.feature.AttributeType;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Numbers;
@@ -36,6 +35,7 @@ import org.apache.sis.internal.util.Coll
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.JDK7;
+import org.apache.sis.internal.simple.SimpleAttributeType;
 
 
 /**
@@ -152,8 +152,8 @@ abstract class RecordDefinition { // Int
         int i = 0;
         for (final Map.Entry<? extends MemberName, ? extends Type> entry : memberTypes.entrySet()) {
             final Type type = entry.getValue();
-            if (type instanceof AttributeType) {
-                final Class<?> c = ((AttributeType) type).getValueClass();
+            if (type instanceof SimpleAttributeType) {
+                final Class<?> c = ((SimpleAttributeType) type).getValueClass();
                 if (c != Object.class) {
                     if (valueClasses == null) {
                         valueClasses = new Class<?>[size];

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -126,14 +126,15 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns the ISO classname (if available) or the Java classname (as a fallback)
-     * of the given code. This method uses the {@link UML} annotation if it exists, or
+     * Returns the ISO classname (if available) or the Java classname (as a fallback) of the given
+     * enumeration or code list value. This method uses the {@link UML} annotation if it exists, or
      * fallback on the {@linkplain Class#getSimpleName() simple class name} otherwise.
      *
      * <div class="note"><b>Examples:</b>
      * <ul>
-     *   <li>{@code getListName(AxisDirection.NORTH)} returns {@code "CS_AxisDirection"}.</li>
-     *   <li>{@code getListName(CharacterSet.UTF_8)} returns {@code "MD_CharacterSetCode"}.</li>
+     *   <li>{@code getListName(ParameterDirection.IN_OUT)}      returns {@code "SV_ParameterDirection"}.</li>
+     *   <li>{@code getListName(AxisDirection.NORTH)}            returns {@code "CS_AxisDirection"}.</li>
+     *   <li>{@code getListName(CharacterSet.UTF_8)}             returns {@code "MD_CharacterSetCode"}.</li>
      *   <li>{@code getListName(ImagingCondition.BLURRED_IMAGE)} returns {@code "MD_ImagingConditionCode"}.</li>
      * </ul>
      * </div>
@@ -151,13 +152,14 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns the ISO name (if available) or the Java name (as a fallback) of the given code.
-     * If the code has no {@link UML} identifier, then the programmatic name is used as a fallback.
+     * Returns the ISO name (if available) or the Java name (as a fallback) of the given enumeration or code list
+     * value. If the value has no {@link UML} identifier, then the programmatic name is used as a fallback.
      *
      * <div class="note"><b>Examples:</b>
      * <ul>
-     *   <li>{@code getCodeName(AxisDirection.NORTH)} returns {@code "north"}.</li>
-     *   <li>{@code getCodeName(CharacterSet.UTF_8)} returns {@code "utf8"}.</li>
+     *   <li>{@code getCodeName(ParameterDirection.IN_OUT)}      returns {@code "in/out"}.</li>
+     *   <li>{@code getCodeName(AxisDirection.NORTH)}            returns {@code "north"}.</li>
+     *   <li>{@code getCodeName(CharacterSet.UTF_8)}             returns {@code "utf8"}.</li>
      *   <li>{@code getCodeName(ImagingCondition.BLURRED_IMAGE)} returns {@code "blurredImage"}.</li>
      * </ul>
      * </div>
@@ -180,7 +182,7 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns a unlocalized title for the given code.
+     * Returns a unlocalized title for the given enumeration or code list value.
      * This method builds a title using heuristics rules, which should give reasonable
      * results without the need of resource bundles. For better results, consider using
      * {@link #getCodeTitle(CodeList)} instead.
@@ -222,7 +224,7 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns the title of the given code. Title are usually much shorter than descriptions.
+     * Returns the title of the given enumeration or code list value. Title are usually much shorter than descriptions.
      * English titles are often the same than the {@linkplain #getCodeLabel(CodeList) code labels}.
      *
      * @param  code The code for which to get the title, or {@code null}.
@@ -235,7 +237,7 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns the description of the given code, or {@code null} if none.
+     * Returns the description of the given enumeration or code list value, or {@code null} if none.
      * For a description of the code list as a whole instead than a particular code,
      * see {@link Types#getDescription(Class)}.
      *

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -38,6 +38,13 @@
  *       <li>{@link org.apache.sis.util.iso.DefaultScopedName} for a composite of a <cite>head</cite> name and a <cite>tail</cite> name.</li>
  *     </ul>
  *   </li>
+ *   <li>Implementations of {@link org.opengis.util.Record} and related classes:
+ *     <ul>
+ *       <li>{@link org.apache.sis.util.iso.DefaultRecord}       for a list of logically related elements as (<var>name</var>, <var>value</var>) pairs.</li>
+ *       <li>{@link org.apache.sis.util.iso.DefaultRecordType}   for definition of the type of a {@code Record}.</li>
+ *       <li>{@link org.apache.sis.util.iso.DefaultRecordSchema} for a collection of {@code RecordType}s in a given namespace.</li>
+ *     </ul>
+ *   </li>
  *   <li>Static utility methods:
  *     <ul>
  *       <li>{@link org.apache.sis.util.iso.Types} for working with UML identifiers and description of GeoAPI types.</li>

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Fri Sep 19 21:46:39 2014
@@ -373,6 +373,11 @@ public final class Errors extends Indexe
         public static final short InconsistentAttribute_2 = 47;
 
         /**
+         * Expected “{0}” namespace for “{1}”.
+         */
+        public static final short InconsistentNamespace_2 = 162;
+
+        /**
          * Inconsistent table columns.
          */
         public static final short InconsistentTableColumns = 48;
@@ -453,6 +458,11 @@ public final class Errors extends Indexe
         public static final short MissingAuthority_1 = 135;
 
         /**
+         * “{0}” has no namespace.
+         */
+        public static final short MissingNamespace_1 = 163;
+
+        /**
          * This operation requires the “{0}” module.
          */
         public static final short MissingRequiredModule_1 = 61;
@@ -668,6 +678,11 @@ public final class Errors extends Indexe
         public static final short PropertyNotFound_2 = 71;
 
         /**
+         * Record “{1}” is already defined in schema “{0}”.
+         */
+        public static final short RecordAlreadyDefined_2 = 161;
+
+        /**
          * Recursive call while creating an object for the “{0}” key.
          */
         public static final short RecursiveCreateCallForKey_1 = 99;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1626345&r1=1626344&r2=1626345&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Fri Sep 19 21:46:39 2014
@@ -84,6 +84,7 @@ IncompatiblePropertyValue_1       = Prop
 IncompatibleUnit_1                = Unit \u201c{0}\u201d is incompatible with current value.
 IncompatibleUnits_2               = Units \u201c{0}\u201d and \u201c{1}\u201d are incompatible.
 InconsistentAttribute_2           = Value \u201c{1}\u201d of attribute \u2018{0}\u2019 is inconsistent with other attributes.
+InconsistentNamespace_2           = Expected \u201c{0}\u201d namespace for \u201c{1}\u201d.
 InconsistentTableColumns          = Inconsistent table columns.
 IdentifierAlreadyBound_1          = Identifier \u201c{0}\u201d is already associated to another object.
 IndexOutOfBounds_1                = Index {0} is out of bounds.
@@ -101,6 +102,7 @@ MismatchedParameterDescriptor_1   = Mism
 MismatchedPropertyType_1          = Mismatched type for \u201c{0}\u201d property.
 MismatchedValueClass_3            = Class of \u201c{0}\u201d values is \u2018{2}\u2019, but the requested type is \u2018{1}\u2019.
 MissingAuthority_1                = No authority was specified for code \u201c{0}\u201d. The expected syntax is \u201cAUTHORITY:CODE\u201d.
+MissingNamespace_1                = \u201c{0}\u201d has no namespace.
 MissingRequiredModule_1           = This operation requires the \u201c{0}\u201d module.
 MissingSchemeInURI                = Missing scheme in URI.
 MissingValueForOption_1           = Missing value for \u201c{0}\u201d option.
@@ -145,9 +147,10 @@ OddArrayLength_1                  = Arra
 PropertyAlreadyExists_2           = Property \u201c{1}\u201d is already exists in \u201c{0}\u201d.
 ParameterNotFound_2               = No parameter named \u201c{1}\u201d has been found in \u201c{0}\u201d.
 PropertyNotFound_2                = No property named \u201c{1}\u201d has been found in \u201c{0}\u201d.
-SingularMatrix                    = Matrix is singular.
+RecordAlreadyDefined_2            = Record \u201c{1}\u201d is already defined in schema \u201c{0}\u201d.
 RecursiveCreateCallForKey_1       = Recursive call while creating an object for the \u201c{0}\u201d key.
 RequireDecimalSeparator           = A decimal separator is required.
+SingularMatrix                    = Matrix is singular.
 StalledThread_1                   = Thread \u201c{0}\u201d seems stalled.
 StreamIsForwardOnly_1             = Can not move backward in the \u201c{0}\u201d stream.
 TooFewArguments_2                 = Expected at least {0} argument{0,choice,1#|2#s}, but got {1}.



Mime
View raw message