On Tue, Mar 6, 2012 at 11:57 AM, Jukka Zitting <jukka.zitt...@gmail.com> wrote: > Hi, > > On Mon, Mar 5, 2012 at 3:06 PM, Stefan Guggisberg > <stefan.guggisb...@gmail.com> wrote: >> Properties and child nodes are all addressed using an unordered >> name->item mapping on the parent node. >> >> what made me change my mind is that the JSON model >> doesn't (naturally) support ordered child entries. i've forgot >> about that and i guess that mandating order in a JSON-like >> model spells trouble sooner or later. > > Right. That's also my intuition. > >> for getChildNodeEntries() we can therefore drop the distinction >> between user-defined and native order and just >> state that the iteration order is stable. > > Sounds good. The nice thing about this is that it's fairly easy to put > orderability back in at a later point as adding an extra API > constraint can't break existing code whereas removing one (like in > dropping the orderability requirement) can get a bit painful in case > we've already started relying on it in higher-level code.
agreed. > > See below for an updated NodeState interface draft that drops the > orderability requirement (but still requires some stable ordering). I > also changed the size and offset types from int to long to resolve the > mini-debate on a potential built-in size limit, regardless of how > likely reaching a 2G limit would have been. Finally, for simplicity I > dropped the length argument from getChildNodeEntries(), as the added > value it gives is pretty small. i'd rather keep the length argument since it maps to the corresponding microkernel method and it might make the implementation easier. OTOH, i don't feel strong about it. > > I'm still keeping the numeric offset parameter since it's needed for > efficiently implementing the MicroKernel interface and there's no easy > alternative that would still keep the MicroKernel directly applicable > as a remote access interface. +1 for this proposal,thanks! cheers stefan > > 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 name -> item mappings. 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 or child nodes may be different for two > * instances of the same state. > * <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 the number of properties of this node. > * > * @return number of properties > */ > long getPropertyCount(); > > /** > * 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 > */ > long getChildNodeCount(); > > /** > * Returns an iterable of the child node entries starting from the > * given offset. Multiple iterations are guaranteed to return the > * child nodes in the same order, but the specific order used is > * implementation-dependent and may change across different states > * of the same node. An empty iterable is returned if the given > * offset is greater than the offset of the last child node entry. > * > * @param offset zero-based offset of the first entry to return > * @return requested child node entries in some stable order > */ > Iterable<ChildNodeEntry> getChildNodeEntries(long offset); > > }