You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/04/22 02:56:05 UTC
svn commit: r650336 - in /jackrabbit/branches/1.4/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
test/java/org/apache/jackrabbit/core/XATest.java
Author: jukka
Date: Mon Apr 21 17:55:58 2008
New Revision: 650336
URL: http://svn.apache.org/viewvc?rev=650336&view=rev
Log:
1.4: Merged revisions 638363 and 638374 (JCR-1484)
Modified:
jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
jackrabbit/branches/1.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java
Modified: jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java?rev=650336&r1=650335&r2=650336&view=diff
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java (original)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java Mon Apr 21 17:55:58 2008
@@ -25,6 +25,8 @@
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
import org.apache.jackrabbit.uuid.UUID;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.commons.collections.Predicate;
import javax.jcr.ReferentialIntegrityException;
import javax.jcr.PropertyType;
@@ -266,14 +268,7 @@
if (virtualProvider != null && virtualProvider.hasNodeReferences(id)) {
return virtualProvider.getNodeReferences(id);
}
- ChangeLog changeLog = getChangeLog();
- if (changeLog != null) {
- NodeReferences refs = changeLog.get(id);
- if (refs != null) {
- return refs;
- }
- }
- return super.getNodeReferences(id);
+ return getReferences(id);
}
/**
@@ -288,13 +283,11 @@
if (virtualProvider != null && virtualProvider.hasNodeReferences(id)) {
return true;
}
- ChangeLog changeLog = getChangeLog();
- if (changeLog != null) {
- if (changeLog.get(id) != null) {
- return true;
- }
+ try {
+ return getReferences(id).hasReferences();
+ } catch (ItemStateException e) {
+ return false;
}
- return super.hasNodeReferences(id);
}
/**
@@ -315,6 +308,108 @@
}
//-------------------------------------------------------< implementation >
+
+ /**
+ * Returns the node references for the given <code>id</code>.
+ *
+ * @param id the node references id.
+ * @return the node references for the given <code>id</code>.
+ * @throws ItemStateException if an error occurs while reading from the
+ * underlying shared item state manager.
+ */
+ private NodeReferences getReferences(NodeReferencesId id)
+ throws ItemStateException {
+ NodeReferences refs;
+ try {
+ refs = super.getNodeReferences(id);
+ } catch (NoSuchItemStateException e) {
+ refs = new NodeReferences(id);
+ }
+ // apply changes from change log
+ ChangeLog changes = getChangeLog();
+ if (changes != null) {
+ UUID uuid = id.getTargetId().getUUID();
+ // check removed reference properties
+ for (Iterator it = filterReferenceProperties(changes.deletedStates());
+ it.hasNext(); ) {
+ PropertyState prop = (PropertyState) it.next();
+ InternalValue[] values = prop.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].getUUID().equals(uuid)) {
+ refs.removeReference(prop.getPropertyId());
+ break;
+ }
+ }
+ }
+ // check added reference properties
+ for (Iterator it = filterReferenceProperties(changes.addedStates());
+ it.hasNext(); ) {
+ PropertyState prop = (PropertyState) it.next();
+ InternalValue[] values = prop.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].getUUID().equals(uuid)) {
+ refs.addReference(prop.getPropertyId());
+ break;
+ }
+ }
+ }
+ // check modified properties
+ for (Iterator it = changes.modifiedStates(); it.hasNext(); ) {
+ ItemState state = (ItemState) it.next();
+ if (state.isNode()) {
+ continue;
+ }
+ try {
+ PropertyState old = (PropertyState) sharedStateMgr.getItemState(state.getId());
+ if (old.getType() == PropertyType.REFERENCE) {
+ // remove if one of the old values references the node
+ InternalValue[] values = old.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].getUUID().equals(uuid)) {
+ refs.removeReference(old.getPropertyId());
+ break;
+ }
+ }
+ }
+ } catch (NoSuchItemStateException e) {
+ // property is stale
+ }
+
+ PropertyState prop = (PropertyState) state;
+ if (prop.getType() == PropertyType.REFERENCE) {
+ // add if modified value references node
+ InternalValue[] values = prop.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].getUUID().equals(uuid)) {
+ refs.addReference(prop.getPropertyId());
+ break;
+ }
+ }
+ }
+ }
+ }
+ return refs;
+ }
+
+ /**
+ * Takes an iterator over {@link ItemState}s and returns a new iterator that
+ * filters out all but REFERENCE {@link PropertyState}s.
+ *
+ * @param itemStates item state source iterator.
+ * @return iterator over reference property states.
+ */
+ private Iterator filterReferenceProperties(Iterator itemStates) {
+ return new FilterIterator(itemStates, new Predicate() {
+ public boolean evaluate(Object object) {
+ ItemState state = (ItemState) object;
+ if (!state.isNode()) {
+ PropertyState prop = (PropertyState) state;
+ return prop.getType() == PropertyType.REFERENCE;
+ }
+ return false;
+ }
+ });
+ }
/**
* Determine all node references whose targets only exist in the view of
Modified: jackrabbit/branches/1.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java?rev=650336&r1=650335&r2=650336&view=diff
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java (original)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java Mon Apr 21 17:55:58 2008
@@ -589,6 +589,154 @@
otherSuperuser.logout();
}
+ /**
+ * Checks if getReferences() reflects an added reference property that has
+ * been saved but not yet committed.
+ * <p/>
+ * Spec say:
+ * <p/>
+ * <i>Some level 2 implementations may only return properties that have been
+ * saved (in a transactional setting this includes both those properties
+ * that have been saved but not yet committed, as well as properties that
+ * have been committed). Other level 2 implementations may additionally
+ * return properties that have been added within the current Session but are
+ * not yet saved.</i>
+ * <p/>
+ * Jackrabbit does not support the latter, but at least has to support the
+ * first.
+ */
+ public void testGetReferencesAddedRef() throws Exception {
+ // create one referenceable node
+ Node target = testRootNode.addNode(nodeName1);
+ target.addMixin(mixReferenceable);
+ // second node, which will later reference the target node
+ Node n = testRootNode.addNode(nodeName2);
+ testRootNode.save();
+
+ UserTransactionImpl tx = new UserTransactionImpl(superuser);
+ tx.begin();
+ try {
+ // create reference
+ n.setProperty(propertyName1, target);
+ testRootNode.save();
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", target.getReferences().hasNext());
+ } finally {
+ tx.rollback();
+ }
+ }
+
+ /**
+ * Checks if getReferences() reflects a removed reference property that has
+ * been saved but not yet committed.
+ */
+ public void testGetReferencesRemovedRef() throws Exception {
+ // create one referenceable node
+ Node target = testRootNode.addNode(nodeName1);
+ target.addMixin(mixReferenceable);
+ // second node, which reference the target node
+ Node n = testRootNode.addNode(nodeName2);
+ // create reference
+ n.setProperty(propertyName1, target);
+ testRootNode.save();
+
+ UserTransactionImpl tx = new UserTransactionImpl(superuser);
+ tx.begin();
+ try {
+ n.getProperty(propertyName1).remove();
+ testRootNode.save();
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", !target.getReferences().hasNext());
+ } finally {
+ tx.rollback();
+ }
+ }
+
+ /**
+ * Checks if getReferences() reflects a modified reference property that has
+ * been saved but not yet committed.
+ */
+ public void testGetReferencesModifiedRef() throws Exception {
+ // create two referenceable node
+ Node target1 = testRootNode.addNode(nodeName1);
+ target1.addMixin(mixReferenceable);
+ // second node, which reference the target1 node
+ Node target2 = testRootNode.addNode(nodeName2);
+ target2.addMixin(mixReferenceable);
+ Node n = testRootNode.addNode(nodeName3);
+ // create reference
+ n.setProperty(propertyName1, target1);
+ testRootNode.save();
+
+ UserTransactionImpl tx = new UserTransactionImpl(superuser);
+ tx.begin();
+ try {
+ // change reference
+ n.setProperty(propertyName1, target2);
+ testRootNode.save();
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", !target1.getReferences().hasNext());
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", target2.getReferences().hasNext());
+ } finally {
+ tx.rollback();
+ }
+ }
+
+ /**
+ * Checks if getReferences() reflects a modified reference property that has
+ * been saved but not yet committed. The old value is a reference, while
+ * the new value is not.
+ */
+ public void testGetReferencesModifiedRefOldValueReferenceable() throws Exception {
+ // create one referenceable node
+ Node target = testRootNode.addNode(nodeName1);
+ target.addMixin(mixReferenceable);
+ Node n = testRootNode.addNode(nodeName2);
+ // create reference
+ n.setProperty(propertyName1, target);
+ testRootNode.save();
+
+ UserTransactionImpl tx = new UserTransactionImpl(superuser);
+ tx.begin();
+ try {
+ // change reference to a string value
+ n.setProperty(propertyName1, "foo");
+ testRootNode.save();
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", !target.getReferences().hasNext());
+ } finally {
+ tx.rollback();
+ }
+ }
+
+ /**
+ * Checks if getReferences() reflects a modified reference property that has
+ * been saved but not yet committed. The new value is a reference, while
+ * the old value wasn't.
+ */
+ public void testGetReferencesModifiedRefNewValueReferenceable() throws Exception {
+ // create one referenceable node
+ Node target = testRootNode.addNode(nodeName1);
+ target.addMixin(mixReferenceable);
+ Node n = testRootNode.addNode(nodeName2);
+ // create string property
+ n.setProperty(propertyName1, "foo");
+ testRootNode.save();
+
+ UserTransactionImpl tx = new UserTransactionImpl(superuser);
+ tx.begin();
+ try {
+ // change string into a reference
+ n.setProperty(propertyName1, target);
+ testRootNode.save();
+ assertTrue("Node.getReferences() must reflect references that have " +
+ "been saved but not yet committed", target.getReferences().hasNext());
+ } finally {
+ tx.rollback();
+ }
+ }
+
//--------------------------------------------------------------< locking >
/**