Class ModifiableMetadata

java.lang.Object
org.apache.sis.metadata.AbstractMetadata
org.apache.sis.metadata.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.
Since:
0.3
Version:
1.1
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static enum 
    Whether the metadata is still editable or has been made final.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private static final byte
    The state value meaning that missing properties can be set, but no existing properties can be modified (including collections).
    private static final byte
    The state value meaning that the metadata is modifiable.
    private static final byte
    A value for state meaning that transitionTo(State.FINAL) has been invoked.
    private static final byte
    A value for state meaning that execution of transitionTo(…) is in progress.
    private static final byte
    See https://issues.apache.org/jira/browse/SIS-81 - not yet committed.
    private byte
    Whether this metadata has been made unmodifiable, as one of EDITABLE, FREEZING COMPLETABLE or FINAL values.
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    protected
    Constructs an initially empty metadata.
  • Method Summary

    Modifier and Type
    Method
    Description
    protected void
    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 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.
    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.
    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.
    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.
    private static <E> List<E>
    createList(Class<E> elementType, Collection<?> source)
    Creates a modifiable list for elements of the given type.
    private static <K, V> Map<K,V>
    createMap(Class<K> keyType, Map<?,?> source)
    Creates a modifiable map for elements of the given type.
    private static <E> Set<E>
    createSet(Class<E> elementType, Collection<?> source)
    Creates a modifiable set for elements of the given type.
    Copies (if necessary) this metadata and all its children.
    private static boolean
    Returns true if empty collection should be returned as null value.
    protected final <E> Collection<E>
    nonNullCollection(Collection<E> current, Class<E> elementType)
    Returns the specified collection, or a new one if current is null.
    protected final <E> List<E>
    nonNullList(List<E> current, Class<E> elementType)
    Returns the specified list, or a new one if current is null.
    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.
    protected final <E> Set<E>
    nonNullSet(Set<E> current, Class<E> elementType)
    Returns the specified set, or a new one if current is null.
    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.
    Tells whether this instance of metadata is editable.
    boolean
    Requests this metadata instance and (potentially) all its children to transition to a new state.
    private <E> boolean
    useSet(Class<E> elementType)
    Returns true if we should use a Set instead of a List for elements of the given type.
    private <E> Collection<E>
    write(Collection<? extends E> source, Collection<E> target, Class<E> elementType, Boolean useSet)
    Writes the content of the source collection into the target list or set, creating it if needed.
    protected final <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 final <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 final <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 final <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 org.apache.sis.metadata.AbstractMetadata

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

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Field Details

    • EDITABLE

      private static final byte EDITABLE
      The state value meaning that the metadata is modifiable. This is the default state when new ModifiableMetadata instances are created.
      See Also:
    • STAGED

      private static final byte STAGED
      See https://issues.apache.org/jira/browse/SIS-81 - not yet committed.
      See Also:
    • FREEZING

      private static final byte FREEZING
      A value for state meaning that execution of transitionTo(…) is in progress. Must be greater than all other values except COMPLETABLE and FINAL.
      See Also:
    • COMPLETABLE

      private static final byte COMPLETABLE
      The state value meaning that missing properties can be set, but no existing properties can be modified (including collections). This is a kind of semi-final state.
      See Also:
    • FINAL

      private static final byte FINAL
      A value for state meaning that transitionTo(State.FINAL) has been invoked. Must be greater than all other values.
      See Also:
    • state

      private transient byte state
      Whether this metadata has been made unmodifiable, as one of EDITABLE, FREEZING COMPLETABLE or FINAL values.

      This field is not yet serialized because we are not sure to keep this information as a byte in the future. We could for example use an int and use remaining bits for caching hash-code value of final metadata.

  • Constructor Details

  • Method Details

    • 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 (editable, completable or final).
      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
    • deepCopy

      public ModifiableMetadata deepCopy(ModifiableMetadata.State target)
      Copies (if necessary) this metadata and all its children. Changes in the returned metadata will not affect this ModifiableMetadata instance, and conversely. The returned metadata will be in the state specified by the target argument. The state of this ModifiableMetadata instance stay unchanged.

      As a special case, this method returns this if and only if the specified target is ModifiableMetadata.State.FINAL and this ModifiableMetadata instance is already in final state. In that particular case, copies are not needed for protecting metadata against changes because neither this or the returned value can be modified.

      This method is typically invoked for getting a modifiable metadata from an unmodifiable one:

      Alternative

      If unconditional copy is desired, or if the metadata to copy may be arbitrary implementations of GeoAPI interfaces (i.e. not necessarily a ModifiableMetadata subclass), then the following code can be used instead: The Metadata type in above example can be replaced by any other ISO 19115 type. Types from other standards can also be used if the MetadataStandard.ISO_19115 constant is replaced accordingly.
      Parameters:
      target - the desired state (editable, completable or final).
      Returns:
      a copy (except in above-cited special case) of this metadata in the specified state.
      Since:
      1.1
      See Also:
    • 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:
    • 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:
    • 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:
    • 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 of 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.
    • write

      private <E> Collection<E> write(Collection<? extends E> source, Collection<E> target, Class<E> elementType, Boolean useSet) throws UnmodifiableMetadataException
      Writes the content of the source collection into the target list or set, creating it if needed.
      Parameters:
      useSet - Boolean.TRUE for creating a set, Boolean.FALSE for creating a list, or null for automatic choice.
      Throws:
      UnmodifiableMetadataException
    • 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:
    • 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.
    • emptyCollectionAsNull

      private static boolean emptyCollectionAsNull()
      Returns true if empty collection should be returned as null value. This is usually not a behavior that we allow in public API. However, this behavior is sometimes desired internally, for example when marshalling with JAXB or when performing a equals, isEmpty or prune operation (for avoiding creating unnecessary collections).
    • 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 of 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
    • createList

      private static <E> List<E> createList(Class<E> elementType, Collection<?> source)
      Creates a modifiable list for elements of the given type. This method is defined mostly for consistency with createSet(Class, Collection).
      Parameters:
      source - the collection to be copied in the new list. This method uses this information only for computing initial capacity; it does not perform the actual copy.
    • createSet

      private static <E> Set<E> createSet(Class<E> elementType, Collection<?> source)
      Creates a modifiable set for elements of the given type. This method will create an EnumSet, CodeListSet or LinkedHashSet depending on the elementType argument. The set must have a stable iteration order (this is needed by TreeTableView).
      Parameters:
      source - the collection to be copied in the new set, or null if unknown. This method uses this information only for computing initial capacity; it does not perform the actual copy.
    • createMap

      private static <K, V> Map<K,V> createMap(Class<K> keyType, Map<?,?> source)
      Creates a modifiable map for elements of the given type. The map must have a stable iteration order (this is needed by TreeTableView).
      Parameters:
      source - the map to be copied in the new map. This method uses this information only for computing initial capacity; it does not perform the actual copy.
    • useSet

      private <E> boolean useSet(Class<E> elementType)
      Returns true if we should use a Set instead of a List for elements of the given type.
    • 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.