Module org.apache.sis.metadata
Package org.apache.sis.metadata

# Class MetadataStandard

Object
MetadataStandard

All Implemented Interfaces:
  `Serializable`

public class MetadataStandard extends Object implements Serializable
Enumeration of some metadata standards. A standard is defined by a set of Java interfaces in a specific package or sub-packages. For example, the ISO 19115 standard is defined by GeoAPI interfaces in the `org​.opengis​.metadata` package and sub-packages.

This class provides some methods operating on metadata instances through Java reflection. The following rules are assumed:

- Metadata properties are defined by the collection of following getter methods found in the interface, ignoring implementation methods:
  - `get*()` methods with arbitrary return type;
  - or `is*()` methods with boolean return type.
- All properties are readable.
- A property is also writable if a `set*(…)` method is defined in the implementation class for the corresponding getter method. The setter method does not need to be defined in the interface.

An instance of `MetadataStandard` is associated to every `AbstractMetadata` objects. The `AbstractMetadata` base class usually form the basis of ISO 19115 implementations but can also be used for other standards.

## Defining new `MetadataStandard` instances

Users should use the predefined constants when applicable. However if new instances need to be defined, then there is a choice:

- For read-only metadata, `MetadataStandard` can be instantiated directly. Only getter methods will be used and all operations that modify the metadata properties will throw an `UnmodifiableMetadataException`.
- For read/write metadata, the `getImplementation(Class)` method must be overridden in a `MetadataStandard` subclass.

## Thread safety

The same `MetadataStandard` instance can be safely used by many threads without synchronization on the part of the caller. Subclasses shall make sure that any overridden methods remain safe to call from multiple threads, because the same `MetadataStandard` instances are typically referenced by a large amount of `ModifiableMetadata`.

Since:
  0.3
See Also:
  - `AbstractMetadata`
  - Serialized Form

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final MetadataStandard`
  `ISO_19111`
  An instance working on ISO 19111 standard as defined by GeoAPI interfaces in the `org​.opengis​.referencing` package and sub-packages.
  `static final MetadataStandard`
  `ISO_19115`
  An instance working on ISO 19115 standard as defined by GeoAPI interfaces in the `org​.opengis​.metadata` package and sub-packages, except `quality`.
  `static final MetadataStandard`
  `ISO_19123`
  An instance working on ISO 19123 standard as defined by GeoAPI interfaces in the `org​.opengis​.coverage` package and sub-packages.
  `static final MetadataStandard`
  `ISO_19157`
  An instance working on ISO 19157 standard as defined by GeoAPI interfaces in the `org​.opengis​.metadata​.quality` package.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `MetadataStandard(Citation citation, Package interfacePackage, MetadataStandard... dependencies)`
  Creates a new instance working on implementation of interfaces defined in the specified package.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `Map<String,Integer>`
  `asIndexMap(Class<?> type, KeyNamePolicy keyPolicy)`
  Returns indices for all properties defined in the given metadata type.
  `Map<String,ExtendedElementInformation>`
  `asInformationMap(Class<?> type, KeyNamePolicy keyPolicy)`
  Returns information about all properties defined in the given metadata type.
  `Map<String,String>`
  `asNameMap(Class<?> type, KeyNamePolicy keyPolicy, KeyNamePolicy valuePolicy)`
  Returns the names of all properties defined in the given metadata type.
  `TreeTable`
  `asTreeTable(Object metadata, Class<?> baseType, ValueExistencePolicy valuePolicy)`
  Returns the specified metadata object as a tree table.
  `Map<String,Class<?>>`
  `asTypeMap(Class<?> type, KeyNamePolicy keyPolicy, TypeValuePolicy valuePolicy)`
  Returns the type of all properties, or their declaring type, defined in the given metadata type.
  `Map<String,Object>`
  `asValueMap(Object metadata, Class<?> baseType, KeyNamePolicy keyPolicy, ValueExistencePolicy valuePolicy)`
  Returns a view of the specified metadata object as a `Map`.
  `boolean`
  `equals(Object metadata1, Object metadata2, ComparisonMode mode)`
  Compares the two specified metadata objects.
  `static MetadataStandard`
  `forClass(Class<?> type)`
  Returns the metadata standard for the given class.
  `Citation`
  `getCitation()`
  Returns a bibliographical reference to the international standard.
  `<T> Class<? extends T>`
  `getImplementation(Class<T> type)`
  Returns the implementation class for the given interface, or `null` if none.
  `<T> Class<? super T>`
  `getInterface(Class<T> type)`
  Returns the metadata interface implemented by the specified implementation class.
  `int`
  `hashCode(Object metadata)`
  Computes a hash code for the specified metadata.
  `boolean`
  `isMetadata(Class<?> type)`
  Returns `true` if the given type is assignable to a type from this standard or one of its dependencies.
  `String`
  `toString()`
  Returns a string representation of this metadata standard.

  ### Methods inherited from class Object

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

- ## Field Details

  - ### ISO_19115

    public static final MetadataStandard ISO_19115
    An instance working on ISO 19115 standard as defined by GeoAPI interfaces in the `org​.opengis​.metadata` package and sub-packages, except `quality`.

  - ### ISO_19157

    public static final MetadataStandard ISO_19157
    An instance working on ISO 19157 standard as defined by GeoAPI interfaces in the `org​.opengis​.metadata​.quality` package.
    Since:
      1.3

  - ### ISO_19111

    public static final MetadataStandard ISO_19111
    An instance working on ISO 19111 standard as defined by GeoAPI interfaces in the `org​.opengis​.referencing` package and sub-packages.

  - ### ISO_19123

    public static final MetadataStandard ISO_19123
    An instance working on ISO 19123 standard as defined by GeoAPI interfaces in the `org​.opengis​.coverage` package and sub-packages.

- ## Constructor Details

  - ### MetadataStandard

    public MetadataStandard(Citation citation, Package interfacePackage, MetadataStandard... dependencies)
    Creates a new instance working on implementation of interfaces defined in the specified package. If this `MetadataStandard` does not support a given class, then the dependencies will be tested in the order declared to this constructor. Consequently, if `isMetadata(Class)` may return `true` for two or more dependencies, then the dependency which should have precedence should be declared first.

    #### Example

    For the ISO 19157 standard reflected by GeoAPI interfaces, `interfacePackage` shall be the `org​.opengis​.metadata​.quality` package. Its dependency is `ISO_19115` in the `org​.opengis​.metadata` package.
    Parameters:
      `citation` - bibliographical reference to the international standard.
      `interfacePackage` - the root package for metadata interfaces.
      `dependencies` - the dependencies to other metadata standards.

- ## Method Details

  - ### forClass

    public static MetadataStandard forClass(Class<?> type)
    Returns the metadata standard for the given class. The argument given to this method can be either an interface defined by the standard, or a class implementing such interface. If the class implements more than one interface, then the first interface recognized by this method, in declaration order, will be retained.

    The current implementation recognizes only the standards defined by the public static constants defined in this class. A future SIS version may recognize user-defined constants.

    Parameters:
      `type` - the metadata standard interface, or an implementation class.
    Returns:
      the metadata standard for the given type, or `null` if not found.

  - ### getCitation

    public Citation getCitation()
    Returns a bibliographical reference to the international standard. The default implementation return the citation given at construction time.
    Returns:
      bibliographical reference to the international standard.

  - ### isMetadata

    public boolean isMetadata(Class<?> type)
    Returns `true` if the given type is assignable to a type from this standard or one of its dependencies. If this method returns `true`, then invoking `getInterface(Class)` is guaranteed to succeed without throwing an exception.
    Parameters:
      `type` - the implementation class (can be `null`).
    Returns:
      `true` if the given class is an interface of this standard, or implements an interface of this standard.

  - ### getInterface

    public <T> Class<? super T> getInterface(Class<T> type) throws ClassCastException
    Returns the metadata interface implemented by the specified implementation class. If the given type is already an interface from this standard, then it is returned unchanged.
    Note: The word "interface" may be taken in a looser sense than the usual Java sense because if the given type is defined in this standard package, then it is returned unchanged. The standard package is usually made of interfaces and code lists only, but this is not verified by this method.
    Type Parameters:
      `T` - the compile-time `type`.
    Parameters:
      `type` - the implementation class.
    Returns:
      the interface implemented by the given implementation class.
    Throws:
      `ClassCastException` - if the specified implementation class does not implement an interface of this standard.
    See Also:
      - `AbstractMetadata​.getInterface()`

  - ### getImplementation

    public <T> Class<? extends T> getImplementation(Class<T> type)
    Returns the implementation class for the given interface, or `null` if none. If non-null, the returned class must have a public no-argument constructor and the metadata instance created by that constructor must be initially empty (no default value). That no-argument constructor should never throw any checked exception.

    The default implementation returns `null` in every cases. Subclasses shall override this method in order to map GeoAPI interfaces to their implementation.

    Type Parameters:
      `T` - the compile-time `type`.
    Parameters:
      `type` - the interface, typically from the `org​.opengis​.metadata` package.
    Returns:
      the implementation class, or `null` if none.

  - ### asNameMap

    public Map<String,String> asNameMap(Class<?> type, KeyNamePolicy keyPolicy, KeyNamePolicy valuePolicy) throws ClassCastException
    Returns the names of all properties defined in the given metadata type. The property names appears both as keys and as values, but may be written differently. The names may be standard identifiers (e.g. as defined by ISO 19115), JavaBeans names, method names or sentences (usually in English).

    #### Example

    The following code prints `"alternateTitles"` (note the plural):

        MetadataStandard standard = MetadataStandard.ISO_19115;
        Map<String, String> names = standard.asNameMap(Citation.class, UML_IDENTIFIER, JAVABEANS_PROPERTY);
        String value = names.get("alternateTitle");
        System.out.println(value);                   // alternateTitles

    The `keyPolicy` argument specify only the string representation of keys returned by the iterators. No matter the key name policy, the `key` argument given to any `Map` method can be any of the above-cited forms of property names.
    Parameters:
      `type` - the interface or implementation class of a metadata.
      `keyPolicy` - determines the string representation of map keys.
      `valuePolicy` - determines the string representation of map values.
    Returns:
      the names of all properties defined by the given metadata type.
    Throws:
      `ClassCastException` - if the specified interface or implementation class does not extend or implement a metadata interface of the expected package.

  - ### asTypeMap

    public Map<String,Class<?>> asTypeMap(Class<?> type, KeyNamePolicy keyPolicy, TypeValuePolicy valuePolicy) throws ClassCastException
    Returns the type of all properties, or their declaring type, defined in the given metadata type. The keys in the returned map are the same than the keys in the above name map. The values are determined by the `valuePolicy` argument, which can be element type or the declaring interface among others.

    #### Example

    the following code prints the `InternationalString` class name:

        MetadataStandard  standard = MetadataStandard.ISO_19115;
        Map<String,Class<?>> types = standard.asTypeMap(Citation.class, UML_IDENTIFIER, ELEMENT_TYPE);
        Class<?> value = types.get("alternateTitle");
        System.out.println(value);                       // class org.opengis.util.InternationalString

    Parameters:
      `type` - the interface or implementation class of a metadata.
      `keyPolicy` - determines the string representation of map keys.
      `valuePolicy` - whether the values shall be property types, the element types (same as property types except for collections) or the declaring interface or class.
    Returns:
      the types or declaring type of all properties defined in the given metadata type.
    Throws:
      `ClassCastException` - if the specified interface or implementation class does not extend or implement a metadata interface of the expected package.

  - ### asInformationMap

    public Map<String,ExtendedElementInformation> asInformationMap(Class<?> type, KeyNamePolicy keyPolicy) throws ClassCastException
    Returns information about all properties defined in the given metadata type. The keys in the returned map are the same than the keys in the above name map. The values contain information inferred from the ISO names, the `Obligation` enumeration and the `ValueRange` annotations.

    In the particular case of Apache SIS implementation, all values in the information map additionally implement the following interfaces:

    - `ReferenceIdentifier` with the following properties:
      - The authority is this metadata standard citation.
      - The codespace is the standard name of the interface that contain the property.
      - The code is the standard name of the property.
    - `CheckedContainer` with the following properties:
      - The element type is the type of property values as defined by `TypeValuePolicy​.ELEMENT_TYPE`.
    Note: the rational for implementing `CheckedContainer` is to consider each `ExtendedElementInformation` instance as the set of all possible values for the property. If the information had a `contains(E)` method, it would return `true` if the given value is valid for that property.
    In addition, for each map entry the value returned by `ExtendedElementInformation​.getDomainValue()` may optionally be an instance of any of the following classes:
    - `NumberRange` if the valid values are constrained to some specific range.
    Parameters:
      `type` - the metadata interface or implementation class.
      `keyPolicy` - determines the string representation of map keys.
    Returns:
      information about all properties defined in the given metadata type.
    Throws:
      `ClassCastException` - if the given type does not implement a metadata interface of the expected package.
    See Also:
      - `DefaultExtendedElementInformation`

  - ### asIndexMap

    public Map<String,Integer> asIndexMap(Class<?> type, KeyNamePolicy keyPolicy) throws ClassCastException
    Returns indices for all properties defined in the given metadata type. The keys in the returned map are the same than the keys in the above name map. The values are arbitrary indices numbered from 0 inclusive to n exclusive, where n is the number of properties declared in the given metadata type.

    Property indices may be used as an alternative to property names by some applications doing their own storage. Such index usages are fine for temporary storage during the Java Virtual Machine lifetime, but indices should not be used in permanent storage. The indices are stable as long as the metadata implementation does not change, but may change when the implementation is upgraded to a newer version.

    Parameters:
      `type` - the interface or implementation class of a metadata.
      `keyPolicy` - determines the string representation of map keys.
    Returns:
      indices of all properties defined by the given metadata type.
    Throws:
      `ClassCastException` - if the specified interface or implementation class does not extend or implement a metadata interface of the expected package.

  - ### asValueMap

    public Map<String,Object> asValueMap(Object metadata, Class<?> baseType, KeyNamePolicy keyPolicy, ValueExistencePolicy valuePolicy) throws ClassCastException
    Returns a view of the specified metadata object as a `Map`. The map is backed by the metadata object using Java reflection, so changes in the underlying metadata object are immediately reflected in the map and conversely.

    The map content is determined by the arguments: `metadata` determines the set of keys, `keyPolicy` determines their `String` representations of those keys and `valuePolicy` determines whether entries having a null value or an empty collection shall be included in the map.

    #### Supported operations

    The map supports the `put(…)` and `remove(…)` operations if the underlying metadata object contains setter methods. The `remove(…)` method is implemented by a call to `put(…, null)`. Note that whether the entry appears as effectively removed from the map or just cleared (i.e. associated to a null value) depends on the `valuePolicy` argument.

    #### Keys and values

    The keys are case-insensitive and can be either the JavaBeans property name, the getter method name or the UML identifier. The value given to a call to the `put(…)` method shall be an instance of the type expected by the corresponding setter method, or an instance of a type convertible to the expected type.

    #### Multi-values entries

    Calls to `put(…)` replace the previous value, with one noticeable exception: if the metadata property associated to the given key is a `Collection` but the given value is a single element (not a collection), then the given value is added to the existing collection. In other words, the returned map behaves as a multi-values map for the properties that allow multiple values. If the intent is to unconditionally discard all previous values, then make sure that the given value is a collection when the associated metadata property expects such collection.

    #### Disambiguating instances that implement more than one metadata interface

    It is some time convenient to implement more than one interface by the same class. For example, an implementation interested only in extents defined by geographic bounding boxes could implement `Extent` and `GeographicBoundingBox` by the same class. In such case, it is necessary to tell to this method which one of those two interfaces shall be reflected in the returned map. This information can be provided by the `baseType` argument. That argument needs to be non-null only in situations where an ambiguity can arise; `baseType` can be null if the given metadata implements only one interface recognized by this `MetadataStandard` instance.
    Parameters:
      `metadata` - the metadata object to view as a map.
      `baseType` - base type of the metadata of interest, or `null` if unspecified.
      `keyPolicy` - determines the string representation of map keys.
      `valuePolicy` - whether the entries having null value or empty collection shall be included in the map.
    Returns:
      a map view over the metadata object.
    Throws:
      `ClassCastException` - if the metadata object does not implement a metadata interface of the expected package.
    Since:
      0.8
    See Also:
      - `AbstractMetadata​.asMap()`

  - ### asTreeTable

    public TreeTable asTreeTable(Object metadata, Class<?> baseType, ValueExistencePolicy valuePolicy) throws ClassCastException
    Returns the specified metadata object as a tree table. The tree table is backed by the metadata object using Java reflection, so changes in the underlying metadata object are immediately reflected in the tree table and conversely.

    The returned `TreeTable` instance contains the following columns:

    - `TableColumn​.IDENTIFIER`
      The UML identifier if any, or the Java Beans property name otherwise, of a metadata property. For example in a tree table view of `DefaultCitation`, there is a node having the `"title"` identifier.
    - `TableColumn​.INDEX`
      If the metadata property is a collection, then the zero-based index of the element in that collection. Otherwise `null`. For example, in a tree table view of `DefaultCitation`, if the `"alternateTitle"` collection contains two elements, then there is a node with index 0 for the first element and another node with index 1 for the second element.
      Note: The `(IDENTIFIER, INDEX)` pair can be used as a primary key for uniquely identifying a node in a list of children. That uniqueness is guaranteed only for the children of a given node; the same keys may appear in the children of any other nodes.
    - `TableColumn​.NAME`
      A human-readable name for the node, derived from the identifier and the index. This is the column shown in the default `toString()` implementation and may be localizable.
    - `TableColumn​.TYPE`
      The base type of the value (usually an interface).
    - `TableColumn​.VALUE`
      The metadata value for the node. Values in this column are writable if the underlying metadata class have a setter method for the property represented by the node.
    - `TableColumn​.REMARKS`
      Remarks or warning on the property value. This is rarely present. It is provided when the value may look surprising, for example the longitude values in a geographic bounding box crossing the anti-meridian.

    #### Write operations

    Only the `VALUE` column may be writable, with one exception: newly created children need to have their `IDENTIFIER` set before any other operation. For example, the following code adds a title to a citation:

        TreeTable.Node node = ...;                               // The node for a DefaultCitation.
        TreeTable.Node child = node.newChild();
        child.setValue(TableColumn.IDENTIFIER, "title");
        child.setValue(TableColumn.VALUE, "Le petit prince");
        // Nothing else to do - the child node has been added.

    Nodes can be removed by invoking the `Iterator​.remove()` method on the children iterator. Note that whether the child appears as effectively removed from the node or just cleared (i.e. associated to a null value) depends on the `valuePolicy` argument.

    #### Disambiguating instances that implement more than one metadata interface

    If the given `metadata` instance implements more than one interface recognized by this `MetadataStandard`, then the `baseType` argument need to be non-null in order to specify which interface to reflect in the tree.
    Parameters:
      `metadata` - the metadata object to view as a tree table.
      `baseType` - base type of the metadata of interest, or `null` if unspecified.
      `valuePolicy` - whether the property having null value or empty collection shall be included in the tree.
    Returns:
      a tree table representation of the specified metadata.
    Throws:
      `ClassCastException` - if the metadata object does not implement a metadata interface of the expected package.
    Since:
      0.8
    See Also:
      - `AbstractMetadata​.asTreeTable()`

  - ### equals

    public boolean equals(Object metadata1, Object metadata2, ComparisonMode mode) throws ClassCastException
    Compares the two specified metadata objects. The two metadata arguments shall be implementations of a metadata interface defined by this `MetadataStandard`, otherwise an exception will be thrown. However, the two arguments do not need to be the same implementation class.

    #### Shallow or deep comparisons

    This method implements a shallow comparison in that properties are compared by invoking their `properties​.equals(…)` method without explicit recursive call to this `standard​.equals(…)` method for children metadata. However, the comparison will do implicit recursive calls if the `properties​.equals(…)` implementations delegate their work to this `standard​.equals(…)` method, as `AbstractMetadata` does. In the latter case, the final result is a deep comparison.
    Parameters:
      `metadata1` - the first metadata object to compare.
      `metadata2` - the second metadata object to compare.
      `mode` - the strictness level of the comparison.
    Returns:
      `true` if the given metadata objects are equals.
    Throws:
      `ClassCastException` - if at least one metadata object does not implement a metadata interface of the expected package.
    See Also:
      - `AbstractMetadata​.equals(Object, ComparisonMode)`

  - ### hashCode

    public int hashCode(Object metadata) throws ClassCastException
    Computes a hash code for the specified metadata. The hash code is defined as the sum of hash code values of all non-empty properties, plus the hash code of the interface. This is a similar contract than `Set​.hashCode()` (except for the interface) and ensures that the hash code value is insensitive to the ordering of properties.
    Parameters:
      `metadata` - the metadata object to compute hash code.
    Returns:
      a hash code value for the specified metadata, or 0 if the given metadata is null.
    Throws:
      `ClassCastException` - if the metadata object does not implement a metadata interface of the expected package.
    See Also:
      - `AbstractMetadata​.hashCode()`

  - ### toString

    public String toString()
    Returns a string representation of this metadata standard. This is for debugging purpose only and may change in any future version.
    Overrides:
      `toString` in class `Object`