jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Dürig <mdue...@apache.org>
Subject Re: [jr3] Tree model
Date Mon, 05 Mar 2012 12:55:50 GMT


On 5.3.12 12:40, Thomas Mueller wrote:
> Hi,
>
>>> If we want to use distinct interfaces for read-only and writable nodes,
>>> what about "ImmutableNode" and "MutableNode extends ImmutableNode".

I wouldn't provide MutableNode at all. Rather I'd provide utilities 
(like builders) to build ImmutableNodes from other ImmutableNodes and 
some changes/change list.

Michael

>>
>> That's troublesome because then a client that's given an ImmutableNode
>> can't rely on the instance being immutable (because it could in fact
>> be a MutableNode instance).
>
> True. So the interfaces would need to be distinct. They could both extend
> NodeState I guess, with MutableNode adding more methods.
>
> The draft looks very good to me now. What about:
>
>      int getChildNodeCount() and
>      getChildNodeEntries(int offset, int length):
>      replace int with long
>
>
>      new method
>      boolean hasProperty(String name)
>
>      new method
>      boolean hasChildNode(String name) or
>
>      boolean exists(String name)
>
>      new method
>      ImmutableNode getImmutableNode() or
>      ImmutableNode makeImmutable()
>      (for ImmutableNode it would typically return "this")
>
>      new method
>      MutableNode getMutableNode() or
>      MutableNode makeMutable()
>
>      (for MutableNode it would typically return "this")
>
>
> Regards,
> Thomas
>
>
>
>
>
>>
>> Anyway, see https://gist.github.com/1977909 (and below) for my latest
>> draft of these interfaces. Note also the javadocs.
>>
>> This draft is fairly close to the model already present in
>> o.a.j.mk.model, with the most crucial difference being that a
>> ChildNodeEntry returns a NodeState reference instead of just a content
>> id. In other words, the underlying addressing mechanism is hidden
>> below this interface.
>>
>> Note that since we considered it best to decouple the methods for
>> accessing properties and child nodes, i.e. have getProperty(String)
>> and getNode(String) instead of just a getItem(String), it actually
>> makes sense to have a getName() method on the PropertyState instance.
>> Otherwise a separate PropertyEntry interface would be needed in order
>> to avoid unnecessary extra string lookups when iterating over all
>> properties. The desire to avoid extra lookups is also why I'd rather
>> use a separate interface for properties instead of adding extra
>> methods to NodeState.
>>
>> BR,
>>
>> Jukka Zitting
>>
>>
>> /**
>> * 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();
>>
>> }
>

Mime
View raw message