This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new b81a8f5  Introduce a new syntax in "RenameOnImport.lst" file for 
declaring that a class inherit the properties of another class. It make the 
file shorter and reduce the amount of hack with namespaces. But the main intent 
is to make easier to extend with profile. This work allow us to fix 
https://issues.apache.org/jira/browse/SIS-404
b81a8f5 is described below

commit b81a8f5a94799bac67588de02e502a00e924f111
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Oct 9 19:33:25 2018 +0200

    Introduce a new syntax in "RenameOnImport.lst" file for declaring that a 
class inherit the properties of another class.
    It make the file shorter and reduce the amount of hack with namespaces. But 
the main intent is to make easier to extend with profile.
    This work allow us to fix https://issues.apache.org/jira/browse/SIS-404
---
 .../apache/sis/internal/jaxb/TypeRegistration.java | 133 +++++---
 .../sis/internal/metadata/MetadataTypes.java       |  13 +-
 .../java/org/apache/sis/xml/MarshallerPool.java    |   2 +-
 .../src/main/java/org/apache/sis/xml/Pooled.java   |  10 +-
 .../java/org/apache/sis/xml/PooledMarshaller.java  |  10 +-
 .../main/java/org/apache/sis/xml/Transformer.java  | 159 +++++----
 .../org/apache/sis/xml/TransformingReader.java     |  15 +-
 .../org/apache/sis/xml/TransformingWriter.java     |   8 +-
 .../src/main/java/org/apache/sis/xml/readme.html   |  74 +++++
 .../org/apache/sis/xml/RenameOnExport.lst          |  15 +-
 .../org/apache/sis/xml/RenameOnImport.lst          | 354 +++------------------
 .../org/apache/sis/xml/RenameListGenerator.java    |  19 +-
 .../sis/internal/referencing/ReferencingTypes.java |  16 +-
 .../sis/internal/system/DelayedExecutor.java       |   2 +-
 .../sis/internal/system/DelayedRunnable.java       |  14 +-
 ide-project/NetBeans/build.xml                     |   3 +
 .../sis/internal/profile/fra/ProfileTypes.java     |  14 +-
 .../sis/internal/profile/fra/package-info.java     |   2 +-
 .../sis/internal/profile/fra/RenameOnImport.lst    |  10 +
 .../profile/fra/DataIdentificationTest.java        |   2 -
 20 files changed, 414 insertions(+), 461 deletions(-)

diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
index a0c0624..e3a4bb3 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
@@ -16,11 +16,15 @@
  */
 package org.apache.sis.internal.jaxb;
 
+import java.util.Set;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.ServiceLoader;
+import java.util.concurrent.TimeUnit;
+import java.util.function.UnaryOperator;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import javax.xml.bind.JAXBContext;
@@ -28,6 +32,8 @@ import javax.xml.bind.JAXBException;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.system.SystemListener;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.system.DelayedExecutor;
+import org.apache.sis.internal.system.DelayedRunnable;
 
 
 /**
@@ -42,7 +48,7 @@ import org.apache.sis.internal.system.DefaultFactories;
  * }
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see org.apache.sis.xml.MarshallerPool
  *
@@ -52,9 +58,9 @@ import org.apache.sis.internal.system.DefaultFactories;
 public abstract class TypeRegistration {
     /**
      * Undocumented (for now) marshaller property for specifying conversions 
to apply on root objects
-     * before marshalling. Conversions are applied by the {@link 
#toImplementation(Object)} method.
+     * before marshalling. Conversions are applied by {@link UnaryOperator} 
instances.
      *
-     * @see #addDefaultRootAdapters(Map)
+     * @see #getPrivateInfo(Map)
      */
     public static final String ROOT_ADAPTERS = 
"org.apache.sis.xml.rootAdapters";
 
@@ -66,12 +72,20 @@ public abstract class TypeRegistration {
     private static Reference<JAXBContext> context;
 
     /**
-     * The {@link TypeRegistration} instances found on the classpath for which 
the
-     * {@link #toImplementation(Object)} method has been overridden.
+     * Converters to apply before to marshal an object, or an empty array if 
none.
+     * This is {@code null} if not yet initialized or if classpath changed.
      *
-     * @see #addDefaultRootAdapters(Map)
+     * @see #getPrivateInfo(Map)
      */
-    private static TypeRegistration[] converters;
+    private static UnaryOperator<Object>[] converters;
+
+    /**
+     * The registrations, cached only a few seconds. We do not need to keep 
them a long time
+     * because {@link TypeRegistration} is used only for initializing some 
classes or fields.
+     *
+     * @see #services()
+     */
+    private static ServiceLoader<TypeRegistration> services;
 
     /**
      * Forces reloading of JAXB context and converters if the classpath 
changes.
@@ -82,6 +96,7 @@ public abstract class TypeRegistration {
                 synchronized (TypeRegistration.class) {
                     context    = null;
                     converters = null;
+                    services   = null;
                 }
             }
         });
@@ -97,75 +112,91 @@ public abstract class TypeRegistration {
      * Adds to the given collection every types that should be given to the 
initial JAXB context.
      * The types added by this method include only implementation classes 
having JAXB annotations.
      * If the module can also marshal arbitrary implementations of some 
interfaces (e.g. GeoAPI),
-     * then the {@link #canMarshalInterfaces()} method should be overridden.
+     * then the {@link #beforeMarshal()} method should be overridden.
      *
      * @param  addTo  the collection in which to add new types.
      */
     protected abstract void getTypes(final Collection<Class<?>> addTo);
 
     /**
-     * Returns {@code true} if the module can also marshal arbitrary 
implementation of some interfaces.
-     * If this method returns {@code true}, then the {@link 
#toImplementation(Object)} method shall be
-     * overridden.
+     * If some objects need to be converted before marshalling, the converter 
for performing those conversions.
+     * The converter {@code apply(Object)} method may return {@code null} if 
the value class is not recognized,
+     * or {@code value} if the class is recognized but the value does not need 
to be changed.
+     * Implementations will typically perform an {@code instanceof} check, 
then invoke one
+     * of the {@code castOrCopy(…)} static methods defined in various Apache 
SIS classes.
      *
-     * @return whether the module can also marshal arbitrary implementation of 
some interfaces.
+     * @return converter for the value to marshal, or {@code null} if there is 
no value to convert.
      *
      * @since 0.8
      */
-    protected boolean canMarshalInterfaces() {
-        return false;
+    protected UnaryOperator<Object> beforeMarshal() {
+        return null;
     }
 
     /**
-     * If the given value needs to be converted before marshalling, apply the 
conversion now.
-     * Otherwise returns {@code null} if the value class is not recognized, or 
{@code value}
-     * if the class is recognized but the value does not need to be changed.
-     *
-     * <p>Subclasses that override this method will typically perform an 
{@code instanceof} check, then
-     * invoke one of the {@code castOrCopy(…)} static methods defined in 
various Apache SIS classes.</p>
+     * Returns {@code true} if {@code "RenameOnImport.lst"} and/or {@code 
"RenameOnExport.lst"} files are provided.
+     * If {@code true}, then those files shall be located in the same 
directory than this {@code TypeRegistration}
+     * subclass.
      *
-     * <p>This method is invoked only if {@link #canMarshalInterfaces()} 
returns {@code true}.</p>
-     *
-     * @param  value  the value to convert before marshalling.
-     * @return the value to marshall; or {@code null} if this method does not 
recognize the value class.
-     * @throws JAXBException if an error occurred while converting the given 
object.
+     * @param  export  {@code true} for {@code "RenameOnImport.lst"}, {@code 
false} for {@code "RenameOnImport.lst"}.
+     * @return whether {@code "RenameOnImport.lst"} and/or {@code 
"RenameOnExport.lst"} files are provided.
+     */
+    protected boolean hasRenameFile(boolean export) {
+        return false;
+    }
+
+    /**
+     * Adds in the given set the classes to use for loading  {@code 
"RenameOnImport.lst"} and/or {@code "RenameOnExport.lst"} files.
+     * The given set should preserve insertion order, since the order in which 
files are loaded may matter.
      *
-     * @since 0.8
+     * @param  export  {@code true} for {@code "RenameOnImport.lst"}, {@code 
false} for {@code "RenameOnImport.lst"}.
+     * @param  addTo   where to add the classes to use for loading the 
resource files.
      */
-    public Object toImplementation(final Object value) throws JAXBException {
-        return null;
+    public static synchronized void getRenameFileLoader(final boolean export, 
final Set<Class<?>> addTo) {
+        for (final TypeRegistration t : services()) {
+            if (t.hasRenameFile(export)) {
+                addTo.add(t.getClass());
+            }
+        }
+    }
+
+    /**
+     * Returns the {@code TypeRegistration} instances.
+     * Must be invoked in a synchronized block.
+     */
+    private static ServiceLoader<TypeRegistration> services() {
+        ServiceLoader<TypeRegistration> s = services;
+        if (s == null) {
+            services = s = 
DefaultFactories.createServiceLoader(TypeRegistration.class);
+            DelayedExecutor.schedule(new DelayedRunnable(1, TimeUnit.MINUTES) {
+                @Override public void run() {services = null;}
+            });
+        }
+        return s;
     }
 
     /**
      * Scans the classpath for root classes to put in JAXB context and for 
converters to those classes.
      * Those lists are determined dynamically from the SIS modules found on 
the classpath.
-     * The list of root classes is created only if the {@code getTypes} 
argument is {@code true}.
+     * This method does nothing if this class already has all required 
information.
+     *
+     * <p>The list of converters is cached (that result is stored in {@link 
#converters}) while the list
+     * of root classes in JAXB context is not cached. So the information about 
whether this method needs
+     * to fetch the list of root classes or not must be specified by the 
{@code getTypes} argument.</p>
      *
      * @param  getTypes  whether to get the root classes to put in JAXB 
context (may cause class loading).
      * @return if {@code getTypes} was {@code true}, the root classes to be 
bound in {@code JAXBContext}.
      */
+    @SuppressWarnings({"unchecked", "rawtypes"})
     private static Class<?>[] load(final boolean getTypes) {
-        /*
-         * Implementation note: do not keep the ServiceLoader in static field 
because:
-         *
-         * 1) It would cache more TypeRegistration instances than needed for 
this method call.
-         * 2) The ClassLoader between different invocations may be different 
in an OSGi context.
-         */
-        final ArrayList<Class<?>> types = new ArrayList<>();
-        final ArrayList<TypeRegistration> toImpl = (converters == null) ? new 
ArrayList<>() : null;
-        if (toImpl != null || getTypes) {
-            for (final TypeRegistration t : 
DefaultFactories.createServiceLoader(TypeRegistration.class)) {
-                if (getTypes) {
-                    t.getTypes(types);
-                }
-                if (toImpl != null && t.canMarshalInterfaces()) {
-                    toImpl.add(t);
-                }
-            }
-            if (toImpl != null) {
-                converters = toImpl.toArray(new 
TypeRegistration[toImpl.size()]);
-            }
+        final ArrayList<Class<?>>              types  = new ArrayList<>();
+        final ArrayList<UnaryOperator<Object>> toImpl = new ArrayList<>();
+        for (final TypeRegistration t : services()) {
+            if (getTypes) t.getTypes(types);
+            final UnaryOperator<Object> c = t.beforeMarshal();
+            if (c != null) toImpl.add(c);
         }
+        converters = toImpl.toArray(new UnaryOperator[toImpl.size()]);
         return types.toArray(new Class<?>[types.size()]);
     }
 
@@ -205,11 +236,11 @@ public abstract class TypeRegistration {
      *
      * @since 0.8
      */
-    public static Map<String,?> addDefaultRootAdapters(final Map<String,?> 
properties) {
+    public static Map<String,?> getPrivateInfo(final Map<String,?> properties) 
{
         if (properties != null && properties.containsKey(ROOT_ADAPTERS)) {
             return properties;
         }
-        TypeRegistration[] c;
+        UnaryOperator<Object>[] c;
         synchronized (TypeRegistration.class) {
             c = converters;
             if (c == null) {
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
index baec5da..67a212d 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.metadata;
 
 import java.util.Collection;
+import java.util.function.UnaryOperator;
 import org.opengis.metadata.Metadata;
 import org.opengis.metadata.content.Band;
 import org.opengis.metadata.content.ImageDescription;
@@ -47,7 +48,7 @@ import org.opengis.metadata.spatial.Georeferenceable;
  * @since   0.3
  * @module
  */
-public final class MetadataTypes extends TypeRegistration {
+public final class MetadataTypes extends TypeRegistration implements 
UnaryOperator<Object> {
     /**
      * Adds to the given collection the metadata types that should be given to 
the initial JAXB context.
      */
@@ -58,13 +59,13 @@ public final class MetadataTypes extends TypeRegistration {
     }
 
     /**
-     * Notifies that the {@code sis-metadata} module can marshal arbitrary 
implementations of some metadata interfaces.
+     * Returns the converter to apply before marshalling objects.
      *
-     * @return {@code true}.
+     * @return {@code this}.
      */
     @Override
-    protected boolean canMarshalInterfaces() {
-        return true;
+    protected UnaryOperator<Object> beforeMarshal() {
+        return this;
     }
 
     /**
@@ -78,7 +79,7 @@ public final class MetadataTypes extends TypeRegistration {
      * @return the given value as a type that can be marshalled, or {@code 
null}.
      */
     @Override
-    public Object toImplementation(final Object value) {
+    public Object apply(final Object value) {
         /*
          * Classes that are most likely to be used should be checked first.  
If a type is a specialization
          * of another type (e.g. ImageDescription extends 
CoverageDescription), the specialized type shall
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/MarshallerPool.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/MarshallerPool.java
index 6d3e9ae..a35a90c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/MarshallerPool.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/MarshallerPool.java
@@ -165,7 +165,7 @@ public class MarshallerPool {
          * We presume that if the user specified his own JAXBContext, then he 
does not expect us to change the
          * classes that he wants to marshal.
          */
-        this(TypeRegistration.getSharedContext(), 
TypeRegistration.addDefaultRootAdapters(properties));
+        this(TypeRegistration.getSharedContext(), 
TypeRegistration.getPrivateInfo(properties));
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
index 3bf4389..e468a6b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
@@ -23,6 +23,7 @@ import java.util.ConcurrentModificationException;
 import java.util.IllformedLocaleException;
 import java.util.Locale;
 import java.util.TimeZone;
+import java.util.function.UnaryOperator;
 import javax.xml.validation.Schema;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.JAXBException;
@@ -146,7 +147,7 @@ abstract class Pooled {
      *
      * @see #getRootAdapters()
      */
-    private TypeRegistration[] rootAdapters;
+    private UnaryOperator<Object>[] rootAdapters;
 
     /**
      * The object to inform about warnings, or {@code null} if none.
@@ -381,8 +382,9 @@ abstract class Pooled {
                     return;
                 }
                 case TypeRegistration.ROOT_ADAPTERS: {
-                    rootAdapters = (TypeRegistration[]) value;
-                    // No clone for now because ROOT_ADAPTERS is not yet a 
public API.
+                    @SuppressWarnings("unchecked")
+                    UnaryOperator<Object>[] c = (UnaryOperator<Object>[]) 
value;
+                    rootAdapters = c;       // No clone for now because 
ROOT_ADAPTERS is not yet a public API.
                     return;
                 }
             }
@@ -487,7 +489,7 @@ abstract class Pooled {
      * @return a direct reference to the internal array of converters - do not 
modify.
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    final TypeRegistration[] getRootAdapters() {
+    final UnaryOperator<Object>[] getRootAdapters() {
         return rootAdapters;
     }
 
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/PooledMarshaller.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/PooledMarshaller.java
index 55027e4..b212908 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/PooledMarshaller.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/PooledMarshaller.java
@@ -22,6 +22,7 @@ import java.io.OutputStream;
 import java.io.FileOutputStream;
 import java.io.BufferedOutputStream;
 import java.io.IOException;
+import java.util.function.UnaryOperator;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.PropertyException;
@@ -36,7 +37,6 @@ import javax.xml.validation.Schema;
 import org.xml.sax.ContentHandler;
 import org.w3c.dom.Node;
 import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.internal.jaxb.TypeRegistration;
 import org.apache.sis.internal.jaxb.UseLegacyMetadata;
 
 
@@ -138,12 +138,12 @@ final class PooledMarshaller extends Pooled implements 
Marshaller {
      * If the given object is not recognized or is already an instance of the 
expected class,
      * then it is returned unchanged.
      */
-    private Object toImplementation(final Object value) throws JAXBException {
+    private Object toImplementation(final Object value) {
         specificBitMasks = 
value.getClass().isAnnotationPresent(UseLegacyMetadata.class) ? 
Context.LEGACY_METADATA : 0;
-        final TypeRegistration[] converters = getRootAdapters();
+        final UnaryOperator<Object>[] converters = getRootAdapters();
         if (converters != null) {
-            for (final TypeRegistration t : converters) {
-                final Object c = t.toImplementation(value);
+            for (final UnaryOperator<Object> t : converters) {
+                final Object c = t.apply(value);
                 if (c != null) return c;
             }
         }
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
index 705ccdb..0c49150 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
@@ -18,14 +18,18 @@ package org.apache.sis.xml;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.Set;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.NoSuchElementException;
 import java.util.InvalidPropertiesFormatException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
+import java.util.function.Function;
 import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamException;
@@ -34,6 +38,7 @@ import javax.xml.stream.events.Namespace;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.jaxb.TypeRegistration;
 
 
 /**
@@ -98,7 +103,15 @@ abstract class Transformer {
     private static final char RENAME_SEPARATOR = '/';
 
     /**
-     * A flag after type name in files loaded by {@link #load(String, int)}, 
meaning that the type itself
+     * Character used for separating a class name from the parent class name. 
When the {@code Child : Parent} syntax
+     * is used, the child inherits all properties defined in the parent. The 
parent class must be defined before the
+     * child class (no forward reference). We do not store the relationship 
between the two classes, so it is not
+     * necessary to extend a parent that define no property.
+     */
+    private static final char EXTENDS = ':';
+
+    /**
+     * A flag after type name in files loaded by {@link #load(boolean, String, 
int)}, meaning that the type itself
      * is in a different namespace than the properties listed below the type. 
For example in the following:
      *
      * {@preformat text
@@ -110,8 +123,9 @@ abstract class Transformer {
      *
      * {@code SV_ServiceIdentification} type is defined in the {@code 
"http://standards.iso.org/iso/19115/-3/srv/2.0"}
      * namespace, but the {@code citation} and {@code abstract} properties 
inherited from {@code Identification} are
-     * defined in the {@code http://standards.iso.org/iso/19115/-3/mri/1.0} 
namespace. If the {@value} flag is not
-     * present, then the type is assumed in the same namespace than the 
properties (this is the most common case).
+     * defined in the {@code http://standards.iso.org/iso/19115/-3/mri/1.0} 
namespace (note: using {@link #EXTENDS}
+     * is a better way to achieve the same result for this particular 
example). If the {@value} flag is not present,
+     * then the type is assumed in the same namespace than the properties 
(this is the most common case).
      */
     static final char NO_NAMESPACE = '!';
 
@@ -184,8 +198,8 @@ abstract class Transformer {
     /**
      * Returns {@code true} if the given string is a namespace URI, or {@code 
false} if it is a property name.
      * This method implements a very fast check based on the presence of 
{@code ':'} in {@code "http://foo.bar"}.
-     * It assumes that all namespaces declared in files loaded by {@link 
#load(String, int)} use the {@code "http"}
-     * protocol and no property name use the {@code ':'} character.
+     * It assumes that all namespaces declared in files loaded by {@link 
#load(boolean, String, int)} use the
+     * {@code "http"} protocol and no property name use the {@code ':'} 
character.
      */
     static boolean isNamespace(final String candidate) {
         return (candidate.length() > 4) && (candidate.charAt(4) == ':');
@@ -220,63 +234,98 @@ abstract class Transformer {
      *   </ul></li>
      * </ul>
      *
+     * @param  export    {@code true} for {@code "RenameOnImport.lst"}, {@code 
false} for {@code "RenameOnImport.lst"}.
      * @param  filename  name of the file to load.
      * @param  capacity  initial hash map capacity. This is only a hint.
      */
-    static Map<String, Map<String,String>> load(final String filename, final 
int capacity) {
+    static Map<String, Map<String,String>> load(final boolean export, final 
String filename, final int capacity) {
         final Map<String, Map<String,String>> m = new HashMap<>(capacity);
-        try (LineNumberReader in = new LineNumberReader(new InputStreamReader(
-                TransformingReader.class.getResourceAsStream(filename), 
"UTF-8")))
-        {
-            Map<String,String> attributes = null;               // All 
attributes for a given type.
-            String namespace = null;                            // Value to 
store in 'attributes' map.
-            String line;
-            while ((line = in.readLine()) != null) {
-                final int length = line.length();
-                final int start = CharSequences.skipLeadingWhitespaces(line, 
0, length);
-                if (start < length && line.charAt(start) != '#') {
-                    String element = line.substring(start).trim();
-                    switch (start) {
-                        case 0: {                                              
     // New namespace URI.
-                            if (!isNamespace(element)) break;                  
     // Report illegal format.
-                            namespace  = element.intern();
-                            attributes = null;
-                            continue;
-                        }
-                        case 1: {                                              
     // New type in above namespace URI.
-                            if (namespace == null) break;                      
     // Report illegal format.
-                            final int s = element.indexOf(NO_NAMESPACE);
-                            if (s >= 0) {
-                                element = element.substring(0, s).trim();
-                            }
-                            element = element.intern();
-                            attributes = m.computeIfAbsent(element, (k) -> new 
HashMap<>());
-                            if (s < 0) {
-                                // Record namespace for this type only if '!' 
is not present.
-                                if (attributes.put(element, namespace) != 
null) break;
+        final Set<Class<?>> renameLoaders = new LinkedHashSet<>(8);
+        renameLoaders.add(Transformer.class);
+        TypeRegistration.getRenameFileLoader(export, renameLoaders);
+        for (final Class<?> loader : renameLoaders) {
+            try (LineNumberReader in = new LineNumberReader(new 
InputStreamReader(loader.getResourceAsStream(filename), "UTF-8"))) {
+                Map<String,String> attributes = null;               // All 
attributes for a given type.
+                String namespace = null;                            // Value 
to store in 'attributes' map.
+                String line;
+                while ((line = in.readLine()) != null) {
+                    final int length = line.length();
+                    final int start = 
CharSequences.skipLeadingWhitespaces(line, 0, length);
+                    if (start < length && line.charAt(start) != '#') {
+                        String element = line.substring(start).trim();
+                        switch (start) {
+                            /*
+                             * Begin a new namespace. Must be before any class 
or property.
+                             */
+                            case 0: {                                          
         // New namespace URI.
+                                if (!isNamespace(element)) break;              
         // Report illegal format.
+                                namespace  = element.intern();
+                                attributes = null;
+                                continue;
                             }
-                            continue;
-                        }
-                        case 2: {                                              
     // New attribute in above type.
-                            if (attributes == null || namespace == null) 
break;     // Report illegal format.
-                            final int s = element.indexOf(RENAME_SEPARATOR);
-                            if (s >= 0) {
-                                final String old = element.substring(0, 
s).trim().intern();
-                                element = 
element.substring(s+1).trim().intern();
-                                if (attributes.put(old, element) != null) 
break;    // Report an error if duplicated values.
-                            } else {
+                            /*
+                             * Add a class into the above-defined namespace.
+                             * The class may inherit the properties of another 
class.
+                             * Inherited properties may be in a different 
namespace than the new class.
+                             */
+                            case 1: {                                          
         // New type in above namespace URI.
+                                if (namespace == null) break;                  
         // Report illegal format.
+                                final int noNS = element.indexOf(NO_NAMESPACE);
+                                if (noNS >= 0) {
+                                    element = 
CharSequences.trimWhitespaces(element, 0, noNS).toString();
+                                }
+                                final Function<String, Map<String,String>> 
init;
+                                final int s = element.indexOf(EXTENDS);
+                                if (s >= 0) {
+                                    final String parent;
+                                    parent  = 
CharSequences.trimWhitespaces(element, s+1, element.length()).toString();
+                                    element = 
CharSequences.trimWhitespaces(element, 0, s).toString();
+                                    init = (k) -> {
+                                        Map<String,String> properties = 
m.get(parent);
+                                        if (properties != null) {
+                                            properties = new 
HashMap<>(properties);
+                                            properties.remove(parent);
+                                            return properties;
+                                        }
+                                        throw new 
NoSuchElementException(parent);
+                                    };
+                                } else {
+                                    init = (k) -> new HashMap<>();
+                                }
                                 element = element.intern();
+                                attributes = m.computeIfAbsent(element, init);
+                                if (noNS < 0) {
+                                    // Record namespace for this type only if 
'!' is not present.
+                                    if (attributes.put(element, namespace) != 
null) break;
+                                }
+                                continue;
+                            }
+                            /*
+                             * Add a property into the above-defined class.
+                             * All properties are associated to above-defined 
namespace.
+                             * A property may have an alias (e.g. 
"center/centre").
+                             */
+                            case 2: {                                          
         // New attribute in above type.
+                                if (attributes == null || namespace == null) 
break;     // Report illegal format.
+                                final int s = 
element.indexOf(RENAME_SEPARATOR);
+                                if (s >= 0) {
+                                    final String old = element.substring(0, 
s).trim().intern();
+                                    element = 
element.substring(s+1).trim().intern();
+                                    if (attributes.put(old, element) != null) 
break;    // Report an error if duplicated values.
+                                } else {
+                                    element = element.intern();
+                                }
+                                if (attributes.put(element, namespace) != 
null) break;  // Report an error if duplicated values.
+                                continue;
                             }
-                            if (attributes.put(element, namespace) != null) 
break;  // Report an error if duplicated values.
-                            continue;
                         }
+                        throw new 
InvalidPropertiesFormatException(Errors.format(       // See method javadoc.
+                                Errors.Keys.ErrorInFileAtLine_2, filename, 
in.getLineNumber()));
                     }
-                    throw new InvalidPropertiesFormatException(Errors.format(  
     // See method javadoc.
-                            Errors.Keys.ErrorInFileAtLine_2, filename, 
in.getLineNumber()));
                 }
+            } catch (IOException e) {
+                throw new ExceptionInInitializerError(e);
             }
-        } catch (IOException e) {
-            throw new ExceptionInInitializerError(e);
         }
         /*
          * At this point we finished computing the map values. Many values are 
maps with only 1 entry.
@@ -443,9 +492,9 @@ abstract class Transformer {
     }
 
     /**
-     * Renames en element using the namespaces map give to the {@code open(…)} 
and {@code close(…)} methods.
-     * When unmarshalling, this imports a name read from the XML document to 
the name to give to JAXB.
-     * When marshalling, this exports a name used in JAXB annotation to the 
name to use in XML document.
+     * Renames en element using the namespaces map given to the {@code 
open(…)} and {@code close(…)} methods.
+     * When unmarshalling, this method converts a name read from the XML 
document to the name to give to JAXB.
+     * When marshalling, this method converts a name used in JAXB annotation 
to the name to use in XML document.
      * The new namespace depends on both the old namespace and the element 
name.
      * The prefix is computed by {@link #prefixReplacement(String, String)}.
      *
@@ -475,7 +524,7 @@ abstract class Transformer {
     }
 
     /**
-     * Returns the map loaded by {@link #load(String, int)}.
+     * Returns the map loaded by {@link #load(boolean, String, int)}.
      * This is a static field in the {@link TransformingReader} or {@link 
TransformingWriter} subclass.
      *
      * @param  namespace  the namespace URI for which to get the substitution 
map (never null).
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
index 34a0a1f..0da5899 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
@@ -39,7 +39,7 @@ import static javax.xml.stream.XMLStreamConstants.*;
 /**
  * A XML reader replacing the namespaces found in XML documents by the 
namespaces expected by SIS at unmarshalling time.
  * This class forwards every method calls to the wrapped {@link 
XMLEventReader}, but with some {@code namespaceURI}
- * modified before being transfered. This class uses a dictionary for 
identifying the XML namespaces expected by JAXB
+ * modified before being transferred. This class uses a dictionary for 
identifying the XML namespaces expected by JAXB
  * implementation. This is needed when a single namespace in a legacy schema 
has been splitted into many namespaces
  * in the newer schema. This happen for example in the upgrade from ISO 
19139:2007 to ISO 19115-3.
  * In such cases, we need to check which attribute is being mapped in order to 
determine the new namespace.
@@ -77,7 +77,7 @@ final class TransformingReader extends Transformer implements 
XMLEventReader {
      *
      * This map is initialized only once and should not be modified after that 
point.
      */
-    private static final Map<String, Map<String,String>> NAMESPACES = 
load(FILENAME, 250);
+    private static final Map<String, Map<String,String>> NAMESPACES = 
load(false, FILENAME, 260);
 
     /**
      * Returns the namespace for the given ISO type, or {@code null} if 
unknown.
@@ -280,11 +280,11 @@ final class TransformingReader extends Transformer 
implements XMLEventReader {
     }
 
     /**
-     * Returns the map loaded by {@link #load(String, int)} if the given 
namespace is a known legacy namespace.
-     * This method returns a non-empty map only for legacy namespaces for 
which the {@value #FILENAME} file has
-     * been designed. This is necessary for avoiding confusion with classes of 
the same name defined in other
-     * standards. For example the {@code Record} class name is used by other 
standards like Catalog Service for
-     * the Web (OGC CSW), and we don't want to replace the namespace of CSW 
classes.
+     * Returns the map loaded by {@link #load(boolean, String, int)} if the 
given namespace is a known legacy namespace.
+     * This method returns a non-empty map only for legacy namespaces for 
which the {@value #FILENAME} file has been designed.
+     * This is necessary for avoiding confusion with classes of the same name 
defined in other standards.
+     * For example the {@code Record} class name is used by other standards 
like Catalog Service for the Web (OGC CSW),
+     * and we don't want to replace the namespace of CSW classes.
      *
      * @param  namespace  the namespace URI for which to get the substitution 
map.
      * @return the substitution map for the given namespace, or an empty map 
if none.
@@ -294,6 +294,7 @@ final class TransformingReader extends Transformer 
implements XMLEventReader {
     final Map<String, Map<String,String>> renamingMap(final String namespace) {
         if (!namespace.isEmpty()) {
             switch (removeTrailingSlash(namespace)) {
+                case "http://www.cnig.gouv.fr/2005/fra":        // TODO: move 
to sis-french-profile module.
                 case LegacyNamespaces.GMI_ALIAS:
                 case LegacyNamespaces.GMI:
                 case LegacyNamespaces.GMD:
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
index ca570d2..2984ed3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
@@ -62,10 +62,10 @@ final class TransformingWriter extends Transformer 
implements XMLEventWriter {
      * Location of the file listing types and their properties contained in 
legacy namespaces.
      * This is used for mapping new ISO 19115-3:2016 namespaces to legacy ISO 
19139:2007 ones,
      * where the same {@code "http://standards.iso.org/iso/19115/-3/…"} URI is 
used in places
-     * where legacy schemas had two distinct URIs: {@code 
"http://www.isotc211.org/2005/gmd"}
+     * where legacy schema had two distinct URIs:  {@code 
"http://www.isotc211.org/2005/gmd"}
      * and {@code "http://standards.iso.org/iso/19115/-2/gmi/1.0"}.
      */
-    static final String FILENAME = "RenameOnExport.lst";
+    private static final String FILENAME = "RenameOnExport.lst";
 
     /**
      * The mapping from (<var>type</var>, <var>attribute</var>) pairs to 
legacy namespaces.
@@ -84,7 +84,7 @@ final class TransformingWriter extends Transformer implements 
XMLEventWriter {
      *
      * This map is initialized only once and should not be modified after that 
point.
      */
-    private static final Map<String, Map<String,String>> NAMESPACES = 
load(FILENAME, 60);
+    private static final Map<String, Map<String,String>> NAMESPACES = 
load(true, FILENAME, 60);
 
     /**
      * Elements that appear in different order in ISO 19139:2007 (or other 
legacy standards) compared
@@ -214,7 +214,7 @@ final class TransformingWriter extends Transformer 
implements XMLEventWriter {
     }
 
     /**
-     * Returns the map loaded by {@link #load(String, int)}.
+     * Returns the map loaded by {@link #load(boolean, String, int)}.
      *
      * @param  namespace  the namespace URI for which to get the substitution 
map.
      * @return the substitution map for the given namespace.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/readme.html 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/readme.html
new file mode 100644
index 0000000..f03b263
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/readme.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Syntax of Rename files</title>
+    <meta charset="UTF-8">
+    <style>
+      p {
+        text-align: justify;
+      }
+      pre {
+        border-left-style: solid;
+        border-left-color: darkgray;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Syntax of <code>RenameOnImport</code>/<code>Export</code> files</h1>
+    <p>
+      <b>WARNING: the syntax documented in this page is not committed API and 
may change in any future SIS version.</b>
+    </p>
+    <p>
+      This package provides two files in the 
<code>resources/org/apache/sis/xml/</code> folder:
+      <code>RenameOnImport.lst</code> and <code>RenameOnExport.lst</code>.
+      Those files are used by <code>TransformingReader.java</code> and 
<code>TransformingWriter.java</code> respectively
+      for converting XML namespaces between new specifications (ISO 
19115-3:2016 and ISO 19115-4) and old specifications
+      (ISO 19139:2007 and ISO 19115-2:2009). The JAXB annotations in Apache 
SIS use the newer specifications.
+      The <code>Rename*.lst</code> files are needed only when reading or 
writing to older specifications.
+      Those files are used for performing the work of a lightweight XSLT 
engine.
+      Both share the same syntax:
+    </p>
+    <ul>
+      <li>Lines with zero-space indentation are namespace URIs.</li>
+      <li>Lines with one-space  indentation are XML type names.</li>
+      <li>Lines with two-spaces indentation are property names.</li>
+      <li>The "/" character in "<var>before</var>/<var>after</var>" means that 
a property name needs to be changed.
+          <var>Before</var> is the name before the renaming process and 
<var>after</var> is the name after the renaming process.</li>
+      <li>The ":" character in "<var>Parent</var> : <var>Child</var>" means 
that a subclass inherits all properties from a parent class.
+          The <var>parent</var> must be defined before the <var>child</var> 
(no forward references).
+      <li>The "!" character in "<var>Class</var> !<var>reason</var>" skips the 
association of current namespace to that class
+          (but namespace will still be associated to the properties). 
<var>Reason</var> is a free text.</li>
+    </ul>
+    <p>
+      For example the following snippet from <code>RenameOnImport.lst</code> 
declares that the <code>Citation.title</code>,
+      <code>Citation.edition</code> and <code>Address.country</code> 
properties are defined in the <b><code>cit</code></b> namespace,
+      while the <code>Extent.description</code> property is defined in the 
<b><code>gex</code></b> namespace
+      and the <code>Georectified.centrePoint</code> property is defined in the 
<b><code>msr</code></b> namespace.
+      Those information are required when reading a file encoded by the old 
standards
+      because almost all properties where in the single <code>gmd</code> 
namespace.
+      In general those information are used for converting only the 
<em>namespaces</em>; the class and property names are unchanged.
+      But in the special case where the "<var>before</var>/<var>after</var>" 
syntax is used, then class and/or property names are also changed.
+      For example in the following example, 
<code>Georectified.centerPoint</code> (from the old standard)
+      is renamed as <code>Georectified.centrePoint</code> (new standard).
+    </p>
+    <blockquote><pre>http://standards.iso.org/iso/19115/-3/<b>cit</b>/1.0
+ CI_Citation
+  title
+  edition
+ CI_Address
+  country
+http://standards.iso.org/iso/19115/-3/<b>gex</b>/1.0
+ EX_Extent
+  description
+http://standards.iso.org/iso/19115/-3/<b>msr</b>/1.0
+ MI_Georectified
+  centerPoint/centrePoint</pre></blockquote>
+    <p>
+      Conversely, when writing a file, some additional renaming can be applied 
<em>after</em> the namespaces have been renamed to <code>gmd</code>.
+      The following snippet from <code>RenameOnExport.lst</code> performs the 
converse of the property renaming shown in previous example:
+    </p>
+    <blockquote><pre>http://www.isotc211.org/2005/gmd
+ MD_Georectified
+  centrePoint/centerPoint</pre></blockquote>
+  </body>
+</html>
diff --git 
a/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst 
b/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
index 308e7ca..2ea16d3 100644
--- a/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
+++ b/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
@@ -1,15 +1,11 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements;
+# and to You under the Apache License, Version 2.0.
 #
-# Elements to rename during exports.
-# Lines with zero-space indentation are namespace URIs.
-# Lines with one-space  indentation are XML types.
-# Lines with two-spaces indentation are properties.
-# actual/exported means that a property needs to be renamed.
+# See readme.html is source code for the syntax of this file.
 #
 http://www.isotc211.org/2005/gmd
  MD_Georectified
   centrePoint/centerPoint
- MI_Georectified !other namespace
-  centrePoint/centerPoint
  DQ_QuantitativeResult
   valueRecordType/valueType
 http://www.isotc211.org/2005/srv
@@ -110,8 +106,7 @@ http://standards.iso.org/iso/19115/-2/gmi/1.0
   detectedPolarisation
  MI_CoverageDescription
   rangeElementDescription
- MI_ImageDescription
-  rangeElementDescription
+ MI_ImageDescription : MI_CoverageDescription
  MI_RangeElementDescription
   name
   definition
@@ -155,7 +150,7 @@ http://standards.iso.org/iso/19115/-2/gmi/1.0
   acquisitionInformation
  MI_Georeferenceable
   geolocationInformation
- MI_Georectified
+ MI_Georectified : MD_Georectified
   checkPoint
  MI_GCP
   geographicCoordinates
diff --git 
a/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst 
b/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
index d924669..5018d16 100644
--- a/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
+++ b/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
@@ -1,9 +1,7 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements;
+# and to You under the Apache License, Version 2.0.
 #
-# Namespaces in which attribute are defined.
-# Lines with zero-space indentation are namespace URIs.
-# Lines with one-space  indentation are XML types.
-# Lines with two-spaces indentation are properties.
-# old/new means that a property needs to be renamed.
+# See readme.html is source code for the syntax of this file.
 #
 http://standards.iso.org/iso/19115/-3/cit/1.0
  AbstractCI_Party
@@ -39,9 +37,7 @@ http://standards.iso.org/iso/19115/-3/cit/1.0
   date
   dateType
  CI_DateTypeCode
- CI_Individual
-  contactInfo
-  name
+ CI_Individual : AbstractCI_Party
   positionName
  CI_OnLineFunctionCode
  CI_OnlineResource
@@ -52,20 +48,15 @@ http://standards.iso.org/iso/19115/-3/cit/1.0
   name
   protocol
   protocolRequest
- CI_Organisation
-  contactInfo
+ CI_Organisation : AbstractCI_Party
   individual
   logo
-  name
  CI_PresentationFormCode
  CI_Responsibility
   extent
   party
   role
- CI_ResponsibleParty !other namespace
-  extent
-  party
-  role
+ CI_ResponsibleParty : CI_Responsibility !legacy
  CI_RoleCode
  CI_Series
   issueIdentification
@@ -96,29 +87,25 @@ http://standards.iso.org/iso/19115/-3/gcx/1.0
 http://standards.iso.org/iso/19115/-3/gex/1.0
  AbstractEX_GeographicExtent
   extentTypeCode
- EX_BoundingPolygon
-  extentTypeCode
+ EX_BoundingPolygon : AbstractEX_GeographicExtent
   polygon
  EX_Extent
   description
   geographicElement
   temporalElement
   verticalElement
- EX_GeographicBoundingBox
+ EX_GeographicBoundingBox : AbstractEX_GeographicExtent
   eastBoundLongitude
-  extentTypeCode
   northBoundLatitude
   southBoundLatitude
   westBoundLongitude
- EX_GeographicDescription
-  extentTypeCode
+ EX_GeographicDescription : AbstractEX_GeographicExtent
   geographicIdentifier
- EX_SpatialTemporalExtent
+ EX_TemporalExtent
   extent
+ EX_SpatialTemporalExtent : EX_TemporalExtent
   spatialExtent
   verticalExtent
- EX_TemporalExtent
-  extent
  EX_VerticalExtent
   maximumValue
   minimumValue
@@ -267,31 +254,19 @@ http://standards.iso.org/iso/19115/-3/mco/1.0
   releasability
   responsibleParty
   useLimitation
- MD_LegalConstraints
+ MD_LegalConstraints : MD_Constraints
   accessConstraints
-  constraintApplicationScope
-  graphic
   otherConstraints
-  reference
-  releasability
-  responsibleParty
   useConstraints
-  useLimitation
  MD_Releasability
   addressee
   disseminationConstraints
   statement
  MD_RestrictionCode
- MD_SecurityConstraints
+ MD_SecurityConstraints : MD_Constraints
   classification
   classificationSystem
-  constraintApplicationScope
-  graphic
   handlingDescription
-  reference
-  releasability
-  responsibleParty
-  useLimitation
   userNote
 http://standards.iso.org/iso/19115/-3/mdb/1.0
  MD_Metadata
@@ -322,31 +297,7 @@ http://standards.iso.org/iso/19115/-3/mdb/1.0
  MD_MetadataScope
   name
   resourceScope
- MI_Metadata !other namespace
-  acquisitionInformation
-  alternativeMetadataReference
-  applicationSchemaInfo
-  contact
-  contentInfo
-  dataQualityInfo
-  dateInfo
-  defaultLocale
-  distributionInfo
-  identificationInfo
-  metadataConstraints
-  metadataExtensionInfo
-  metadataIdentifier
-  metadataLinkage
-  metadataMaintenance
-  metadataProfile
-  metadataScope
-  metadataStandard
-  otherLocale
-  parentMetadata
-  portrayalCatalogueInfo
-  referenceSystemInfo
-  resourceLineage
-  spatialRepresentationInfo
+ MI_Metadata : MD_Metadata !other namespace
 http://standards.iso.org/iso/19115/-3/mdt/1.0
  MX_DataFile
   featureTypes
@@ -387,31 +338,6 @@ http://standards.iso.org/iso/19115/-3/mrc/1.0
  MD_AttributeGroup
   attribute
   contentType
- MD_Band
-  bandBoundaryDefinition
-  bitsPerValue
-  boundMax
-  boundMin
-  boundUnits
-  description
-  detectedPolarisation
-  maxValue
-  meanValue
-  minValue
-  name
-  nominalSpatialResolution
-  numberOfValues
-  offset
-  otherProperty
-  otherPropertyType
-  peakResponse
-  scaleFactor
-  sequenceIdentifier
-  standardDeviation
-  toneGradation
-  transferFunctionType
-  transmittedPolarisation
-  units
  MD_CoverageContentTypeCode
  MD_CoverageDescription
   attributeDescription
@@ -427,9 +353,7 @@ http://standards.iso.org/iso/19115/-3/mrc/1.0
  MD_FeatureTypeInfo
   featureInstanceCount
   featureTypeName
- MD_ImageDescription
-  attributeDescription
-  attributeGroup
+ MD_ImageDescription : MD_CoverageDescription
   cameraCalibrationInformationAvailability
   cloudCoverPercentage
   compressionGenerationQuantity
@@ -439,77 +363,40 @@ http://standards.iso.org/iso/19115/-3/mrc/1.0
   imageQualityCode
   imagingCondition
   lensDistortionInformationAvailability
-  processingLevelCode
   radiometricCalibrationDataAvailability
-  rangeElementDescription
   triangulationIndicator
  MD_ImagingConditionCode
  MD_RangeDimension
   description
   name
   sequenceIdentifier
- MD_SampleDimension
+ MD_SampleDimension : MD_RangeDimension
   bitsPerValue
-  description
   maxValue
   meanValue
   minValue
-  name
   numberOfValues
   offset
   otherProperty
   otherPropertyType
   scaleFactor
-  sequenceIdentifier
   standardDeviation
   units
- MI_Band
+ MD_Band : MD_SampleDimension
   bandBoundaryDefinition
-  bitsPerValue
   boundMax
   boundMin
   boundUnits
-  description
   detectedPolarisation
-  maxValue
-  meanValue
-  minValue
-  name
   nominalSpatialResolution
-  numberOfValues
-  offset
-  otherProperty
-  otherPropertyType
   peakResponse
-  scaleFactor
-  sequenceIdentifier
-  standardDeviation
   toneGradation
   transferFunctionType
   transmittedPolarisation
-  units
+ MI_Band : MD_Band
  MI_BandDefinition
- MI_CoverageDescription
-  attributeDescription
-  attributeGroup
-  processingLevelCode
-  rangeElementDescription
- MI_ImageDescription
-  attributeDescription
-  attributeGroup
-  cameraCalibrationInformationAvailability
-  cloudCoverPercentage
-  compressionGenerationQuantity
-  filmDistortionInformationAvailability
-  illuminationAzimuthAngle
-  illuminationElevationAngle
-  imageQualityCode
-  imagingCondition
-  lensDistortionInformationAvailability
-  processingLevelCode
-  radiometricCalibrationDataAvailability
-  rangeElementDescription
-  triangulationIndicator
+ MI_CoverageDescription : MD_CoverageDescription
+ MI_ImageDescription : MD_ImageDescription
  MI_RangeElementDescription
   definition
   name
@@ -579,7 +466,7 @@ http://standards.iso.org/iso/19115/-3/mri/1.0
   topicCategory
  DS_AssociationTypeCode
  DS_InitiativeTypeCode
- MD_AggregateInformation !other namespace
+ MD_AggregateInformation !legacy
   metadataReference
   name
  MD_AssociatedResource
@@ -587,31 +474,11 @@ http://standards.iso.org/iso/19115/-3/mri/1.0
   initiativeType
   metadataReference
   name
- MD_DataIdentification
-  abstract
-  additionalDocumentation
-  associatedResource
-  citation
-  credit
+ MD_DataIdentification : AbstractMD_Identification
   defaultLocale
-  descriptiveKeywords
   environmentDescription
-  extent
-  graphicOverview
   otherLocale
-  pointOfContact
-  processingLevel
-  purpose
-  resourceConstraints
-  resourceFormat
-  resourceMaintenance
-  resourceSpecificUsage
-  spatialRepresentationType
-  spatialResolution
-  status
   supplementalInformation
-  temporalResolution
-  topicCategory
  MD_KeywordClass
   className
   conceptIdentifier
@@ -638,27 +505,6 @@ http://standards.iso.org/iso/19115/-3/mri/1.0
   usageDateTime
   userContactInfo
   userDeterminedLimitations
- SV_ServiceIdentification !other namespace
-  abstract
-  additionalDocumentation
-  associatedResource
-  citation
-  credit
-  descriptiveKeywords
-  extent
-  graphicOverview
-  pointOfContact
-  processingLevel
-  purpose
-  resourceConstraints
-  resourceFormat
-  resourceMaintenance
-  resourceSpecificUsage
-  spatialRepresentationType
-  spatialResolution
-  status
-  temporalResolution
-  topicCategory
 http://standards.iso.org/iso/19115/-3/mrl/1.0
  LE_Algorithm
   citation
@@ -740,71 +586,40 @@ http://standards.iso.org/iso/19115/-3/msr/1.0
  MD_GeometricObjects
   geometricObjectCount
   geometricObjectType
- MD_Georectified
+ MD_GridSpatialRepresentation
   axisDimensionProperties
   cellGeometry
-  centrePoint
+  numberOfDimensions
+  transformationParameterAvailability
+ MD_Georectified : MD_GridSpatialRepresentation
+  centerPoint/centrePoint
   checkPoint
   checkPointAvailability
   checkPointDescription
   cornerPoints
-  numberOfDimensions
   pointInPixel
   transformationDimensionDescription
   transformationDimensionMapping
-  transformationParameterAvailability
- MD_Georeferenceable
-  axisDimensionProperties
-  cellGeometry
+ MD_Georeferenceable : MD_GridSpatialRepresentation
   controlPointAvailability
   geolocationInformation
   georeferencedParameters
-  numberOfDimensions
   orientationParameterAvailability
   orientationParameterDescription
   parameterCitation
-  transformationParameterAvailability
- MD_GridSpatialRepresentation
-  axisDimensionProperties
-  cellGeometry
-  numberOfDimensions
-  transformationParameterAvailability
  MD_TopologyLevelCode
  MD_VectorSpatialRepresentation
   geometricObjects
   topologyLevel
  MI_GCP
   accuracyReport
- MI_GCPCollection
+ MI_GCPCollection : AbstractMI_GeolocationInformation
   collectionIdentification
   collectionName
   coordinateReferenceSystem
   gcp
-  qualityInfo
- MI_Georectified
-  axisDimensionProperties
-  cellGeometry
-  centerPoint/centrePoint
-  checkPoint
-  checkPointAvailability
-  checkPointDescription
-  cornerPoints
-  numberOfDimensions
-  pointInPixel
-  transformationDimensionDescription
-  transformationDimensionMapping
-  transformationParameterAvailability
- MI_Georeferenceable
-  axisDimensionProperties
-  cellGeometry
-  controlPointAvailability
-  geolocationInformation
-  georeferencedParameters
-  numberOfDimensions
-  orientationParameterAvailability
-  orientationParameterDescription
-  parameterCitation
-  transformationParameterAvailability
+ MI_Georectified : MD_Georectified
+ MI_Georeferenceable : MD_Georeferenceable
 http://standards.iso.org/iso/19115/-3/srv/2.0
  DCPList
  SV_CoupledResource
@@ -831,7 +646,7 @@ http://standards.iso.org/iso/19115/-3/srv/2.0
   repeatability
   valueType
  SV_ParameterDirection
- SV_ServiceIdentification
+ SV_ServiceIdentification : AbstractMD_Identification
   accessProperties
   containsChain
   containsOperations
@@ -844,74 +659,22 @@ http://standards.iso.org/iso/19115/-3/srv/2.0
   serviceType
   serviceTypeVersion
 http://standards.iso.org/iso/19157/-2/dqc/1.0
- AbstractDQ_Completeness !other namespace
-  dateTime
  AbstractDQ_Element !other namespace
   dateTime
- AbstractDQ_LogicalConsistency !other namespace
-  dateTime
- AbstractDQ_PositionalAccuracy !other namespace
-  dateTime
- AbstractDQ_TemporalAccuracy !other namespace
-  dateTime
- AbstractDQ_ThematicAccuracy !other namespace
-  dateTime
- DQ_AbsoluteExternalPositionalAccuracy !other namespace
-  dateTime
- DQ_AccuracyOfATimeMeasurement !other namespace
-  dateTime
- DQ_CompletenessCommission !other namespace
-  dateTime
- DQ_CompletenessOmission !other namespace
-  dateTime
- DQ_ConceptualConsistency !other namespace
-  dateTime
- DQ_DomainConsistency !other namespace
-  dateTime
- DQ_FormatConsistency !other namespace
-  dateTime
- DQ_GriddedDataPositionalAccuracy !other namespace
-  dateTime
- DQ_NonQuantitativeAttributeAccuracy !other namespace
-  dateTime
- DQ_QuantitativeAttributeAccuracy !other namespace
-  dateTime
- DQ_RelativeInternalPositionalAccuracy !other namespace
-  dateTime
- DQ_TemporalConsistency !other namespace
-  dateTime
- DQ_TemporalValidity !other namespace
-  dateTime
- DQ_ThematicClassificationCorrectness !other namespace
-  dateTime
- DQ_TopologicalConsistency !other namespace
-  dateTime
- QE_Usability !other namespace
-  dateTime
 http://standards.iso.org/iso/19157/-2/mdq/1.0
- AbstractDQ_Completeness
-  result
  AbstractDQ_Element
   result
- AbstractDQ_LogicalConsistency
-  result
- AbstractDQ_PositionalAccuracy
-  result
+ AbstractDQ_Completeness : AbstractDQ_Element
+ AbstractDQ_LogicalConsistency : AbstractDQ_Element
+ AbstractDQ_PositionalAccuracy : AbstractDQ_Element
  AbstractDQ_Result
- AbstractDQ_TemporalAccuracy !other namespace
-  result
- AbstractDQ_ThematicAccuracy
-  result
- DQ_AbsoluteExternalPositionalAccuracy
-  result
- DQ_AccuracyOfATimeMeasurement
-  result
- DQ_CompletenessCommission
-  result
- DQ_CompletenessOmission
-  result
- DQ_ConceptualConsistency
-  result
+ AbstractDQ_TemporalAccuracy : AbstractDQ_Element !other namespace
+ AbstractDQ_ThematicAccuracy : AbstractDQ_Element
+ DQ_AbsoluteExternalPositionalAccuracy : AbstractDQ_PositionalAccuracy
+ DQ_AccuracyOfATimeMeasurement : AbstractDQ_TemporalAccuracy
+ DQ_CompletenessCommission : AbstractDQ_Completeness
+ DQ_CompletenessOmission : AbstractDQ_Completeness
+ DQ_ConceptualConsistency : AbstractDQ_LogicalConsistency
  DQ_ConformanceResult
   explanation
   pass
@@ -919,39 +682,28 @@ http://standards.iso.org/iso/19157/-2/mdq/1.0
  DQ_DataQuality
   report
   scope
- DQ_DomainConsistency
-  result
+ DQ_DomainConsistency : AbstractDQ_LogicalConsistency
  DQ_EvaluationMethodTypeCode
- DQ_FormatConsistency
-  result
- DQ_GriddedDataPositionalAccuracy
-  result
- DQ_NonQuantitativeAttributeAccuracy !other namespace
-  result
- DQ_QuantitativeAttributeAccuracy
-  result
+ DQ_FormatConsistency : AbstractDQ_LogicalConsistency
+ DQ_GriddedDataPositionalAccuracy : AbstractDQ_PositionalAccuracy
+ DQ_NonQuantitativeAttributeAccuracy : AbstractDQ_ThematicAccuracy !other 
namespace
+ DQ_QuantitativeAttributeAccuracy : AbstractDQ_ThematicAccuracy
  DQ_QuantitativeResult
   value
   valueType/valueRecordType
   valueUnit
- DQ_RelativeInternalPositionalAccuracy
-  result
- DQ_TemporalConsistency
-  result
- DQ_TemporalValidity
-  result
- DQ_ThematicClassificationCorrectness
-  result
- DQ_TopologicalConsistency
-  result
+ DQ_RelativeInternalPositionalAccuracy : AbstractDQ_PositionalAccuracy
+ DQ_TemporalConsistency : AbstractDQ_TemporalAccuracy
+ DQ_TemporalValidity : AbstractDQ_TemporalAccuracy
+ DQ_ThematicClassificationCorrectness : AbstractDQ_ThematicAccuracy
+ DQ_TopologicalConsistency : AbstractDQ_LogicalConsistency
  QE_CoverageResult
   resultContentDescription
   resultFile
   resultFormat
   resultSpatialRepresentation
   spatialRepresentationType
- QE_Usability !other namespace
-  result
+ QE_Usability : AbstractDQ_Element !other namespace
 http://www.isotc211.org/2005/gts
  TM_Duration
  TM_PeriodDuration
diff --git 
a/core/sis-metadata/src/test/java/org/apache/sis/xml/RenameListGenerator.java 
b/core/sis-metadata/src/test/java/org/apache/sis/xml/RenameListGenerator.java
index 98d6c26..3381457 100644
--- 
a/core/sis-metadata/src/test/java/org/apache/sis/xml/RenameListGenerator.java
+++ 
b/core/sis-metadata/src/test/java/org/apache/sis/xml/RenameListGenerator.java
@@ -37,11 +37,11 @@ import org.apache.sis.internal.xml.LegacyNamespaces;
 
 
 /**
- * Creates the {@value TransformingReader#FILENAME} file. This class needs to 
be executed only when the content
+ * Creates a file in the {@value TransformingReader#FILENAME} format. This 
class can be executed if the content
  * has changed, or for verifying the current file. Output format contains 
namespaces first, then classes,
  * then properties. Example:
  *
- * {@preformat
+ * {@preformat text
  * http://standards.iso.org/iso/19115/-3/cit/1.0
  *   CI_Address
  *     administrativeArea
@@ -49,6 +49,21 @@ import org.apache.sis.internal.xml.LegacyNamespaces;
  *   CI_Citation
  *     citedResponsibleParty
  * }
+ *
+ * This class can be used as a starting point for generating a new file from 
scratch.
+ * It should not be used for updating the existing file (unless a lot of 
things have changed)
+ * because some of {@value TransformingReader#FILENAME} content have been 
edited by hand.
+ * For generating a new file:
+ *
+ * {@preformat java
+ *     public static void main(String[] args) throws Exception {
+ *         RenameListGenerator gen = new 
RenameListGenerator(Paths.get("/path/to/your/classes"));
+ *         gen.add(Paths.get("root/package/of/classes/to/add"));
+ *         try (final BufferedWriter out = 
Files.newBufferedWriter(Paths.get("MyOutputFile.lst"))) {
+ *             gen.print(out);
+ *         }
+ *     }
+ * }
  */
 public final class RenameListGenerator {
     /**
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingTypes.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingTypes.java
index bd6b00b..f1fa6f8 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingTypes.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingTypes.java
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.referencing;
 
 import java.util.Collection;
+import java.util.function.UnaryOperator;
 import org.apache.sis.internal.jaxb.TypeRegistration;
 import org.apache.sis.parameter.DefaultParameterValue;
 import org.apache.sis.parameter.DefaultParameterValueGroup;
@@ -30,11 +31,11 @@ import org.opengis.referencing.ReferenceSystem;
  * This class is declared in the {@code 
META-INF/services/org.apache.sis.internal.jaxb.TypeRegistration} file.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.4
  * @module
  */
-public final class ReferencingTypes extends TypeRegistration {
+public final class ReferencingTypes extends TypeRegistration implements 
UnaryOperator<Object> {
     /**
      * Adds to the given collection the referencing types that should be given 
to the initial JAXB context.
      */
@@ -46,14 +47,13 @@ public final class ReferencingTypes extends 
TypeRegistration {
     }
 
     /**
-     * Notifies that the {@code sis-referencing} module can marshal arbitrary 
implementations
-     * of some coordinate reference system interfaces.
+     * Returns the converter to apply before marshalling objects.
      *
-     * @return {@code true}.
+     * @return {@code this}.
      */
     @Override
-    protected boolean canMarshalInterfaces() {
-        return true;
+    protected UnaryOperator<Object> beforeMarshal() {
+        return this;
     }
 
     /**
@@ -64,7 +64,7 @@ public final class ReferencingTypes extends TypeRegistration {
      * @return the given value as a type that can be marshalled, or {@code 
null}.
      */
     @Override
-    public Object toImplementation(final Object value) {
+    public Object apply(final Object value) {
         return (value instanceof ReferenceSystem) ? 
AbstractReferenceSystem.castOrCopy((ReferenceSystem) value) : null;
     }
 }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
 
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
index 161fea5..cf26ccc 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
@@ -39,7 +39,7 @@ import org.apache.sis.util.logging.Logging;
  * (profiling shows that even a single thread has very low activity), which 
reduces the interest of that class.
  * Combination of {@code ThreadPoolExecutor} super-class with {@code 
DelayedQueue} were not successful neither.
  *
- * <p>Given that it:</p>
+ * <p>Given that:</p>
  * <ul>
  *   <li>it seems difficult to configure {@code (Scheduled)ThreadPoolExecutor} 
in such a way
  *       that two or more threads are created only when really needed,</li>
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
 
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
index 80c3114..816a9e3 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicLong;
  * for more information.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -49,9 +49,19 @@ public abstract class DelayedRunnable implements Delayed, 
Runnable {
     final long timestamp;
 
     /**
+     * Creates a new task to be executed after the given delay.
+     *
+     * @param delay  delay before execution of this task.
+     * @param unit   unit of measurement of given {@code delay}.
+     */
+    protected DelayedRunnable(final int delay, final TimeUnit unit) {
+        timestamp = System.nanoTime() + unit.toNanos(delay);
+    }
+
+    /**
      * Creates a new task to be executed at the given time.
      * It is user's responsibility to add the {@link System#nanoTime()} value
-     * to the delay he wants to wait.
+     * to the delay (s)he wants to wait.
      *
      * @param timestamp  time of execution of this task, in nanoseconds 
relative to {@link System#nanoTime()}.
      */
diff --git a/ide-project/NetBeans/build.xml b/ide-project/NetBeans/build.xml
index 3051311..8c66df3 100644
--- a/ide-project/NetBeans/build.xml
+++ b/ide-project/NetBeans/build.xml
@@ -116,6 +116,9 @@
       <fileset 
dir="${project.root}/application/sis-console/src/main/resources">
         <include name="**/*.properties"/>
       </fileset>
+      <fileset 
dir="${project.root}/profiles/sis-french-profile/src/main/resources">
+        <include name="**/*.lst"/>
+      </fileset>
     </copy>
 
 
diff --git 
a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/ProfileTypes.java
 
b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/ProfileTypes.java
index 27c1783..1b7c4cb 100644
--- 
a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/ProfileTypes.java
+++ 
b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/ProfileTypes.java
@@ -25,7 +25,7 @@ import org.apache.sis.internal.jaxb.TypeRegistration;
  * This class is declared in the {@code 
META-INF/services/org.apache.sis.internal.jaxb.TypeRegistration} file.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -42,4 +42,16 @@ public final class ProfileTypes extends TypeRegistration {
         addTo.add(LegalConstraints.class);
         addTo.add(SecurityConstraints.class);
     }
+
+    /**
+     * Returns {@code true} for {@code export = false} in order to notify that 
we provide
+     * a {@code "RenameOnImport.lst"} file that need to be read.
+     *
+     * @param  export  {@code true} for {@code "RenameOnImport.lst"}, {@code 
false} for {@code "RenameOnImport.lst"}.
+     * @return {@code true} for {@code "RenameOnImport.lst"}, {@code false} 
otherwise.
+     */
+    @Override
+    protected boolean hasRenameFile(boolean export) {
+        return !export;
+    }
 }
diff --git 
a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/package-info.java
 
b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/package-info.java
index 224e525..e94357b 100644
--- 
a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/package-info.java
+++ 
b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/package-info.java
@@ -23,7 +23,7 @@
  *
  * @author  Cédric Briançon (Geomatys)
  * @author  Guilhem Legal (Geomatys)
- * @version 0.4
+ * @version 1.0
  *
  * @see org.apache.sis.profile.france
  *
diff --git 
a/profiles/sis-french-profile/src/main/resources/org/apache/sis/internal/profile/fra/RenameOnImport.lst
 
b/profiles/sis-french-profile/src/main/resources/org/apache/sis/internal/profile/fra/RenameOnImport.lst
new file mode 100644
index 0000000..fc0fa04
--- /dev/null
+++ 
b/profiles/sis-french-profile/src/main/resources/org/apache/sis/internal/profile/fra/RenameOnImport.lst
@@ -0,0 +1,10 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements;
+# and to You under the Apache License, Version 2.0.
+#
+http://www.cnig.gouv.fr/2005/fra
+ FRA_DataIdentification : MD_DataIdentification
+ FRA_DirectReferenceSystem : MD_ReferenceSystem
+ FRA_IndirectReferenceSystem : MD_ReferenceSystem
+ FRA_Constraints : MD_Constraints
+ FRA_LegalConstraints : MD_LegalConstraints
+ FRA_SecurityConstraints : MD_SecurityConstraints
diff --git 
a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DataIdentificationTest.java
 
b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DataIdentificationTest.java
index 1c800a5..a9435ba 100644
--- 
a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DataIdentificationTest.java
+++ 
b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DataIdentificationTest.java
@@ -18,7 +18,6 @@ package org.apache.sis.internal.profile.fra;
 
 import javax.xml.bind.JAXBException;
 import org.apache.sis.test.xml.TestCase;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.sis.test.MetadataAssert.*;
@@ -42,7 +41,6 @@ public final strictfp class DataIdentificationTest extends 
TestCase {
      * @see <a href="https://issues.apache.org/jira/browse/SIS-404";>SIS-404</a>
      */
     @Test
-    @Ignore("Verify if we should discontinue this profile.")
     public void testMarshalling() throws JAXBException {
         final String xml =
                 "<fra:FRA_DataIdentification 
xmlns:gmd=\"http://www.isotc211.org/2005/gmd\""; +

Reply via email to