Skip to content

Instantly share code, notes, and snippets.

@jukka
Created March 5, 2012 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jukka/1977909 to your computer and use it in GitHub Desktop.
Save jukka/1977909 to your computer and use it in GitHub Desktop.
Draft NodeState, PropertyState and ChildNodeEntry interfaces for jr3
/**
* A content tree consists of nodes and properties, each of which
* evolves through different states during its lifecycle. This interface
* represents a specific, immutable state of a node in a content tree.
* Depending on context, a NodeState instance can be interpreted as
* representing the state of just that node, of the subtree starting at
* that node, or of an entire tree in case it's a root node.
* <p>
* The crucial difference between this interface and the similarly named
* class in Jackrabbit 2.x is that this interface represents a specific,
* immutable state of a node, whereas the Jackrabbit 2.x class represented
* the "current" state of a node.
*
* <h2>Properties and child nodes</h2>
* <p>
* A node consists of an unordered set of properties, and an ordered set
* of child nodes. Each property and child node is uniquely named and a
* single name can only refer to a property or a child node, not both at
* the same time.
*
* <h2>Immutability and thread-safety</h2>
* <p>
* As mentioned above, all node and property states are always immutable.
* Thus repeating a method call is always guaranteed to produce the same
* result as before unless some internal error occurs (see below). Note
* however that this immutability only applies to a specific state instance.
* Different states of a node can obviously be different, and in some cases
* even different instances of the same state may behave slightly differently.
* For example due to performance optimization or other similar changes the
* iteration order of properties may be different for two instances of the
* same node state. However, all such changes must file
* <p>
* In addition to being immutable, a specific state instance guaranteed to
* be fully thread-safe. Possible caching or other internal changes need to
* be properly synchronized so that any number of concurrent clients can
* safely access a state instance.
*
* <h2>Persistence and error-handling</h2>
* <p>
* A node state can be (and often is) backed by local files or network
* resources. All IO operations or related concerns like caching should be
* handled transparently below this interface. Potential IO problems and
* recovery attempts like retrying a timed-out network access need to be
* handled below this interface, and only hard errors should be thrown up
* as {@link RuntimeException unchecked exceptions} that higher level code
* is not expected to be able to recover from.
* <p>
* Since this interface exposes no higher level constructs like access
* controls, locking, node types or even path parsing, there's no way
* for content access to fail because of such concerns. Such functionality
* and related checked exceptions or other control flow constructs should
* be implemented on a higher level above this interface.
*
* <h2>Decoration and virtual content</h2>
* <p>
* Not all content exposed by this interface needs to be backed by actual
* persisted data. An implementation may want to provide provide derived
* data like for example the aggregate size of the entire subtree as an
* extra virtual property. A virtualization, sharding or caching layer
* could provide a composite view over multiple underlying content trees.
* Or a basic access control layer could decide to hide certain content
* based on specific rules. All such features need to be implemented
* according to the API contract of this interface. A separate higher level
* interface needs to be used if an implementation can't for example
* guarantee immutability of exposed content as discussed above.
*/
public interface NodeState {
/**
* Returns the named property. The name is an opaque string and
* is not parsed or otherwise interpreted by this method.
* <p>
* The namespace of properties and child nodes is shared, so if
* this method returns a non-<code>null</code> value for a given
* name, then {@link #getChildNode(String)} is guaranteed to return
* <code>null</code> for the same name.
*
* @param name name of the property to return
* @return named property, or <code>null</code> if not found
*/
PropertyState getProperty(String name);
/**
* Returns an iterable of the properties of this node. Multiple
* iterations are guaranteed to return the properties in the same
* order, but the specific order used is implementation-dependent
* and may change across different states of the same node.
*
* @return properties in some stable order
*/
Iterable<PropertyState> getProperties();
/**
* Returns the named child node. The name is an opaque string and
* is not parsed or otherwise interpreted by this method.
* <p>
* The namespace of properties and child nodes is shared, so if
* this method returns a non-<code>null</code> value for a given
* name, then {@link #getProperty(String)} is guaranteed to return
* <code>null</code> for the same name.
*
* @param name name of the child node to return
* @return named child node, or <code>null</code> if not found
*/
NodeState getChildNode(String name);
/**
* Returns the number of child nodes of this node.
*
* @return number of child nodes
*/
int getChildNodeCount();
/**
* Returns an iterable of the child node entries starting from the
* given offset and containing the given number of entries. The order
* of child nodes is normally as specified by the client that created
* or reordered them.
* <p>
* The order of child nodes is by default as specified by the
* client that created or reordered them, but the caller can also
* ask the underlying implementation to return nodes in their
* native order that may be more efficient to iterate over.
* To request such native ordering, the caller should specify
* the offset parameter in ones' complement form
* (i.e. <code>~offset</code>).
* <p>
* If the requested range is completely or partially beyond the number
* of child nodes of this node, then only those child nodes that match
* the range are returned. Thus the returned iterable may contain less
* than the requested number of entries.
*
* @param offset start offset from which to return entries;
* with <code>0</code> being the offset of the first entry,
* and negative offsets interpreted as described above
* @param length maximum number of entries to return;
* use <code>-1</code> to return all remaining entries
* @return requested child node entries
*/
Iterable<ChildNodeEntry> getChildNodeEntries(int offset, int length);
}
/**
* TODO: document
*/
public interface PropertyState {
/**
* TODO: document
*/
String getName();
/**
* FIXME: replace with type-specific accessors
*/
String getEncodedValue();
}
/**
* TODO: document
*/
public interface ChildNodeEntry {
/**
* TODO: document
*/
String getName();
/**
* TODO: document
*/
NodeState getNode();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment