Merge of versioned checked-in nodes fails to set mergeFailed correctly
ashelepko Aug 6, 2013 8:38 AMHello,
I've bumped into a problem with merging versionable records.
First, here are some snippets from JCR 2.0 specification on Merge operation, that is a bit self-contradictory:
15.9 Merge
Like update, merge does not respect the checked-in status of nodes. A merge may change a node even if it is currently checked-in.
...
...
The merge test is performed by comparing N with its corresponding node in srcWorkspace, call it N'.
The merge test is done by comparing the base version of N (call it V) and the base version of N' (call it V').
For any versionable node N there are three possible outcomes of the merge test: update, leave or failed.
If N does not have a corresponding node then the merge result for N is leave.
If N is currently checked-in then:
- If V' is an eventual successor of V, then the merge result for N is update.
- If V' is an eventual predecessor of V or if V and V' are identical (i.e., are actually the same version), then the merge result for N is leave.
- If V is neither an eventual successor of, eventual predecessor of, nor identical with V', then the merge result for N is failed. This is the case where N and N' represent divergent branches of the version graph.
If N is currently checked-out then:
- If V' is an eventual predecessor of V or if V and V' are identical (i.e., are actually the same version), then the merge result for N is leave.
- If any other relationship holds between V and V', then the merge result for N is fail.
...
...
If bestEffort is true then:
- Each versionable node N with result update is updated to reflect the state of N'. The state of a node in this context refers to its set of properties and child node links.
- Each versionable node N with result leave is left unchanged, unless N is the child of a node with status update and N does not have a corresponding node in srcWorkspace. I such a case, N is removed.
- Each versionable node N with result failed is left unchanged except that the identifier of V' (which is, in some sense, the “offending” version; the one that caused the merge to fail on that N) is added to the multi-value REFERENCE property jcr:mergeFailed of N. If the identifier of V' is already in jcr:mergeFailed, it is not added again. The jcr:mergeFailed property never contains repeated references to the same version. If the jcr:mergeFailed property does not yet exist then it is created. If present, the jcr:mergeFailed property will always contain at least one value. If not present on a node, this indicates that no merge failure has occurred on that node. Note that the presence of this property on a node will in any case prevent it from being checked-in because the OnParentVersion setting of jcr:mergeFailed is ABORT.
- This property can later be used by the application to find those nodes in the subgraph that have failed to merge and thus require special attention (see §15.9.2 Merging Branches). This property is multi-valued so that a record of successive failed merges can be kept.
First, the spec states that merge doesn't pay attention to checked-in status of nodes.
Then, a little later it lists different flows for nodes that are checked-in and not checked-in.
After that, it describes behavior of setting jcr:mergeFailed property when bestEffort is true. Note that no difference is made for checked-in and non-checked-in nodes.
From what I understand, if I want a node to be updated, I have to check it in.
When a node is checked in, and a best-effort merge result for it is failed, merge operation should set jcr:mergeFailed property on the node.
However, it fails to do so, because the node is checked-in and thus read-only.
Checking out the node will lead to forfeiting any attempts to update it during merge.
So, I'm a bit confused here.
The way I see it now, jcr:mergeFailed should be set irrespectively of node's checked-in status. Please correct me if I'm wrong.
I tried to dig through the code to propose a pull request for this, but ended up being afraid to break something.
I've found out that there are methods
AbstractJcrNode: /*package*/ final AbstractJcrProperty void setProperty( Name name, JcrValue value, boolean skipReferenceValidation, boolean skipProtectedValidation, boolean skipVersioningValidation )
JcrSingleValueProperty: protected void setValue( JcrValue jcrValue )
that allow bypassing versioning check when setting a single-value property.
But, jcr:mergeFailed is multi-value, and there are no methods for bypassing versioning check when setting a multi-value property.
I can offer a test case that demonstrates the problem, please find in attached. I've run it from org.modeshape.jcr.JcrVersioningTest, but you can run it from anywhere by adding some code that sets up a standard repository.
Thanks.
-
PartOf_JcrVersioningTest.java.zip 864 bytes