jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dominique Pfister <dpfis...@adobe.com>
Subject Re: [jr3] Tree model
Date Mon, 05 Mar 2012 12:59:31 GMT
Hi,

On Mar 5, 2012, at 1:40 PM, Thomas Mueller wrote:

> Hi,
>
>>> If we want to use distinct interfaces for read-only and writable  
>>> nodes,
>>> what about "ImmutableNode" and "MutableNode extends ImmutableNode".
>>
>> 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

More than 2 billion child nodes? Don't you think that's a bit too  
optimistic?

>    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")

Why do we need 2 interfaces? Since NodeState contains nothing but read- 
only methods, I consider it immutable, and would rather add a  
subinterface MutableNode.

Dominique

>
>
> 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