Package org.apache.sis.metadata

## Class ModifiableMetadata

- Object
- - AbstractMetadata
  - - ModifiableMetadata

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

      public abstract class ModifiableMetadata
      extends AbstractMetadata

  Base class of metadata having an editable content. Newly created `ModifiableMetadata` are initially in editable state. The metadata can be populated using the setter methods provided by subclasses, then transition to the final state for making it safe to share by many consumers.
  Tip for subclass implementations
  Subclasses can follow the pattern below for every `get` and `set` methods, with a different processing for singleton value or for collections.

  >     public class MyMetadata {

  >         // ==== Example for a singleton value =============================

  >         private Foo property;

  >         public Foo getProperty() {
  >             return property;
  >         }

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

  >         // ==== Example for a collection ==================================

  >         private Collection<Foo> properties;

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

  >         public void setProperties(Collection<Foo> newValues) {
  >             // the call to checkWritePermission() is implicit
  >             properties = writeCollection(newValues, properties, Foo.class);
  >         }
  >     }

  Since:
    0.3

  Defined in the `sis-metadata` module

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class | Description
    --- | --- | ---
    `static class` | `ModifiableMetadata.State` | Whether the metadata is still editable or has been made final.

  - ### Constructor Summary

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

  - ### Method Summary

    All Methods Instance Methods Concrete Methods Deprecated Methods
    Modifier and Type | Method | Description
    --- | --- | ---
    `protected void` | `checkWritePermission()` | Deprecated. Replaced by `checkWritePermission(Object)`.
    `protected void` | `checkWritePermission​(Object current)` | Checks if changes in the metadata are allowed.
    `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 <K,​V> Map<K,​V>` | `copyMap​(Map<? extends K,​? extends V> source, Class<K> keyType)` | Creates a map with the content of the `source` map, 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()` | Deprecated. Replaced by `transition(State​.FINAL)`.
    `boolean` | `isModifiable()` | Deprecated. Replaced by `state() !`
    `protected <E> Collection<E>` | `nonNullCollection​(Collection<E> current, Class<E> elementType)` | Returns the specified collection, or a new one if `current` is null.
    `protected <E> List<E>` | `nonNullList​(List<E> current, Class<E> elementType)` | Returns the specified list, or a new one if `current` is null.
    `protected <K,​V> Map<K,​V>` | `nonNullMap​(Map<K,​V> current, Class<K> keyType)` | Returns the specified map, or a new one if `current` is null.
    `protected <E> Set<E>` | `nonNullSet​(Set<E> current, Class<E> elementType)` | Returns the specified set, or a new one if `current` 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.
    `ModifiableMetadata.State` | `state()` | Tells whether this instance of metadata is editable.
    `boolean` | `transitionTo​(ModifiableMetadata.State target)` | Requests this metadata instance and (potentially) all its children to transition to a new state.
    `AbstractMetadata` | `unmodifiable()` | Deprecated. Replaced by `MetadataCopier​.forModifiable(getStandard()).copy(this)​.transition(State​.FINAL)`.
    `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 <K,​V> Map<K,​V>` | `writeMap​(Map<? extends K,​? extends V> source, Map<K,​V> target, Class<K> keyType)` | Writes the content of the `source` map into the `target` map, 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

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

- - ### Constructor Detail

    - #### ModifiableMetadata

          protected ModifiableMetadata()

      Constructs an initially empty metadata. The initial state is `ModifiableMetadata​.State​.EDITABLE`.

  - ### Method Detail

    - #### state

          public ModifiableMetadata.State state()

      Tells whether this instance of metadata is editable. This is initially `ModifiableMetadata​.State​.EDITABLE` for new `ModifiableMetadata` instances, but can be changed by a call to `transitionTo(State)`.

      `ModifiableMetadata​.State​.FINAL` implies that all properties are also final. This recursivity does not necessarily apply to other states. For example `ModifiableMetadata​.State​.EDITABLE` does not imply that all `ModifiableMetadata` children are also editable.

      API note: the `ModifiableMetadata` state is not a metadata per se, but rather an information about this particular instance of a metadata class. Two metadata instances may be in different states but still have the same metadata content. For this reason, this method does not have `get` prefix for avoiding confusion with getter and setter methods of metadata properties.
      Returns:
        the state (editable, completable or final) of this `ModifiableMetadata` instance.
      Since:
        1.0

    - #### transitionTo

          public boolean transitionTo​(ModifiableMetadata.State target)

      Requests this metadata instance and (potentially) all its children to transition to a new state. The action performed by this method depends on the source state and the given target state, as listed in the following table:

      State transitions
      Current state | Target state | Action
      --- | --- | ---
      Any | Same | Does nothing and returns `false`.
      `ModifiableMetadata.State.EDITABLE` | `ModifiableMetadata.State.COMPLETABLE` | Marks this metadata and all children as completable.
      Any | `ModifiableMetadata.State.FINAL` | Marks this metadata and all children as unmodifiable.
      `ModifiableMetadata.State.FINAL` | Any other | Throws `UnmodifiableMetadataException`.

      The effect of invoking this method may be recursive. For example transitioning to `ModifiableMetadata​.State​.FINAL` implies transitioning all children `ModifiableMetadata` instances to the final state too.
      Parameters:
        `target` - the desired new state.
      Returns:
        `true` if the state of this `ModifiableMetadata` changed as a result of this method call.
      Throws:
        `UnmodifiableMetadataException` - if a transition to a less restrictive state (e.g. from `ModifiableMetadata​.State​.FINAL` to `ModifiableMetadata​.State​.EDITABLE`) was attempted.
      Since:
        1.0

    - #### isModifiable

          @Deprecated
          public final boolean isModifiable()

      Deprecated.
      Replaced by `state() != State​.FINAL`. See SIS-81.
      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

          @Deprecated
          public AbstractMetadata unmodifiable()

      Deprecated.
      Replaced by `MetadataCopier​.forModifiable(getStandard()).copy(this)​.transition(State​.FINAL)`.
      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

          @Deprecated
          public void freeze()

      Deprecated.
      Replaced by `transition(State​.FINAL)`.
      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:
        `state()`, `checkWritePermission()`

    - #### checkWritePermission

          @Deprecated
          protected void checkWritePermission()
                                       throws UnmodifiableMetadataException

      Deprecated.
      Replaced by `checkWritePermission(Object)`.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.

    - #### checkWritePermission

          protected void checkWritePermission​(Object current)
                                       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. The current property value should be specified in argument.
      Parameters:
        `current` - the current value, or `null` if none.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.
      Since:
        1.0
      See Also:
        `state()`

    - #### 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(Object)` 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(Object)` 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(Object)` 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 implementer 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.

    - #### writeMap

          protected final <K,​V> Map<K,​V> writeMap​(Map<? extends K,​? extends V> source,
                                                              Map<K,​V> target,
                                                              Class<K> keyType)
                                                       throws UnmodifiableMetadataException

      Writes the content of the `source` map into the `target` map, creating it if needed. This method performs the following steps:
      - Invokes `checkWritePermission(Object)` 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 `Map`.
      - Copies the content of the given `source` into the target.
      Type Parameters:
        `K` - the type of keys represented by the `Class` argument.
        `V` - the type of values in the map.
      Parameters:
        `source` - the source map, or `null`.
        `target` - the target map, or `null` if not yet created.
        `keyType` - the base type of keys to put in the map.
      Returns:
        a map (possibly the `target` instance) containing the `source` entries, or `null` if the source was null.
      Throws:
        `UnmodifiableMetadataException` - if this metadata is unmodifiable.
      Since:
        1.0
      See Also:
        `nonNullMap(Map, Class)`

    - #### 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.

    - #### copyMap

          protected final <K,​V> Map<K,​V> copyMap​(Map<? extends K,​? extends V> source,
                                                             Class<K> keyType)

      Creates a map with the content of the `source` map, or returns `null` if the source is `null` or empty. This is a convenience method for copying fields in subclass copy constructors.
      Type Parameters:
        `K` - the type of keys represented by the `Class` argument.
        `V` - the type of values in the map.
      Parameters:
        `source` - the source map, or `null`.
        `keyType` - the base type of keys to put in the map.
      Returns:
        a map containing the `source` entries, or `null` if the source was null or empty.
      Since:
        1.0

    - #### 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> current,
                                                  Class<E> elementType)

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

    - #### nonNullSet

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

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

    - #### nonNullCollection

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

      Returns the specified collection, or a new one if `current` 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 implementer 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:
        `current` - the existing collection, or `null` if the collection has not yet been created.
        `elementType` - the element type (used only if `current` is null).
      Returns:
        `current`, or a new collection if `current` is null.

    - #### nonNullMap

          protected final <K,​V> Map<K,​V> nonNullMap​(Map<K,​V> current,
                                                                Class<K> keyType)

      Returns the specified map, or a new one if `current` is null. This is a convenience method for implementation of `getFoo()` methods.
      Type Parameters:
        `K` - the type of keys represented by the `Class` argument.
        `V` - the type of values in the map.
      Parameters:
        `current` - the existing map, or `null` if the map has not yet been created.
        `keyType` - the key type (used only if `current` is null).
      Returns:
        `current`, or a new map if `current` is null.
      Since:
        1.0

    - #### 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.