# Class FeatureOperations

Object
Static
FeatureOperations

public final class FeatureOperations extends Static
A set of predefined operations expecting a `Feature` as input and producing an `Attribute` as output. Those operations can be used for creating dynamic properties which compute their value on-the-fly from the values of other properties.

A flexible but relatively cumbersome way to define arbitrary computations is to subclass `AbstractOperation`. This `FeatureOperations` class provides a more convenient way to get a few commonly-used operations.

## Operation name, designation and description

All operations are identified by a programmatic name, but can also have a more human-readable designation for Graphical User Interfaces (GUI). Those identification information are specified in a `Map<String,?>`. The recognized entries are the same as the ones documented in `AbstractIdentifiedType`, augmented with entries that describe the operation result. Those entries are summarized below:

Recognized map entries
Map key | Value type | Returned by
--- | --- | ---
"name" | `GenericName` or `String` | `Operation.getName()` (mandatory)
"definition" | `InternationalString` or `String` | `Operation.getDefinition()`
"designation" | `InternationalString` or `String` | `Operation.getDesignation()`
"description" | `InternationalString` or `String` | `Operation.getDescription()`
"result.name" | `GenericName` or `String` | `Attribute.getName()` on the result
"result.definition" | `InternationalString` or `String` | `Attribute.getDefinition()` on the result
"result.designation" | `InternationalString` or `String` | `Attribute.getDesignation()` on the result
"result.description" | `InternationalString` or `String` | `Attribute.getDescription()` on the result
"locale" | `Locale` | (none)

If no `"result.*"` entry is provided, then the methods in this class will use some default name, designation and other information for the result type. Those defaults are operation specific; they are often, but not necessarily, the same as the operation name, designation, etc.

Since:
  0.7

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static AbstractOperation`
  `compound(Map<String,?> identification, String delimiter, String prefix, String suffix, AbstractIdentifiedType... singleAttributes)`
  Creates an operation concatenating the string representations of the values of multiple properties.
  `static AbstractOperation`
  `envelope(Map<String,?> identification, CoordinateReferenceSystem crs, AbstractIdentifiedType... geometryAttributes)`
  Creates an operation computing the envelope that encompass all geometries found in the given attributes.
  `static <V> AbstractOperation`
  `expression(Map<String,?> identification, Expression<? super AbstractFeature, ?> expression, DefaultAttributeType<V> resultType)`
  Creates an operation which delegates the computation to a given expression producing values of unknown type.
  `static Expression<? super AbstractFeature, ?>`
  `expressionOf(AbstractIdentifiedType property)`
  Returns an expression for fetching the values of properties identified by the given type.
  `static <V> AbstractOperation`
  `function(Map<String,?> identification, Function<? super AbstractFeature, ? extends V> expression, DefaultAttributeType<? super V> resultType)`
  Creates an operation which delegates the computation to a given expression.
  `static AbstractOperation`
  `groupAsPolyline(Map<String,?> identification, GeometryLibrary library, AbstractIdentifiedType components)`
  Creates a single geometry from a sequence of points or polylines stored in another property.
  `static AbstractOperation`
  `link(Map<String,?> identification, AbstractIdentifiedType referent)`
  Creates an operation which is only an alias for another property.

  ### Methods inherited from class Object

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

- ## Method Details

  - ### link

    public static AbstractOperation link(Map<String,?> identification, AbstractIdentifiedType referent)
    Creates an operation which is only an alias for another property.

    #### Example

    Features often have a property that can be used as identifier or primary key. But the name of that property may vary between features of different types. For example, features of type Country may have identifiers named “ISO country code” while features of type Car may have identifiers named “license plate number”. In order to simplify identifier usages regardless of their name, an application could choose to add in all features a virtual property named `"identifier"` which links to whatever property is used as an identifier in an arbitrary feature. So the definition of the Car feature could contain the following code:

        AttributeType licensePlateNumber = ...;            // Attribute creation omitted for brevity
        FeatureType car = new DefaultFeatureType(...,      // Arguments omitted for brevity
                licensePlateNumber, model, owner,
                FeatureOperations.link(Map.of(NAME_KEY, "identifier"), licensePlateNumber);

    Since this method does not create new property (it only redirects to an existing property), this method ignores all `"result.*"` entries in the given `identification` map.

    #### Read/write behavior

    Since the `Operation​.apply(…)` method returns directly the property identified by the `referent` argument, the returned property is writable if the referenced property is also writable.
    Warning: The type of `referent` parameter will be changed to `PropertyType` if and when such interface will be defined in GeoAPI.
    Parameters:
      `identification` - the name and other information to be given to the operation.
      `referent` - the referenced attribute or feature association.
    Returns:
      an operation which is an alias for the `referent` property.
    See Also:
      - `Features​.getLinkTarget(AbstractIdentifiedType)`

  - ### compound

    public static AbstractOperation compound(Map<String,?> identification, String delimiter, String prefix, String suffix, AbstractIdentifiedType... singleAttributes)
    Creates an operation concatenating the string representations of the values of multiple properties. This operation can be used for creating a compound key as a `String` that consists of two or more attribute values that uniquely identify a feature instance.

    The `delimiter`, `prefix` and `suffix` arguments given to this method are used in the same way as `StringJoiner`, except for null values. Null prefix, suffix and property values are handled as if they were empty strings.

    If the same character sequences as the given delimiter appears in a property value, the `'\'` escape character will be inserted before that sequence. If the `'\'` character appears in a property value, it will be doubled.

    #### Restrictions

    - The single properties can be either attributes or operations that produce attributes; feature associations are not allowed, unless they have an `"sis:identifier"` property.
    - Each attribute shall contain at most one value; multi-valued attributes are not allowed.
    - The delimiter cannot contain the `'\'` escape character.

    #### Read/write behavior

    This operation supports both reading and writing. When setting a value on the attribute created by this operation, the given string value will be split around the `delimiter` and each substring will be forwarded to the corresponding single property.
    Warning: The type of `singleAttributes` elements will be changed to `PropertyType` if and when such interface will be defined in GeoAPI.
    Parameters:
      `identification` - the name and other information to be given to the operation.
      `delimiter` - the characters to use as delimiter between each single property value.
      `prefix` - characters to use at the beginning of the concatenated string, or `null` if none.
      `suffix` - characters to use at the end of the concatenated string, or `null` if none.
      `singleAttributes` - identification of the single attributes (or operations producing attributes) to concatenate.
    Returns:
      an operation which concatenates the string representations of all referenced single property values.
    Throws:
      `IllegalArgumentException` - if `singleAttributes` is an empty sequence, or contains a property which is neither an `AttributeType` or an `Operation` computing an attribute, or an attribute has a maximum number of occurrences greater than 1, or uses a value class not convertible from a `String`.
    See Also:
      - Compound key on Wikipedia

  - ### envelope

    public static AbstractOperation envelope(Map<String,?> identification, CoordinateReferenceSystem crs, AbstractIdentifiedType... geometryAttributes) throws FactoryException
    Creates an operation computing the envelope that encompass all geometries found in the given attributes. Geometries can be in different coordinate reference systems, in which case they will be transformed to the first non-null CRS in the following choices:
    1. the CRS specified to this method,
    2. the CRS of the default geometry, or
    3. the CRS of the first non-empty geometry.
    The result of this operation is an `Attribute` with values of type `Envelope`. If the `crs` argument given to this method is non-null, then the envelope CRS will be that CRS.

    #### Limitations

    If a geometry contains other geometries, this operation queries only the envelope of the root geometry. It is the root geometry responsibility to take in account the envelope of all its children.

    #### Read/write behavior

    This operation is read-only. Calls to `Attribute​.setValue(Envelope)` will result in an `UnsupportedOperationException` to be thrown.
    Warning: The type of `geometryAttributes` elements will be changed to `PropertyType` if and when such interface will be defined in GeoAPI.
    Parameters:
      `identification` - the name and other information to be given to the operation.
      `crs` - the Coordinate Reference System in which to express the envelope, or `null`.
      `geometryAttributes` - the operation or attribute type from which to get geometry values. Any element which is `null` or has a non-geometric value class will be ignored.
    Returns:
      an operation which will compute the envelope encompassing all geometries in the given attributes.
    Throws:
      `FactoryException` - if a coordinate operation to the target CRS cannot be created.

  - ### groupAsPolyline

    public static AbstractOperation groupAsPolyline(Map<String,?> identification, GeometryLibrary library, AbstractIdentifiedType components)
    Creates a single geometry from a sequence of points or polylines stored in another property. When evaluated, this operation reads a feature property containing a sequence of `Point`s or `Polyline`s. Those geometries shall be instances of the specified geometry library (e.g. JTS or ESRI). The merged geometry is usually a `Polyline`, unless the sequence of source geometries is empty or contains a single element. The merged geometry is re-computed every time that the operation is evaluated.

    #### Examples

    Polylines created from points: a boat that record it's position every hour. The input is a list of all positions stored in an attribute with [0 … ∞] multiplicity. This operation will extract each position and create a line as a new attribute.

    Polylines created from other polylines: a boat that record track every hour. The input is a list of all tracks stored in an attribute with [0 … ∞] multiplicity. This operation will extract each track and create a polyline as a new attribute.

    #### Read/write behavior

    This operation is read-only. Calls to `Attribute​.setValue(…)` will result in an `UnsupportedOperationException` to be thrown.
    Parameters:
      `identification` - the name of the operation, together with optional information.
      `library` - the library providing the implementations of geometry objects to read and write.
      `components` - attribute, association or operation providing the geometries to group as a polyline.
    Returns:
      a feature operation which computes its values by merging points or polylines.
    Since:
      1.4

  - ### function

    public static <V> AbstractOperation function(Map<String,?> identification, Function<? super AbstractFeature, ? extends V> expression, DefaultAttributeType<? super V> resultType)
    Creates an operation which delegates the computation to a given expression. The `expression` argument should generally be an instance of `Expression`, but more generic functions are accepted as well.

    #### Read/write behavior

    This operation is read-only. Calls to `Attribute​.setValue(…)` will result in an `UnsupportedOperationException` to be thrown.
    Type Parameters:
      `V` - the type of values computed by the expression and assigned to the feature property.
    Parameters:
      `identification` - the name of the operation, together with optional information.
      `expression` - the expression to evaluate on feature instances.
      `resultType` - type of values computed by the expression.
    Returns:
      a feature operation which computes its values using the given expression.
    Since:
      1.4

  - ### expression

    public static <V> AbstractOperation expression(Map<String,?> identification, Expression<? super AbstractFeature, ?> expression, DefaultAttributeType<V> resultType)
    Creates an operation which delegates the computation to a given expression producing values of unknown type. This method can be used as an alternative to `function(…)` when the constraint on the parameterized type `<V>` between `expression` and `result` cannot be enforced at compile time. This method casts or converts the expression to the expected type by a call to `Expression​.toValueType(Class)`.

    #### Read/write behavior

    This operation is read-only. Calls to `Attribute​.setValue(…)` will result in an `UnsupportedOperationException` to be thrown.
    Type Parameters:
      `V` - the type of values computed by the expression and assigned to the feature property.
    Parameters:
      `identification` - the name of the operation, together with optional information.
      `expression` - the expression to evaluate on feature instances.
      `resultType` - type of values computed by the expression.
    Returns:
      a feature operation which computes its values using the given expression.
    Throws:
      `ClassCastException` - if the result type is not a target type supported by the expression.
    Since:
      1.4

  - ### expressionOf

    public static Expression<? super AbstractFeature, ?> expressionOf(AbstractIdentifiedType property)
    Returns an expression for fetching the values of properties identified by the given type. The returned expression will be the first of the following choices which is applicable:
    - If the property is an expression built by `expression(…)`, then the expression given to that method, or a derivative of that expression, is returned.
    - If the property is a link, then a `ValueReference` fetching the link target is returned.
    - Otherwise, a value reference is created for the name of the given property.
    Parameters:
      `property` - the property for which to get an expression.
    Returns:
      an expression for fetching the values of the property identified by the given type.
    Since:
      1.5