sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1609863 [1/2] - in /sis/branches/JDK7: ./ 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/metadata/ core/sis-...
Date Fri, 11 Jul 2014 22:58:30 GMT
Author: desruisseaux
Date: Fri Jul 11 22:58:29 2014
New Revision: 1609863

URL: http://svn.apache.org/r1609863
Log:
Merge from the JDK8 branch.

Added:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
      - copied, changed from r1609862, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
      - copied unchanged from r1609862, sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_RestrictionCode.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/CollectionsExtTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK8:r1607690-1609862

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -276,9 +276,9 @@ public class DefaultFeatureType extends 
                 minimumOccurs = ((AttributeType<?>) property).getMinimumOccurs();
                 maximumOccurs = ((AttributeType<?>) property).getMaximumOccurs();
                 isSimple &= (minimumOccurs == maximumOccurs);
-            } else if (property instanceof FieldType) { // TODO: check for AssociationRole instead (after GeoAPI upgrade).
-                minimumOccurs = ((FieldType) property).getMinimumOccurs();
-                maximumOccurs = ((FieldType) property).getMaximumOccurs();
+            } else if (property instanceof FeatureAssociationRole) {
+                minimumOccurs = ((FeatureAssociationRole) property).getMinimumOccurs();
+                maximumOccurs = ((FeatureAssociationRole) property).getMaximumOccurs();
                 isSimple = false;
             } else {
                 continue; // For feature operations, maximumOccurs is implicitly 0.

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -198,7 +198,14 @@ header: for (int i=0; ; i++) {
             if (feature != null) {
                 value = feature.getPropertyValue(propertyType.getName().toString());
                 if (value == null) {
-                    if (propertyType instanceof FieldType && ((FieldType) propertyType).getMinimumOccurs() == 0) {
+                    if (propertyType instanceof AttributeType &&
+                            ((AttributeType) propertyType).getMinimumOccurs() == 0)
+                    {
+                        continue; // If no value, skip the full row.
+                    }
+                    if (propertyType instanceof FeatureAssociationRole &&
+                            ((FeatureAssociationRole) propertyType).getMinimumOccurs() == 0)
+                    {
                         continue; // If no value, skip the full row.
                     }
                 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_RestrictionCode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_RestrictionCode.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_RestrictionCode.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_RestrictionCode.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -47,15 +47,27 @@ public final class MD_RestrictionCode ex
     }
 
     /**
-     * {@inheritDoc}
+     * Fix the spelling of words that changed between ISO 19115:2003 and ISO 19115:2014,
+     * then wraps the proxy value into an adapter.
+     *
+     * <p>The spelling of "license" was changed to "licence" in latest standard, but XML
+     * marshalling shall use the previous spelling until XML schema are updated.</p>
+     *
+     * @param proxy The proxy version of {@link CodeList}, to be marshalled.
+     * @return The adapter that wraps the proxy value.
      */
     @Override
     protected MD_RestrictionCode wrap(CodeListProxy proxy) {
+        if ("licence".equals(proxy.codeListValue)) {
+            proxy.codeListValue = "license";
+        }
         return new MD_RestrictionCode(proxy);
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the class of code list wrapped by this adapter.
+     *
+     * @return The code list class.
      */
     @Override
     protected Class<Restriction> getCodeListClass() {
@@ -75,10 +87,16 @@ public final class MD_RestrictionCode ex
 
     /**
      * Invoked by JAXB on unmarshalling.
+     * This method performs the reverse of the {@link #wrap(CodeListProxy)} spelling change:
+     * it converts "license" (ISO 19115:2003) to "licence" (ISO 19115:2014) in order to have
+     * only one {@code CodeList} instance for both.
      *
      * @param proxy The unmarshalled value.
      */
     public void setElement(final CodeListProxy proxy) {
+        if ("license".equals(proxy.codeListValue)) {
+            proxy.codeListValue = "licence";
+        }
         this.proxy = proxy;
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import org.apache.sis.metadata.AbstractMetadata;
+import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.util.ArgumentChecks;
 
@@ -159,8 +160,8 @@ public abstract class LegacyPropertyAdap
                         }
                         caller.warningOccurred = true;
                     }
-                    MetadataUtilities.warning(callerClass, callerMethod,
-                            Messages.Keys.IgnoredPropertiesAfterFirst_1, valueClass);
+                    Context.warningOccured(Context.current(), callerClass, callerMethod,
+                            Messages.class, Messages.Keys.IgnoredPropertiesAfterFirst_1, valueClass);
                 }
                 return value;
             }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -105,7 +105,11 @@ final class Cloner extends org.apache.si
                 } else {
                     // Conservatively assumes a List if we are not sure to have a Set,
                     // since the list is less destructive (no removal of duplicated).
-                    collection = Containers.unmodifiableList(array);
+                    switch (array.length) {
+                        case 0:  collection = Collections.EMPTY_LIST; break; // Redundant with isEmpty(), but we are paranoiac.
+                        case 1:  collection = Collections.singletonList(array[0]); break;
+                        default: collection = Containers.unmodifiableList(array); break;
+                    }
                 }
             }
             return collection;

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -385,7 +385,7 @@ public abstract class ModifiableMetadata
             if (unmodifiable == FREEZING) {
                 /*
                  * freeze() method is under progress. The source collection is already
-                 * an unmodifiable instance created by unmodifiable(Object).
+                 * an unmodifiable instance created by Cloner.clone(Object).
                  */
                 assert collectionType(elementType).isInstance(source);
                 return (Collection<E>) source;

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -1100,9 +1100,7 @@ class PropertyAccessor {
     {
         assert type.isInstance(metadata1) : metadata1;
         assert type.isInstance(metadata2) : metadata2;
-        final int count = (mode == ComparisonMode.STRICT &&
-                EXTRA_GETTER.getDeclaringClass().isInstance(metadata2)) ? allCount : standardCount;
-        for (int i=0; i<count; i++) {
+        for (int i=0; i<standardCount; i++) {
             final Method method = getters[i];
             final Object value1 = get(method, metadata1);
             final Object value2 = get(method, metadata2);
@@ -1118,6 +1116,16 @@ class PropertyAccessor {
                 return false;
             }
         }
+        /*
+         * One final check for the IdentifiedObjects.getIdentifiers() collection.
+         */
+        if (mode == ComparisonMode.STRICT && EXTRA_GETTER.getDeclaringClass().isInstance(metadata2)) {
+            final Object value1 = get(EXTRA_GETTER, metadata1);
+            final Object value2 = get(EXTRA_GETTER, metadata2);
+            if (!isNullOrEmpty(value1) || !isNullOrEmpty(value2)) {
+                return Utilities.deepEquals(value1, value2, mode);
+            }
+        }
         return true;
     }
 
@@ -1134,7 +1142,20 @@ class PropertyAccessor {
             final Cloner cloner = new Cloner();
             for (int i=0; i<allCount; i++) {
                 final Method setter = setters[i];
-                if (setter != null && !setter.isAnnotationPresent(Deprecated.class)) {
+                if (setter != null) {
+                    if (setter.isAnnotationPresent(Deprecated.class)) {
+                        /*
+                         * We need to skip deprecated setter methods, because those methods may delegate
+                         * their work to other setter methods in different objects and those objects may
+                         * have been made unmodifiable by previous iteration in this loop.  If we do not
+                         * skip them, we get an UnmodifiableMetadataException in the call to set(…).
+                         *
+                         * Note that in some cases, only the setter method is deprecated, not the getter.
+                         * This happen when Apache SIS classes represent a more recent ISO standard than
+                         * the GeoAPI interfaces.
+                         */
+                        continue;
+                    }
                     final Method getter = getters[i];
                     final Object source = get(getter, metadata);
                     final Object target = cloner.clone(source);
@@ -1142,7 +1163,7 @@ class PropertyAccessor {
                         arguments[0] = target;
                         set(setter, metadata, arguments);
                         /*
-                         * We invoke the set(...) method which do not perform type conversion
+                         * We invoke the set(…) method variant that do not perform type conversion
                          * because we don't want it to replace the immutable collection created
                          * by ModifiableMetadata.unmodifiable(source). Conversion should not be
                          * required anyway because the getter method should have returned a value

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -28,7 +28,7 @@ import org.apache.sis.util.iso.Types;
 
 
 /**
- * Information about the individual and / or organisation of the party.
+ * Information about the individual and / or organization of the party.
  *
  * @author  Rémi Maréchal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -174,7 +174,7 @@ public class DefaultCitation extends ISO
      * Constructs a citation with the specified responsible party.
      * This convenience constructor initializes the citation title
      * to the first non-null of the following properties:
-     * {@linkplain DefaultResponsibleParty#getOrganisationName() organisation name},
+     * {@linkplain DefaultResponsibleParty#getOrganisationName() organization name},
      * {@linkplain DefaultResponsibleParty#getPositionName() position name} or
      * {@linkplain DefaultResponsibleParty#getIndividualName() individual name}.
      *

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -16,6 +16,9 @@
  */
 package org.apache.sis.metadata.iso.citation;
 
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
@@ -24,7 +27,11 @@ import org.opengis.metadata.citation.Add
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.Telephone;
 import org.opengis.metadata.citation.OnlineResource;
+import org.opengis.metadata.citation.TelephoneType;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.util.resources.Messages;
+import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
 
 /**
@@ -33,8 +40,9 @@ import org.apache.sis.metadata.iso.ISOMe
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
+ * @author  Rémi Maréchal (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlType(name = "CI_Contact_Type", propOrder = {
@@ -49,22 +57,22 @@ public class DefaultContact extends ISOM
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 3844283689911660546L;
+    private static final long serialVersionUID = -969735574940462381L;
 
     /**
      * Telephone numbers at which the organization or individual may be contacted.
      */
-    private Telephone phone;
+    private Collection<Telephone> phones;
 
     /**
-     * Physical and email address at which the organization or individual may be contacted.
+     * Physical and email addresses at which the organization or individual may be contacted.
      */
-    private Address address;
+    private Collection<Address> addresses;
 
     /**
      * On-line information that can be used to contact the individual or organization.
      */
-    private OnlineResource onlineResource;
+    private Collection<OnlineResource> onlineResources;
 
     /**
      * Time period (including time zone) when individuals can contact the organization or individual.
@@ -77,6 +85,11 @@ public class DefaultContact extends ISOM
     private InternationalString contactInstructions;
 
     /**
+     * Type of the contact.
+     */
+    private InternationalString contactType;
+
+    /**
      * Constructs an initially empty contact.
      */
     public DefaultContact() {
@@ -89,7 +102,7 @@ public class DefaultContact extends ISOM
      *        organization, or {@code null} if none.
      */
     public DefaultContact(final OnlineResource resource) {
-        this.onlineResource = resource;
+        this.onlineResources = singleton(resource, OnlineResource.class);
     }
 
     /**
@@ -104,11 +117,12 @@ public class DefaultContact extends ISOM
     public DefaultContact(final Contact object) {
         super(object);
         if (object != null) {
-            phone               = object.getPhone();
-            address             = object.getAddress();
-            onlineResource      = object.getOnlineResource();
+            phones              = copyCollection(object.getPhones(), Telephone.class);
+            addresses           = copyCollection(object.getAddresses(), Address.class);
+            onlineResources     = copyCollection(object.getOnlineResources(), OnlineResource.class);
             hoursOfService      = object.getHoursOfService();
             contactInstructions = object.getContactInstructions();
+            contactType         = object.getContactType();
         }
     }
 
@@ -140,64 +154,208 @@ public class DefaultContact extends ISOM
     /**
      * Returns telephone numbers at which the organization or individual may be contacted.
      *
+     * @return Telephone numbers at which the organization or individual may be contacted.
+     *
+     * @since 0.5
+     */
+    @Override
+    public Collection<Telephone> getPhones() {
+        return phones = nonNullCollection(phones, Telephone.class);
+    }
+
+    /**
+     * Sets telephone numbers at which the organization or individual may be contacted.
+     *
+     * @param newValues The new telephones.
+     *
+     * @since 0.5
+     */
+    public void setPhones(Collection<? extends Telephone> newValues) {
+        phones = writeCollection(newValues, phones, Telephone.class);
+        /*
+         * Code below this point will be deleted after we removed the deprecated methods in DefaultTelephone.
+         * This code notifies all DefaultTelephone instances about the the list of phones in order to allow
+         * the deprecated Telephone.getVoices() and Telephone.getFacsimiles() methods to fetches information
+         * from the phones list.
+         */
+        if (phones != null) {
+            boolean modified = false;
+            final Telephone[] p = phones.toArray(new Telephone[newValues.size()]);
+            for (int i=0; i<p.length; i++) {
+                final Telephone phone = p[i];
+                if (phone instanceof DefaultTelephone) {
+                    p[i] = ((DefaultTelephone) phone).setOwner(phones);
+                    modified |= (p[i] != phone);
+                }
+            }
+            if (modified) {
+                phones.clear();
+                phones.addAll(Arrays.asList(p));
+            }
+        }
+    }
+
+    /**
+     * Returns telephone numbers at which the organization or individual may be contacted.
+     * This method returns the first telephone number associated to {@link TelephoneType#VOICE}
+     * or {@link TelephoneType#FACSIMILE FACSIMILE}.
+     *
      * @return Telephone numbers at which the organization or individual may be contacted, or {@code null}.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #getPhones()}.
      */
     @Override
+    @Deprecated
     @XmlElement(name = "phone")
-    public Telephone getPhone() {
+    public final Telephone getPhone() {
+        Telephone phone = null;
+        if (phones != null) {
+            TelephoneType ignored = null;
+            for (final Telephone c : phones) {
+                final TelephoneType type = c.getNumberType();
+                if (TelephoneType.VOICE.equals(type) || TelephoneType.FACSIMILE.equals(type)) {
+                    if (phone == null) {
+                        phone = c;
+                    }
+                } else if (ignored == null) {
+                    ignored = type;
+                }
+            }
+            if (ignored != null) {
+                Context.warningOccured(Context.current(), DefaultContact.class, "getPhone",
+                        Messages.class, Messages.Keys.IgnoredPropertyAssociatedTo_1, ignored.toString());
+            }
+        }
         return phone;
     }
 
     /**
      * Sets telephone numbers at which the organization or individual may be contacted.
+     * This method delegates to {@link #setPhones(Collection)}.
      *
      * @param newValue The new telephone, or {@code null} if none.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #setPhones(Collection)}.
      */
-    public void setPhone(final Telephone newValue) {
-        checkWritePermission();
-        phone = newValue;
+    @Deprecated
+    public final void setPhone(Telephone newValue) {
+        Collection<Telephone> newValues = null;
+        if (newValue != null) {
+            if (newValue instanceof DefaultTelephone) {
+                newValues = ((DefaultTelephone) newValue).getOwner();
+            } else {
+                newValues = new ArrayList<>(4);
+                for (String number : newValue.getVoices()) {
+                    newValues.add(new DefaultTelephone(number, TelephoneType.VOICE));
+                }
+                for (String number : newValue.getFacsimiles()) {
+                    newValues.add(new DefaultTelephone(number, TelephoneType.FACSIMILE));
+                }
+            }
+        }
+        setPhones(newValues);
+    }
+
+    /**
+     * Returns the physical and email addresses at which the organization or individual may be contacted.
+     *
+     * @return Physical and email addresses at which the organization or individual may be contacted, or {@code null}.
+     *
+     * @since 0.5
+     */
+    @Override
+    public Collection<Address> getAddresses() {
+        return addresses = nonNullCollection(addresses, Address.class);
+    }
+
+    /**
+     * Sets the physical and email addresses at which the organization or individual may be contacted.
+     *
+     * @param newValues The new addresses.
+     *
+     * @since 0.5
+     */
+    public void setAddresses(final Collection<? extends Address> newValues) {
+        addresses = writeCollection(newValues, addresses, Address.class);
     }
 
     /**
      * Returns the physical and email address at which the organization or individual may be contacted.
+     * This method returns the first {@link #getAddresses() adress} element, or null if none.
      *
      * @return Physical and email address at which the organization or individual may be contacted, or {@code null}.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #getAddresses()}.
      */
     @Override
+    @Deprecated
     @XmlElement(name = "address")
-    public Address getAddress() {
-        return address;
+    public final Address getAddress() {
+        return LegacyPropertyAdapter.getSingleton(addresses, Address.class, null, DefaultContact.class, "getAddress");
     }
 
     /**
      * Sets the physical and email address at which the organization or individual may be contacted.
+     * This method delegates to {@link #setAddresses(Collection)}.
      *
      * @param newValue The new address, or {@code null} if none.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #setAddresses(Collectio)}.
      */
-    public void setAddress(final Address newValue) {
-        checkWritePermission();
-        address = newValue;
+    @Deprecated
+    public final void setAddress(final Address newValue) {
+        setAddresses(LegacyPropertyAdapter.asCollection(newValue));
+    }
+
+    /**
+     * Returns on-line information that can be used to contact the individual or organization.
+     *
+     * @return On-line information that can be used to contact the individual or organization.
+     *
+     * @since 0.5
+     */
+    @Override
+    public Collection<OnlineResource> getOnlineResources() {
+        return onlineResources = nonNullCollection(onlineResources, OnlineResource.class);
+    }
+
+    /**
+     * Sets on-line information that can be used to contact the individual or organization.
+     *
+     * @param newValues The new online resources.
+     *
+     * @since 0.5
+     */
+    public void setOnlineResources(final Collection<? extends OnlineResource> newValues) {
+        onlineResources = writeCollection(newValues, onlineResources, OnlineResource.class);
     }
 
     /**
-     * Return on-line information that can be used to contact the individual or organization.
+     * Returns on-line information that can be used to contact the individual or organization.
+     * This method returns the first {@link #getOnlineResources() online resource} element, or null if none.
      *
      * @return On-line information that can be used to contact the individual or organization, or {@code null}.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #getOnlineResources()}.
      */
     @Override
+    @Deprecated
     @XmlElement(name = "onlineResource")
     public OnlineResource getOnlineResource() {
-        return onlineResource;
+        return LegacyPropertyAdapter.getSingleton(onlineResources, OnlineResource.class, null, DefaultContact.class, "getOnlineResource");
     }
 
     /**
      * Sets on-line information that can be used to contact the individual or organization.
+     * This method delegates to {@link #setOnlineResources(Collection)}.
      *
      * @param newValue The new online resource, or {@code null} if none.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #setOnlineResources(Collection)}.
      */
+    @Deprecated
     public void setOnlineResource(final OnlineResource newValue) {
-        checkWritePermission();
-        onlineResource = newValue;
+        setOnlineResources(LegacyPropertyAdapter.asCollection(newValue));
     }
 
     /**
@@ -241,4 +399,30 @@ public class DefaultContact extends ISOM
         checkWritePermission();
         contactInstructions = newValue;
     }
+
+    /**
+     * Type of the contact.
+     * Returns {@code null} if none.
+     *
+     * @return Type of the contact, or {@code null} if none.
+     *
+     * @since 0.5
+     */
+    @Override
+/// @XmlElement(name = "contactType")
+    public InternationalString getContactType() {
+        return contactType;
+    }
+
+    /**
+     * Sets new type of the contact.
+     *
+     * @param newValue The new type of the contact.
+     *
+     * @since 0.5
+     */
+    public void setContactType(final InternationalString newValue) {
+        checkWritePermission();
+        contactType = newValue;
+    }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -30,7 +30,7 @@ import org.opengis.util.InternationalStr
  * organizations associated with the dataset.
  *
  * @deprecated As of ISO 19115:2014, the {@code ResponsibleParty} type has been replaced by {@code Responsibility}
- *             to allow more flexible associations of individuals, organisations, and roles.
+ *             to allow more flexible associations of individuals, organizations, and roles.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -1,4 +1,4 @@
-/*
+ /*
  * 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.
@@ -16,22 +16,42 @@
  */
 package org.apache.sis.metadata.iso.citation;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
 import org.opengis.metadata.citation.Telephone;
+import org.opengis.metadata.citation.TelephoneType;
+import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
 
 /**
  * Telephone numbers for contacting the responsible individual or organization.
  *
+ * {@section Differences between versions 2003 and 2014 of ISO 19115}
+ * For any contact having more than one telephone number, the way to organize the information
+ * changed significantly between the two versions of ISO standard:
+ *
+ * <ul>
+ *   <li>In ISO 19115:2003, each {@code Contact} had only one {@code Telephone} instance, but that instance
+ *       could have an arbitrary amount of "voice" and "facsimile" numbers. The methods (now deprecated) were
+ *       {@link DefaultContact#getPhone()}, {@link #getVoices()} and {@link #getFacsimiles()}.</li>
+ *   <li>In ISO 19115:2014, each {@code Contact} has an arbitrary amount of {@code Telephone} instances, and
+ *       each telephone has exactly one number. The new methods are {@link DefaultContact#getPhones()},
+ *       {@link #getNumber()} and {@link #getNumberType()}.</li>
+ * </ul>
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Cédric Briançon (Geomatys)
- * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @author  Rémi Maréchal (Geomatys)
+ * @since   0.5 (derived from geotk-2.1)
+ * @version 0.5
  * @module
+ *
+ * @see DefaultContact#getPhones()
  */
 @XmlType(name = "CI_Telephone_Type", propOrder = {
     "voices",
@@ -42,17 +62,17 @@ public class DefaultTelephone extends IS
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -1920621361930970869L;
+    private static final long serialVersionUID = 5156405432420742237L;
 
     /**
-     * Telephone numbers by which individuals can speak to the responsible organization or individual.
+     * Telephone number by which individuals can contact responsible organization or individual.
      */
-    private Collection<String> voices;
+    private String number;
 
     /**
-     * Telephone numbers of a facsimile machine for the responsible organization or individual.
+     * Type of telephone number.
      */
-    private Collection<String> facsimiles;
+    private TelephoneType numberType;
 
     /**
      * Constructs a default telephone.
@@ -61,6 +81,19 @@ public class DefaultTelephone extends IS
     }
 
     /**
+     * Constructs a telephone with the given number and type.
+     *
+     * @param number     The telephone number, or {@code null}.
+     * @param numberType The type of telephone number, or {@code null}.
+     *
+     * @since 0.5
+     */
+    public DefaultTelephone(final String number, final TelephoneType numberType) {
+        this.number     = number;
+        this.numberType = numberType;
+    }
+
+    /**
      * Constructs a new instance initialized with the values from the specified metadata object.
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
@@ -72,8 +105,8 @@ public class DefaultTelephone extends IS
     public DefaultTelephone(final Telephone object) {
         super(object);
         if (object != null) {
-            voices     = copyCollection(object.getVoices(), String.class);
-            facsimiles = copyCollection(object.getFacsimiles(), String.class);
+            number     = object.getNumber();
+            numberType = object.getNumberType();
         }
     }
 
@@ -103,42 +136,171 @@ public class DefaultTelephone extends IS
     }
 
     /**
+     * Returns the telephone number by which individuals can contact responsible organization or individual.
+     *
+     * @return Telephone number by which individuals can contact responsible organization or individual.
+     *
+     * @since 0.5
+     */
+    @Override
+/// @XmlElement(name = "number", required = true)
+    public String getNumber() {
+        return number;
+    }
+
+    /**
+     * Sets the telephone number by which individuals can contact responsible organization or individual.
+     *
+     * @param newValue The new telephone number by which individuals can contact responsible organization or individual.
+     *
+     * @since 0.5
+     */
+    public void setNumber(final String newValue) {
+        checkWritePermission();
+        number = newValue;
+    }
+
+    /**
+     * Returns the type of telephone number, or {@code null} if none.
+     *
+     * @return Type of telephone number, or {@code null} if none.
+     *
+     * @since 0.5
+     */
+    @Override
+/// @XmlElement(name = "numberType")
+    public TelephoneType getNumberType() {
+        return numberType;
+    }
+
+    /**
+     * Set the type of telephone number.
+     *
+     * @param newValue The new type of telephone number.
+     *
+     * @since 0.5
+     */
+    public void setNumberType(final TelephoneType newValue) {
+        checkWritePermission();
+        numberType = newValue;
+    }
+
+    /**
+     * For implementation of {@link #getVoices()} and {@link #getFacsimiles()} deprecated methods.
+     * Shall be the telephones list of the enclosing {@link DefaultContact} object.
+     *
+     * <p>This field references the same collection than {@link DefaultContact#phones} when possible.
+     * Note that the link between this collection and {@code DefaultContact.phones} is broken when
+     * {@link DefaultContact#freeze()} is invoked, since the {@code Cloner.clone(Object)} method
+     * creates a new (unmodifiable) collection.</p>
+     *
+     * @deprecated This field will be removed after we removed the deprecated public methods.
+     */
+    @Deprecated
+    private Collection<Telephone> owner;
+
+    /**
+     * Specifies the collection which contains this telephone number.
+     * This method is invoked by {@link DefaultContact#setPhones(Collection)}
+     * when the contact "takes possession" of a {@code DefaultTelephone}.
+     *
+     * <p>This method will be removed after we removed the deprecated public methods.</p>
+     *
+     * @param  phones The collection which should contains this telephone number.
+     * @return {@code this}, or a copy of this instance if we conservatively choose to not modify this instance.
+     */
+    final DefaultTelephone setOwner(final Collection<Telephone> phones) {
+        if (owner != phones) {
+            if (owner != null && !CollectionsExt.identityEquals(owner.iterator(), phones.iterator())) {
+                final DefaultTelephone copy = new DefaultTelephone(this);
+                copy.owner = phones;
+                return copy;
+            }
+            owner = phones;
+        }
+        return this;
+    }
+
+    /**
+     * Returns the collection that own this telephone number, or create a new collection.
+     * Creating a new collection is needed when this phone number has not yet been given
+     * to a {@link DefaultContact}.
+     *
+     * <p>This method will be removed after we removed the deprecated public methods.</p>
+     */
+    final Collection<Telephone> getOwner() {
+       if (owner == null) {
+           if (isModifiable()) {
+               owner = new ArrayList<>(4);
+               owner.add(this);
+           } else {
+               owner = Collections.<Telephone>singletonList(this);
+           }
+       }
+       return owner;
+    }
+
+    /**
      * Returns the telephone numbers by which individuals can speak to the responsible organization or individual.
+     * This method searches in the {@linkplain DefaultContact#getPhones() contact phones}, if the contact that own
+     * this phone is known.
      *
      * @return Telephone numbers by which individuals can speak to the responsible organization or individual.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by a {@linkplain #getNumber() number}
+     *             with {@link TelephoneType#VOICE}.
      */
     @Override
+    @Deprecated
     @XmlElement(name = "voice")
-    public Collection<String> getVoices() {
-        return voices = nonNullCollection(voices, String.class);
+    public final Collection<String> getVoices() {
+        return new LegacyTelephones(getOwner(), TelephoneType.VOICE);
     }
 
     /**
      * Sets the telephone numbers by which individuals can speak to the responsible organization or individual.
+     * This method writes in the {@linkplain DefaultContact#getPhones() contact phones}, if the contact that own
+     * this phone is known.
      *
      * @param newValues The new telephone numbers, or {@code null} if none.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by a {@linkplain #setNumber(String) number}
+     *             with {@link TelephoneType#VOICE}.
      */
-    public void setVoices(final Collection<? extends String> newValues) {
-        voices = writeCollection(newValues, voices, String.class);
+    @Deprecated
+    public final void setVoices(final Collection<? extends String> newValues) {
+        ((LegacyTelephones) getVoices()).setValues(newValues);
     }
 
     /**
      * Returns the telephone numbers of a facsimile machine for the responsible organization or individual.
+     * This method searches in the {@linkplain DefaultContact#getPhones() contact phones}, if the contact
+     * that own this phone is known.
      *
      * @return Telephone numbers of a facsimile machine for the responsible organization or individual.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by a {@linkplain #getNumber() number}
+     *             with {@link TelephoneType#FACSIMILE}.
      */
     @Override
+    @Deprecated
     @XmlElement(name = "facsimile")
-    public Collection<String> getFacsimiles() {
-        return facsimiles = nonNullCollection(facsimiles, String.class);
+    public final Collection<String> getFacsimiles() {
+        return new LegacyTelephones(getOwner(), TelephoneType.FACSIMILE);
     }
 
     /**
      * Sets the telephone number of a facsimile machine for the responsible organization or individual.
+     * This method writes in the {@linkplain DefaultContact#getPhones() contact phones}, if the contact
+     * that own this phone is known.
      *
      * @param newValues The new telephone number, or {@code null} if none.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by a {@linkplain #setNumber(String) number}
+     *             with {@link TelephoneType#FACSIMILE}.
      */
-    public void setFacsimiles(final Collection<? extends String> newValues) {
-        facsimiles = writeCollection(newValues, facsimiles, String.class);
+    @Deprecated
+    public final void setFacsimiles(final Collection<? extends String> newValues) {
+        ((LegacyTelephones) getFacsimiles()).setValues(newValues);
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -30,9 +30,9 @@ import org.opengis.metadata.content.Rang
 import org.opengis.metadata.content.RangeElementDescription;
 import org.opengis.util.RecordType;
 import org.apache.sis.xml.Namespaces;
+import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
-import org.apache.sis.internal.metadata.MetadataUtilities;
 
 
 /**
@@ -229,8 +229,8 @@ public class DefaultCoverageDescription 
                         if (type == null) {
                             type = t;
                         } else {
-                            MetadataUtilities.warning(DefaultCoverageDescription.class, "getContentType",
-                                    Messages.Keys.IgnoredPropertiesAfterFirst_1, CoverageContentType.class);
+                            Context.warningOccured(Context.current(), DefaultCoverageDescription.class, "getContentType",
+                                    Messages.class, Messages.Keys.IgnoredPropertiesAfterFirst_1, CoverageContentType.class);
                             break;
                         }
                     }

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -86,7 +86,7 @@ public final strictfp class TreeNodeTest
         final DefaultContact contact = new DefaultContact();
         final DefaultAddress address = new DefaultAddress();
         address.getElectronicMailAddresses().add("Some email");
-        contact.setAddress(address);
+        contact.getAddresses().add(address);
         party.setContactInfo(contact);
         citation.getCitedResponsibleParties().add(party);
         return citation;
@@ -236,7 +236,7 @@ public final strictfp class TreeNodeTest
               ONE,          // citedResponsibleParty
                 null,       // individualName
                 null,       // contactInfo
-                  null,     // address
+                  ZERO,     // address
                     ZERO,   // electronicMailAddress
                 null,       // role
               ZERO,         // presentationForm

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -57,7 +57,7 @@ public final strictfp class DefaultMetad
     private Object[] parameters;
 
     /**
-     * For internal {@code DefaultLegalConstraints} usage.
+     * For internal {@code DefaultMetadata} usage.
      *
      * @return {@code Object.class}.
      */

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -27,7 +27,7 @@ import org.apache.sis.util.logging.Warni
 import org.apache.sis.test.XMLTestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
 
@@ -36,7 +36,7 @@ import static org.apache.sis.test.TestUt
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.5
  * @module
  */
 public final strictfp class DefaultLegalConstraintsTest extends XMLTestCase implements WarningListener<Object> {
@@ -119,4 +119,34 @@ public final strictfp class DefaultLegal
         assertEquals("warning", "NullCollectionElement_1", resourceKey);
         assertArrayEquals("warning", new String[] {"CodeListSet<Restriction>"}, parameters);
     }
+
+    /**
+     * Tests (un)marshalling of a XML fragment containing the {@link Restriction#LICENCE} code.
+     * The spelling changed between ISO 19115:2003 and 19115:2014, from "license" to "licence".
+     * We need to ensure that XML marshalling use the old spelling, until the XML schema is updated.
+     *
+     * @throws JAXBException If an error occurred during the during unmarshalling processes.
+     */
+    @Test
+    public void testLicenceCode() throws JAXBException {
+        final String xml =
+                "<gmd:MD_LegalConstraints xmlns:gmd=\"" + Namespaces.GMD + "\">\n" +
+                "  <gmd:useConstraints>\n" +
+                "    <gmd:MD_RestrictionCode"
+                        + " codeList=\"http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#MD_RestrictionCode\""
+                        + " codeListValue=\"license\""                              // Note the "s" - from old ISO 19115:2013 spelling.
+                        + " codeSpace=\"eng\">Licence</gmd:MD_RestrictionCode>\n" + // Note the "c" - this one come from resource file.
+                "  </gmd:useConstraints>\n" +
+                "</gmd:MD_LegalConstraints>\n";
+
+        final DefaultLegalConstraints c = new DefaultLegalConstraints();
+        c.getUseConstraints().add(Restriction.LICENCE);
+        assertXmlEquals(xml, marshal(c), "xmlns:*");
+        /*
+         * Unmarshall and ensure that we got back the original LICENCE code, not a new "LICENSE" code.
+         */
+        final DefaultLegalConstraints actual = unmarshal(xml);
+        assertSame(Restriction.LICENCE, getSingleton(actual.getUseConstraints()));
+        assertEquals(c, actual);
+    }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -60,6 +60,7 @@ import org.junit.BeforeClass;
     org.apache.sis.xml.XLinkMarshallingTest.class,
 
     // ISO implementations.
+    org.apache.sis.metadata.iso.citation.DefaultContactTest.class,
     org.apache.sis.metadata.iso.citation.DefaultCitationDateTest.class,
     org.apache.sis.metadata.iso.citation.DefaultCitationTest.class,
     org.apache.sis.metadata.iso.maintenance.DefaultScopeDescriptionTest.class,

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -51,7 +51,7 @@ import org.apache.sis.internal.jdk8.Func
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.4
+ * @version 0.5
  * @module
  */
 public final class CollectionsExt extends Static {
@@ -634,4 +634,21 @@ public final class CollectionsExt extend
         }
         return map;
     }
+
+    /**
+     * Returns {@code true} if the next elements returned by the given iterators are the same.
+     * This method compares using the identity operation ({@code ==}), not {@code equals(Object)}.
+     *
+     * @param  it1 The first iterator.
+     * @param  it2 The second iterator.
+     * @return If both iterators return the same objects.
+     */
+    public static boolean identityEquals(final Iterator<?> it1, final Iterator<?> it2) {
+        while (it1.hasNext()) {
+            if (!it2.hasNext() || it1.next() != it2.next()) {
+                return false;
+            }
+        }
+        return !it2.hasNext();
+    }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultLocalName.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -60,6 +60,9 @@ import java.util.Objects;
  * @since   0.3 (derived from geotk-2.1)
  * @version 0.3
  * @module
+ *
+ * @see DefaultNameSpace
+ * @see DefaultScopedName
  */
 @XmlType(name = "LocalName") // Actually 'gml:CodeType', but the later is used elsewhere.
 @XmlRootElement(name = "LocalName")
@@ -309,7 +312,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/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultMemberName.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -24,6 +24,9 @@ import org.opengis.util.TypeName;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
+// Branch-dependent imports
+import java.util.Objects;
+
 
 /**
  * The name to identify a member of a {@linkplain org.opengis.util.Record record}.
@@ -41,8 +44,12 @@ 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
  */
 @XmlRootElement(name = "MemberName")
 public class DefaultMemberName extends DefaultLocalName implements MemberName {
@@ -87,4 +94,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/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -72,6 +72,13 @@ 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 {
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -55,6 +55,12 @@ import java.util.Objects;
  * @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/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java (from r1609862, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java?p2=sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java&p1=sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java&r1=1609862&r2=1609863&rev=1609863&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -186,6 +186,12 @@ public class DefaultRecord implements Re
             }
             throw new NoSuchElementException();
         }
+
+        /** Unsupported operation. */
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -18,20 +18,29 @@ 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.NameFactory;
 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 java.util.Objects;
@@ -43,23 +52,52 @@ import java.util.Objects;
  * 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 +118,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 +140,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<>(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 NameFactory nameFactory)
+    {
+        this.typeName  = typeName;
+        this.container = container;
+        final NameSpace namespace = nameFactory.createNameSpace(typeName, null);
+        final Map<MemberName,Type> memberTypes = new LinkedHashMap<>(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<>(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 +279,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 +295,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 +321,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 +349,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 +367,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 +415,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 +428,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/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultScopedName.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -52,6 +52,9 @@ import org.apache.sis.internal.util.Unmo
  * @since   0.3 (derived from geotk-2.1)
  * @version 0.3
  * @module
+ *
+ * @see DefaultNameSpace
+ * @see DefaultLocalName
  */
 @XmlType(name = "ScopedName") // Actually 'gml:CodeType', but the later is used elsewhere.
 @XmlRootElement(name = "ScopedName")
@@ -183,7 +186,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/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java?rev=1609863&r1=1609862&r2=1609863&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java [UTF-8] Fri Jul 11 22:58:29 2014
@@ -39,6 +39,9 @@ import org.opengis.util.NameSpace;
  * @since   0.3 (derived from geotk-3.00)
  * @version 0.3
  * @module
+ *
+ * @see DefaultMemberName
+ * @see DefaultNameFactory
  */
 @XmlRootElement(name = "TypeName")
 public class DefaultTypeName extends DefaultLocalName implements TypeName {



Mime
View raw message