Author: desruisseaux Date: Wed Oct 7 13:16:04 2015 New Revision: 1707295 URL: http://svn.apache.org/viewvc?rev=1707295&view=rev Log: Allow DefaultRepresentativeFraction to be immutable (SIS-107). Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFractionTest.java Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java?rev=1707295&r1=1707294&r2=1707295&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/Cloner.java [UTF-8] Wed Oct 7 13:16:04 2015 @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import org.apache.sis.util.collection.Containers; import org.apache.sis.util.collection.CodeListSet; import org.apache.sis.internal.util.CollectionsExt; +import org.apache.sis.metadata.iso.identification.DefaultRepresentativeFraction; /** @@ -84,12 +85,17 @@ final class Cloner extends org.apache.si @Override public Object clone(final Object object) throws CloneNotSupportedException { /* - * CASE 1 - The object is an implementation of ModifiableMetadata. It may have + * CASE 1 - The object is an org.apache.sis.metadata.* implementation. It may have * its own algorithm for creating an unmodifiable view of metadata. */ if (object instanceof ModifiableMetadata) { return ((ModifiableMetadata) object).unmodifiable(); } + if (object instanceof DefaultRepresentativeFraction) { + final DefaultRepresentativeFraction c = ((DefaultRepresentativeFraction) object).clone(); + c.freeze(); + return c; + } /* * CASE 2 - The object is a collection. All elements are replaced by their * unmodifiable variant and stored in a new collection of similar Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java?rev=1707295&r1=1707294&r2=1707295&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java [UTF-8] Wed Oct 7 13:16:04 2015 @@ -26,7 +26,9 @@ import javax.xml.bind.annotation.adapter import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; import org.opengis.metadata.Identifier; import org.opengis.metadata.identification.RepresentativeFraction; +import org.apache.sis.metadata.UnmodifiableMetadataException; import org.apache.sis.internal.jaxb.ModifiableIdentifierMap; +import org.apache.sis.internal.jaxb.IdentifierMapAdapter; import org.apache.sis.internal.jaxb.gco.GO_Integer64; import org.apache.sis.internal.util.CheckedArrayList; import org.apache.sis.measure.ValueRange; @@ -63,14 +65,14 @@ import static org.apache.sis.internal.me * @author Cédric Briançon (Geomatys) * @author Martin Desruisseaux (Geomatys) * @since 0.3 - * @version 0.6 + * @version 0.7 * @module * * @see DefaultResolution#getEquivalentScale() */ @XmlType(name = "MD_RepresentativeFraction_Type") @XmlRootElement(name = "MD_RepresentativeFraction") -public class DefaultRepresentativeFraction extends Number implements RepresentativeFraction, IdentifiedObject, Emptiable { +public class DefaultRepresentativeFraction extends Number implements RepresentativeFraction, IdentifiedObject, Emptiable, Cloneable { /** * Serial number for compatibility with different versions. */ @@ -88,6 +90,11 @@ public class DefaultRepresentativeFracti private Collection identifiers; /** + * {@code true} if this representative fraction has been made unmodifiable. + */ + private transient boolean isUnmodifiable; + + /** * Creates a uninitialized representative fraction. * The {@linkplain #getDenominator() denominator} is initially zero * and the {@linkplain #doubleValue() double value} is NaN. @@ -161,6 +168,9 @@ public class DefaultRepresentativeFracti * @throws IllegalArgumentException if the given value is negative. */ public void setDenominator(final long denominator) { + if (isUnmodifiable) { + throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata)); + } if (ensurePositive(DefaultRepresentativeFraction.class, "denominator", false, denominator)) { this.denominator = denominator; } @@ -176,6 +186,9 @@ public class DefaultRepresentativeFracti * @throws IllegalArgumentException if the given scale is our of range. */ public void setScale(final double scale) { + if (isUnmodifiable) { + throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata)); + } /* * 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 @@ -259,6 +272,35 @@ public class DefaultRepresentativeFracti } /** + * Makes this representative fraction unmodifiable. After invocation to this method, + * any call to a setter method will throw an {@link UnmodifiableMetadataException}. + * + * @since 0.7 + * + * @see org.apache.sis.metadata.ModifiableMetadata#freeze() + */ + public void freeze() { + isUnmodifiable = true; + } + + /** + * Returns a modifiable copy of this representative fraction. + * + * @return A modifiable copy of this representative fraction. + */ + @Override + public DefaultRepresentativeFraction clone() { + final DefaultRepresentativeFraction c; + try { + c = (DefaultRepresentativeFraction) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); // Should never happen since we are cloneable. + } + c.isUnmodifiable = false; + return c; + } + + /** * Compares this object with the specified value for equality. * * @param object The object to compare with. @@ -326,7 +368,9 @@ public class DefaultRepresentativeFracti */ @Override public IdentifierMap getIdentifierMap() { - return new ModifiableIdentifierMap(getIdentifiers()); + final Collection identifiers = getIdentifiers(); + return isUnmodifiable ? new IdentifierMapAdapter(identifiers) + : new ModifiableIdentifierMap(identifiers); } Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFractionTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFractionTest.java?rev=1707295&r1=1707294&r2=1707295&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFractionTest.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFractionTest.java [UTF-8] Wed Oct 7 13:16:04 2015 @@ -31,7 +31,7 @@ import static org.apache.sis.test.Assert * * @author Martin Desruisseaux (Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ public final strictfp class DefaultRepresentativeFractionTest extends TestCase { @@ -72,4 +72,27 @@ public final strictfp class DefaultRepre */ assertEquals(fraction, XML.unmarshal(xml)); } + + /** + * Tests indirectly {@link DefaultRepresentativeFraction#freeze()}. + * This method verifies that a call to {@link DefaultResolution#freeze()} + * implies a call to {@link DefaultRepresentativeFraction#freeze()}. + * + * @since 0.7 + */ + @Test + public void testFreeze() { + final DefaultRepresentativeFraction fraction = new DefaultRepresentativeFraction(1000); + final DefaultResolution resolution = new DefaultResolution(fraction); + resolution.freeze(); + final DefaultRepresentativeFraction clone = (DefaultRepresentativeFraction) resolution.getEquivalentScale(); + assertEquals ("Fraction should have the same value.", fraction, clone); + assertNotSame("Should have copied the fraction instance.", fraction, clone); + try { + clone.setDenominator(10); + fail("Shall not be allowed to modify an unmodifiable fraction."); + } catch (UnsupportedOperationException e) { + // This is the expected exception. + } + } }