Class MetadataVisitor<R>

java.lang.Object
org.apache.sis.metadata.MetadataVisitor<R>
Type Parameters:
R - the type of result of walking in the metadata.
Direct Known Subclasses:
HashCode, MetadataCopier, Pruner, StateChanger

abstract class MetadataVisitor<R> extends Object
A visitor of metadata properties with a safety against infinite recursivity. The visitor may compute a result, for example a hash code value or a boolean testing whether the metadata is empty. Each MetadataVisitor instance is used by one thread; this class does not need to be thread-safe.
Since:
1.0
Version:
1.0
  • Field Details

    • SKIP_SIBLINGS

      static final Object SKIP_SIBLINGS
      Sentinel value that may be returned by visit(Class, Object) for notifying the walker to stop. This value causes walk(…) to stop its iteration, but does not stop iteration by the parent if walk(…) has been invoked recursively. The result() method shall return a valid result even if the iteration has been terminated.
    • visited

      private final Map<Object,R> visited
      A guard against infinite recursivity in walk(MetadataStandard, Class, Object, boolean). Keys are visited metadata instances and values are computed value. The value may be null if the computation is in progress.

      The problem

      Cyclic associations can exist in ISO 19115 metadata. For example, Instrument has a reference to the platform it is mounted on, and the Platform has a list of instruments mounted on it. Consequently, walking down the metadata tree can cause infinite recursivity, unless we keep trace of previously visited metadata objects in order to avoid visiting them again. We use an IdentityHashMap for that purpose, since the recursivity problem exists only when revisiting the exact same instance. Furthermore, HashMap would not suit since it invokes equals(Object) and hashCode(), which are among the methods that we want to avoid invoking twice.
    • propertyPath

      private String[] propertyPath
      The name of the property being visited as the last element of the queue. If visit method is invoked recursively, then the properties before the last one are the parent properties. The number of valid elements is nestedCount.
    • nestedCount

      private int nestedCount
      Count of nested calls to walk(MetadataStandard, Class, Object, boolean) method. When this count reach zero, the visitor should be removed from the thread local variable.
      See Also:
    • allowNull

      private boolean allowNull
      Value of the Semaphores.NULL_COLLECTION flag when we started the walk. The NULL_COLLECTION flag prevents creation of new empty collections by getter methods (a consequence of lazy instantiation). The intent is to avoid creation of unnecessary objects for all unused properties. Users should not see behavioral difference, except if they override some getters with an implementation invoking other getters. However in such cases, users would have been exposed to null values at XML marshalling time anyway.
  • Constructor Details

    • MetadataVisitor

      MetadataVisitor()
      Creates a new visitor.
  • Method Details

    • creator

      ThreadLocal<? extends MetadataVisitor<?>> creator()
      The thread-local variable that created this MetadataVisitor instance. This is usually a static final VISITORS constant defined in the subclass. May be null if this visitor does not use thread-local instances.

      If this method returns a non-null value, then ThreadLocal.remove() will be invoked after MetadataVisitor finished to walk through a metadata and all its children.

    • setCurrentProperty

      final void setCurrentProperty(String name)
      Sets the name of the method being visited. This is invoked by PropertyAccessor.walk methods only.
    • getCurrentPropertyPath

      List<String> getCurrentPropertyPath()
      Returns the path to the currently visited property. Each element in the list is the UML identifier of a property. Element at index 0 is the name of the property of the root metadata object being visited. Element at index 1 is the name of a property which is a children of above property, etc.

      The returned list is valid only during visit(Class, Object) method execution. The content of this list become undetermined after the visit method returned.

      Returns:
      the path to the currently visited property.
    • walk

      final R walk(MetadataStandard standard, Class<?> type, Object metadata, boolean mandatory)
      Invokes visit(Class, Object) for all elements of the given metadata if that metadata has not already been visited. The computation result is returned (may be the result of a previous computation).

      This method is typically invoked recursively while we iterate down the metadata tree. It maintains a map of visited nodes for preventing the same node to be visited twice.

      Parameters:
      standard - the metadata standard implemented by the object to visit.
      type - the standard interface implemented by the metadata object, or null if unknown.
      metadata - the metadata to visit.
      mandatory - true for throwing an exception for unsupported metadata type, or false for ignoring.
      Returns:
      the value of result() after all elements of the given metadata have been visited. If the given metadata instance has already been visited, then this is the previously computed value. If the computation is in progress (e.g. a cyclic graph), then this method returns null.
    • preVisit

      Invoked when a new metadata is about to be visited. After this method has been invoked, visit(Class, Object) will be invoked for each property in the metadata object.
      Parameters:
      accessor - information about the standard interface and implementation of the metadata being visited.
      Returns:
      most common values are NON_EMPTY for visiting all non-empty properties (the default), or WRITABLE for visiting only writable properties.
    • visit

      abstract Object visit(Class<?> type, Object value) throws Exception
      Invoked when a new metadata property is being visited. The current property value is given in argument. The return value is interpreted as below:
      • SKIP_SIBLINGS: do not iterate over other properties of current metadata, but continue iteration over properties of the parent metadata.
      • value: continue with next sibling property without setting any value.
      • null: clear the property value, then continue with next sibling property. If the property type is a collection, then "null" value is interpreted as an instruction to clear the collection.
      • Any other value: set the property value to the given value, then continue with next sibling property.
      Parameters:
      type - the type of elements. Note that this is not necessarily the type of given value argument if the latter is a collection.
      value - value of the metadata property being visited.
      Returns:
      the new property value to set, or SKIP_SIBLINGS.
      Throws:
      Exception - if the visit operation failed.
    • result

      R result()
      Returns the result of visiting all elements in a metadata instance. This method is invoked zero or one time per metadata instance. The invocation time depends on the value returned by preVisit(PropertyAccessor): The value returned by this method will be cached in case the same metadata instance is revisited again. This value can be null.