blob: c6865e36b7443b40f210643c144bd6cd90ff623e [file] [log] [blame]
/*
* 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.jackrabbit.oak.api;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A tree instance represents a snapshot of the {@link ContentRepository}
* tree at the time the instance was acquired from a {@link ContentSession}.
* Tree instances may become invalid over time due to garbage collection of
* old content, at which point an outdated snapshot will start throwing
* {@code IllegalStateException}s to indicate that the snapshot is no
* longer available.
*
* <h2>Order and orderability</h2>
* The children of a {@code Tree} are generally unordered. That is, the
* sequence of the children returned by {@link #getChildren()} may change over
* time as this {@code Tree} is modified either directly or through some other
* session. Calling {@link #orderBefore(String)} will persist the current order
* and maintain the order as new children are added or removed. In this case a
* new child will be inserted after the last child as seen by {@link #getChildren()}.
*
* <h2>State and state transitions</h2>
* A tree instance belongs to the client and its state is only modified
* in response to method calls made by the client. The various accessors
* on this interface mirror these of the underlying {@code NodeState}
* interface. However, since instances of this class are mutable return
* values may change between invocations.
* <p>
* All tree instances created in the context of a content session become invalid
* after the content session is closed. Any method called on an invalid tree instance
* will throw an {@code InvalidStateException}.
* <p>
* {@link Tree} instances may become non existing after a call to
* {@link Root#refresh()}, {@link Root#rebase()} or {@link Root#commit()}.
* Any write access to non existing {@code Tree} instances will cause an
* {@code InvalidStateException}.
*
* <h2>Thread safety</h2>
* Tree instances are not thread-safe for write access, so writing clients
* need to ensure that they are not accessed concurrently from multiple
* threads. Instances are however thread-safe for read access, so
* implementations need to ensure that all reading clients see a
* coherent state.
*
* <h2>Visibility and access control</h2>
* The data returned by this class and intermediary objects such as are access
* controlled governed by the {@code ContentSession} instance from which
* the containing {@code Root} was obtained.
*
* <h2>Existence and iterability of trees</h2>
* <p>
* The {@link #getChild(String)} method is special in that it <em>never</em>
* returns a {@code null} value, even if the named tree does not exist.
* Instead a client should use the {@link #exists()} method on the returned
* tree to check whether that tree exists.
* <p>
* The <em>iterability</em> of a tree is a related to existence. A node
* state is <em>iterable</em> if it is included in the return values of the
* {@link #getChildrenCount(long)} and {@link #getChildren()} methods. An iterable
* node is guaranteed to exist, though not all existing nodes are necessarily
* iterable.
* <p>
* Furthermore, a non-existing node is guaranteed to contain no properties
* or iterable child nodes. It can, however contain non-iterable children.
* Such scenarios are typically the result of access control restrictions.
*/
public interface Tree {
/**
* Status of an item in a {@code Tree}
*/
enum Status {
/**
* Item is unchanged
*/
UNCHANGED,
/**
* Item is new
*/
NEW,
/**
* Item is modified: has added or removed children or added, removed or modified
* properties.
*/
MODIFIED
}
/**
* @return the name of this {@code Tree} instance.
*/
@NotNull
String getName();
/**
* @return {@code true} iff this is the root
*/
boolean isRoot();
/**
* @return the absolute path of this {@code Tree} instance from its {@link Root}.
*/
@NotNull
String getPath();
/**
* Get the {@code Status} of this tree instance.
*
* @return The status of this tree instance.
*/
@NotNull
Status getStatus();
/**
* Determine whether this tree has been removed or does not exist otherwise (e.g. caused
* by a refresh, rebase or commit) or is not visible due to access control restriction
* or does not exist at all.
* @return {@code true} if this tree exists, {@code false} otherwise.
*/
boolean exists();
/**
* @return the possibly non existent parent of this {@code Tree}.
* @throws IllegalStateException if called on the root tree.
*/
@NotNull
Tree getParent();
/**
* Get a property state
*
* @param name The name of the property state.
* @return the property state with the given {@code name} or {@code null}
* if no such property state exists or the property is not accessible.
*/
@Nullable
PropertyState getProperty(@NotNull String name);
/**
* Get the {@code Status} of a property state or {@code null}.
*
* @param name The name of the property state.
* @return The status of the property state with the given {@code name}
* or {@code null} in no such property state exists or if the name refers
* to a property that is not accessible.
*/
@Nullable
Status getPropertyStatus(@NotNull String name);
/**
* Determine if a property state exists and is accessible.
*
* @param name The name of the property state
* @return {@code true} if and only if a property with the given {@code name}
* exists and is accessible.
*/
boolean hasProperty(@NotNull String name);
/**
* Determine the number of properties accessible to the current content session.
*
* @return The number of accessible properties.
*/
long getPropertyCount();
/**
* All accessible property states. The returned {@code Iterable} has snapshot
* semantics. That is, it reflect the state of this {@code Tree} instance at
* the time of the call. Later changes to this instance are no visible to
* iterators obtained from the returned iterable.
*
* @return An {@code Iterable} for all accessible property states.
*/
@NotNull
Iterable<? extends PropertyState> getProperties();
/**
* Get a possibly non existing child of this {@code Tree}.
* @param name The name of the child to retrieve.
* @return The child with the given {@code name}.
* @throws IllegalArgumentException if the given name is invalid
*/
@NotNull
Tree getChild(@NotNull String name) throws IllegalArgumentException;
/**
* Determine if a child of this {@code Tree} instance exists. If no child
* exists or an existing child isn't accessible this method returns {@code false}.
*
* @param name The name of the child
* @return {@code true} if and only if a child with the given {@code name}
* exists and is accessible for the current content session.
*/
boolean hasChild(@NotNull String name);
/**
* Determine the number of children of this {@code Tree} instance taking
* access restrictions into account.
* <p>
* If an implementation does know the exact value, it returns it (even if
* the value is higher than max). If the implementation does not know the
* exact value, and the child node count is higher than max, it may return
* Long.MAX_VALUE. The cost of the operation is at most O(max).
*
* @param max the maximum value
* @return the number of accessible children.
*/
long getChildrenCount(long max);
/**
* All accessible children of this {@code Tree} instance. The returned
* {@code Iterable} has snapshot semantics. That is, it reflect the state of
* this {@code Tree} instance at the time of the call. Later changes to this
* instance are not visible to iterators obtained from the returned iterable.
*
* @return An {@code Iterable} for all accessible children
*/
@NotNull
Iterable<Tree> getChildren();
/**
* Remove this tree instance. This operation never succeeds for the root tree.
*
* @return {@code true} if the node was removed; {@code false} otherwise.
*/
boolean remove();
/**
* Add a child with the given {@code name}. Does nothing if such a child
* already exists.
*
* @param name name of the child. A valid name does not start with a colon,
* is not empty and does not contain a forward slash.
* @return the {@code Tree} instance of the child with the given {@code name}.
* @throws IllegalArgumentException if {@code name} is not valid.
*/
@NotNull
Tree addChild(@NotNull String name) throws IllegalArgumentException;
/**
* Changes the nature of this tree such that the order of the children
* is kept stable. The expected behavior is as follows:
* <p>
* <ol>
* <li>Calling {@code setOrderableChildren(true)} on a tree
* the first time will stabilize the order of existing children. Any
* subsequent {@link #addChild(String)} call is guaranteed to insert
* the new tree and the end of the child list.</li>
* <li>Calling {@code setOrderableChildren(true)} on a tree
* that already has its children ordered has no effect.</li>
* <li>Calling {@code setOrderableChildren(false)} on a tree that
* doesn't have ordered children has not effect</li>
* <li>Calling {@code setOrderableChildren(false)} on a tree
* with ordered children will remove the necessity to keep the child
* list stable. The order of children upon {@link #getChildren()} is
* subsequently undefined.</li>
* </ol>
* <p>
* Calling {@link #orderBefore(String)} on a tree, implicitly enables
* orderable children on the parent tree.
*
* @param enable Enable (or disable) orderable children for this tree.
*/
void setOrderableChildren(boolean enable);
/**
* Orders this {@code Tree} before the sibling tree with the given
* {@code name}. Calling this method for the first time on this
* {@code Tree} or any of its siblings will persist the current order
* of siblings and maintain it from this point on.
*
* @param name the name of the sibling node where this tree is ordered
* before. This tree will become the last sibling if
* {@code name} is {@code null}.
* @return {@code false} if there is no sibling with the given
* {@code name} or no reordering was performed;
* {@code true} otherwise.
* @throws IllegalArgumentException if the given name is invalid
*/
boolean orderBefore(@Nullable String name);
/**
* Set a property state
*
* @param property The property state to set
* @throws IllegalArgumentException if {@code property} has a non valid name. A valid name
* does not start with a colon, is not empty and does not contain a forward slash.
*/
void setProperty(@NotNull PropertyState property);
/**
* Set a property state
*
* @param name The name of this property. A valid name does not start with a colon,
* is not empty and does not contain a forward slash.
* @param value The value of this property
* @param <T> The type of this property. Must be one of {@code String, Blob, byte[], Long, Integer, Double, Boolean, BigDecimal}
* @throws IllegalArgumentException if {@code T} is not one of the above types or
* if {@code name} is not valid.
*/
<T> void setProperty(@NotNull String name, @NotNull T value)
throws IllegalArgumentException;
/**
* Set a property state
*
* @param name The name of this property. A valid name does not start with a colon,
* is not empty and does not contain a forward slash.
* @param value The value of this property
* @param type The type of this property.
* @param <T> The type of this property.
* @throws IllegalArgumentException if {@code name} is not valid.
*/
<T> void setProperty(@NotNull String name, @NotNull T value, @NotNull Type<T> type)
throws IllegalArgumentException;
/**
* Remove the property with the given name. This method has no effect if a
* property of the given {@code name} does not exist.
*
* @param name The name of the property
*/
void removeProperty(@NotNull String name);
/**
* Empty array of trees.
*/
Tree[] EMPTY_ARRAY = new Tree[0];
}