sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1635941 [1/2] - in /sis/trunk: ./ core/sis-feature/src/test/java/org/apache/sis/feature/ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-meta...
Date Sat, 01 Nov 2014 12:25:48 GMT
Author: desruisseaux
Date: Sat Nov  1 12:25:46 2014
New Revision: 1635941

URL: http://svn.apache.org/r1635941
Log:
Merge from the JDK6 branch.

Added:
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java
      - copied, changed from r1635937, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java
      - copied, changed from r1635937, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
      - copied, changed from r1635937, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java
      - copied unchanged from r1635937, sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java
Removed:
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingUtilities.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultNominalResolution.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/AbstractElement.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeometricObjects.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGridSpatialRepresentation.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/package-info.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/APIVerifier.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBoxTest.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectReference.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/Country.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/SC_VerticalCRS.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Supervisor.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CheckedArrayList.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK8:r1635198-1635930
  Merged /sis/branches/JDK7:r1635200-1635932
  Merged /sis/branches/JDK6:r1635204-1635937

Copied: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java (from r1635937, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java?p2=sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java&p1=sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java&r1=1635937&r2=1635941&rev=1635941&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -20,7 +20,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Random;
-import org.opengis.feature.Feature;
 
 import static java.util.Collections.singletonMap;
 
@@ -125,7 +124,7 @@ public final class FeatureMemoryBenchmar
         final Float  latitude  = random.nextFloat() * 180 -  90;
         final Float  longitude = random.nextFloat() * 360 - 180;
         if (type != null) {
-            final Feature feature = type.newInstance();
+            final AbstractFeature feature = type.newInstance();
             feature.setPropertyValue("city",      city);
             feature.setPropertyValue("latitude",  latitude);
             feature.setPropertyValue("longitude", longitude);

Copied: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java (from r1635937, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java?p2=sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java&p1=sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java&r1=1635937&r2=1635941&rev=1635941&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.KeywordClass;
 import org.apache.sis.metadata.iso.identification.DefaultKeywordClass;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@ import org.apache.sis.internal.jaxb.gco.
  * @version 0.5
  * @module
  */
-public final class MD_KeywordClass extends PropertyType<MD_KeywordClass, KeywordClass> {
+public final class MD_KeywordClass extends PropertyType<MD_KeywordClass, DefaultKeywordClass> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -46,14 +45,14 @@ public final class MD_KeywordClass exten
      * @return {@code KeywordClass.class}
      */
     @Override
-    protected Class<KeywordClass> getBoundType() {
-        return KeywordClass.class;
+    protected Class<DefaultKeywordClass> getBoundType() {
+        return DefaultKeywordClass.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private MD_KeywordClass(final KeywordClass metadata) {
+    private MD_KeywordClass(final DefaultKeywordClass metadata) {
         super(metadata);
     }
 
@@ -65,7 +64,7 @@ public final class MD_KeywordClass exten
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected MD_KeywordClass wrap(final KeywordClass metadata) {
+    protected MD_KeywordClass wrap(final DefaultKeywordClass metadata) {
         return new MD_KeywordClass(metadata);
     }
 
@@ -78,7 +77,7 @@ public final class MD_KeywordClass exten
      */
     @XmlElementRef
     public DefaultKeywordClass getElement() {
-        return DefaultKeywordClass.castOrCopy(metadata);
+        return metadata;
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/LegacyPropertyAdapter.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import org.apache.sis.metadata.AbstractMetadata;
+import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.util.ArgumentChecks;
@@ -178,7 +179,7 @@ public abstract class LegacyPropertyAdap
     public static void warnIgnoredExtraneous(final Class<?> valueClass,
             final Class<?> callerClass, final String callerMethod)
     {
-        Context.warningOccured(Context.current(), callerClass, callerMethod,
+        Context.warningOccured(Context.current(), ISOMetadata.LOGGER, callerClass, callerMethod,
                 Messages.class, Messages.Keys.IgnoredPropertiesAfterFirst_1, valueClass);
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -17,16 +17,13 @@
 package org.apache.sis.internal.metadata;
 
 import java.util.Date;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
 import org.apache.sis.xml.NilReason;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.resources.Messages;
+import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.InvalidMetadataException;
 import org.apache.sis.internal.jaxb.PrimitiveTypeProperties;
-
-import static org.apache.sis.metadata.iso.ISOMetadata.LOGGER;
+import org.apache.sis.internal.jaxb.Context;
 
 
 /**
@@ -88,45 +85,87 @@ public final class MetadataUtilities ext
     }
 
     /**
-     * Ensures that the given argument value is {@code false}. This method is invoked by private setter methods,
-     * which are themselves invoked by JAXB at unmarshalling time. Invoking this method from those setter methods
-     * serves two purposes:
+     * Convenience method invoked when an argument was expected to be positive, but the user gave a negative value
+     * or (in some case) zero. This method logs a warning if we are in process of (un)marshalling a XML document,
+     * or throw an exception otherwise.
      *
+     * <p><b>When to use:</b></p>
      * <ul>
-     *   <li>Make sure that a singleton property is not defined twice in the XML document.</li>
-     *   <li>Protect ourselves against changes in immutable objects outside unmarshalling. It should
-     *       not be necessary since the setter methods shall not be public, but we are paranoiac.</li>
-     *   <li>Be a central point where we can trace all setter methods, in case we want to improve
-     *       warning or error messages in future SIS versions.</li>
+     *   <li>This method is for setter methods that may be invoked by JAXB. Constructors or methods ignored
+     *       by JAXB should use the simpler {@link org.apache.sis.util.ArgumentChecks} class instead.</li>
+     *   <li>This method should be invoked only when ignoring the warning will not cause information lost.
+     *       The stored metadata value may be invalid, but not lost.</li>
      * </ul>
+     * <div class="note"><b>Note:</b> the later point is the reason why problems during XML (un)marshalling
+     * are only warnings for this method, while they are errors by default for
+     * {@link org.apache.sis.xml.ValueConverter} (the later can not store the value in case of error).</div>
+     *
+     * @param  classe   The caller class.
+     * @param  property The property name. Method name will be inferred by the usual Java bean convention.
+     * @param  strict   {@code true} if the value was expected to be strictly positive, or {@code false} if 0 is accepted.
+     * @param  value    The invalid argument value.
+     * @throws IllegalArgumentException if we are not (un)marshalling a XML document.
+     */
+    public static void warnNonPositiveArgument(final Class<?> classe, final String property, final boolean strict,
+            final Number value) throws IllegalArgumentException
+    {
+        final String msg = logOrFormat(classe, property,
+                strict ? Errors.Keys.ValueNotGreaterThanZero_2 : Errors.Keys.NegativeArgument_2, property, value);
+        if (msg != null) {
+            throw new IllegalArgumentException(msg);
+        }
+    }
+
+    /**
+     * Convenience method invoked when an argument is outside the expected range of values. This method logs
+     * a warning if we are in process of (un)marshalling a XML document, or throw an exception otherwise.
      *
-     * @param  name The property name, used only in case of error message to format.
-     * @param  isDefined Whether the property in the caller object is current defined.
-     * @return {@code true} if the caller can set the property.
-     * @throws IllegalStateException If {@code isDefined} is {@code true}.
-     */
-    public static boolean canSetProperty(final String name, final boolean isDefined) throws IllegalStateException {
-        if (isDefined) {
-            // Future SIS version could log a warning instead if a unmarshalling is in progress.
-            throw new IllegalStateException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, name));
+     * <p><b>When to use:</b></p>
+     * <ul>
+     *   <li>This method is for setter methods that may be invoked by JAXB. Constructors or methods ignored
+     *       by JAXB should use the simpler {@link org.apache.sis.util.ArgumentChecks} class instead.</li>
+     *   <li>This method should be invoked only when ignoring the warning will not cause information lost.
+     *       The stored metadata value may be invalid, but not lost.</li>
+     * </ul>
+     * <div class="note"><b>Note:</b> the later point is the reason why problems during XML (un)marshalling
+     * are only warnings for this method, while they are errors by default for
+     * {@link org.apache.sis.xml.ValueConverter} (the later can not store the value in case of error).</div>
+     *
+     * @param  classe   The caller class.
+     * @param  property The property name. Method name will be inferred by the usual Java bean convention.
+     * @param  minimum  The minimal legal value.
+     * @param  maximum  The maximal legal value.
+     * @param  value    The invalid argument value.
+     * @throws IllegalArgumentException if we are not (un)marshalling a XML document.
+     */
+    public static void warnOutOfRangeArgument(final Class<?> classe, final String property,
+            final Number minimum, final Number maximum, final Number value) throws IllegalArgumentException
+    {
+        final String msg = logOrFormat(classe, property, Errors.Keys.ValueOutOfRange_4, property, minimum, maximum, value);
+        if (msg != null) {
+            throw new IllegalArgumentException(msg);
         }
-        return true;
     }
 
     /**
-     * Convenience method for logging a warning to the {@code ISOMetadata} logger.
-     * The message will be produced using the {@link Messages} resources bundle.
+     * Formats an error message and logs it is we are (un)marshalling a document, or return the message otherwise.
+     * In the later case, it is caller's responsibility to use the message for throwing an exception.
      *
-     * @param  caller    The public class which is invoking this method.
-     * @param  method    The public method which is invoking this method.
-     * @param  key       The key from the message resource bundle to use for creating a message.
-     * @param  arguments The arguments to be used together with the key for building the message.
-     */
-    public static void warning(final Class<?> caller, final String method, final short key, final Object... arguments) {
-        final LogRecord record = Messages.getResources(null).getLogRecord(Level.WARNING, key, arguments);
-        record.setSourceClassName(caller.getCanonicalName());
-        record.setSourceMethodName(method);
-        record.setLoggerName(LOGGER.getName());
-        LOGGER.log(record);
+     * @param  classe    The caller class, used only in case of warning message to log.
+     * @param  property  The property name. Method name will be inferred by the usual Java bean convention.
+     * @param  key       A {@code Errors.Keys} value.
+     * @param  arguments The argument to use for formatting the error message.
+     * @return {@code null} if the message has been logged, or the message to put in an exception otherwise.
+     */
+    private static String logOrFormat(final Class<?> classe, final String property, final short key, final Object... arguments) {
+        final Context context = Context.current();
+        if (context == null) {
+            return Errors.format(key, arguments);
+        } else {
+            final StringBuilder buffer = new StringBuilder(property.length() + 3).append("set").append(property);
+            buffer.setCharAt(3, Character.toUpperCase(buffer.charAt(3)));
+            Context.warningOccured(context, ISOMetadata.LOGGER, classe, buffer.toString(), Errors.class, key, arguments);
+            return null;
+        }
     }
 }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingUtilities.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingUtilities.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.metadata;
 
 import java.util.Collection;
+import java.util.logging.Logger;
 import javax.measure.unit.Unit;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
@@ -27,6 +28,9 @@ import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.operation.*;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.jaxb.Context;
 
 
 /**
@@ -38,11 +42,16 @@ import org.apache.sis.util.Static;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-2.0)
- * @version 0.4
+ * @version 0.5
  * @module
  */
 public final class ReferencingUtilities extends Static {
     /**
+     * The logger to use for messages related to the {@code sis-referencing} module.
+     */
+    public static final Logger LOGGER = Logging.getLogger("org.apache.sis.referencing");
+
+    /**
      * Subtypes of {@link IdentifiedObject} for which a URN type is defined.
      * For each interface at index <var>i</var>, the URN type is {@code URN_TYPES[i]}.
      *
@@ -216,4 +225,39 @@ public final class ReferencingUtilities 
         }
         return sameContent;
     }
+
+    /**
+     * Ensures that the given argument value is {@code false}. This method is invoked by private setter methods,
+     * which are themselves invoked by JAXB at unmarshalling time. Invoking this method from those setter methods
+     * serves two purposes:
+     *
+     * <ul>
+     *   <li>Make sure that a singleton property is not defined twice in the XML document.</li>
+     *   <li>Protect ourselves against changes in immutable objects outside unmarshalling. It should
+     *       not be necessary since the setter methods shall not be public, but we are paranoiac.</li>
+     *   <li>Be a central point where we can trace all setter methods, in case we want to improve
+     *       warning or error messages in future SIS versions.</li>
+     * </ul>
+     *
+     * @param  classe    The caller class, used only in case of warning message to log.
+     * @param  method    The caller method, used only in case of warning message to log.
+     * @param  name      The property name, used only in case of error message to format.
+     * @param  isDefined Whether the property in the caller object is current defined.
+     * @return {@code true} if the caller can set the property.
+     * @throws IllegalStateException If {@code isDefined} is {@code true} and we are not unmarshalling an object.
+     */
+    public static boolean canSetProperty(final Class<?> classe, final String method,
+            final String name, final boolean isDefined) throws IllegalStateException
+    {
+        if (!isDefined) {
+            return true;
+        }
+        final Context context = Context.current();
+        if (context != null) {
+            Context.warningOccured(context, LOGGER, classe, method, Errors.class, Errors.Keys.ElementAlreadyPresent_1, name);
+            return false;
+        } else {
+            throw new IllegalStateException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, name));
+        }
+    }
 }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -19,6 +19,7 @@ package org.apache.sis.metadata;
 import java.util.Map;
 import java.util.logging.Logger;
 import javax.xml.bind.annotation.XmlTransient;
+import org.apache.sis.internal.system.Semaphores;
 import org.apache.sis.util.Emptiable;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.LenientComparable;
@@ -72,7 +73,7 @@ import org.apache.sis.util.logging.Loggi
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.4)
- * @version 0.3
+ * @version 0.5
  * @module
  *
  * @see MetadataStandard
@@ -144,7 +145,21 @@ public abstract class AbstractMetadata i
      */
     @Override
     public boolean isEmpty() {
-        return Pruner.isEmpty(this, true, false);
+        /*
+         * The NULL_COLLECTION semaphore prevents creation of new empty collections by getter methods
+         * (a consequence of lazy instantiation). The intend is to avoid creation of unnecessary objects
+         * for all unused properties. Users should not see behavioral difference, except if they override
+         * some getters with an implementation invoking other getters. However in such cases, users would
+         * have been exposed to null values at XML marshalling time anyway.
+         */
+        final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+        try {
+            return Pruner.isEmpty(this, true, false);
+        } finally {
+            if (!allowNull) {
+                Semaphores.clear(Semaphores.NULL_COLLECTION);
+            }
+        }
     }
 
     /**
@@ -155,7 +170,15 @@ public abstract class AbstractMetadata i
      * @throws UnmodifiableMetadataException If this metadata is not modifiable.
      */
     public void prune() {
-        Pruner.isEmpty(this, true, true);
+        // See comment in 'isEmpty()' about NULL_COLLECTION semaphore purpose.
+        final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+        try {
+            Pruner.isEmpty(this, true, true);
+        } finally {
+            if (!allowNull) {
+                Semaphores.clear(Semaphores.NULL_COLLECTION);
+            }
+        }
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -38,6 +38,7 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.collection.TreeTable;
 import org.apache.sis.util.collection.CheckedContainer;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.Semaphores;
 import org.apache.sis.internal.system.SystemListener;
 import org.apache.sis.internal.simple.SimpleCitation;
 
@@ -904,10 +905,23 @@ public class MetadataStandard implements
          */
         final ObjectPair pair = new ObjectPair(metadata1, metadata2);
         final Set<ObjectPair> inProgress = ObjectPair.CURRENT.get();
-        if (inProgress.add(pair)) try {
-            return accessor.equals(metadata1, metadata2, mode);
-        } finally {
-            inProgress.remove(pair);
+        if (inProgress.add(pair)) {
+            /*
+             * The NULL_COLLECTION semaphore prevents creation of new empty collections by getter methods
+             * (a consequence of lazy instantiation). The intend is to avoid creation of unnecessary objects
+             * for all unused properties. Users should not see behavioral difference, except if they override
+             * some getters with an implementation invoking other getters. However in such cases, users would
+             * have been exposed to null values at XML marshalling time anyway.
+             */
+            final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+            try {
+                return accessor.equals(metadata1, metadata2, mode);
+            } finally {
+                inProgress.remove(pair);
+                if (!allowNull) {
+                    Semaphores.clear(Semaphores.NULL_COLLECTION);
+                }
+            }
         } else {
             /*
              * If we get here, a cycle has been found. Returns 'true' in order to allow the caller to continue
@@ -934,16 +948,23 @@ public class MetadataStandard implements
     public int hashCode(final Object metadata) throws ClassCastException {
         if (metadata != null) {
             final Map<Object,Object> inProgress = RecursivityGuard.HASH_CODES.get();
-            if (inProgress.put(metadata, Boolean.TRUE) == null) try {
-                return getAccessor(metadata.getClass(), true).hashCode(metadata);
-            } finally {
-                inProgress.remove(metadata);
+            if (inProgress.put(metadata, Boolean.TRUE) == null) {
+                // See comment in 'equals(…) about NULL_COLLECTION semaphore purpose.
+                final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+                try {
+                    return getAccessor(metadata.getClass(), true).hashCode(metadata);
+                } finally {
+                    inProgress.remove(metadata);
+                    if (!allowNull) {
+                        Semaphores.clear(Semaphores.NULL_COLLECTION);
+                    }
+                }
             }
             /*
              * If we get there, a cycle has been found. We can not compute a hash code value for that metadata.
              * However it should not be a problem since this metadata is part of a bigger metadata object, and
              * that enclosing object has other properties for computing its hash code. We just need the result
-             * to be consistent, we should be the case if properties ordering is always the same.
+             * to be consistent, wich should be the case if properties ordering is always the same.
              */
         }
         return 0;

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -33,9 +33,9 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.collection.CodeListSet;
 import org.apache.sis.internal.util.CheckedHashSet;
 import org.apache.sis.internal.util.CheckedArrayList;
+import org.apache.sis.internal.system.Semaphores;
 
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
-import static org.apache.sis.internal.jaxb.Context.isMarshalling;
 
 
 /**
@@ -83,7 +83,7 @@ import static org.apache.sis.internal.ja
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlTransient
@@ -221,12 +221,23 @@ public abstract class ModifiableMetadata
     public void freeze() {
         if (isModifiable()) {
             ModifiableMetadata success = null;
+            /*
+             * The NULL_COLLECTION semaphore prevents creation of new empty collections by getter methods
+             * (a consequence of lazy instantiation). The intend is to avoid creation of unnecessary objects
+             * for all unused properties. Users should not see behavioral difference, except if they override
+             * some getters with an implementation invoking other getters. However in such cases, users would
+             * have been exposed to null values at XML marshalling time anyway.
+             */
+            final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
             try {
                 unmodifiable = FREEZING;
                 getStandard().freeze(this);
                 success = this;
             } finally {
                 unmodifiable = success;
+                if (!allowNull) {
+                    Semaphores.clear(Semaphores.NULL_COLLECTION);
+                }
             }
         }
     }
@@ -510,6 +521,17 @@ public abstract class ModifiableMetadata
     }
 
     /**
+     * Returns {@code true} if empty collection should be returned as {@code null} value.
+     * This is usually not a behavior that we allow in public API. However this behavior
+     * is sometime desired internally, for example when marshalling with JAXB or when
+     * performing a {@code equals}, {@code isEmpty} or {@code prune} operation
+     * (for avoiding creating unnecessary collections).
+     */
+    private static boolean emptyCollectionAsNull() {
+        return Semaphores.query(Semaphores.NULL_COLLECTION);
+    }
+
+    /**
      * Returns the specified list, or a new one if {@code c} is null.
      * This is a convenience method for implementation of {@code getFoo()} methods.
      *
@@ -520,9 +542,9 @@ public abstract class ModifiableMetadata
      */
     protected final <E> List<E> nonNullList(final List<E> c, final Class<E> elementType) {
         if (c != null) {
-            return c.isEmpty() && isMarshalling() ? null : c;
+            return c.isEmpty() && emptyCollectionAsNull() ? null : c;
         }
-        if (isMarshalling()) {
+        if (emptyCollectionAsNull()) {
             return null;
         }
         if (isModifiable()) {
@@ -549,9 +571,9 @@ public abstract class ModifiableMetadata
      */
     protected final <E> Set<E> nonNullSet(final Set<E> c, final Class<E> elementType) {
         if (c != null) {
-            return c.isEmpty() && isMarshalling() ? null : c;
+            return c.isEmpty() && emptyCollectionAsNull() ? null : c;
         }
-        if (isMarshalling()) {
+        if (emptyCollectionAsNull()) {
             return null;
         }
         if (isModifiable()) {
@@ -580,9 +602,9 @@ public abstract class ModifiableMetadata
     protected final <E> Collection<E> nonNullCollection(final Collection<E> c, final Class<E> elementType) {
         if (c != null) {
             assert collectionType(elementType).isInstance(c);
-            return c.isEmpty() && isMarshalling() ? null : c;
+            return c.isEmpty() && emptyCollectionAsNull() ? null : c;
         }
-        if (isMarshalling()) {
+        if (emptyCollectionAsNull()) {
             return null;
         }
         final boolean isModifiable = isModifiable();

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -29,6 +29,7 @@ import org.apache.sis.util.collection.Ta
 import org.apache.sis.util.collection.TreeTableFormat;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.internal.system.LocalizedStaticObject;
+import org.apache.sis.internal.system.Semaphores;
 
 
 /**
@@ -45,7 +46,7 @@ import org.apache.sis.internal.system.Lo
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.5
  * @module
  */
 final class TreeTableView implements TreeTable, Serializable {
@@ -137,7 +138,21 @@ final class TreeTableView implements Tre
                 f.setColumns(TableColumn.NAME, TableColumn.VALUE);
                 format = f;
             }
-            return format.format(this);
+            /*
+             * The NULL_COLLECTION semaphore prevents creation of new empty collections by getter methods
+             * (a consequence of lazy instantiation). The intend is to avoid creation of unnecessary objects
+             * for all unused properties. Users should not see behavioral difference, except if they override
+             * some getters with an implementation invoking other getters. However in such cases, users would
+             * have been exposed to null values at XML marshalling time anyway.
+             */
+            final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+            try {
+                return format.format(this);
+            } finally {
+                if (!allowNull) {
+                    Semaphores.clear(Semaphores.NULL_COLLECTION);
+                }
+            }
         }
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -27,10 +27,12 @@ import org.opengis.metadata.citation.Res
 import org.opengis.metadata.ExtendedElementInformation;
 import org.opengis.util.InternationalString;
 import org.apache.sis.measure.ValueRange;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
+// Branch-specific imports
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
 
@@ -198,6 +200,13 @@ public class DefaultExtendedElementInfor
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(ExtendedElementInformation)
@@ -429,13 +438,13 @@ public class DefaultExtendedElementInfor
     /**
      * Sets the maximum occurrence of the extended element.
      *
-     * @param newValue The new maximum occurrence.
+     * @param newValue The new maximum occurrence, or {@code null}.
      * @throws IllegalArgumentException if the given value is negative.
      */
-    public void setMaximumOccurrence(final Integer newValue) throws IllegalArgumentException {
+    public void setMaximumOccurrence(final Integer newValue) {
         checkWritePermission();
-        if (newValue != null) {
-            ArgumentChecks.ensurePositive("maximumOccurrence", newValue);
+        if (newValue != null && newValue < 0) {
+            warnNonPositiveArgument(DefaultExtendedElementInformation.class, "maximumOccurrence", false, newValue);
         }
         maximumOccurrence = newValue;
     }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -23,7 +23,8 @@ import org.opengis.metadata.acquisition.
 import org.opengis.util.InternationalString;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.metadata.iso.ISOMetadata;
-import org.apache.sis.util.ArgumentChecks;
+
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnOutOfRangeArgument;
 
 
 /**
@@ -41,7 +42,7 @@ import org.apache.sis.util.ArgumentCheck
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.03)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlType(name = "MI_EnvironmentalRecord_Type", propOrder = {
@@ -88,6 +89,13 @@ public class DefaultEnvironmentalRecord 
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(EnvironmentalRecord)
@@ -163,12 +171,13 @@ public class DefaultEnvironmentalRecord 
     /**
      * Sets the maximum relative humidity along the flight pass during the photo flight.
      *
-     * @param newValue The new maximum relative humidity.
+     * @param newValue The new maximum relative humidity, or {@code null}.
+     * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setMaxRelativeHumidity(final Double newValue) {
         checkWritePermission();
-        if (newValue != null) {
-            ArgumentChecks.ensureBetween("maxRelativeHumidity", 0, 100, newValue);
+        if (newValue != null && !(newValue >= 0 && newValue <= 100)) { // Use '!' for catching NaN.
+            warnOutOfRangeArgument(DefaultEnvironmentalRecord.class, "maxRelativeHumidity", 0, 100, newValue);
         }
         maxRelativeHumidity = newValue;
     }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -247,7 +247,7 @@ public class DefaultContact extends ISOM
                 }
             }
             if (ignored != null) {
-                Context.warningOccured(Context.current(), DefaultContact.class, "getPhone",
+                Context.warningOccured(Context.current(), LOGGER, DefaultContact.class, "getPhone",
                         Messages.class, Messages.Keys.IgnoredPropertyAssociatedTo_1, ignored);
             }
         }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -87,7 +87,7 @@
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns = {

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/package-info.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/package-info.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -64,7 +64,7 @@
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns = {

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -30,6 +30,9 @@ import org.opengis.metadata.content.Tran
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.measure.ValueRange;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
+// Branch-specific imports
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
 
@@ -136,6 +139,13 @@ public class DefaultBand extends Default
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(Band)
@@ -185,6 +195,22 @@ public class DefaultBand extends Default
     }
 
     /**
+     * Ensures that the given property value is positive.
+     *
+     * @param property Name of the property to check.
+     * @param strict   {@code false} is zero is a legal value.
+     * @param newValue The property value to verify.
+     * @throws IllegalArgumentException if the given value is negative and the problem has not been logged.
+     */
+    private static void ensurePositive(final String property, final boolean strict, final Double newValue)
+            throws IllegalArgumentException
+    {
+        if (newValue != null && !(strict ? newValue > 0 : newValue >= 0)) { // Use '!' for catching NaN.
+            warnNonPositiveArgument(DefaultBand.class, property, strict, newValue);
+        }
+    }
+
+    /**
      * Returns the shortest wavelength that the sensor is capable of collecting within a designated band.
      * The units of measurement is given by {@link #getBoundUnit()}.
      *
@@ -203,12 +229,14 @@ public class DefaultBand extends Default
     /**
      * Sets the shortest wavelength that the sensor is capable of collecting within a designated band.
      *
-     * @param newValue The new shortest wavelength.
+     * @param newValue The new shortest wavelength, or {@code null}.
+     * @throws IllegalArgumentException if the given value is negative.
      *
      * @since 0.5
      */
     public void setBoundMin(final Double newValue) {
         checkWritePermission();
+        ensurePositive("boundMin", false, newValue);
         boundMin = newValue;
     }
 
@@ -231,12 +259,14 @@ public class DefaultBand extends Default
     /**
      * Sets the longest wavelength that the sensor is capable of collecting within a designated band.
      *
-     * @param newValue The new longest wavelength.
+     * @param newValue The new longest wavelength, or {@code null}.
+     * @throws IllegalArgumentException if the given value is negative.
      *
      * @since 0.5
      */
     public void setBoundMax(final Double newValue) {
         checkWritePermission();
+        ensurePositive("boundMax", false, newValue);
         boundMax = newValue;
     }
 
@@ -333,10 +363,12 @@ public class DefaultBand extends Default
     /**
      * Sets the wavelength at which the response is the highest.
      *
-     * @param newValue The new peak response.
+     * @param newValue The new peak response, or {@code null}.
+     * @throws IllegalArgumentException if the given value is negative.
      */
     public void setPeakResponse(final Double newValue) {
         checkWritePermission();
+        ensurePositive("peakResponse", false, newValue);
         peakResponse = newValue;
     }
 
@@ -377,6 +409,9 @@ public class DefaultBand extends Default
      */
     public void setToneGradation(final Integer newValue) {
         checkWritePermission();
+        if (newValue != null && newValue < 0) {
+            warnNonPositiveArgument(DefaultBand.class, "toneGradation", false, newValue);
+        }
         toneGradation = newValue;
     }
 
@@ -432,9 +467,11 @@ public class DefaultBand extends Default
      * as specified in instrument design.
      *
      * @param newValue The new nominal spatial resolution.
+     * @throws IllegalArgumentException if the given value is negative.
      */
     public void setNominalSpatialResolution(final Double newValue) {
         checkWritePermission();
+        ensurePositive("nominalSpatialResolution", true, newValue);
         nominalSpatialResolution = newValue;
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -22,7 +22,8 @@ import javax.xml.bind.annotation.XmlType
 import org.opengis.util.GenericName;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.metadata.iso.ISOMetadata;
-import org.apache.sis.util.ArgumentChecks;
+
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
 
 // Branch-specific imports
 import org.opengis.annotation.UML;
@@ -99,6 +100,13 @@ public class DefaultFeatureTypeInfo exte
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      */
     public DefaultFeatureTypeInfo(final DefaultFeatureTypeInfo object) {
@@ -150,10 +158,10 @@ public class DefaultFeatureTypeInfo exte
      * @param newValue the new number of occurrence.
      * @throws IllegalArgumentException if the given value is negative.
      */
-    public void setFeatureInstanceCount(final Integer newValue) throws IllegalArgumentException {
+    public void setFeatureInstanceCount(final Integer newValue) {
         checkWritePermission();
-        if (newValue != null) {
-            ArgumentChecks.ensurePositive("featureInstanceCount", newValue);
+        if (newValue != null && newValue < 0) {
+            warnNonPositiveArgument(DefaultFeatureTypeInfo.class, "featureInstanceCount", true, newValue);
         }
         featureInstanceCount = newValue;
     }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -25,6 +25,9 @@ import org.opengis.metadata.content.Imag
 import org.opengis.metadata.content.ImagingCondition;
 import org.apache.sis.measure.ValueRange;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnOutOfRangeArgument;
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
 
 /**
  * Information about an image's suitability for use.
@@ -42,7 +45,7 @@ import org.apache.sis.measure.ValueRange
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.4
+ * @version 0.5
  * @module
  */
 @XmlType(name = "MD_ImageDescription_Type", propOrder = {
@@ -141,6 +144,13 @@ public class DefaultImageDescription ext
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether
+     * a value is out of range). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(ImageDescription)
@@ -188,6 +198,26 @@ public class DefaultImageDescription ext
     }
 
     /**
+     * Ensures that the given argument is either null or between the given minimum and maximum values.
+     *
+     * @param property Name of the property to check.
+     * @param min      The minimal legal value.
+     * @param max      The maximal legal value.
+     * @param newValue The value given by the user.
+     * @throws IllegalArgumentException if the given value is out of range and the problem has not been logged.
+     */
+    private static void ensureInRange(final String property, final double min, final double max, final Double newValue)
+            throws IllegalArgumentException
+    {
+        if (newValue != null) {
+            final double v = newValue;
+            if (!(v >= min && v <= max)) { // Use '!' for catching NaN.
+                warnOutOfRangeArgument(DefaultImageDescription.class, property, min, max, v);
+            }
+        }
+    }
+
+    /**
      * Returns the illumination elevation measured in degrees clockwise from the target plane at
      * intersection of the optical line of sight with the Earth's surface.
      * For images from a scanning device, refer to the centre pixel of the image.
@@ -208,10 +238,12 @@ public class DefaultImageDescription ext
      * intersection of the optical line of sight with the Earth's surface. For images from a
      * scanning device, refer to the centre pixel of the image.
      *
-     * @param newValue The new illumination elevation angle.
+     * @param newValue The new illumination elevation angle, or {@code null}.
+     * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setIlluminationElevationAngle(final Double newValue) {
         checkWritePermission();
+        ensureInRange("illuminationElevationAngle", -90, +90, newValue);
         illuminationElevationAngle = newValue;
     }
 
@@ -232,10 +264,12 @@ public class DefaultImageDescription ext
      * Sets the illumination azimuth measured in degrees clockwise from true north at the time the
      * image is taken. For images from a scanning device, refer to the centre pixel of the image.
      *
-     * @param newValue The new illumination azimuth angle.
+     * @param newValue The new illumination azimuth angle, or {@code null}.
+     * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setIlluminationAzimuthAngle(final Double newValue) {
         checkWritePermission();
+        ensureInRange("illuminationAzimuthAngle", 0, 360, newValue);
         illuminationAzimuthAngle = newValue;
     }
 
@@ -296,10 +330,12 @@ public class DefaultImageDescription ext
     /**
      * Sets the area of the dataset obscured by clouds, expressed as a percentage of the spatial extent.
      *
-     * @param newValue The new cloud cover percentage.
+     * @param newValue The new cloud cover percentage, or {@code null}.
+     * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setCloudCoverPercentage(final Double newValue) {
         checkWritePermission();
+        ensureInRange("cloudCoverPercentage", 0, 100, newValue);
         cloudCoverPercentage = newValue;
     }
 
@@ -344,9 +380,13 @@ public class DefaultImageDescription ext
      * Sets the count of the number the number of lossy compression cycles performed on the image.
      *
      * @param newValue The new compression generation quantity.
+     * @throws IllegalArgumentException if the given value is negative.
      */
     public void setCompressionGenerationQuantity(final Integer newValue) {
         checkWritePermission();
+        if (newValue != null && newValue < 0) {
+            warnNonPositiveArgument(DefaultImageDescription.class, "compressionGenerationQuantity", false, newValue);
+        }
         compressionGenerationQuantity = newValue;
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -26,6 +26,8 @@ import org.opengis.util.RecordType;
 import org.opengis.metadata.content.Band;
 import org.apache.sis.measure.ValueRange;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
 // Branch-specific imports
 import org.opengis.annotation.UML;
 import static org.opengis.annotation.Obligation.OPTIONAL;
@@ -149,6 +151,13 @@ public class DefaultSampleDimension exte
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(SampleDimension)
@@ -197,6 +206,22 @@ public class DefaultSampleDimension exte
     }
 
     /**
+     * Ensures that the given property value is positive.
+     *
+     * @param property Name of the property to check.
+     * @param strict   {@code false} is zero is a legal value.
+     * @param newValue The property value to verify.
+     * @throws IllegalArgumentException if the given value is negative and the problem has not been logged.
+     */
+    private static void ensurePositive(final String property, final boolean strict, final Integer newValue)
+            throws IllegalArgumentException
+    {
+        if (newValue != null && !(strict ? newValue > 0 : newValue >= 0)) {
+            warnNonPositiveArgument(DefaultSampleDimension.class, property, strict, newValue);
+        }
+    }
+
+    /**
      * Returns the minimum value of data values in each dimension included in the resource.
      *
      * @return Minimum value of data values in each dimension included in the resource, or {@code null} if unspecified.
@@ -264,6 +289,7 @@ public class DefaultSampleDimension exte
      *
      * @return The number of values used in a thematic classification resource, or {@code null} if none.
      */
+    @ValueRange(minimum = 0)
 /// @XmlElement(name = "numberOfValues")
     @UML(identifier="numberOfValues", obligation=OPTIONAL, specification=ISO_19115)
     public Integer getNumberOfValues() {
@@ -273,11 +299,13 @@ public class DefaultSampleDimension exte
     /**
      * Sets the number of values used in a thematic classification resource.
      *
-     * @param newValues The new number of values used in a thematic classification resource.
+     * @param newValue The new number of values used in a thematic classification resource.
+     * @throws IllegalArgumentException if the given value is negative.
      */
-    public void setNumberOfValues(final Integer newValues) {
+    public void setNumberOfValues(final Integer newValue) {
         checkWritePermission();
-        numberOfValues = newValues;
+        ensurePositive("numberOfValues", false, newValue);
+        numberOfValues = newValue;
     }
 
     /**
@@ -383,9 +411,11 @@ public class DefaultSampleDimension exte
      * for the value in each band of each pixel.
      *
      * @param newValue The new maximum number of significant bits.
+     * @throws IllegalArgumentException if the given value is zero or negative.
      */
     public void setBitsPerValue(final Integer newValue) {
         checkWritePermission();
+        ensurePositive("bitsPerValue", true, newValue);
         bitsPerValue = newValue;
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -90,7 +90,7 @@
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns = {

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -30,8 +30,10 @@ import org.opengis.metadata.distribution
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.metadata.iso.ISOMetadata;
-import org.apache.sis.util.ArgumentChecks;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
+// Branch-specific imports
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
 
@@ -110,6 +112,13 @@ public class DefaultDigitalTransferOptio
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(DigitalTransferOptions)
@@ -194,13 +203,13 @@ public class DefaultDigitalTransferOptio
      * Sets an estimated size of a unit in the specified transfer format, expressed in megabytes.
      * The transfer shall be greater than zero.
      *
-     * @param newValue The new transfer size.
-     * @throws IllegalArgumentException if the given value is negative.
+     * @param newValue The new transfer size, or {@code null}.
+     * @throws IllegalArgumentException if the given value is NaN or negative.
      */
-    public void setTransferSize(final Double newValue) throws IllegalArgumentException {
+    public void setTransferSize(final Double newValue) {
         checkWritePermission();
-        if (newValue != null) {
-            ArgumentChecks.ensurePositive("transferSize", newValue);
+        if (newValue != null && !(newValue >= 0)) { // Use '!' for catching NaN.
+            warnNonPositiveArgument(DefaultDigitalTransferOptions.class, "transferSize", true, newValue);
         }
         transferSize = newValue;
     }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -32,6 +32,9 @@ import org.apache.sis.metadata.iso.ISOMe
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
+
+// Branch-specific imports
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
 
@@ -112,6 +115,13 @@ public class DefaultMedium extends ISOMe
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
      * @param object The metadata to copy values from, or {@code null} if none.
      *
      * @see #castOrCopy(Medium)
@@ -196,10 +206,15 @@ public class DefaultMedium extends ISOMe
      * The number shall be greater than zero.
      *
      * @param newValue The new density.
+     * @throws IllegalArgumentException if the given value is NaN, zero or negative.
      *
      * @since 0.5
      */
     public void setDensity(final Double newValue) {
+        checkWritePermission();
+        if (newValue != null && !(newValue > 0)) { // Use '!' for catching NaN.
+            warnNonPositiveArgument(DefaultMedium.class, "density", true, newValue);
+        }
         densities = writeCollection(LegacyPropertyAdapter.asCollection(newValue), densities, Double.class);
     }
 
@@ -261,10 +276,14 @@ public class DefaultMedium extends ISOMe
     /**
      * Sets the number of items in the media identified.
      *
-     * @param newValue The new volumes.
+     * @param newValue The new volumes, or {@code null}.
+     * @throws IllegalArgumentException if the given value is negative.
      */
     public void setVolumes(final Integer newValue) {
         checkWritePermission();
+        if (newValue != null && newValue < 0) {
+            warnNonPositiveArgument(DefaultMedium.class, "volumes", false, newValue);
+        }
         volumes = newValue;
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -70,7 +70,7 @@
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns = {

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/package-info.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/package-info.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -136,7 +136,7 @@
  * @author  Cédric Briançon (Geomatys)
  * @author  Guilhem Legal (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns = {

Copied: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java (from r1635937, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java?p2=sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java&p1=sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java&r1=1635937&r2=1635941&rev=1635941&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -22,7 +22,6 @@ import javax.xml.bind.annotation.XmlElem
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.KeywordClass;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
@@ -31,6 +30,14 @@ import org.apache.sis.util.iso.Types;
  * Specification of a class to categorize keywords in a domain-specific vocabulary
  * that has a binding to a formal ontology.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code KeywordClass} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -51,7 +58,7 @@ import org.apache.sis.util.iso.Types;
     "ontology"
 })
 @XmlRootElement(name = "MD_KeywordClass")
-public class DefaultKeywordClass extends ISOMetadata implements KeywordClass {
+public class DefaultKeywordClass extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -99,7 +106,7 @@ public class DefaultKeywordClass extends
      *
      * @see #castOrCopy(KeywordClass)
      */
-    public DefaultKeywordClass(final KeywordClass object) {
+    public DefaultKeywordClass(final DefaultKeywordClass object) {
         super(object);
         if (object != null) {
             className         = object.getClassName();
@@ -109,36 +116,10 @@ public class DefaultKeywordClass extends
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultKeywordClass}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultKeywordClass} instance is created using the
-     *       {@linkplain #DefaultKeywordClass(KeywordClass) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @return A SIS implementation containing the values of the given object (may be the
-     *         given object itself), or {@code null} if the argument was null.
-     */
-    public static DefaultKeywordClass castOrCopy(final KeywordClass object) {
-        if (object == null || object instanceof DefaultKeywordClass) {
-            return (DefaultKeywordClass) object;
-        }
-        return new DefaultKeywordClass(object);
-    }
-
-    /**
      * Returns a label for the keyword category in natural language.
      *
      * @return The keyword category in natural language.
      */
-    @Override
     @XmlElement(name = "className", required = true)
     public InternationalString getClassName() {
         return className;
@@ -159,7 +140,6 @@ public class DefaultKeywordClass extends
      *
      * @return URI of concept in the ontology, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "conceptIdentifier")
     public URI getConceptIdentifier() {
         return conceptIdentifier;
@@ -180,7 +160,6 @@ public class DefaultKeywordClass extends
      *
      * @return A reference that binds the keyword class to a formal conceptualization.
      */
-    @Override
     @XmlElement(name = "ontology", required = true)
     public Citation getOntology() {
         return ontology;

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java?rev=1635941&r1=1635940&r2=1635941&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java [UTF-8] Sat Nov  1 12:25:46 2014
@@ -29,6 +29,7 @@ import org.opengis.metadata.identificati
 import org.apache.sis.internal.jaxb.IdentifierMapWithSpecialCases;
 import org.apache.sis.internal.jaxb.gco.GO_Integer64;
 import org.apache.sis.internal.util.CheckedArrayList;
+import org.apache.sis.measure.ValueRange;
 import org.apache.sis.xml.IdentifierMap;
 import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.xml.IdentifiedObject;
@@ -37,6 +38,7 @@ import org.apache.sis.util.ArgumentCheck
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
+import static org.apache.sis.internal.metadata.MetadataUtilities.warnNonPositiveArgument;
 
 
 /**
@@ -60,7 +62,7 @@ import static org.apache.sis.util.collec
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.4)
- * @version 0.4
+ * @version 0.5
  * @module
  *
  * @see DefaultResolution#getEquivalentScale()
@@ -96,9 +98,9 @@ public class DefaultRepresentativeFracti
      * Creates a new representative fraction from the specified denominator.
      *
      * @param  denominator The denominator as a positive number, or 0 if unspecified.
-     * @throws IllegalArgumentException If the given value is not a positive number or zero.
+     * @throws IllegalArgumentException If the given value is negative.
      */
-    public DefaultRepresentativeFraction(final long denominator) throws IllegalArgumentException {
+    public DefaultRepresentativeFraction(final long denominator) {
         ArgumentChecks.ensurePositive("denominator", denominator);
         this.denominator = denominator;
     }
@@ -106,13 +108,18 @@ public class DefaultRepresentativeFracti
     /**
      * Constructs a new representative fraction initialized to the value of the given object.
      *
-     * @param  object The metadata to copy values from, or {@code null} if none.
-     * @throws IllegalArgumentException If the denominator of the given source is negative.
+     * <div class="note"><b>Note on properties validation:</b>
+     * This constructor does not verify the property values of the given metadata (e.g. whether it contains
+     * unexpected negative values). This is because invalid metadata exist in practice, and verifying their
+     * validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
+     * metadata instances can also be obtained by unmarshalling an invalid XML document.
+     * </div>
+     *
+     * @param object The metadata to copy values from, or {@code null} if none.
      */
-    public DefaultRepresentativeFraction(final RepresentativeFraction object) throws IllegalArgumentException {
+    public DefaultRepresentativeFraction(final RepresentativeFraction object) {
         if (object != null) {
             denominator = object.getDenominator();
-            ArgumentChecks.ensurePositive("object", denominator);
         }
     }
 
@@ -139,6 +146,7 @@ public class DefaultRepresentativeFracti
      * @return The denominator.
      */
     @Override
+    @ValueRange(minimum = 0)
     @XmlJavaTypeAdapter(value = GO_Integer64.class, type = long.class)
     @XmlElement(name = "denominator", required = true)
     public long getDenominator() {
@@ -149,26 +157,35 @@ public class DefaultRepresentativeFracti
      * Sets the denominator value.
      *
      * @param  denominator The new denominator value, or 0 if none.
-     * @throws IllegalArgumentException If the given value is not a positive number or zero.
+     * @throws IllegalArgumentException if the given value is negative.
      */
-    public void setDenominator(final long denominator) throws IllegalArgumentException {
-        ArgumentChecks.ensurePositive("denominator", denominator);
+    public void setDenominator(final long denominator) {
+        if (denominator < 0) {
+            warnNonPositiveArgument(DefaultRepresentativeFraction.class, "denominator", false, denominator);
+        }
         this.denominator = denominator;
     }
 
     /**
-     * Sets the denominator from a scale in the [-1 … +1] range.
+     * Sets the denominator from a scale in the (0 … 1] range.
      * The denominator is computed by {@code round(1 / scale)}.
      *
-     * @param  scale The scale as a number between -1 and +1 inclusive, or NaN.
+     * <p>The equivalent of a {@code getScale()} method is {@link #doubleValue()}.</p>
+     *
+     * @param  scale The scale as a number between 0 exclusive and 1 inclusive, or NaN.
      * @throws IllegalArgumentException if the given scale is our of range.
      */
-    public void setScale(final double scale) throws IllegalArgumentException {
-        if (Math.abs(scale) > 1) {
-            throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.ValueOutOfRange_4, "scale", -1, +1, scale));
+    public void setScale(final double scale) {
+        /*
+         * For the following argument check, we do not need to use a Metadatautility method because
+         * 'setScale' is never invoked at (un)marshalling time. Note also that we accept NaN values
+         * since round(NaN) == 0, which is the desired value.
+         */
+        if (scale <= 0 || scale > 1) {
+            throw new IllegalArgumentException((scale <= 0)
+                    ? Errors.format(Errors.Keys.ValueNotGreaterThanZero_2, "scale", scale)
+                    : Errors.format(Errors.Keys.ValueOutOfRange_4, "scale", 0, 1, scale));
         }
-        // round(NaN) == 0, which is the desired value.
         setDenominator(Math.round(1.0 / scale));
     }
 



Mime
View raw message