sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1574562 - in /sis/branches/JDK7/core: sis-metadata/src/main/java/org/apache/sis/metadata/iso/ sis-referencing/src/main/java/org/apache/sis/parameter/ sis-referencing/src/main/java/org/apache/sis/referencing/ sis-referencing/src/test/java/o...
Date Wed, 05 Mar 2014 16:23:54 GMT
Author: desruisseaux
Date: Wed Mar  5 16:23:53 2014
New Revision: 1574562

URL: http://svn.apache.org/r1574562
Log:
Refactored the builder: moved all identification information (i.e. properties related to IdentifiedObject)
to a new super class, to be shared by the Datum, CS and CRS builder to be provided in a future SIS version.
Renamed the remaining of DescriptorBuilder as ParameterBuilder for clarity.

Added:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
      - copied, changed from r1574221, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
      - copied, changed from r1574221, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java
      - copied, changed from r1574221, sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DescriptorBuilderTest.java
Removed:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DescriptorBuilderTest.java
Modified:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1574562&r1=1574561&r2=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -454,11 +454,12 @@ public class ImmutableIdentifier extends
 
     /**
      * Organization or party responsible for definition and maintenance of the
-     * {@linkplain #getCode code}.
+     * {@linkplain #getCode() code}.
      *
-     * @return The authority, or {@code null} if not available.
+     * <div class="note"><b>Example:</b> Coordinate Reference System (CRS) identified by an EPSG code will return
+     * {@link Citations#OGP}, since OGP is the organization maintaining the EPSG geodetic database.</div>
      *
-     * @see org.apache.sis.metadata.iso.citation.Citations#EPSG
+     * @return The authority, or {@code null} if not available.
      */
     @Override
     public Citation getAuthority() {
@@ -467,7 +468,7 @@ public class ImmutableIdentifier extends
 
     /**
      * Identifier of the version of the associated code space or code, as specified by the
-     * code authority. This version is included only when the {@linkplain #getCode code}
+     * code authority. This version is included only when the {@linkplain #getCode() code}
      * uses versions. When appropriate, the edition is identified by the effective date,
      * coded using ISO 8601 date format.
      *

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java (from r1574221, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java&r1=1574221&r2=1574562&rev=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -16,36 +16,19 @@
  */
 package org.apache.sis.parameter;
 
-import java.util.Map;
-import java.util.List;
-import java.util.HashMap;
-import java.util.ArrayList;
 import javax.measure.unit.Unit;
-import org.opengis.util.NameSpace;
-import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
-import org.opengis.metadata.citation.Citation;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.referencing.ReferenceIdentifier;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
-import org.apache.sis.referencing.NamedIdentifier;
-import org.apache.sis.metadata.iso.ImmutableIdentifier;
-import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.measure.Range;
-import org.apache.sis.util.resources.Errors;
+import org.apache.sis.referencing.Builder;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.internal.system.DefaultFactories.NAMES;
-
-// Related to JDK7
-import java.util.Objects;
 
 
 /**
- * Provides convenience methods for easier {@link DefaultParameterDescriptor} instantiations.
+ * Provides convenience methods for easier {@code DefaultParameterDescriptor} instantiations.
  * This builder can be helpful for map projection <em>providers</em>, or for implementation of
  * any process that use parameters. Map projection or process <em>users</em> do not need this
  * builder since they can invoke {@link ParameterDescriptor#createValue()} on the descriptor
@@ -62,7 +45,7 @@ import java.util.Objects;
  *
  * <p>Parameters can have at most one remark, which is specified by the {@code remarks(…)} method.</p>
  *
- * <p>All the above-cited properties are cleared after a call to any {@code create(…)} method,
+ * <p>All the above-cited properties are cleared after a call to any {@code createXXX(…)} method,
  * since those properties are specific to the each parameter. Other properties like codespace,
  * version and cardinality are left unchanged because they may be shared by many parameters.</p>
  *
@@ -74,45 +57,33 @@ import java.util.Objects;
  * with no scale factor and no false easting/northing.
  *
  * {@preformat java
- *   DescriptorBuilder builder = new DescriptorBuilder();
+ *   ParameterBuilder builder = new ParameterBuilder();
  *   builder.codespace(Citations.OGP, "EPSG").mandatory();
  *   ParameterDescriptor<Double>[] parameters = {
- *       builder.name("Latitude of natural origin")     .createBounded( -80,  +80, 0, NonSI.DEGREE_ANGLE),
- *       builder.name("Longitude of natural origin")    .createBounded(-180, +180, 0, NonSI.DEGREE_ANGLE),
- *       builder.name("Scale factor at natural origin") .createStrictlyPositive(1, Unit.ONE),
- *       builder.name("False easting")                  .create(0, SI.METRE),
- *       builder.name("False northing")                 .create(0, SI.METRE)
+ *       builder.name("Latitude of natural origin")    .createBounded( -80,  +84, 0, NonSI.DEGREE_ANGLE),
+ *       builder.name("Longitude of natural origin")   .createBounded(-180, +180, 0, NonSI.DEGREE_ANGLE),
+ *       builder.name("Scale factor at natural origin").createStrictlyPositive(1, Unit.ONE),
+ *       builder.name("False easting")                 .create(0, SI.METRE),
+ *       builder.name("False northing")                .create(0, SI.METRE)
  *   };
  * }
  *
+ * Note that different softwares or standards may use different names for the same parameters.
+ * Aliases may be defined to any parameters like below:
+ *
+ * {@preformat java
+ *   builder.name("Longitude of natural origin")        // Primary name in builder default namespace.
+ *          .name(Citations.OGC, "central_meridian")    // First alias in "OGC" namespace.
+ *          .name(Citations.GEOTIFF, "NatOriginLong")   // Second alias in "GeoTIFF" namespace.
+ *          .createBounded(-80, +84, 0, NonSI.DEGREE_ANGLE);
+ * }
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
  * @version 0.4
  * @module
  */
-public class DescriptorBuilder {
-    /**
-     * The name, alias, identifiers and remarks properties.
-     */
-    private final Map<String,Object> properties;
-
-    /**
-     * The aliases.
-     */
-    private final List<GenericName> aliases;
-
-    /**
-     * The identifiers.
-     */
-    private final List<ReferenceIdentifier> identifiers;
-
-    /**
-     * The codespace as a {@code NameSpace} object, or {@code null} if not yet created.
-     *
-     * @see #namespace()
-     */
-    private NameSpace namespace;
-
+public class ParameterBuilder extends Builder<ParameterBuilder> {
     /**
      * {@code true} if the parameter is mandatory, or {@code false} if optional.
      *
@@ -124,294 +95,7 @@ public class DescriptorBuilder {
     /**
      * Creates a new builder.
      */
-    public DescriptorBuilder() {
-        properties  = new HashMap<>(8);
-        aliases     = new ArrayList<>(4);
-        identifiers = new ArrayList<>(4);
-    }
-
-    /**
-     * Clears the identification information.
-     * This does not clear the codespace, version and cardinality (mandatory versus optional) properties.
-     */
-    private void clearIdentification() {
-        properties .put(ParameterDescriptor.NAME_KEY, null);
-        properties .remove(ParameterDescriptor.REMARKS_KEY);
-        aliases    .clear();
-        identifiers.clear();
-    }
-
-    /**
-     * Sets the property value for the given key, if a change is still possible. The check for change permission
-     * is needed for all keys defined in the {@link ReferenceIdentifier} interface. This check is not needed for
-     * other keys, so callers do not need to invoke this method for other keys.
-     *
-     * @param  key The key of the property to set.
-     * @param  value The value to set.
-     * @return {@code true} if the property changed as a result of this method call.
-     * @throws IllegalStateException if a new value is specified in a phase where the value can not be changed.
-     */
-    private boolean setProperty(final String key, final Object value) throws IllegalStateException {
-        if (Objects.equals(properties.get(key), value)) {
-            return false;
-        }
-        if (properties.get(ParameterDescriptor.NAME_KEY) != null) {
-            throw new IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1, key));
-        }
-        properties.put(key, value);
-        return true;
-    }
-
-    /**
-     * Returns the namespace, creating it when first needed.
-     */
-    private NameSpace namespace() {
-        if (namespace == null) {
-            final String codespace = (String) properties.get(ReferenceIdentifier.CODESPACE_KEY);
-            if (codespace != null) {
-                namespace = NAMES.createNameSpace(NAMES.createLocalName(null, codespace), null);
-            }
-        }
-        return namespace;
-    }
-
-    /**
-     * Sets the authority and code space. This method is typically invoked only once, since
-     * a group of parameters often uses the same code space for all individual parameters.
-     *
-     * <p><b>Condition:</b>
-     * this method can not be invoked after one or more names or identifiers have been added (by calls to the
-     * {@code name(…)} or {@code identifier(…)} methods) for the next descriptor to create. This method can be
-     * invoked again after the name, aliases and identifiers have been cleared by a call to {@code createXXX(…)}.</p>
-     *
-     * <p><b>Life cycle:</b>
-     * this property is kept unchanged until this {@code codespace(…)} method is invoked again.</p>
-     *
-     * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  codespace The parameter codespace, or {@code null} for inferring it from the authority.
-     * @return {@code this}, for method call chaining.
-     * @throws IllegalStateException if {@code name(…)} or {@code identifier(…)} has been invoked at least
-     *         once since builder construction or since the last call to a {@code createXXX(…)} method.
-     */
-    public DescriptorBuilder codespace(final Citation authority, final String codespace) {
-        if (!setProperty(ReferenceIdentifier.CODESPACE_KEY, codespace)) {
-            namespace = null;
-        }
-        setProperty(ReferenceIdentifier.AUTHORITY_KEY, authority);
-        return this;
-    }
-
-    /**
-     * Sets the version of parameter definitions. This method is typically invoked only once,
-     * since a group of parameters often uses the same version for all individual parameters.
-     *
-     * <p><b>Condition:</b>
-     * this method can not be invoked after one or more names or identifiers have been added (by calls to the
-     * {@code name(…)} or {@code identifier(…)} methods) for the next descriptor to create. This method can be
-     * invoked again after the name, aliases and identifiers have been cleared by a call to {@code createXXX(…)}.</p>
-     *
-     * <p><b>Life cycle:</b>
-     * this property is kept unchanged until this {@code version(…)} method is invoked again.</p>
-     *
-     * @param  version The version of code definitions, or {@code null} if none.
-     * @return {@code this}, for method call chaining.
-     * @throws IllegalStateException if {@code name(…)} or {@code identifier(…)} has been invoked at least
-     *         once since builder construction or since the last call to a {@code createXXX(…)} method.
-     */
-    public DescriptorBuilder version(final String version) {
-        setProperty(ReferenceIdentifier.VERSION_KEY, version);
-        return this;
-    }
-
-    /**
-     * Adds a parameter name given by a {@code String} or {@code InternationalString}.
-     * The given string will be combined with the authority, {@linkplain #codespace(Citation, String) code space}
-     * and {@linkplain #version(String) version} information for creating the {@link ReferenceIdentifier} or
-     * {@link GenericName} object.
-     *
-     * {@section Name and aliases}
-     * This method can be invoked many times. The first invocation sets the
-     * {@linkplain AbstractIdentifiedObject#getName() primary name}, and
-     * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
-     *
-     * <p><b>Life cycle:</b>
-     * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  name The parameter name.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder name(final CharSequence name) {
-        ensureNonNull("name", name);
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, name.toString());
-        if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
-            aliases.add(name instanceof GenericName ? (GenericName) name : NAMES.createLocalName(namespace(), name));
-        }
-        return this;
-    }
-
-    /**
-     * Adds a parameter name in an alternative namespace. This method is typically invoked for
-     * {@linkplain AbstractIdentifiedObject#getAlias() aliases} defined after the primary name.
-     *
-     * <div class="note"><b>Example:</b>
-     * The "<cite>Longitude of natural origin</cite>" parameter defined by EPSG is named differently
-     * by OGC and GeoTIFF. Those alternative names can be defined as below:
-     *
-     * {@preformat java
-     *   builder.name("Longitude of natural origin")        // Primary name in builder default namespace.
-     *          .name(Citations.OGC, "central_meridian")    // First alias in "OGC" namespace.
-     *          .name(Citations.GEOTIFF, "NatOriginLong");  // Second alias in "GeoTIFF" namespace.
-     * }
-     *
-     * In this example, {@code "central_meridian"} will be the
-     * {@linkplain org.apache.sis.util.iso.DefaultScopedName#tip() tip} and {@code "OGC"} will be the
-     * {@linkplain org.apache.sis.util.iso.DefaultScopedName#head() head} of the first alias.</div>
-     *
-     * <p><b>Life cycle:</b>
-     * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  name The parameter alias as a name in the namespace of the given authority.
-     * @return {@code this}, for method call chaining.
-     *
-     * @see #identifier(Citation, String)
-     */
-    public DescriptorBuilder name(final Citation authority, final CharSequence name) {
-        ensureNonNull("name", name);
-        final NamedIdentifier identifier;
-        if (name instanceof InternationalString) {
-            identifier = new NamedIdentifier(authority, (InternationalString) name);
-        } else {
-            identifier = new NamedIdentifier(authority, name.toString());
-        }
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, identifier);
-        if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
-            aliases.add(identifier);
-        }
-        return this;
-    }
-
-    /**
-     * Adds a parameter name fully specified by the given identifier.
-     * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
-     * {@linkplain #version(String) version} specified to this builder (if any), since the given
-     * identifier already contains those information.
-     *
-     * {@section Name and aliases}
-     * This method can be invoked many times. The first invocation sets the
-     * {@linkplain AbstractIdentifiedObject#getName() primary name} to the given value, and
-     * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
-     *
-     * <p><b>Life cycle:</b>
-     * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  name The parameter name as an identifier.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder name(final ReferenceIdentifier name) {
-        ensureNonNull("name", name);
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, name);
-        if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
-            aliases.add(name instanceof GenericName ? (GenericName) name : new NamedIdentifier(name));
-        }
-        return this;
-    }
-
-    /**
-     * Adds a parameter name fully specified by the given generic name.
-     * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
-     * {@linkplain #version(String) version} specified to this builder (if any), since the given
-     * generic name already contains those information.
-     *
-     * {@section Name and aliases}
-     * This method can be invoked many times. The first invocation sets the
-     * {@linkplain AbstractIdentifiedObject#getName() primary name} to the given value, and
-     * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
-     *
-     * <p><b>Life cycle:</b>
-     * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  name The parameter name as an identifier.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder name(final GenericName name) {
-        ensureNonNull("name", name);
-        if (properties.get(ParameterDescriptor.NAME_KEY) == null) {
-            properties.put(ParameterDescriptor.NAME_KEY, new NamedIdentifier(name));
-        } else {
-            aliases.add(name);
-        }
-        return this;
-    }
-
-    /**
-     * Adds a parameter identifier given by a {@code String}.
-     * The given string will be combined with the authority, {@linkplain #codespace(Citation, String) code space}
-     * and {@linkplain #version(String) version} information for creating the {@link ReferenceIdentifier} object.
-     *
-     * <p><b>Life cycle:</b>
-     * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  identifier The parameter identifier.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder identifier(final String identifier) {
-        ensureNonNull("identifier", identifier);
-        identifiers.add(new ImmutableIdentifier((Citation) properties.get(ReferenceIdentifier.AUTHORITY_KEY),
-                (String) properties.get(ReferenceIdentifier.CODESPACE_KEY), identifier));
-        return this;
-    }
-
-    /**
-     * Adds a parameter identifier in an alternative namespace. This method is typically invoked in
-     * complement to {@link #name(Citation, CharSequence)}.
-     *
-     * <p><b>Life cycle:</b>
-     * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  identifier The parameter identifier as a code in the namespace of the given authority.
-     * @return {@code this}, for method call chaining.
-     *
-     * @see #name(Citation, CharSequence)
-     */
-    public DescriptorBuilder identifier(final Citation authority, final String identifier) {
-        ensureNonNull("identifier", identifier);
-        identifiers.add(new ImmutableIdentifier(authority, Citations.getIdentifier(authority), identifier));
-        return this;
-    }
-
-    /**
-     * Adds a parameter identifier fully specified by the given identifier.
-     * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
-     * {@linkplain #version(String) version} specified to this builder (if any), since the given
-     * identifier already contains those information.
-     *
-     * <p><b>Life cycle:</b>
-     * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
-     *
-     * @param  identifier The parameter identifier.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder identifier(final ReferenceIdentifier identifier) {
-        ensureNonNull("identifier", identifier);
-        identifiers.add(identifier);
-        return this;
-    }
-
-    /**
-     * Sets remarks as a {@code String} or {@code InternationalString} instance.
-     * Calls to this method overwrite any previous value.
-     *
-     * @param  remarks The remarks, or {@code null} if none.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder remarks(final CharSequence remarks) {
-        properties.put(ParameterDescriptor.REMARKS_KEY, remarks);
-        return this;
+    public ParameterBuilder() {
     }
 
     /**
@@ -420,7 +104,7 @@ public class DescriptorBuilder {
      *
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder mandatory() {
+    public ParameterBuilder mandatory() {
         this.required = true;
         return this;
     }
@@ -431,7 +115,7 @@ public class DescriptorBuilder {
      *
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder optional() {
+    public ParameterBuilder optional() {
         this.required = false;
         return this;
     }
@@ -536,6 +220,22 @@ public class DescriptorBuilder {
     }
 
     /**
+     * Creates a descriptor for values in the domain represented by the given {@code Range} object.
+     * This method allows to specify whether the minimum and maximum values are inclusive or not.
+     *
+     * @param  <T>          The type of the parameter values.
+     * @param  valueDomain  The minimum value, maximum value and unit of measurement.
+     * @param  defaultValue The default value for the parameter, or {@code null} if none.
+     * @return The parameter descriptor for the given domain of values.
+     */
+    public <T extends Comparable<? super T>> ParameterDescriptor<T> createBounded(
+            final Range<T> valueDomain, final T defaultValue)
+    {
+        ensureNonNull("valueDomain", valueDomain);
+        return create(valueDomain.getElementType(), valueDomain, null, defaultValue);
+    }
+
+    /**
      * Creates a descriptor for a parameter restricted to a set of valid values.
      * The descriptor has no minimal or maximal value and no unit.
      *
@@ -551,21 +251,21 @@ public class DescriptorBuilder {
      * @return The parameter descriptor for the given set of valid values.
      */
     public <T> ParameterDescriptor<T> createEnumerated(final Class<T> valueClass, final T[] validValues, final T defaultValue) {
+        ensureNonNull("valueClass", valueClass);
         return create(valueClass, null, validValues, defaultValue);
     }
 
     /**
-     * Invoked by all {@code createXXX(…)} method for creating the descriptor from the properties currently set
-     * in this builder.
+     * Invoked by all {@code createXXX(…)} methods for creating the descriptor from the properties
+     * currently set in this builder. Identification information are cleared after this method call.
      */
     private <T> ParameterDescriptor<T> create(final Class<T> valueClass, final Range<?> valueDomain,
             final T[] validValues, final T defaultValue)
     {
-        properties.put(ParameterDescriptor.ALIAS_KEY, aliases.toArray(new GenericName[aliases.size()]));
-        properties.put(ParameterDescriptor.IDENTIFIERS_KEY, identifiers.toArray(new ReferenceIdentifier[identifiers.size()]));
+        onCreate(false);
         final ParameterDescriptor<T> descriptor = new DefaultParameterDescriptor<>(
                 properties, valueClass, valueDomain, validValues, defaultValue, required);
-        clearIdentification();
+        onCreate(true);
         return descriptor;
     }
 }

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java (from r1574221, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java&r1=1574221&r2=1574562&rev=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DescriptorBuilder.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -14,27 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.parameter;
+package org.apache.sis.referencing;
 
 import java.util.Map;
 import java.util.List;
 import java.util.HashMap;
 import java.util.ArrayList;
-import javax.measure.unit.Unit;
+import java.lang.reflect.Type;
+import java.lang.reflect.ParameterizedType;
 import org.opengis.util.NameSpace;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.ReferenceIdentifier;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
-import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.measure.MeasurementRange;
-import org.apache.sis.measure.NumberRange;
-import org.apache.sis.measure.Range;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -45,64 +40,100 @@ import java.util.Objects;
 
 
 /**
- * Provides convenience methods for easier {@link DefaultParameterDescriptor} instantiations.
- * This builder can be helpful for map projection <em>providers</em>, or for implementation of
- * any process that use parameters. Map projection or process <em>users</em> do not need this
- * builder since they can invoke {@link ParameterDescriptor#createValue()} on the descriptor
- * provided by the implementor.
- *
- * {@section Identification properties}
- * Each parameter must have a name, which can be specified by any of the {@code name(…)} methods.
- * Parameters can optionally have an arbitrary amount of aliases, which are also specified by the
- * {@code name(…)} methods — each call after the first one adds an alias.
- *
- * <p>Parameters can also have an arbitrary amount of identifiers, which are specified by the
- * {@code identifier(…)} methods. Like names, more than one identifier can be added by invoking
- * the method many time.</p>
- *
- * <p>Parameters can have at most one remark, which is specified by the {@code remarks(…)} method.</p>
- *
- * <p>All the above-cited properties are cleared after a call to any {@code create(…)} method,
- * since those properties are specific to the each parameter. Other properties like codespace,
- * version and cardinality are left unchanged because they may be shared by many parameters.</p>
- *
- * {@section Usage example}
- * Parameter descriptors are typically grouped in a {@link ParameterDescriptorGroup}.
- * All parameters usually have the same namespace, which can be declared only once.
- * The following example creates parameters for "<cite>Mercator (variant A)</cite>" projection method (EPSG:9804)
- * with all parameter names in the "EPSG" namespace. The default values define a projection centered on (0°,0°)
- * with no scale factor and no false easting/northing.
+ * Base class of builders for various kind of {@code IdentifiedObject}. {@code Builder}s aim to make object
+ * creation easier — they do not add any new functionality to {@link org.opengis.referencing.ObjectFactory}.
+ * Builder methods like {@link #name(CharSequence)} and {@link #identifier(String)} provide convenient ways
+ * to fill the {@link #properties} map, which will be given to the {@code ObjectFactory} methods at
+ * {@code IdentifiedObject} creation time. Creations happen when any {@code createXXX(…)} method defined in
+ * the builder subclasses is invoked.
  *
+ * <p>This base class provides method for defining the following {@link IdentifiedObject} properties:</p>
+ * <ul>
+ *   <li><p><b>{@link AbstractIdentifiedObject#getName() Name}:</b><br>
+ *     Each {@code IdentifiedObject} must have a name, which can be specified by a call to any of the
+ *     {@code name(…)} methods defined in this class.</p></li>
+ *
+ *   <li><p><b>{@link AbstractIdentifiedObject#getAlias() Aliases}:</b><br>
+ *     Identified objects can optionally have an arbitrary amount of aliases, which are also specified
+ *     by the {@code name(…)} methods — each call after the first one adds an alias.</p></li>
+ *
+ *   <li><p><b>{@link AbstractIdentifiedObject#getIdentifiers() Identifiers}:</b><br>
+ *     Identified objects can also have an arbitrary amount of identifiers, which are specified by the
+ *     {@code identifier(…)} methods. Like names, more than one identifier can be added by invoking
+ *     the method many time.</p></li>
+ *
+ *   <li><p><b>{@link AbstractIdentifiedObject#getRemarks() Remarks}:</b><br>
+ *     Identified objects can have at most one remark, which is specified by the {@code remarks(…)} method.</p></li>
+ * </ul>
+ *
+ * {@section Builder property lifetimes}
+ * The same builder can be used for creating many objects, since constructing a Coordinate Reference System (CRS)
+ * may require constructing many components (coordinate system, datum, ellipsoid, prime meridian, <i>etc.</i>),
+ * some of them sharing common properties. In order to simplify the most common usage scenarios, identification
+ * properties have two different lifetimes in the {@code Builder} class:
+ *
+ * <ul>
+ *   <li>{@linkplain NamedIdentifier#getAuthority() Authority}, {@linkplain NamedIdentifier#getCodeSpace() code space}
+ *       and {@linkplain NamedIdentifier#getVersion() version} information specified to this {@code Builder} will stay
+ *       active until they are specified again, because those information are typically shared by all components.</li>
+ *   <li>Other properties (name, aliases, identifiers and remarks) are cleared after each call to a {@code createXXX(…)}
+ *       method, because they are usually specific to a particular {@code IdentifiedObject} instance.</li>
+ * </ul>
+ *
+ *
+ * <div class="note"><b>Note for subclass implementors:</b>
+ * <ul>
+ *   <li>The type {@code <B>} shall be exactly the subclass type.
+ *       For performance reasons, this is verified only if Java assertions are enabled.</li>
+ *   <li>All {@code createXXX(…)} methods shall invoke {@link #onCreate(boolean)} before and after
+ *       usage of {@link #properties} map by the factory.</li>
+ * </ul>
+ *
+ * <b>Example:</b>
  * {@preformat java
- *   DescriptorBuilder builder = new DescriptorBuilder();
- *   builder.codespace(Citations.OGP, "EPSG").mandatory();
- *   ParameterDescriptor<Double>[] parameters = {
- *       builder.name("Latitude of natural origin")     .createBounded( -80,  +80, 0, NonSI.DEGREE_ANGLE),
- *       builder.name("Longitude of natural origin")    .createBounded(-180, +180, 0, NonSI.DEGREE_ANGLE),
- *       builder.name("Scale factor at natural origin") .createStrictlyPositive(1, Unit.ONE),
- *       builder.name("False easting")                  .create(0, SI.METRE),
- *       builder.name("False northing")                 .create(0, SI.METRE)
- *   };
+ *     public class MyBuilder extends Builder<MyBuilder> {
+ *         public Foo createFoo() {
+ *             onCreate(false);
+ *             Foo foo = factory.createFoo(properties);
+ *             onCreate(true);
+ *             return foo;
+ *         }
+ *     }
  * }
+ * </div>
+ *
+ * @param <B> The builder subclass.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
  * @version 0.4
  * @module
  */
-public class DescriptorBuilder {
+public abstract class Builder<B extends Builder<B>> {
     /**
-     * The name, alias, identifiers and remarks properties.
+     * The properties to be given to {@link org.opengis.referencing.ObjectFactory} methods.
+     * This map may contain values for the
+     * {@value org.opengis.referencing.IdentifiedObject#NAME_KEY},
+     * {@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY},
+     * {@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY} and
+     * {@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY} keys.
+     * Subclasses may add other entries like
+     * {@value org.opengis.referencing.ReferenceSystem#DOMAIN_OF_VALIDITY_KEY},
+     * {@value org.opengis.referencing.ReferenceSystem#SCOPE_KEY} keys.
+     *
+     * <p>See <cite>Notes for subclass implementors</cite> in class javadoc for usage conditions.</p>
+     *
+     * @see #onCreate(boolean)
      */
-    private final Map<String,Object> properties;
+    protected final Map<String,Object> properties;
 
     /**
-     * The aliases.
+     * A temporary list for aliases, before to assign them to the {@link #properties}.
      */
     private final List<GenericName> aliases;
 
     /**
-     * The identifiers.
+     * A temporary list for identifiers, before to assign them to the {@link #properties}.
      */
     private final List<ReferenceIdentifier> identifiers;
 
@@ -114,31 +145,43 @@ public class DescriptorBuilder {
     private NameSpace namespace;
 
     /**
-     * {@code true} if the parameter is mandatory, or {@code false} if optional.
-     *
-     * @see #mandatory()
-     * @see #optional()
-     */
-    private boolean required;
-
-    /**
      * Creates a new builder.
      */
-    public DescriptorBuilder() {
+    protected Builder() {
+        assert isSelf(getClass());
         properties  = new HashMap<>(8);
         aliases     = new ArrayList<>(4);
         identifiers = new ArrayList<>(4);
     }
 
     /**
-     * Clears the identification information.
-     * This does not clear the codespace, version and cardinality (mandatory versus optional) properties.
+     * Verifies that {@code B} in {@code <B extends Builder<B>} is the expected class.
+     * This method is for assertion purposes only.
      */
-    private void clearIdentification() {
-        properties .put(ParameterDescriptor.NAME_KEY, null);
-        properties .remove(ParameterDescriptor.REMARKS_KEY);
-        aliases    .clear();
-        identifiers.clear();
+    private static boolean isSelf(final Class<?> expected) {
+        for (Class<?> c = expected; c != null; c = c.getSuperclass()) {
+            Type type = c.getGenericSuperclass();
+            if (type instanceof ParameterizedType) {
+                final ParameterizedType p = (ParameterizedType) type;
+                if (p.getRawType() == Builder.class) {
+                    type = p.getActualTypeArguments()[0];
+                    if (type == expected) return true;
+                    throw new AssertionError(type);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code this} casted to {@code <B>}. The cast is valid if the assertion performed
+     * at construction time passes. Since the {@code <B>} type is hard-coded in the source code,
+     * if the JUnit test passes then the cast should always be valid for all instances of the
+     * same builder class.
+     */
+    @SuppressWarnings("unchecked")
+    private B self() {
+        return (B) this;
     }
 
     /**
@@ -155,7 +198,7 @@ public class DescriptorBuilder {
         if (Objects.equals(properties.get(key), value)) {
             return false;
         }
-        if (properties.get(ParameterDescriptor.NAME_KEY) != null) {
+        if (properties.get(IdentifiedObject.NAME_KEY) != null) {
             throw new IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1, key));
         }
         properties.put(key, value);
@@ -176,41 +219,41 @@ public class DescriptorBuilder {
     }
 
     /**
-     * Sets the authority and code space. This method is typically invoked only once, since
-     * a group of parameters often uses the same code space for all individual parameters.
+     * Sets the {@code ReferenceIdentifier} authority and code space. This method is typically invoked only once,
+     * since a compound object often uses the same code space for all individual components.
      *
      * <p><b>Condition:</b>
      * this method can not be invoked after one or more names or identifiers have been added (by calls to the
-     * {@code name(…)} or {@code identifier(…)} methods) for the next descriptor to create. This method can be
+     * {@code name(…)} or {@code identifier(…)} methods) for the next object to create. This method can be
      * invoked again after the name, aliases and identifiers have been cleared by a call to {@code createXXX(…)}.</p>
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * this property is kept unchanged until this {@code codespace(…)} method is invoked again.</p>
      *
      * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  codespace The parameter codespace, or {@code null} for inferring it from the authority.
+     * @param  codespace The {@code IdentifiedObject} codespace, or {@code null} for inferring it from the authority.
      * @return {@code this}, for method call chaining.
      * @throws IllegalStateException if {@code name(…)} or {@code identifier(…)} has been invoked at least
      *         once since builder construction or since the last call to a {@code createXXX(…)} method.
      */
-    public DescriptorBuilder codespace(final Citation authority, final String codespace) {
+    public B codespace(final Citation authority, final String codespace) {
         if (!setProperty(ReferenceIdentifier.CODESPACE_KEY, codespace)) {
             namespace = null;
         }
         setProperty(ReferenceIdentifier.AUTHORITY_KEY, authority);
-        return this;
+        return self();
     }
 
     /**
-     * Sets the version of parameter definitions. This method is typically invoked only once,
-     * since a group of parameters often uses the same version for all individual parameters.
+     * Sets the {@code ReferenceIdentifier} version of object definitions. This method is typically invoked only once,
+     * since a compound object often uses the same version for all individual components.
      *
      * <p><b>Condition:</b>
      * this method can not be invoked after one or more names or identifiers have been added (by calls to the
-     * {@code name(…)} or {@code identifier(…)} methods) for the next descriptor to create. This method can be
+     * {@code name(…)} or {@code identifier(…)} methods) for the next object to create. This method can be
      * invoked again after the name, aliases and identifiers have been cleared by a call to {@code createXXX(…)}.</p>
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * this property is kept unchanged until this {@code version(…)} method is invoked again.</p>
      *
      * @param  version The version of code definitions, or {@code null} if none.
@@ -218,13 +261,13 @@ public class DescriptorBuilder {
      * @throws IllegalStateException if {@code name(…)} or {@code identifier(…)} has been invoked at least
      *         once since builder construction or since the last call to a {@code createXXX(…)} method.
      */
-    public DescriptorBuilder version(final String version) {
+    public B version(final String version) {
         setProperty(ReferenceIdentifier.VERSION_KEY, version);
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter name given by a {@code String} or {@code InternationalString}.
+     * Adds an {@code IdentifiedObject} name given by a {@code String} or {@code InternationalString}.
      * The given string will be combined with the authority, {@linkplain #codespace(Citation, String) code space}
      * and {@linkplain #version(String) version} information for creating the {@link ReferenceIdentifier} or
      * {@link GenericName} object.
@@ -234,24 +277,24 @@ public class DescriptorBuilder {
      * {@linkplain AbstractIdentifiedObject#getName() primary name}, and
      * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The parameter name.
+     * @param  name The {@code IdentifiedObject} name.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder name(final CharSequence name) {
+    public B name(final CharSequence name) {
         ensureNonNull("name", name);
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, name.toString());
+        final Object old = properties.put(IdentifiedObject.NAME_KEY, name.toString());
         if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
+            properties.put(IdentifiedObject.NAME_KEY, old); // Restore previous value.
             aliases.add(name instanceof GenericName ? (GenericName) name : NAMES.createLocalName(namespace(), name));
         }
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter name in an alternative namespace. This method is typically invoked for
+     * Adds an {@code IdentifiedObject} name in an alternative namespace. This method is typically invoked for
      * {@linkplain AbstractIdentifiedObject#getAlias() aliases} defined after the primary name.
      *
      * <div class="note"><b>Example:</b>
@@ -259,7 +302,8 @@ public class DescriptorBuilder {
      * by OGC and GeoTIFF. Those alternative names can be defined as below:
      *
      * {@preformat java
-     *   builder.name("Longitude of natural origin")        // Primary name in builder default namespace.
+     *   builder.codespace(Citations.OGP, "EPSG")           // Sets the default namespace to "EPSG".
+     *          .name("Longitude of natural origin")        // Primary name in builder default namespace.
      *          .name(Citations.OGC, "central_meridian")    // First alias in "OGC" namespace.
      *          .name(Citations.GEOTIFF, "NatOriginLong");  // Second alias in "GeoTIFF" namespace.
      * }
@@ -268,16 +312,16 @@ public class DescriptorBuilder {
      * {@linkplain org.apache.sis.util.iso.DefaultScopedName#tip() tip} and {@code "OGC"} will be the
      * {@linkplain org.apache.sis.util.iso.DefaultScopedName#head() head} of the first alias.</div>
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
      * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  name The parameter alias as a name in the namespace of the given authority.
+     * @param  name The {@code IdentifiedObject} alias as a name in the namespace of the given authority.
      * @return {@code this}, for method call chaining.
      *
      * @see #identifier(Citation, String)
      */
-    public DescriptorBuilder name(final Citation authority, final CharSequence name) {
+    public B name(final Citation authority, final CharSequence name) {
         ensureNonNull("name", name);
         final NamedIdentifier identifier;
         if (name instanceof InternationalString) {
@@ -285,16 +329,16 @@ public class DescriptorBuilder {
         } else {
             identifier = new NamedIdentifier(authority, name.toString());
         }
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, identifier);
+        final Object old = properties.put(IdentifiedObject.NAME_KEY, identifier);
         if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
+            properties.put(IdentifiedObject.NAME_KEY, old); // Restore previous value.
             aliases.add(identifier);
         }
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter name fully specified by the given identifier.
+     * Adds an {@code IdentifiedObject} name fully specified by the given identifier.
      * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
      * {@linkplain #version(String) version} specified to this builder (if any), since the given
      * identifier already contains those information.
@@ -304,24 +348,24 @@ public class DescriptorBuilder {
      * {@linkplain AbstractIdentifiedObject#getName() primary name} to the given value, and
      * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The parameter name as an identifier.
+     * @param  name The {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder name(final ReferenceIdentifier name) {
+    public B name(final ReferenceIdentifier name) {
         ensureNonNull("name", name);
-        final Object old = properties.put(ParameterDescriptor.NAME_KEY, name);
+        final Object old = properties.put(IdentifiedObject.NAME_KEY, name);
         if (old != null) {
-            properties.put(ParameterDescriptor.NAME_KEY, old); // Restore previous value.
+            properties.put(IdentifiedObject.NAME_KEY, old); // Restore previous value.
             aliases.add(name instanceof GenericName ? (GenericName) name : new NamedIdentifier(name));
         }
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter name fully specified by the given generic name.
+     * Adds an {@code IdentifiedObject} name fully specified by the given generic name.
      * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
      * {@linkplain #version(String) version} specified to this builder (if any), since the given
      * generic name already contains those information.
@@ -331,241 +375,123 @@ public class DescriptorBuilder {
      * {@linkplain AbstractIdentifiedObject#getName() primary name} to the given value, and
      * all subsequent invocations add an {@linkplain AbstractIdentifiedObject#getAlias() alias}.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The parameter name as an identifier.
+     * @param  name The {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder name(final GenericName name) {
+    public B name(final GenericName name) {
         ensureNonNull("name", name);
-        if (properties.get(ParameterDescriptor.NAME_KEY) == null) {
-            properties.put(ParameterDescriptor.NAME_KEY, new NamedIdentifier(name));
+        if (properties.get(IdentifiedObject.NAME_KEY) == null) {
+            properties.put(IdentifiedObject.NAME_KEY, new NamedIdentifier(name));
         } else {
             aliases.add(name);
         }
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter identifier given by a {@code String}.
+     * Adds an {@code IdentifiedObject} identifier given by a {@code String}.
      * The given string will be combined with the authority, {@linkplain #codespace(Citation, String) code space}
      * and {@linkplain #version(String) version} information for creating the {@link ReferenceIdentifier} object.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  identifier The parameter identifier.
+     * @param  identifier The {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder identifier(final String identifier) {
+    public B identifier(final String identifier) {
         ensureNonNull("identifier", identifier);
         identifiers.add(new ImmutableIdentifier((Citation) properties.get(ReferenceIdentifier.AUTHORITY_KEY),
                 (String) properties.get(ReferenceIdentifier.CODESPACE_KEY), identifier));
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter identifier in an alternative namespace. This method is typically invoked in
-     * complement to {@link #name(Citation, CharSequence)}.
+     * Adds an {@code IdentifiedObject} identifier in an alternative namespace.
+     * This method is typically invoked in complement to {@link #name(Citation, CharSequence)}.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
      * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  identifier The parameter identifier as a code in the namespace of the given authority.
+     * @param  identifier The {@code IdentifiedObject} identifier as a code in the namespace of the given authority.
      * @return {@code this}, for method call chaining.
      *
      * @see #name(Citation, CharSequence)
      */
-    public DescriptorBuilder identifier(final Citation authority, final String identifier) {
+    public B identifier(final Citation authority, final String identifier) {
         ensureNonNull("identifier", identifier);
         identifiers.add(new ImmutableIdentifier(authority, Citations.getIdentifier(authority), identifier));
-        return this;
+        return self();
     }
 
     /**
-     * Adds a parameter identifier fully specified by the given identifier.
+     * Adds an {@code IdentifiedObject} identifier fully specified by the given identifier.
      * This method ignores the authority, {@linkplain #codespace(Citation, String) code space} or
      * {@linkplain #version(String) version} specified to this builder (if any), since the given
      * identifier already contains those information.
      *
-     * <p><b>Life cycle:</b>
+     * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  identifier The parameter identifier.
+     * @param  identifier The {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder identifier(final ReferenceIdentifier identifier) {
+    public B identifier(final ReferenceIdentifier identifier) {
         ensureNonNull("identifier", identifier);
         identifiers.add(identifier);
-        return this;
+        return self();
     }
 
     /**
      * Sets remarks as a {@code String} or {@code InternationalString} instance.
      * Calls to this method overwrite any previous value.
      *
-     * @param  remarks The remarks, or {@code null} if none.
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder remarks(final CharSequence remarks) {
-        properties.put(ParameterDescriptor.REMARKS_KEY, remarks);
-        return this;
-    }
-
-    /**
-     * Sets the parameter as mandatory.
-     * The minimum number of times that values are required will be 1.
-     *
-     * @return {@code this}, for method call chaining.
-     */
-    public DescriptorBuilder mandatory() {
-        this.required = true;
-        return this;
-    }
-
-    /**
-     * Sets the parameter as optional.
-     * The minimum number of times that values are required will be 0.
+     * <p><b>Lifetime:</b>
+     * previous remarks are discarded by calls to {@code remarks(…)}.
+     * Remarks are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
+     * @param  remarks The remarks, or {@code null} if none.
      * @return {@code this}, for method call chaining.
      */
-    public DescriptorBuilder optional() {
-        this.required = false;
-        return this;
+    public B remarks(final CharSequence remarks) {
+        properties.put(IdentifiedObject.REMARKS_KEY, remarks);
+        return self();
     }
 
     /**
-     * Creates a descriptor for floating point values without domain restriction.
-     * All {@code double} values are considered valid.
+     * Initializes/cleanups the {@link #properties} map before/after a {@code createXXX(…)} execution.
+     * Subclasses shall invoke this method in their {@code createXXX(…)} methods as below:
      *
-     * @param  defaultValue The default value for the parameter, or {@link Double#NaN} if none.
-     * @param  unit         The default unit, or {@code null} if none.
-     * @return The parameter descriptor for the given default value and unit.
-     */
-    public ParameterDescriptor<Double> create(final double defaultValue, final Unit<?> unit) {
-        final Range<Double> valueDomain;
-        if (unit != null) {
-            valueDomain = MeasurementRange.create(Double.NEGATIVE_INFINITY, false, Double.POSITIVE_INFINITY, false, unit);
-        } else {
-            valueDomain = null;
-        }
-        return create(Double.class, valueDomain, null, Double.valueOf(defaultValue));
-    }
-
-    /**
-     * Creates a descriptor for floating point values greater than zero.
-     * The zero value is not considered valid. There is no maximal value.
-     *
-     * @param  defaultValue The default value for the parameter, or {@link Double#NaN} if none.
-     * @param  unit         The default unit, or {@code null} if none.
-     * @return The parameter descriptor for the given default value and unit.
-     */
-    public ParameterDescriptor<Double> createStrictlyPositive(final double defaultValue, final Unit<?> unit) {
-        final Range<Double> valueDomain;
-        if (unit != null) {
-            valueDomain = MeasurementRange.create(0.0, false, Double.POSITIVE_INFINITY, false, unit);
-        } else {
-            valueDomain = NumberRange.create(0.0, false, Double.POSITIVE_INFINITY, false);
-        }
-        return create(Double.class, valueDomain, null, Double.valueOf(defaultValue));
-    }
-
-    /**
-     * Creates a descriptor for floating point values restricted to the given domain.
-     *
-     * @param  minimumValue The minimum parameter value (inclusive), or {@link Double#NEGATIVE_INFINITY} if none.
-     * @param  maximumValue The maximum parameter value (inclusive), or {@link Double#POSITIVE_INFINITY} if none.
-     * @param  defaultValue The default value for the parameter, or {@link Double#NaN} if none.
-     * @param  unit         The unit for default, minimum and maximum values, or {@code null} if none.
-     * @return The parameter descriptor for the given domain of values.
-     */
-    public ParameterDescriptor<Double> createBounded(final double minimumValue, final double maximumValue,
-            final double defaultValue, final Unit<?> unit)
-    {
-        final Range<Double> valueDomain;
-        if (unit != null) {
-            valueDomain = MeasurementRange.create(minimumValue, true, maximumValue, true, unit);
-        } else if (minimumValue != Double.NEGATIVE_INFINITY || maximumValue != Double.POSITIVE_INFINITY) {
-            valueDomain = NumberRange.create(minimumValue, true, maximumValue, true);
-        } else {
-            valueDomain = null;
-        }
-        return create(Double.class, valueDomain, null, Double.valueOf(defaultValue));
-    }
-
-    /**
-     * Creates a descriptor for integer values restricted to the given domain.
-     *
-     * @param  minimumValue The minimum parameter value (inclusive).
-     * @param  maximumValue The maximum parameter value (inclusive).
-     * @param  defaultValue The default value for the parameter.
-     * @return The parameter descriptor for the given domain of values.
-     */
-    public ParameterDescriptor<Integer> createBounded(final int minimumValue, final int maximumValue,
-            final int defaultValue)
-    {
-        return create(Integer.class, NumberRange.create(minimumValue, true, maximumValue, true), null, defaultValue);
-    }
-
-    /**
-     * Creates a descriptor for values of the given type restricted to the given domain.
+     * {@preformat java
+     *     public Foo createFoo() {
+     *         onCreate(false);
+     *         Foo foo = factory.createFoo(properties);
+     *         onCreate(true);
+     *         return foo;
+     *     }
+     * }
      *
-     * @param  <T>          The compile-time type of the {@code valueClass} argument.
-     * @param  valueClass   The class that describe the type of the parameter values.
-     * @param  minimumValue The minimum parameter value (inclusive), or {@code null} if none.
-     * @param  maximumValue The maximum parameter value (inclusive), or {@code null} if none.
-     * @param  defaultValue The default value for the parameter, or {@code null} if none.
-     * @return The parameter descriptor for the given domain of values.
-     */
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public <T extends Comparable<? super T>> ParameterDescriptor<T> createBounded(final Class<T> valueClass,
-            final T minimumValue, final T maximumValue, final T defaultValue)
-    {
-        ensureNonNull("valueClass", valueClass);
-        final Range<T> valueDomain;
-        if (minimumValue == null && maximumValue == null) {
-            valueDomain = null;
-        } else if (Number.class.isAssignableFrom(valueClass)) {
-            valueDomain = new NumberRange((Class) valueClass, (Number) minimumValue, true, (Number) maximumValue, true);
-        } else {
-            valueDomain = new Range<>(valueClass, minimumValue, true, maximumValue, true);
+     * If {@code cleanup} is {@code true}, then this method clears the identification information
+     * (name, aliases, identifiers and remarks) for preparing the builder to the construction of
+     * an other object. The authority, codespace and version properties are not cleared by this method.
+     *
+     * @param cleanup {@code false} when this method is invoked before object creation, and
+     *                {@code true} when this method is invoked after object creation.
+     *
+     * @see #properties
+     */
+    protected void onCreate(final boolean cleanup) {
+        properties.put(IdentifiedObject.ALIAS_KEY,       cleanup ? null : aliases    .toArray(new GenericName        [aliases    .size()]));
+        properties.put(IdentifiedObject.IDENTIFIERS_KEY, cleanup ? null : identifiers.toArray(new ReferenceIdentifier[identifiers.size()]));
+        if (cleanup) {
+            properties .put(IdentifiedObject.NAME_KEY, null);
+            properties .remove(IdentifiedObject.REMARKS_KEY);
+            aliases    .clear();
+            identifiers.clear();
         }
-        return create(valueClass, valueDomain, null, defaultValue);
-    }
-
-    /**
-     * Creates a descriptor for a parameter restricted to a set of valid values.
-     * The descriptor has no minimal or maximal value and no unit.
-     *
-     * <p>The {@code validValues} property is mostly for restricting values to
-     * a {@linkplain org.opengis.util.CodeList code list} or enumeration subset.
-     * It is not necessary to provide this property when all values from the code list or enumeration are valid.</p>
-     *
-     * @param <T>          The compile-time type of the {@code valueClass} argument.
-     * @param valueClass   The class that describe the type of the parameter values.
-     * @param validValues  A finite set of valid values (usually from a {@linkplain CodeList code list})
-     *                     or {@code null} if it doesn't apply.
-     * @param defaultValue The default value for the parameter, or {@code null} if none.
-     * @return The parameter descriptor for the given set of valid values.
-     */
-    public <T> ParameterDescriptor<T> createEnumerated(final Class<T> valueClass, final T[] validValues, final T defaultValue) {
-        return create(valueClass, null, validValues, defaultValue);
-    }
-
-    /**
-     * Invoked by all {@code createXXX(…)} method for creating the descriptor from the properties currently set
-     * in this builder.
-     */
-    private <T> ParameterDescriptor<T> create(final Class<T> valueClass, final Range<?> valueDomain,
-            final T[] validValues, final T defaultValue)
-    {
-        properties.put(ParameterDescriptor.ALIAS_KEY, aliases.toArray(new GenericName[aliases.size()]));
-        properties.put(ParameterDescriptor.IDENTIFIERS_KEY, identifiers.toArray(new ReferenceIdentifier[identifiers.size()]));
-        final ParameterDescriptor<T> descriptor = new DefaultParameterDescriptor<>(
-                properties, valueClass, valueDomain, validValues, defaultValue, required);
-        clearIdentification();
-        return descriptor;
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1574562&r1=1574561&r2=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -68,8 +68,8 @@ import java.util.Objects;
  *   <li><b>{@linkplain #head() Head}:</b> derived from the identifier {@linkplain #getCodeSpace() code space}.</li>
  *   <li><b>{@linkplain #scope() Scope}:</b> derived from the shortest {@linkplain #getAuthority() authority}'s
  *     {@linkplain Citation#getAlternateTitles() alternate titles}, or the {@linkplain Citation#getTitle() main title}
- *     if there is no alternate titles. Note that according ISO 19115, citation alternate titles often contain
- *     abbreviation (for example "DCW" as an alternative title for "<cite>Digital Chart of the World</cite>").</li>
+ *     if there is no alternate titles. This policy exploits the ISO 19115 comment saying that citation alternate titles
+ *     often contain abbreviation (for example "DCW" as an alternative title for "<cite>Digital Chart of the World</cite>").</li>
  * </ul>
  *
  * <div class="note"><b>Example:</b>

Copied: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java (from r1574221, sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DescriptorBuilderTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java?p2=sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java&p1=sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DescriptorBuilderTest.java&r1=1574221&r2=1574562&rev=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DescriptorBuilderTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -30,7 +30,7 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests {@link DescriptorBuilder}.
+ * Tests {@link ParameterBuilder}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
@@ -38,20 +38,20 @@ import static org.junit.Assert.*;
  * @module
  */
 @DependsOn({DefaultParameterDescriptorTest.class, DefaultParameterValueTest.class})
-public final strictfp class DescriptorBuilderTest extends TestCase {
+public final strictfp class ParameterBuilderTest extends TestCase {
     /**
      * Tests the "<cite>Mercator (variant A)</cite>" example given in Javadoc.
      */
     @Test
-    public void testMercatorExample() {
-        final DescriptorBuilder builder = new DescriptorBuilder();
+    public void testMercatorProjection() {
+        final ParameterBuilder builder = new ParameterBuilder();
         builder.codespace(HardCodedCitations.OGP, "EPSG").mandatory();
         final ParameterDescriptor[] parameters = {
             builder.name("Longitude of natural origin")
                    .name(HardCodedCitations.OGC, "central_meridian")
                    .name(HardCodedCitations.GEOTIFF, "NatOriginLong")
                    .remarks("Some remarks.")               .createBounded(-180, +180, 0, NonSI.DEGREE_ANGLE),
-            builder.name("Latitude of natural origin")     .createBounded( -80,  +80, 0, NonSI.DEGREE_ANGLE),
+            builder.name("Latitude of natural origin")     .createBounded( -80,  +84, 0, NonSI.DEGREE_ANGLE),
             builder.name("Scale factor at natural origin") .createStrictlyPositive(1, Unit.ONE),
             builder.name("False easting")                  .create(0, SI.METRE),
             builder.name("False northing")                 .create(0, SI.METRE)
@@ -60,8 +60,9 @@ public final strictfp class DescriptorBu
         assertEquals("EPSG",             parameters[1].getName().getCodeSpace());
         assertEquals("False easting",    parameters[3].getName().getCode());
         assertEquals("Some remarks.",    parameters[0].getRemarks().toString());
-        assertEquals(Double.valueOf(80), parameters[1].getMaximumValue());
+        assertEquals(Double.valueOf(84), parameters[1].getMaximumValue());
         assertEquals(SI.METRE,           parameters[4].getUnit());
+        assertTrue  (                    parameters[1].getAlias().isEmpty());
 
         final GenericName alias = parameters[0].getAlias().iterator().next();
         assertEquals("central_meridian",     alias.tip().toString());

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1574562&r1=1574561&r2=1574562&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Wed Mar  5 16:23:53 2014
@@ -53,7 +53,7 @@ import org.junit.BeforeClass;
     org.apache.sis.parameter.DefaultParameterDescriptorTest.class,
     org.apache.sis.parameter.DefaultParameterValueTest.class,
     org.apache.sis.parameter.ParametersTest.class,
-    org.apache.sis.parameter.DescriptorBuilderTest.class,
+    org.apache.sis.parameter.ParameterBuilderTest.class,
     org.apache.sis.referencing.datum.BursaWolfParametersTest.class,
     org.apache.sis.referencing.datum.TimeDependentBWPTest.class,
     org.apache.sis.referencing.datum.DefaultEllipsoidTest.class,



Mime
View raw message