org.apache.sis.metadata

## Class ModifiableMetadata

- Object
- - AbstractMetadata
  - - ModifiableMetadata

- All Implemented Interfaces:
    Cloneable, Emptiable, LenientComparable
  Direct Known Subclasses:
    ISOMetadata

      public abstract class ModifiableMetadata
      extends AbstractMetadata
      implements Cloneable

  Provides convenience methods for support of modifiable properties in metadata implementations. Implementations typically provide `set*(…)` methods for each corresponding `get*()` method. Subclasses can follow the pattern below for every `get` and `set` methods, with a different processing for singleton value or for collections.

  For singleton value:

      public class MyMetadata {
          private Foo property;

          public Foo getProperty() {
              return property;
          }

          public void setProperty(Foo newValue) {
              checkWritePermission();
              property = newValue;
          }
      }

  For collections (note that the call to `checkWritePermission()` is implicit):

      public class MyMetadata {
          private Collection<Foo> properties;

          public Collection<Foo> getProperties() {
              return properties = nonNullCollection(properties, Foo.class);
          }

          public void setProperties(Collection<Foo> newValues) {
              properties = writeCollection(newValues, properties, Foo.class);
          }
      }

  An initially modifiable metadata may become unmodifiable at a later stage (typically after its construction is completed) by the call to the `freeze()` method.
  Since:
    0.3

  Defined in the `sis-metadata` module

- - ### Constructor Summary

    Constructors
    Modifier | Constructor and Description
    --- | ---
    `protected` | `ModifiableMetadata()` Constructs an initially empty metadata.

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `protected void` | `checkWritePermission()` Checks if changes in the metadata are allowed.
    `protected ModifiableMetadata` | `clone()` Creates a shallow copy of this metadata.
    `protected <E> Class<? extends Collection<E>>` | `collectionType(Class<E> elementType)` Returns the type of collection to use for the given type.
    `protected <E> Collection<E>` | `copyCollection(Collection<? extends E> source, Class<E> elementType)` Creates a list or set with the content of the `source` collection, or returns `null` if the source is `null` or empty.
    `protected <E> List<E>` | `copyList(Collection<? extends E> source, Class<E> elementType)` Creates a list with the content of the `source` collection, or returns `null` if the source is `null` or empty.
    `protected <E> Set<E>` | `copySet(Collection<? extends E> source, Class<E> elementType)` Creates a set with the content of the `source` collection, or returns `null` if the source is `null` or empty.
    `void` | `freeze()` Declares this metadata and all its properties as unmodifiable.
    `boolean` | `isModifiable()` Returns `true` if this metadata is modifiable.
    `protected <E> Collection<E>` | `nonNullCollection(Collection<E> c, Class<E> elementType)` Returns the specified collection, or a new one if `c` is null.
    `protected <E> List<E>` | `nonNullList(List<E> c, Class<E> elementType)` Returns the specified list, or a new one if `c` is null.
    `protected <E> Set<E>` | `nonNullSet(Set<E> c, Class<E> elementType)` Returns the specified set, or a new one if `c` is null.
    `protected <E> Collection<E>` | `singleton(E value, Class<E> elementType)` Creates a singleton list or set containing only the given value, if non-null.
    `AbstractMetadata` | `unmodifiable()` Returns an unmodifiable copy of this metadata.
    `protected <E> Collection<E>` | `writeCollection(Collection<? extends E> source, Collection<E> target, Class<E> elementType)` Writes the content of the `source` collection into the `target` list or set, creating it if needed.
    `protected <E> List<E>` | `writeList(Collection<? extends E> source, List<E> target, Class<E> elementType)` Writes the content of the `source` collection into the `target` list, creating it if needed.
    `protected <E> Set<E>` | `writeSet(Collection<? extends E> source, Set<E> target, Class<E> elementType)` Writes the content of the `source` collection into the `target` set, creating it if needed.

    - ### Methods inherited from class AbstractMetadata

      `asMap, asTreeTable, equals, equals, getInterface, getStandard, hashCode, isEmpty, prune, toString`

    - ### Methods inherited from class Object

      `finalize, getClass, notify, notifyAll, wait, wait, wait`

- - ### Constructor Detail

    - #### ModifiableMetadata

          protected ModifiableMetadata()

      Constructs an initially empty metadata.

  - ### Method Detail

    - #### isModifiable

          public final boolean isModifiable()

      Returns `true` if this metadata is modifiable. This method returns `false` if `freeze()` has been invoked on this object.
      Returns:
        `true` if this metadata is modifiable.
      See Also:
        `freeze()`, `checkWritePermission()`

    - #### unmodifiable

          public AbstractMetadata unmodifiable()

      Returns an unmodifiable copy of this metadata. Any attempt to modify a property of the returned object will throw an `UnmodifiableMetadataException`. The state of this object is not modified.

      This method is useful for reusing the same metadata object as a template. For example:

          DefaultCitation myCitation = new DefaultCitation();
          myCitation.setTitle(new SimpleInternationalString("The title of my book"));
          myCitation.setEdition(new SimpleInternationalString("First edition"));
          final Citation firstEdition = (Citation) myCitation.unmodifiable();

          myCitation.setEdition(new SimpleInternationalString("Second edition"));
          final Citation secondEdition = (Citation) myCitation.unmodifiable();
          // The title of the second edition is unchanged compared to the first edition.

      The default implementation makes the following choice:
      - If this metadata is itself unmodifiable, then this method returns `this` unchanged.
      - Otherwise this method clone this metadata and freeze the clone before to return it.
      Returns:
        an unmodifiable copy of this metadata.
      See Also:
        `MetadataCopier`

    - #### freeze

          public void freeze()

      Declares this metadata and all its properties as unmodifiable. Any attempt to modify a property after this method call will throw an `UnmodifiableMetadataException`. If this metadata is already unmodifiable, then this method does nothing.

      Subclasses usually do not need to override this method since the default implementation performs its work using Java reflection.

      See Also:
        `isModifiable()`, `checkWritePermission()`

    - #### checkWritePermission

          protected void checkWritePermission()
                                       throws UnmodifiableMetadataException

      Checks if changes in the metadata are allowed. All `setFoo(…)` methods in subclasses shall invoke this method (directly or indirectly) before to apply any change.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.
      See Also:
        `isModifiable()`, `freeze()`

    - #### writeList

          protected final <E> List<E> writeList(Collection<? extends E> source,
                                                List<E> target,
                                                Class<E> elementType)
                                         throws UnmodifiableMetadataException

      Writes the content of the `source` collection into the `target` list, creating it if needed. This method performs the following steps:
      - Invokes `checkWritePermission()` in order to ensure that this metadata is modifiable.
      - If `source` is null or empty, returns `null` (meaning that the metadata property is not provided).
      - If `target` is null, creates a new `List`.
      - Copies the content of the given `source` into the target.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source list, or `null`.
        `target` - the target list, or `null` if not yet created.
        `elementType` - the base type of elements to put in the list.
      Returns:
        a list (possibly the `target` instance) containing the `source` elements, or `null` if the source was null.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.
      See Also:
        `nonNullList(List, Class)`

    - #### writeSet

          protected final <E> Set<E> writeSet(Collection<? extends E> source,
                                              Set<E> target,
                                              Class<E> elementType)
                                       throws UnmodifiableMetadataException

      Writes the content of the `source` collection into the `target` set, creating it if needed. This method performs the following steps:
      - Invokes `checkWritePermission()` in order to ensure that this metadata is modifiable.
      - If `source` is null or empty, returns `null` (meaning that the metadata property is not provided).
      - If `target` is null, creates a new `Set`.
      - Copies the content of the given `source` into the target.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source set, or `null`.
        `target` - the target set, or `null` if not yet created.
        `elementType` - the base type of elements to put in the set.
      Returns:
        a set (possibly the `target` instance) containing the `source` elements, or `null` if the source was null.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.
      See Also:
        `nonNullSet(Set, Class)`

    - #### writeCollection

          protected final <E> Collection<E> writeCollection(Collection<? extends E> source,
                                                            Collection<E> target,
                                                            Class<E> elementType)
                                                     throws UnmodifiableMetadataException

      Writes the content of the `source` collection into the `target` list or set, creating it if needed. This method performs the following steps:
      - Invokes `checkWritePermission()` in order to ensure that this metadata is modifiable.
      - If `source` is null or empty, returns `null` (meaning that the metadata property is not provided).
      - If `target` is null, creates a new `Set` or a new `List` depending on the value returned by `collectionType(Class)`.
      - Copies the content of the given `source` into the target.
      Choosing a collection type
      Implementations shall invoke `writeList` or `writeSet` methods instead than this method when the collection type is enforced by ISO specification. When the type is not enforced by the specification, some freedom are allowed at implementor choice. The default implementation invokes `collectionType(Class)` in order to get a hint about whether a `List` or a `Set` should be used.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source collection, or `null`.
        `target` - the target collection, or `null` if not yet created.
        `elementType` - the base type of elements to put in the collection.
      Returns:
        a collection (possibly the `target` instance) containing the `source` elements, or `null` if the source was null.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.

    - #### copyList

          protected final <E> List<E> copyList(Collection<? extends E> source,
                                               Class<E> elementType)

      Creates a list with the content of the `source` collection, or returns `null` if the source is `null` or empty. This is a convenience method for copying fields in subclass copy constructors.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source collection, or `null`.
        `elementType` - the base type of elements to put in the list.
      Returns:
        a list containing the `source` elements, or `null` if the source was null or empty.

    - #### copySet

          protected final <E> Set<E> copySet(Collection<? extends E> source,
                                             Class<E> elementType)

      Creates a set with the content of the `source` collection, or returns `null` if the source is `null` or empty. This is a convenience method for copying fields in subclass copy constructors.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source collection, or `null`.
        `elementType` - the base type of elements to put in the set.
      Returns:
        a set containing the `source` elements, or `null` if the source was null or empty.

    - #### copyCollection

          protected final <E> Collection<E> copyCollection(Collection<? extends E> source,
                                                           Class<E> elementType)

      Creates a list or set with the content of the `source` collection, or returns `null` if the source is `null` or empty. This is a convenience method for copying fields in subclass copy constructors.

      The collection type is selected as described in the `nonNullCollection(Collection, Class)`.

      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `source` - the source collection, or `null`.
        `elementType` - the base type of elements to put in the collection.
      Returns:
        a collection containing the `source` elements, or `null` if the source was null or empty.

    - #### singleton

          protected final <E> Collection<E> singleton(E value,
                                                      Class<E> elementType)

      Creates a singleton list or set containing only the given value, if non-null. This is a convenience method for initializing fields in subclass constructors.

      The collection type is selected as described in the `nonNullCollection(Collection, Class)`.

      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `value` - the singleton value to put in the returned collection, or `null`.
        `elementType` - the element type (used only if `value` is non-null).
      Returns:
        a new modifiable collection containing the given value, or `null` if the given value was null.

    - #### nonNullList

          protected final <E> List<E> nonNullList(List<E> c,
                                                  Class<E> elementType)

      Returns the specified list, or a new one if `c` is null. This is a convenience method for implementation of `getFoo()` methods.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `c` - the existing list, or `null` if the list has not yet been created.
        `elementType` - the element type (used only if `c` is null).
      Returns:
        `c`, or a new list if `c` is null.

    - #### nonNullSet

          protected final <E> Set<E> nonNullSet(Set<E> c,
                                                Class<E> elementType)

      Returns the specified set, or a new one if `c` is null. This is a convenience method for implementation of `getFoo()` methods.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `c` - the existing set, or `null` if the set has not yet been created.
        `elementType` - the element type (used only if `c` is null).
      Returns:
        `c`, or a new set if `c` is null.

    - #### nonNullCollection

          protected final <E> Collection<E> nonNullCollection(Collection<E> c,
                                                              Class<E> elementType)

      Returns the specified collection, or a new one if `c` is null. This is a convenience method for implementation of `getFoo()` methods.
      Choosing a collection type
      Implementations shall invoke `nonNullList(…)` or `nonNullSet(…)` instead than this method when the collection type is enforced by ISO specification. When the type is not enforced by the specification, some freedom are allowed at implementor choice. The default implementation invokes `collectionType(Class)` in order to get a hint about whether a `List` or a `Set` should be used.
      Type Parameters:
        `E` - the type represented by the `Class` argument.
      Parameters:
        `c` - the existing collection, or `null` if the collection has not yet been created.
        `elementType` - the element type (used only if `c` is null).
      Returns:
        `c`, or a new collection if `c` is null.

    - #### collectionType

          protected <E> Class<? extends Collection<E>> collectionType(Class<E> elementType)

      Returns the type of collection to use for the given type. The current implementation can return only two values: `Set.class` if the property should not accept duplicated values, or `List.class` otherwise. Future SIS versions may accept other types.

      The default implementation returns `Set.class` if the element type is assignable to `CodeList`, `Enum`, `String`, `Charset`, `Locale` or `Currency`, and `List.class` otherwise. Subclasses can override this method for choosing different kind of collections. Note however that `Set` should be used only with immutable element types, for hash code stability.

      Type Parameters:
        `E` - the type of elements in the collection to be created.
      Parameters:
        `elementType` - the type of elements in the collection to be created.
      Returns:
        `List​.class` or `Set​.class` depending on whether the property shall accept duplicated values or not.

    - #### clone

          protected ModifiableMetadata clone()
                                      throws CloneNotSupportedException

      Creates a shallow copy of this metadata. The clone operation is required for the internal working of the `unmodifiable()` method, which needs shallow copies of metadata entities. For deep copies, see `MetadataCopier`.
      API note
      While `Cloneable`, the `ModifiableMetadata` subclasses should not provide the `clone()` operation as part of their public API, because the cloned object share reference to the same collections than the original object.
      Note for subclass implementors
      The default `Object​.clone()` implementation is sufficient in most cases. The need to override this method should be rare, but may happen if the object contains for example connection to a database.
      Overrides:
        `clone` in class `Object`
      Returns:
        a shallow copy of this metadata.
      Throws:
        `CloneNotSupportedException` - if the clone is not supported.
      See Also:
        `unmodifiable()`, `MetadataCopier`

Copyright © 2010–2017 The Apache Software Foundation. All rights reserved.