[dna-issues] [JBoss JIRA] Commented: (DNA-466) JCR requires connectors to expose UUID as identifier property

Randall Hauch (JIRA) jira-events at lists.jboss.org
Thu Jul 9 13:50:29 EDT 2009


    [ https://jira.jboss.org/jira/browse/DNA-466?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12475655#action_12475655 ] 

Randall Hauch commented on DNA-466:
-----------------------------------

Okay, after several weeks of working on this issue (including several failed attempts at more direct fixes to address the problem), I was finally able to commit the code.  The new design is obviously much improved when it comes to getting and using the paths.  But it also relies upon the paths and no longer expects UUIDs from connectors (other than in cases where nodes are referenceable, per the JCR specification).

The new design broke the functionality in SessionCache into two distinct parts.  A new GraphSession class (in org.jboss.dna.graph.session) now handles the job of maintaining a cached representation of a portion of the graph structure, including accumulating changes and batching various connector requests.  The JCR-specific functionality is now in SessionCache (still in org.jboss.dna.jcr) and is responsible for checking constraints, ensuring proper node and property types, maintaining cached representations of type names, and management of the JCR Node and Property implementation objects.  One big plus is that it helps separate the different kinds of logic, making testing easier.

The GraphSession class maintains a structured tree of node objects, ensuring that this transient structure stays in sync as various nodes are created, moved, deleted, cloned, or changed.  The session's behavior is patterned after JCR: it maintains transient state and changes, and these changes are pushed to the store upon 'save()'.  The node structure is not designed to be extended; rather, each node has a payload object that can be configured and customized (via generics).  Similarly, each node consists of a property info object for each property, and this property info contains a payload object that is customizable.  (SessionCache uses payload classes that store/cache the JCR-specific data.)  Quite a few hooks are available for inserting logic at various points in the lifecycle; for example, when a node is being loaded into the session, a hook is called to allow a client to populate the property info objects and child nodes, given the Graph node object.  This allows SessionCache to insert its own logic, including the determination of the primary type and child node definition, as well as caching any JCR-specific information in the payload.

As alluded to in a previous comment, the GraphSession structure maintains a Location object for every node.  That Path object in that Location is created from the Path of the parent node, which means that the ChildPath implementation can be used for all Path objects.  This means that each Path.Segment appears only once but is reused in every Path object on all nodes at or below that spot.  The Location and Path objects are also made to reflects the SNS indexes, so as the SNS indexes change, the paths are recomputed.  (Yes, this makes moves, deletes, and reorders more expensive, especially for large subgraphs, but then almost every other operation becomes much faster.)  And like the previous SessionCache implementation, the GraphSession uses a MultiMap to efficiently manage the children of a node, without having to compute the SNS indexes (other than when updating the Location objects, which is done only when needed).

The GraphSession also takes a different approach to storing the transient changes.  The old SessionCache design kept immutable snapshots of each node state as read from the store.  The idea was that the changes could be easily discarded while keeping the last-read state.   But in practice, the only times the changes are discarded is via javax.jcr.Session.refresh() or javax.jcr.Node.refresh() methods, which also throws out any cached state.  Thus, the old design unnecessarily maintained separate "read" states from the mutable "changed" states.  The new design simply keeps the structure in-sync with all changes, and each node maintains some state about whether it is new or has changed, and whether any nodes below it have changed.  This makes it easy to walk the structure to find out what areas are changed, what's new, and what hasn't even been loaded yet.  (The new design uses visitors to accomplish the walking activities.)

So, apart from the faster access to paths, the new design was to get around the difficulty of the javax.jcr.Node and javax.jcr.Property implementation objects requiring UUIDs.  In the old design, these implementation objects were very lightweight - almost every activity required looking up in the SessionCache the corresponding node/property information object and then delegating to methods on that object.  All nodes were identified by UUID, so each javax.jcr.Node and javax.jcr.Property implementation object simply had to know the UUID.  Unfortunately, this design doesn't work when the node has no UUID.  (Earlier, I experimented with creating artificial UUIDs, but this is not durable and causes problems when 'save()' or 'refresh()' are performed, causing the javax.jcr.Node and javax.jcr.Property implementation objects to become stale and unable to find the corresponding node/property info objects.)

In the new design, we still have very lightweight javax.jcr.Node and javax.jcr.Property implementation objects that still hold on to a unique key.  However, rather than a single UUID, the key is a session-specific NodeId (which can become invalid) and a durable Location of the node.  (The javax.jcr.Property implementations maintain a reference to the javax.jcr.Node implementation object and the property's name).  The SessionCache is able to find the corresponding GraphSession node/property given this combined key, and can almost always locate the node/property because the key has the last-known path.  Also, because the Location objects *might* have identification properties, these are used when the path is not sufficient or is no longer valid.  There are cases when this is not successful, but those cases correspond to those in the JCR specification (e.g., nodes being deleted or nodes being changed in other sessions).  In these cases, the JCR client gets an InvalidItemStateException, and retrieves the node from the session.

There are a few outstanding items and known issues that have to be resolved.  However, these will be tracked as separate issues. In fact, this issue will likely be dependent on a few of those - when they're finished, this issue can be marked as resolved.

> JCR requires connectors to expose UUID as identifier property
> -------------------------------------------------------------
>
>                 Key: DNA-466
>                 URL: https://jira.jboss.org/jira/browse/DNA-466
>             Project: DNA
>          Issue Type: Bug
>          Components: JCR
>    Affects Versions: 0.5
>            Reporter: Randall Hauch
>            Assignee: Randall Hauch
>            Priority: Blocker
>             Fix For: 0.6
>
>
> The JCR implementation currently expects connectors to return a UUID as the identifier property.  This is obviously incorrect, as it goes against several of the connectors we've already implemented.  In particular, the SessionCache is expecting to find the UUID, and submits requests to the source with only the UUID (not the path).

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

       




More information about the dna-issues mailing list