| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.util.collection; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| |
| /** |
| * Defines the structure (list of columns) of a table and provides the root of the tree |
| * containing the data. {@code TreeTable} can be seen as a table in which the first |
| * column contains a tree. Every row in this table is a {@link Node} instance, and each |
| * node can have an arbitrary number of {@linkplain Node#getChildren() children} nodes. |
| * |
| * <p>Below is an example of what a two-columns {@code TreeTable} instance may look like |
| * when {@linkplain TreeTableFormat formatted as a text}:</p> |
| * |
| * {@preformat text |
| * Citation |
| * ├─Title…………………………………………………………… Open Geospatial Consortium |
| * ├─Presentation Forms………………………… document digital |
| * ├─Cited Responsible Parties |
| * │ ├─Organisation Name………………… Open Geospatial Consortium |
| * │ ├─Role…………………………………………………… resource provider |
| * │ └─Contact Info |
| * │ └─Online Resource |
| * │ ├─Linkage……………………… http://www.opengeospatial.org/ |
| * │ └─Function…………………… information |
| * └─Identifiers |
| * └─Code…………………………………………………… OGC |
| * } |
| * |
| * <p>In many cases, the columns are known in advance as hard-coded static constants. |
| * Those column constants are typically documented close to the class producing the |
| * {@code TreeTable} instance. Using directly those static constants provides type |
| * safety, as in the following example:</p> |
| * |
| * {@preformat java |
| * TreeTable table = ...; // Put here a TreeTable instance. |
| * TreeTable.Node node = table.getRoot(); |
| * CharSequence name = node.getValue(TableColumn.NAME); |
| * Class<?> type = node.getValue(TableColumn.TYPE); |
| * } |
| * |
| * In the above example, the type of value returned by the {@link Node#getValue(TableColumn)} |
| * method is determined by the column constant. However this approach is possible only when |
| * the table structure is known in advance. If a method needs to work with arbitrary tables, |
| * then that method can get the list of columns by a call to {@link #getColumns()}. However |
| * this column list does not provide the above type-safety. |
| * |
| * @author Martin Desruisseaux (Geomatys) |
| * @version 0.3 |
| * @since 0.3 |
| * @module |
| */ |
| public interface TreeTable { |
| /** |
| * Returns the table columns, in the order they shall be rendered by default. |
| * This method returns the union of all table columns in every nodes of this |
| * tree. However any {@link Node} instance can return {@code null} for a |
| * particular column if the node doesn't have that column. |
| * |
| * @return the union of all table columns in every tree node. |
| * |
| * @see Node#getValue(TableColumn) |
| * @see Node#setValue(TableColumn, Object) |
| */ |
| List<TableColumn<?>> getColumns(); |
| |
| /** |
| * Returns the root node of the tree. |
| * |
| * @return the root node of the tree. |
| */ |
| Node getRoot(); |
| |
| /** |
| * A node in a tree combined with a row in a table. A {@code TreeTable.Node} can be seen as a |
| * tree node associated to a single {@linkplain #getUserObject() user object} (like ordinary trees), |
| * augmented with the capability to describe some aspects of the user object in pre-defined columns. |
| * The list of allowed columns is given by the {@link TreeTable#getColumns()} method. |
| * |
| * <p>The following table summarizes the tree-related and table-related methods:</p> |
| * |
| * <table class="sis"> |
| * <caption>Tree-table methods</caption> |
| * <tr> |
| * <th>Tree-related methods</th> |
| * <th>Table-related methods</th> |
| * </tr> |
| * <tr><td><ul> |
| * <li>{@link #getParent()}</li> |
| * <li>{@link #getChildren()}</li> |
| * <li>{@link #newChild()}</li> |
| * </ul></td> |
| * <td><ul> |
| * <li>{@link #getValue(TableColumn)}</li> |
| * <li>{@link #setValue(TableColumn, Object)}</li> |
| * <li>{@link #isEditable(TableColumn)}</li> |
| * </ul></td></tr> |
| * </table> |
| * |
| * In addition, each {@code Node} can be associated to an arbitrary object by the |
| * {@link #getUserObject()} method. This object is not used directly by the tree tables. |
| * |
| * @author Martin Desruisseaux (IRD, Geomatys) |
| * @version 0.8 |
| * @since 0.3 |
| * @module |
| */ |
| public interface Node { |
| /** |
| * Returns the parent node, or {@code null} if this node is the root of the tree. |
| * |
| * <p>There is intentionally no {@code setParent(Node)} method, as children and parent managements |
| * are highly implementation-dependant. If the {@linkplain #getChildren() children collection} is |
| * modifiable, then implementations are encouraged to update automatically the parent when a child |
| * is <em>added to</em> or <em>removed from</em> that collection.</p> |
| * |
| * @return the parent, or {@code null} if none. |
| * @category tree |
| */ |
| Node getParent(); |
| |
| /** |
| * Returns {@code true} if this node can not have any children. The {@linkplain #getChildren() children |
| * collection} of a leaf node can only be empty, and adding {@linkplain #newChild() new child} |
| * is an unsupported operation. |
| * |
| * <p>This value is provided as a tip for graphical user interfaces, in order to determine if |
| * a node is expandable (even if empty). {@link TreeTableFormat} does not use this value.</p> |
| * |
| * @return {@code true} if this node can not have any children. |
| */ |
| boolean isLeaf(); |
| |
| /** |
| * Returns the children of this node. The returned collection may or may not be modifiable, at |
| * implementation choice. If the collection is modifiable, then it shall be <cite>live</cite>, |
| * i.e. any modification to the returned collection are reflected immediately in the tree. |
| * This allows addition or removal of child nodes as below: |
| * |
| * {@preformat java |
| * TreeTable.Node newNode = new ...; // Create a new node here. |
| * parent.getChildren().add(newNode); |
| * } |
| * |
| * The collection is often a {@link List}, but not necessarily. For some implementations like the |
| * {@linkplain org.apache.sis.metadata.AbstractMetadata#asTreeTable() metadata tree table view}, |
| * compliance to the {@code List} contract is impractical or inefficient. |
| * |
| * @return the children, or an empty collection if none. |
| * @category tree |
| */ |
| Collection<Node> getChildren(); |
| |
| /** |
| * Creates a new child with the same columns than the other children, and adds it to |
| * the {@linkplain #getChildren() children collection}. The new child is typically added at |
| * the end of the collection, but this is not mandatory: implementations can add the child |
| * at whatever position they see fit. |
| * |
| * @return the new child. |
| * @throws UnsupportedOperationException if this node can not add new children. |
| */ |
| Node newChild() throws UnsupportedOperationException; |
| |
| /** |
| * Returns the value in the given column, or {@code null} if none. |
| * |
| * @param <V> the base type of values in the given column. |
| * @param column identifier of the column from which to get the value. |
| * @return the value in the given column, or {@code null} if none. |
| * |
| * @see TreeTable#getColumns() |
| * @category table |
| */ |
| <V> V getValue(TableColumn<V> column); |
| |
| /** |
| * Sets the value for the given column (optional operation). |
| * The {@link #isEditable(TableColumn)} method can be invoked before this setter method |
| * for determining if the given column is modifiable. |
| * |
| * @param <V> the base type of values in the given column. |
| * @param column identifier of the column into which to set the value. |
| * @param value the value to set. |
| * @throws IllegalArgumentException if the given column is not a legal column for this node. |
| * @throws UnsupportedOperationException if values in the given column can not be modified. |
| * |
| * @see TreeTable#getColumns() |
| * @see #isEditable(TableColumn) |
| * @category table |
| */ |
| <V> void setValue(TableColumn<V> column, V value) throws IllegalArgumentException, UnsupportedOperationException; |
| |
| /** |
| * Determines whether the value in the specified column is editable. If the given |
| * column is not a legal column for this {@code Node} instance, then this method |
| * returns {@code false}. |
| * |
| * @param column the column to query. |
| * @return {@code true} if the given column is a legal column for this {@code Node} |
| * implementation and the corresponding value is editable, or {@code false} |
| * otherwise. |
| * @category table |
| */ |
| boolean isEditable(TableColumn<?> column); |
| |
| /** |
| * Returns the user object associated to this node. |
| * The user object is for information purpose only and does not appear in the rendered tree. |
| * It is typically a Java object whose content is splitted into the various table columns. |
| * |
| * <div class="note"><b>Example:</b> |
| * If a {@code CityLocation} class is defined as a (<var>city name</var>, <var>latitude</var>, |
| * <var>longitude</var>) tuple, then a {@code TreeTable.Node} could be defined to have 3 columns for the |
| * above 3 tuple components, and the user object could be the original {@code CityLocation} instance.</div> |
| * |
| * @return any object stored at this node by the user, or {@code null} if none. |
| * @category tree |
| */ |
| Object getUserObject(); |
| |
| /** |
| * Returns {@code true} if the given object is a node with the same content than this node. |
| * For this method, the meaning of <cite>same content</cite> is defined as below: |
| * |
| * <ul> |
| * <li>The given object is also a {@code Node}.</li> |
| * <li>The list returned by {@link TreeTable#getColumns()} is equals for both nodes.</li> |
| * <li>The objects returned by {@link #getValue(TableColumn)} are equal for each column.</li> |
| * <li>The list returned by {@linkplain #getChildren() children} is equals for both node.</li> |
| * </ul> |
| * |
| * The node returned by {@link #getParent()} shall <strong>not</strong> be taken in account. |
| * It is necessary to ignore the parent for consistency with {@linkplain DefaultTreeTable#clone() clone} |
| * and for avoiding infinite recursivity when comparing the children. |
| * A third reason is given in the <cite>purpose</cite> example below. |
| * |
| * <div class="note"><b>Purpose of this method: example with ISO metadata</b><br> |
| * Consider the following tree made of ISO 19115 metadata objects: a platform containing a list of instruments, |
| * and an instrument containing a reference to the platform on which the instrument is installed. In this example, |
| * nodes 2 and 4 contain a reference to the same {@code Platform} instance, so we have a cyclic graph: |
| * |
| * <table class="compact"> |
| * <caption>Metadata tree example</caption> |
| * <tr><th>Node 1:</th><td>{@code }{@linkplain org.apache.sis.metadata.iso.acquisition.DefaultAcquisitionInformation Acquisition information}</td></tr> |
| * <tr><th>Node 2:</th><td>{@code └─}{@linkplain org.apache.sis.metadata.iso.acquisition.DefaultPlatform Platform}</td></tr> |
| * <tr><th>Node 3:</th><td>{@code └─}{@linkplain org.apache.sis.metadata.iso.acquisition.DefaultInstrument Instrument}</td></tr> |
| * <tr><th>Node 4:</th><td>{@code └─}{@linkplain org.apache.sis.metadata.iso.acquisition.DefaultPlatform Platform} (same instance than above)</td></tr> |
| * <tr><th>Node 5:</th><td>{@code └─}<i>etc…</i></td></tr> |
| * </table> |
| * |
| * The {@link org.apache.sis.metadata.AbstractMetadata#asTreeTable()} method gives a view in which each node |
| * has its content fully generated from wrapped metadata object. Consequently a naive walk over the above tree |
| * causes an infinite loop with {@code TreeTable} generating nodes with identical content as we bounce between |
| * {@code Platform} and {@code Instrument} metadata objects. To break this loop, we need to know when the |
| * <em>content</em> of a node (in this example, the wrapped metadata object) has already been visited. |
| * The parent shall <strong>not</strong> be taken in account since node 2 and 4 have different parents |
| * despite having the same {@code Platform} content. |
| * |
| * <p>In this use case, the {@code Node.equals(Object)} implementation needs only to compare the wrapped |
| * metadata (usually given by the {@linkplain #getUserObject() user object}) since the node content, |
| * including the list of children, is fully determined by those metadata. An identity comparison |
| * (with {@code ==}) is sufficient for the purpose of avoiding infinite recursivity.</p></div> |
| * |
| * <div class="section">Flexibility in implementations</div> |
| * The above list specifies minimal conditions that must be true when two nodes are considered equal. |
| * Implementations should not relax those conditions, but are free to make them more restrictive. |
| * In particular, many implementations will require that the two nodes are instances of the same class. |
| * Some implementations may also perform identity comparisons (with the {@code ==} operator) between values |
| * instead than using {@link Object#equals(Object)}. This flexibility means that even if all above conditions |
| * are true, this is not a guarantee that this method will return {@code true}. |
| * |
| * <p>It is okay to <em>not</em> override this method at all since the identity comparison inherited from |
| * {@link Object#equals(Object)} is consistent with this method contract. Alternatively, {@code Node} |
| * implementations having a content fully determined by the wrapped {@linkplain #getUserObject() user |
| * object} need only the following implementation:</p> |
| * |
| * {@preformat java |
| * @Override |
| * public boolean equals(Object obj) { |
| * return (obj instanceof MyNode) && ((MyNode) obj).getUserObject() == getUserObject(); |
| * } |
| * } |
| * |
| * Implementation details may vary, for example in the way to compare {@code null} user objects or by invoking |
| * {@link Object#equals(Object)} instead than performing identity comparisons. Note however that since this |
| * method purpose is to detect cyclic graphs (see above example), user objects should be compared with |
| * {@code equals(Object)} only if their implementations are known to be safe against infinite recursivity. |
| * |
| * @param other the other object to compare with this node. |
| * @return whether the two objects are nodes with equal values and equal children, ignoring parents. |
| * |
| * @since 0.8 |
| */ |
| @Override |
| boolean equals(Object other); |
| |
| /** |
| * Returns a hash code value consistent with the {@code equals(Object)} implementation for this node. |
| * If the {@link #equals(Object)} method has not been overridden, then this {@code hashCode()} method |
| * should not be overridden neither. Otherwise if this node content ({@linkplain #getValue values} and |
| * {@linkplain #getChildren() children}) is fully generated from the {@linkplain #getUserObject() user |
| * object}, then the {@code equals(…)} and {@code hashCode()} methods may be implemented like below: |
| * |
| * {@preformat java |
| * @Override |
| * public boolean equals(Object obj) { |
| * return (obj instanceof MyNode) && ((MyNode) obj).getUserObject() == getUserObject(); |
| * } |
| * |
| * @Override |
| * public int hashCode() { |
| * return System.identityHashCode(getUserObject()); |
| * } |
| * } |
| * |
| * Otherwise this method should compute a hash code based on values and children of this node, ignoring parent. |
| * |
| * @return a hash code for this node, potentially based on values and children but ignoring parent. |
| * |
| * @since 0.8 |
| */ |
| @Override |
| int hashCode(); |
| } |
| } |