You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/11/20 09:06:20 UTC
svn commit: r477095 [2/2] - in
/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi:
./ lock/ operation/ state/ state/entry/ version/
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java Mon Nov 20 00:06:18 2006
@@ -27,6 +27,7 @@
import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
import org.apache.jackrabbit.jcr2spi.state.entry.ChildPropertyEntry;
import org.apache.jackrabbit.jcr2spi.state.entry.PropertyReference;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildItemEntry;
import org.apache.jackrabbit.value.QValue;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
@@ -40,8 +41,8 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Set;
import java.util.Map;
+import java.util.Arrays;
/**
* <code>NodeState</code> represents the state of a <code>Node</code>.
@@ -161,7 +162,9 @@
if (mixinTypeNames != null) {
this.mixinTypeNames = mixinTypeNames;
}
- // re-create property references
+ // set the node references
+ this.references = references;
+ // add property references
propertiesInAttic.clear();
properties.clear();
Iterator it = propertyNames.iterator();
@@ -170,15 +173,13 @@
ChildPropertyEntry pe = PropertyReference.create(this, propName, isf, idFactory);
properties.put(propName, pe);
}
- // re-create child node entries
+ // add child node entries
childNodeEntries.removeAll();
it = childEntries.iterator();
while (it.hasNext()) {
ChildNodeEntry cne = (ChildNodeEntry) it.next();
childNodeEntries.add(cne.getName(), cne.getUUID(), cne.getIndex());
}
- // set the node references
- this.references = references;
}
//----------------------------------------------------------< ItemState >---
@@ -207,14 +208,175 @@
return getNodeId();
}
- public void refresh() {
- // TODO
+ /**
+ * {@inheritDoc}
+ * @see ItemState#reload(boolean)
+ */
+ public void reload(boolean keepChanges) {
+ // recursivly reload states from peristent storage including props
+ // that are in the attic.
+ for (Iterator it = getAllChildEntries(true, true); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ if (ce.isAvailable()) {
+ try {
+ ce.getItemState().reload(keepChanges);
+ } catch (ItemStateException e) {
+ // should not occur
+ }
+ }
+ }
+
+ if (isWorkspaceState()) {
+ // reload from persistent storage ('keepChanges' not relevant).
+ try {
+ NodeState tmp = isf.createNodeState(getNodeId(), parent);
+ if (merge(tmp, false) || getStatus() == Status.INVALIDATED) {
+ setStatus(Status.MODIFIED);
+ }
+ } catch (NoSuchItemStateException e) {
+ // remove entry from parent
+ parent.childNodeEntries.remove(this);
+ // inform overlaying state and listeners
+ setStatus(Status.REMOVED);
+ } catch (ItemStateException e) {
+ // todo rather throw? remove from parent?
+ log.warn("Exception while refreshing property state: " + e);
+ log.debug("Stacktrace: ", e);
+ }
+ } else {
+ /* session-state: if keepChanges is true only existing or invalidated
+ states must be updated. otherwise the state gets updated and might
+ be marked 'Stale' if transient changes are present and the
+ workspace-state is modified. */
+ if (!keepChanges || getStatus() == Status.EXISTING || getStatus() == Status.INVALIDATED) {
+ // calling refresh on the workspace state will in turn reset this state
+ overlayedState.reload(keepChanges);
+ }
+ }
}
- public void invalidate() {
- // TODO
+ boolean merge(ItemState another, boolean keepChanges) {
+ if (another == null) {
+ return false;
+ }
+ if (another == null || !another.isNode()) {
+ throw new IllegalArgumentException("Attempt to merge node state with property state.");
+ }
+ boolean modified = false;
+ synchronized (another) {
+ NodeState nState = (NodeState) another;
+ name = nState.name;
+ setUUID(nState.uuid);
+ nodeTypeName = nState.nodeTypeName;
+ definition = nState.definition;
+
+ // refs, mixin-types can be copied. they are never transiently changed.
+ references = nState.references;
+ List mixN = Arrays.asList(nState.mixinTypeNames);
+ modified = (mixN.size() != mixinTypeNames.length || !mixN.containsAll(Arrays.asList(mixinTypeNames)));
+ mixinTypeNames = nState.mixinTypeNames;
+
+ if (!keepChanges && !propertiesInAttic.isEmpty()) {
+ // remove all entries in the attic
+ modified = true;
+ propertiesInAttic.clear();
+ }
+
+ /* merge child entries without loosing valid entries and connected states. */
+ // add all entry from wspState that are missing in this state
+ for (Iterator it = nState.getAllChildEntries(false, false); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ QName childName = ce.getName();
+ if (ce.denotesNode()) {
+ ChildNodeEntry cne = (ChildNodeEntry) ce;
+ int index = cne.getIndex();
+ if (!childNodeEntries.contains(childName, index, cne.getUUID())) {
+ modified = true;
+ childNodeEntries.add(childName, cne.getUUID(), index);
+ }
+ } else {
+ if (!hasPropertyName(childName)) {
+ modified = true;
+ addPropertyEntry(PropertyReference.create(this, childName, isf, idFactory));
+ }
+ }
+ }
+
+ // if keepChanges is false, remove all entries from this state,
+ // that are missing in the given other state.
+ if (!keepChanges) {
+ for (Iterator it = getAllChildEntries(true, false); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ QName childName = ce.getName();
+ boolean toRemove = false;
+ if (ce.denotesNode()) {
+ ChildNodeEntry cne = (ChildNodeEntry) ce;
+ int index = cne.getIndex();
+ toRemove = !nState.childNodeEntries.contains(childName, index, cne.getUUID());
+ } else {
+ toRemove = !nState.properties.containsKey(childName);
+ }
+
+ if (toRemove) {
+ modified = true;
+ if (ce.isAvailable()) {
+ // TODO: check if correct.
+ try {
+ ItemState st = ce.getItemState();
+ if (st.getStatus() == Status.EXISTING_MODIFIED) {
+ st.setStatus(Status.STALE_DESTROYED);
+ } else {
+ st.setStatus(Status.REMOVED);
+ }
+ } catch (ItemStateException e) {
+ log.error("Internal error", e);
+ }
+ }
+ // and remove the corresponding entry
+ if (ce.denotesNode()) {
+ childNodeEntries.remove(childName, ((ChildNodeEntry)ce).getIndex());
+ } else {
+ properties.remove(childName);
+ }
+ }
+ }
+ }
+ }
+
+ return modified;
}
+ /**
+ * {@inheritDoc}
+ * @see ItemState#invalidate(boolean)
+ */
+ public void invalidate(boolean recursive) {
+ if (recursive) {
+ for (Iterator it = getAllChildEntries(false, false); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ if (ce.isAvailable()) {
+ try {
+ ce.getItemState().invalidate(true);
+ } catch (ItemStateException e) {
+ // should not occur
+ }
+ }
+ }
+ // TODO: props-in-attic?
+ }
+ // ... and invalidate this state
+ if (isWorkspaceState()) {
+ // workspace state
+ setStatus(Status.INVALIDATED);
+ } else {
+ // todo only invalidate if existing?
+ if (getStatus() == Status.EXISTING) {
+ // set workspace state invalidated, this will in turn invalidate
+ // this (session) state as well
+ overlayedState.setStatus(Status.INVALIDATED);
+ }
+ }
+ }
//----------------------------------------------------------< NodeState >---
/**
* Returns the id of this node state.
@@ -578,8 +740,9 @@
*
* @param propName
*/
- private void removePropertyEntry(QName propName) {
- if (properties.remove(propName) != null) {
+ private ChildPropertyEntry removePropertyEntry(QName propName) {
+ ChildPropertyEntry cpe = (ChildPropertyEntry) properties.remove(propName);
+ if (cpe != null) {
if (isWorkspaceState()) {
if (QName.JCR_UUID.equals(propName)) {
setUUID(null);
@@ -588,6 +751,7 @@
}
}
}
+ return cpe;
}
/**
@@ -699,7 +863,7 @@
* @see ItemState#persisted(ChangeLog)
*/
void persisted(ChangeLog changeLog) throws IllegalStateException {
-
+ // TODO: review...in case of CacheBehaviour.MANUAL and .INVALIDATION, some states must be invalidate (e.g. autocreated)
// remember parent states that have need to adjust their uuid/mixintypes
// or that got a new child entry added or existing entries removed.
Map modParents = new HashMap();
@@ -760,7 +924,7 @@
}
// make sure the new state gets updated (e.g. uuid created by server)
- addedState.reset();
+ addedState.merge(addedState.overlayedState, true);
// and mark the added-state existing
addedState.setStatus(Status.EXISTING);
// if parent is modified -> remember for final status reset
@@ -829,7 +993,9 @@
IteratorChain chain = new IteratorChain(its);
while (chain.hasNext()) {
ItemState state = (ItemState) chain.next();
- if (!(state.getStatus() == Status.EXISTING || state.getStatus() == Status.REMOVED)) {
+ if (!(state.getStatus() == Status.EXISTING ||
+ state.getStatus() == Status.REMOVED ||
+ state.getStatus() == Status.INVALIDATED)) {
// error: state has not been processed
// TODO: discard state and force reload of all data
}
@@ -837,248 +1003,82 @@
}
/**
- * {@inheritDoc}
- * @see ItemState#reset()
- */
- synchronized void reset() {
- checkIsSessionState();
-
- if (overlayedState != null) {
- synchronized (overlayedState) {
- NodeState wspState = (NodeState) overlayedState;
- name = wspState.name;
- setUUID(wspState.uuid);
- nodeTypeName = wspState.nodeTypeName;
- definition = wspState.definition;
-
- mixinTypeNames = wspState.mixinTypeNames;
-
- // remove all entries in the attic
- propertiesInAttic.clear();
-
- // merge prop-names
- Collection wspPropNames = wspState.getPropertyNames();
- for (Iterator it = wspPropNames.iterator(); it.hasNext();) {
- QName propName = (QName) it.next();
- if (!hasPropertyName(propName)) {
- addPropertyEntry(PropertyReference.create(this, propName, isf, idFactory));
- }
- }
- for (Iterator it = properties.keySet().iterator(); it.hasNext();) {
- // remove all prop-entries in the session state that are
- // not present in the wsp-state.
- if (!wspPropNames.contains(it.next())) {
- it.remove();
- }
- }
-
- // merge child node entries
- for (Iterator it = wspState.getChildNodeEntries().iterator(); it.hasNext();) {
- ChildNodeEntry cne = (ChildNodeEntry) it.next();
- int index = cne.getIndex();
- if (!childNodeEntries.contains(cne.getName(), index, cne.getUUID())) {
- childNodeEntries.add(cne.getName(), cne.getUUID(), index);
- }
- }
- List toRemove = new ArrayList();
- for (Iterator it = getChildNodeEntries().iterator(); it.hasNext();) {
- ChildNodeEntry cne = (ChildNodeEntry) it.next();
- if (!wspState.childNodeEntries.contains(cne.getName(), cne.getIndex(), cne.getUUID())) {
- toRemove.add(cne);
- }
- }
- for (Iterator it = toRemove.iterator(); it.hasNext();) {
- ChildNodeEntry cne = (ChildNodeEntry) it.next();
- childNodeEntries.remove(cne.getName(), cne.getIndex());
- }
- // set the node references
- references = wspState.references;
- }
- }
- }
-
- /**
+ * Recursively removes all child states and then calls {@link ItemState#remove()}.
+ *
* @inheritDoc
* @see ItemState#remove()
*/
void remove() throws ItemStateException {
checkIsSessionState();
-
if (!isValid()) {
throw new ItemStateException("cannot remove an invalid NodeState");
}
- // first remove all properties
- for (Iterator it = properties.values().iterator(); it.hasNext(); ) {
- ChildPropertyEntry cpe = ((ChildPropertyEntry) it.next());
- if (cpe.isAvailable()) {
- PropertyState pState = cpe.getPropertyState();
- if (pState.isValid()) {
- pState.remove();
- } else {
+ for (Iterator it = getAllChildEntries(true, false); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ if (ce.isAvailable()) {
+ ItemState childState = ce.getItemState();
+ if (childState.isValid()) {
+ childState.remove();
+ } else if (!ce.denotesNode()) {
// remove invalid property state from properties map
it.remove();
+ // TODO: check if for node-entries no action is required
}
- } else {
+ } else if (!ce.denotesNode()) {
// remove unresolved entry from properties map
it.remove();
+ // TODO check if for node entries no action required
}
}
- // move all properties from attic back to properties map
- properties.putAll(propertiesInAttic);
- propertiesInAttic.clear();
- // then remove child node entries
- for (Iterator it = childNodeEntries.iterator(); it.hasNext(); ) {
- NodeState nodeState = ((ChildNodeEntry) it.next()).getNodeState();
- if (nodeState.isValid()) {
- nodeState.remove();
- } else {
- // already removed
- }
- }
- if (getStatus() == Status.EXISTING || getStatus() == Status.EXISTING_MODIFIED) {
- setStatus(Status.EXISTING_REMOVED);
- } else if (getStatus() == Status.NEW) {
- setStatus(Status.REMOVED);
+ if (!propertiesInAttic.isEmpty()) {
+ // move all properties from attic back to properties map
+ properties.putAll(propertiesInAttic);
+ propertiesInAttic.clear();
}
- // now inform parent
- getParent().childNodeStateRemoved(this);
+
+ // process this state as well.
+ super.remove();
}
/**
- * Calls {@link #revert(Set) on all child states and add itself to the
- * set of affected states, if the current status indicates, that this
- * <code>NodeState</code> has been transiently modified.
+ * Calls {@link ItemState#revert()} and moves all properties from the attic
+ * back into th properties map.
*
* @inheritDoc
- * @see ItemState#revert(Set)
+ * @see ItemState#revert()
*/
- void revert(Set affectedItemStates) {
- checkIsSessionState();
-
- // copy to new list, when a property is reverted it may call this node
- // state to remove itself from properties.
- List props = new ArrayList(properties.values());
- for (Iterator it = props.iterator(); it.hasNext(); ) {
- ChildPropertyEntry entry = (ChildPropertyEntry) it.next();
- if (entry.isAvailable()) {
- try {
- PropertyState propState = entry.getPropertyState();
- propState.revert(affectedItemStates);
- } catch (ItemStateException e) {
- // should not happen because PropertyReference is resolved
- log.warn("Unable to get PropertyState from resolved PropertyReference");
- }
- } else {
- // not touched or accessed before
- }
- }
-
- // revert property states in attic
- props.clear();
- props.addAll(propertiesInAttic.values());
- for (Iterator it = props.iterator(); it.hasNext(); ) {
- PropertyReference ref = (PropertyReference) it.next();
- try {
- PropertyState propState = ref.getPropertyState();
- propState.revert(affectedItemStates);
- } catch (ItemStateException e) {
- // probably stale destroyed property
- // cleaned up when propertiesInAttic is cleared
- }
- }
- propertiesInAttic.clear();
-
- // now revert child node states
- List children = new ArrayList(childNodeEntries);
- for (Iterator it = children.iterator(); it.hasNext(); ) {
- ChildNodeEntry entry = (ChildNodeEntry) it.next();
- if (entry.isAvailable()) {
- try {
- NodeState nodeState = entry.getNodeState();
- nodeState.revert(affectedItemStates);
- } catch (ItemStateException e) {
- // should not happen because ChildNodeReference is resolved
- log.warn("Unable to get NodeState from resolved ChildNodeReference");
- }
- } else {
- // not touched or accessed before
- }
- }
-
- // now revert this node state
- switch (getStatus()) {
- case Status.EXISTING:
- // nothing to do
- break;
- case Status.EXISTING_MODIFIED:
- case Status.EXISTING_REMOVED:
- case Status.STALE_MODIFIED:
- // revert state from overlayed
- reset();
- setStatus(Status.EXISTING);
- affectedItemStates.add(this);
- break;
- case Status.NEW:
- // set removed
- setStatus(Status.REMOVED);
- // remove from parent
- getParent().childNodeStateRemoved(this);
- affectedItemStates.add(this);
- break;
- case Status.REMOVED:
- // shouldn't happen actually, because a 'removed' state is not
- // accessible anymore
- log.warn("trying to revert an already removed node state");
- getParent().childNodeStateRemoved(this);
- break;
- case Status.STALE_DESTROYED:
- // overlayed state does not exist anymore
- getParent().childNodeStateRemoved(this);
- affectedItemStates.add(this);
- break;
+ void revert() throws ItemStateException {
+ super.revert();
+ if (!propertiesInAttic.isEmpty()) {
+ // move all properties from attic back to properties map
+ properties.putAll(propertiesInAttic);
+ propertiesInAttic.clear();
}
}
/**
+ * Adds this state to the changeLog if it is transiently modified, new or stale
+ * and subsequently calls this method on all child states including those
+ * property states that have been moved to the attic.
+ *
* @inheritDoc
- * @see ItemState#collectTransientStates(Collection)
+ * @see ItemState#collectStates(ChangeLog, boolean)
*/
- void collectTransientStates(Collection transientStates) {
- checkIsSessionState();
+ void collectStates(ChangeLog changeLog, boolean throwOnStale) throws StaleItemStateException {
+ super.collectStates(changeLog, throwOnStale);
- switch (getStatus()) {
- case Status.EXISTING_MODIFIED:
- case Status.EXISTING_REMOVED:
- case Status.NEW:
- case Status.STALE_DESTROYED:
- case Status.STALE_MODIFIED:
- transientStates.add(this);
- }
- // call available property states
- for (Iterator it = properties.values().iterator(); it.hasNext(); ) {
- ChildPropertyEntry entry = (ChildPropertyEntry) it.next();
- if (entry.isAvailable()) {
+ // collect transient child states including properties in attic.
+ for (Iterator it = getAllChildEntries(false, true); it.hasNext();) {
+ ChildItemEntry ce = (ChildItemEntry) it.next();
+ if (ce.isAvailable()) {
try {
- entry.getPropertyState().collectTransientStates(transientStates);
+ ce.getItemState().collectStates(changeLog, throwOnStale);
} catch (ItemStateException e) {
// should not happen because ref is available
}
}
}
- // add all properties in attic
- transientStates.addAll(propertiesInAttic.values());
- // call available child node states
- for (Iterator it = childNodeEntries.iterator(); it.hasNext(); ) {
- ChildNodeEntry cne = (ChildNodeEntry) it.next();
- if (cne.isAvailable()) {
- try {
- cne.getNodeState().collectTransientStates(transientStates);
- } catch (ItemStateException e) {
- // should not happen because cne is available
- }
- }
- }
}
/**
@@ -1098,32 +1098,11 @@
}
/**
- * Notifies this node state that a child node state has been removed.
- *
- * @param childState the node state that has been removed.
- * @throws IllegalArgumentException if <code>this</code> is not the parent
- * of <code>nodeState</code>.
- */
- private synchronized void childNodeStateRemoved(NodeState childState) {
- checkIsSessionState();
-
- if (childState.getParent() != this) {
- throw new IllegalArgumentException("This NodeState is not the parent of nodeState");
- }
- // if nodeState does not exist anymore remove its child node entry
- if (childState.getStatus() == Status.REMOVED) {
- childNodeEntries.remove(childState);
- }
- markModified();
- }
-
- /**
* Adds a property state to this node state.
*
* @param propState the property state to add.
- * @throws ItemExistsException if <code>this</code> node state already
- * contains a property state with the same
- * name as <code>propState</code>.
+ * @throws ItemExistsException If <code>this</code> node state already
+ * contains a valid property state with the same name as <code>propState</code>.
* @throws IllegalArgumentException if <code>this</code> is not the parent
* of <code>propState</code>.
*/
@@ -1157,24 +1136,45 @@
}
/**
- * Notifies this node state that a property state has been removed.
+ * Notifies this node state that a child item state has been removed or
+ * otherwise modified.
*
- * @param propState the property state that has been removed.
+ * @param childState the child item state that has been removed or modified.
* @throws IllegalArgumentException if <code>this</code> is not the parent
- * of <code>propState</code>.
+ * of the given <code>ItemState</code>.
*/
- synchronized void propertyStateRemoved(PropertyState propState) {
+ synchronized void childStatusChanged(ItemState childState, int previousStatus) {
checkIsSessionState();
- if (propState.getParent() != this) {
+ if (childState.getParent() != this) {
throw new IllegalArgumentException("This NodeState is not the parent of propState");
}
- // remove property state from map of properties if it does not exist
- // anymore, otherwise leave the property state in the map
- if (propState.getStatus() == Status.REMOVED) {
- removePropertyEntry(propState.getQName());
+
+ switch (childState.getStatus()) {
+ case Status.EXISTING_REMOVED:
+ markModified();
+ break;
+ case Status.REMOVED:
+ if (childState.isNode()) {
+ childNodeEntries.remove((NodeState) childState);
+ } else {
+ removePropertyEntry(childState.getQName());
+ }
+ // TODO: not correct. removing a NEW state may even remove the 'modified'
+ // flag from the parent, if this NEW state was the only modification.
+ if (previousStatus != Status.NEW) {
+ markModified();
+ }
+ break;
+ case Status.EXISTING:
+ if (previousStatus == Status.EXISTING_REMOVED && !childState.isNode()) {
+ QName propName = childState.getQName();
+ if (propertiesInAttic.containsKey(propName)) {
+ properties.put(childState.getQName(), propertiesInAttic.remove(propName));
+ }
+ }
}
- markModified();
}
+
/**
* Reorders the child node <code>insertNode</code> before the child node
* <code>beforeNode</code>.
@@ -1219,6 +1219,14 @@
newParent.markModified();
}
+ /**
+ *
+ * @param newParent
+ * @param childState
+ * @param newName
+ * @param newDefinition
+ * @throws RepositoryException
+ */
private void moveEntry(NodeState newParent, NodeState childState, QName newName, QNodeDefinition newDefinition) throws RepositoryException {
ChildNodeEntry oldEntry = childNodeEntries.remove(childState);
if (oldEntry != null) {
@@ -1234,6 +1242,36 @@
}
}
+ /**
+ *
+ * @param createNewList if true, both properties and childNodeEntries are
+ * copied to new list, since recursive calls may call this node state to
+ * inform the removal of a child entry.
+ *
+ * @return
+ */
+ private Iterator getAllChildEntries(boolean createNewList, boolean includeAttic) {
+ Iterator[] its;
+ if (createNewList) {
+ List props = new ArrayList(properties.values());
+ List children = new ArrayList(childNodeEntries);
+ if (includeAttic) {
+ List attic = new ArrayList(propertiesInAttic.values());
+ its = new Iterator[] {attic.iterator(), props.iterator(), children.iterator()};
+ } else {
+ its = new Iterator[] {props.iterator(), children.iterator()};
+ }
+ } else {
+ if (includeAttic) {
+ its = new Iterator[] {propertiesInAttic.values().iterator(), properties.values().iterator(), childNodeEntries.iterator()};
+ } else {
+ its = new Iterator[] {properties.values().iterator(),
+ childNodeEntries.iterator()};
+ }
+ }
+ IteratorChain chain = new IteratorChain(its);
+ return chain;
+ }
//-------------------------------< internal >-------------------------------
/**
* Returns <code>true</code> if the collection of child node
@@ -1373,7 +1411,7 @@
// make sure all other modifications on the overlayed state are
// reflected on the session-state.
- sState.reset();
+ sState.merge(overlayed, false);
// make sure, the session-state gets its status reset to Existing.
if (sState.getStatus() == Status.EXISTING_MODIFIED) {
sState.setStatus(Status.EXISTING);
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java Mon Nov 20 00:06:18 2006
@@ -32,7 +32,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Set;
import java.util.Collection;
import java.util.Iterator;
@@ -78,7 +77,7 @@
this.name = overlayedState.name;
this.def = overlayedState.def;
- reset();
+ init(overlayedState.getType(), overlayedState.getValues());
}
/**
@@ -152,41 +151,69 @@
/**
* {@inheritDoc}
- * @see ItemState#refresh()
+ * @see ItemState#reload(boolean)
*/
- public void refresh() {
+ public void reload(boolean keepChanges) {
if (isWorkspaceState()) {
- // refresh from persistent storage
+ // refresh from persistent storage ('keepChanges' not relevant).
try {
PropertyState tmp = isf.createPropertyState(getPropertyId(), parent);
- init(tmp.getType(), tmp.getValues());
- setStatus(Status.MODIFIED);
+ if (merge(tmp, false) || getStatus() == Status.INVALIDATED) {
+ setStatus(Status.MODIFIED);
+ }
} catch (NoSuchItemStateException e) {
- // does not exist anymore
+ // TODO: make sure the property-entry is removed from the parent state
+ // inform overlaying state and listeners
setStatus(Status.REMOVED);
- // todo also remove from parent? how do we make sure the parent
- // todo does not get modified by this removal?
- // parent.propertyStateRemoved(this);
} catch (ItemStateException e) {
// todo rather throw? remove from parent?
log.warn("Exception while refreshing property state: " + e);
log.debug("Stacktrace: ", e);
}
} else {
- // session state
- if (getStatus() == Status.EXISTING || getStatus() == Status.INVALIDATED) {
- // calling refresh on the workspace state will in turn
- // also refresh / reset the session state
- overlayedState.refresh();
+ /* session-state: if keepChanges is true only existing or invalidated
+ states must be updated. otherwise the state gets updated and might
+ be marked 'Stale' if transient changes are present and the
+ workspace-state is modified. */
+ if (!keepChanges || getStatus() == Status.EXISTING || getStatus() == Status.INVALIDATED) {
+ // calling refresh on the workspace state will in turn reset this state
+ overlayedState.reload(keepChanges);
}
}
}
/**
+ * If <code>keepChanges</code> is true, this method does nothing and returns
+ * false. Otherwise type and values of the other property state are compared
+ * to this state. If they differ, they will be copied to this state and
+ * this method returns true.
+ *
+ * @see ItemState#merge(ItemState, boolean)
+ */
+ boolean merge(ItemState another, boolean keepChanges) {
+ if (another == null) {
+ return false;
+ }
+ if (another.isNode()) {
+ throw new IllegalArgumentException("Attempt to merge property state with node state.");
+ }
+ if (keepChanges || !diff(this, (PropertyState) another)) {
+ // nothing to do.
+ return false;
+ }
+
+ synchronized (another) {
+ PropertyState pState = (PropertyState) another;
+ init(pState.type, pState.values);
+ }
+ return true;
+ }
+
+ /**
* {@inheritDoc}
- * @see ItemState#invalidate()
+ * @see ItemState#invalidate(boolean)
*/
- public void invalidate() {
+ public void invalidate(boolean recursive) {
if (isWorkspaceState()) {
// workspace state
setStatus(Status.INVALIDATED);
@@ -195,7 +222,7 @@
if (getStatus() == Status.EXISTING) {
// set workspace state invalidated, this will in turn invalidate
// this (session) state as well
- overlayedState.invalidate();
+ overlayedState.invalidate(recursive);
}
}
}
@@ -282,20 +309,8 @@
break;
case Event.PROPERTY_CHANGED:
- // TODO: improve.
- /* retrieve property value and type from server even if
- changes were issued from this session (changelog).
- this is currently the only way to update the workspace
- state, which is not connected to its overlaying session-state.
- */
- try {
- PropertyState tmp = isf.createPropertyState(getPropertyId(), parent);
- init(tmp.getType(), tmp.getValues());
- setStatus(Status.MODIFIED);
- } catch (ItemStateException e) {
- // TODO: rather throw?
- log.error("Internal Error", e);
- }
+ // retrieve modified property value and type from server.
+ reload(false);
break;
case Event.PROPERTY_ADDED:
@@ -318,7 +333,8 @@
/*
NOTE: overlayedState must be existing, otherwise save was not
possible on prop. Similarly a property can only be the changelog
- target, if it was modified. removal, add must be persisted on parent.
+ target, if it was modified. removal, add and implicit modification
+ of protected properties must be persisted by save on parent.
*/
// push changes to overlayed state and reset status
((PropertyState) overlayedState).init(getType(), getValues());
@@ -326,100 +342,7 @@
}
}
}
-
- /**
- * {@inheritDoc}
- * @see ItemState#reset()
- */
- synchronized void reset() {
- checkIsSessionState();
- if (overlayedState != null) {
- synchronized (overlayedState) {
- PropertyState wspState = (PropertyState) overlayedState;
- init(wspState.type, wspState.values);
- }
- }
- }
-
- /**
- * @inheritDoc
- * @see ItemState#remove()
- */
- void remove() {
- checkIsSessionState();
- if (getStatus() == Status.NEW) {
- setStatus(Status.REMOVED);
- } else {
- setStatus(Status.EXISTING_REMOVED);
- }
- getParent().propertyStateRemoved(this);
- }
-
- /**
- * @inheritDoc
- * @see ItemState#revert(Set)
- */
- void revert(Set affectedItemStates) {
- checkIsSessionState();
-
- switch (getStatus()) {
- case Status.EXISTING:
- // nothing to do
- break;
- case Status.EXISTING_MODIFIED:
- case Status.EXISTING_REMOVED:
- case Status.STALE_MODIFIED:
- // revert state from overlayed
- reset();
- setStatus(Status.EXISTING);
- affectedItemStates.add(this);
- break;
- case Status.NEW:
- // set removed
- setStatus(Status.REMOVED);
- // and remove from parent
- getParent().propertyStateRemoved(this);
- affectedItemStates.add(this);
- break;
- case Status.REMOVED:
- // shouldn't happen actually, because a 'removed' state is not
- // accessible anymore
- log.warn("trying to revert an already removed property state");
- getParent().propertyStateRemoved(this);
- break;
- case Status.STALE_DESTROYED:
- // overlayed does not exist anymore
- getParent().propertyStateRemoved(this);
- affectedItemStates.add(this);
- break;
- }
- }
-
- /**
- * @inheritDoc
- * @see ItemState#collectTransientStates(Collection)
- */
- void collectTransientStates(Collection transientStates) {
- checkIsSessionState();
-
- switch (getStatus()) {
- case Status.EXISTING_MODIFIED:
- case Status.EXISTING_REMOVED:
- case Status.NEW:
- case Status.STALE_DESTROYED:
- case Status.STALE_MODIFIED:
- transientStates.add(this);
- break;
- case Status.EXISTING:
- case Status.REMOVED:
- log.debug("Collecting transient states: Ignored PropertyState with status " + getStatus());
- break;
- default:
- // should never occur. status is validated upon setStatus(int)
- log.error("Internal error: Invalid state " + getStatus());
- }
- }
-
+
/**
* Sets the value(s) of this property.
*
@@ -469,5 +392,35 @@
}
}
ValueConstraint.checkValueConstraints(definition, values);
+ }
+
+ /**
+ * Returns true, if type and/or values of the given property states differ.
+ *
+ * @param p1
+ * @param p2
+ * @return if the 2 <code>PropertyState</code>s are different in terms of
+ * type and/or values.
+ */
+ private static boolean diff(PropertyState p1, PropertyState p2) {
+ // compare type
+ if (p1.getType() != p2.getType()) {
+ return true;
+ }
+
+ QValue[] vs1 = p1.getValues();
+ QValue[] vs2 = p2.getValues();
+ if (vs1.length != vs2.length) {
+ return true;
+ } else {
+ for (int i = 0; i < vs1.length; i++) {
+ boolean eq = (vs1[i] == null) ? vs2[i] == null : vs1[i].equals(vs2[i]);
+ if (!eq) {
+ return true;
+ }
+ }
+ }
+ // no difference
+ return false;
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java Mon Nov 20 00:06:18 2006
@@ -44,6 +44,7 @@
import org.apache.jackrabbit.jcr2spi.operation.LockRelease;
import org.apache.jackrabbit.jcr2spi.operation.AddLabel;
import org.apache.jackrabbit.jcr2spi.operation.RemoveLabel;
+import org.apache.jackrabbit.jcr2spi.operation.RemoveVersion;
import org.apache.jackrabbit.name.NamespaceResolver;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
@@ -55,6 +56,7 @@
import org.apache.jackrabbit.spi.IdFactory;
import org.apache.jackrabbit.value.QValue;
import org.apache.jackrabbit.uuid.UUID;
+import org.apache.commons.collections.iterators.IteratorChain;
import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemNotFoundException;
@@ -79,7 +81,6 @@
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedHashSet;
import java.io.InputStream;
import java.io.IOException;
@@ -285,17 +286,17 @@
}
// collect the changes to be saved
- ChangeLog changeLog = getChangeLog(state);
+ ChangeLog changeLog = getChangeLog(state, true);
if (!changeLog.isEmpty()) {
// only pass changelog if there are transient modifications available
// for the specified item and its decendants.
workspaceItemStateMgr.execute(changeLog);
- }
- // remove operations just processed
- transientStateMgr.disposeOperations(changeLog.getOperations());
- // now its save to clear the changeLog
- changeLog.reset();
+ // remove states and operations just processed from the transient ISM
+ transientStateMgr.dispose(changeLog);
+ // now its save to clear the changeLog
+ changeLog.reset();
+ }
}
/**
@@ -309,18 +310,21 @@
* to be canceled as well in another sub-tree.
*/
public void undo(ItemState itemState) throws ItemStateException, ConstraintViolationException {
- // check if self contained
- ChangeLog changeLog = new ChangeLog(itemState);
- collectTransientStates(itemState, changeLog, false);
- changeLog.checkIsSelfContained();
- changeLog.collectOperations(transientStateMgr.getOperations());
-
- // now do it for real
- Set affectedItemStates = new HashSet();
- itemState.revert(affectedItemStates);
+ ChangeLog changeLog = getChangeLog(itemState, false);
+ if (!changeLog.isEmpty()) {
+ // now do it for real
+ // TODO: check if states are reverted in correct order
+ Iterator[] its = new Iterator[] {changeLog.addedStates(), changeLog.deletedStates(), changeLog.modifiedStates()};
+ IteratorChain chain = new IteratorChain(its);
+ while (chain.hasNext()) {
+ ItemState state = (ItemState) chain.next();
+ state.revert();
+ }
- // remove all canceled operations
- transientStateMgr.disposeOperations(changeLog.getOperations());
+ // remove transient states and related operations from the t-statemanager
+ transientStateMgr.dispose(changeLog);
+ changeLog.reset();
+ }
}
/**
@@ -364,85 +368,35 @@
/**
*
* @param itemState
+ * @param throwOnStale Throws StaleItemStateException if either the given
+ * <code>ItemState</code> or any of its decendants is stale and the flag is true.
* @return
- * @throws StaleItemStateException
- * @throws ItemStateException
- */
- private ChangeLog getChangeLog(ItemState itemState) throws StaleItemStateException, ItemStateException, ConstraintViolationException {
- // build changelog for affected and decendant states only
- ChangeLog changeLog = new ChangeLog(itemState);
- collectTransientStates(itemState, changeLog, true);
- changeLog.collectOperations(transientStateMgr.getOperations());
-
- changeLog.checkIsSelfContained();
- return changeLog;
- }
-
- /**
- * Builds a <code>ChangeLog</code> of transient (i.e. new, modified or
- * deleted) item states that are within the scope of <code>state</code>.
- *
* @throws StaleItemStateException if a stale <code>ItemState</code> is
- * encountered while traversing the state
- * hierarchy. The <code>changeLog</code>
- * might have been populated with some
- * transient item states. A client should
- * therefore not reuse the <code>changeLog</code>
- * if such an exception is thrown.
+ * encountered while traversing the state hierarchy. The <code>changeLog</code>
+ * might have been populated with some transient item states. A client should
+ * therefore not reuse the <code>changeLog</code> if such an exception is thrown.
* @throws ItemStateException if <code>state</code> is a new item state.
*/
- private void collectTransientStates(ItemState state, ChangeLog changeLog, boolean throwOnStale)
- throws StaleItemStateException, ItemStateException {
+ private ChangeLog getChangeLog(ItemState itemState, boolean throwOnStale) throws StaleItemStateException, ItemStateException, ConstraintViolationException {
+ // build changelog for affected and decendant states only
+ ChangeLog changeLog = new ChangeLog(itemState);
// fail-fast test: check status of this item's state
- if (state.getStatus() == Status.NEW) {
- String msg = LogUtil.safeGetJCRPath(state, nsResolver) + ": cannot save a new item.";
+ if (itemState.getStatus() == Status.NEW) {
+ String msg = "Cannot save an item with status NEW (" +LogUtil.safeGetJCRPath(itemState, nsResolver)+ ").";
log.debug(msg);
throw new ItemStateException(msg);
}
-
- if (throwOnStale && Status.isStale(state.getStatus())) {
- String msg = LogUtil.safeGetJCRPath(state, nsResolver) + ": the item cannot be saved because it has been modified/removed externally.";
+ if (throwOnStale && Status.isStale(itemState.getStatus())) {
+ String msg = "Attempt to save an item, that has been externally modified (" +LogUtil.safeGetJCRPath(itemState, nsResolver)+ ").";
log.debug(msg);
throw new StaleItemStateException(msg);
}
+ // collect transient/stale states that should be persisted or reverted
+ itemState.collectStates(changeLog, throwOnStale);
- // Set of transient states that should be persisted
- Set transientStates = new LinkedHashSet();
- state.collectTransientStates(transientStates);
-
- for (Iterator it = transientStates.iterator(); it.hasNext();) {
- ItemState transientState = (ItemState) it.next();
- // fail-fast test: check status of transient state
- switch (transientState.getStatus()) {
- case Status.NEW:
- changeLog.added(transientState);
- break;
- case Status.EXISTING_MODIFIED:
- changeLog.modified(transientState);
- break;
- case Status.EXISTING_REMOVED:
- changeLog.deleted(transientState);
- break;
- case Status.STALE_MODIFIED:
- if (throwOnStale) {
- String msg = transientState.getId() + ": the item cannot be saved because it has been modified externally.";
- log.debug(msg);
- throw new StaleItemStateException(msg);
- } else {
- changeLog.modified(transientState);
- }
- case Status.STALE_DESTROYED:
- if (throwOnStale) {
- String msg = transientState.getId() + ": the item cannot be saved because it has been deleted externally.";
- log.debug(msg);
- throw new StaleItemStateException(msg);
- }
- default:
- log.debug("unexpected state status (" + transientState.getStatus() + ")");
- // ignore
- break;
- }
- }
+ changeLog.collectOperations(transientStateMgr.getOperations());
+ changeLog.checkIsSelfContained();
+ return changeLog;
}
//--------------------------------------------------------------------------
@@ -659,6 +613,10 @@
throw new UnsupportedOperationException("Internal error: RemoveLabel cannot be handled by session ItemStateManager.");
}
+ public void visit(RemoveVersion operation) throws VersionException, AccessDeniedException, ReferentialIntegrityException, RepositoryException {
+ throw new UnsupportedOperationException("Internal error: RemoveVersion cannot be handled by session ItemStateManager.");
+ }
+
//--------------------------------------------< Internal State Handling >---
/**
*
@@ -745,7 +703,7 @@
private void removeItemState(ItemState itemState, int options) throws RepositoryException {
validator.checkRemoveItem(itemState, options);
- // recursively remove the complete tree including the given node state.
+ // recursively remove the given state and all child states.
boolean success = false;
try {
itemState.remove();
@@ -843,6 +801,7 @@
// nt:version node type defines jcr:created property
genValues = new QValue[]{QValue.create(Calendar.getInstance())};
}
+ // TODO: defaults???
}
return genValues;
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Mon Nov 20 00:06:18 2006
@@ -96,15 +96,6 @@
}
/**
- * Removes the <code>operation</code> from the list of operations.
- * @param operation the Operation to remove.
- * @return <code>true</code> if the operation was removed.
- */
- boolean removeOperation(Operation operation) {
- return changeLog.removeOperation(operation);
- }
-
- /**
* @return <code>true</code> if this transient ISM has pending changes.
*/
boolean hasPendingChanges() {
@@ -169,14 +160,13 @@
}
/**
- * Disposes a collection of {@link org.apache.jackrabbit.jcr2spi.operation.Operation}s.
+ * Remove the states and operations listed in the changeLog from the
+ * internal changeLog.
*
- * @param operations the operations.
+ * @param subChangeLog
*/
- void disposeOperations(Iterator operations) {
- while (operations.hasNext()) {
- changeLog.removeOperation((Operation) operations.next());
- }
+ void dispose(ChangeLog subChangeLog) {
+ changeLog.removeAll(subChangeLog);
}
//---------------------------------------------------< ItemStateManager >---
@@ -250,11 +240,6 @@
* @see ItemStateLifeCycleListener#statusChanged(ItemState, int)
*/
public void statusChanged(ItemState state, int previousStatus) {
- if (!Status.isValidStatusChange(previousStatus, state.getStatus(), false)) {
- log.error("ItemState has invalid status: " + state.getStatus());
- return;
- }
-
// TODO: depending on status of state adapt change log
// e.g. a revert on states will reset the status from
// 'existing modified' to 'existing'.
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Mon Nov 20 00:06:18 2006
@@ -285,7 +285,7 @@
this.cache = cache;
}
- //------------------------------------------------------< ChildNodeEntry >---
+ //-----------------------------------------------------< ChildNodeEntry >---
private class CNE implements ChildNodeEntry {
private final QName name;
@@ -302,6 +302,10 @@
throw new UnsupportedOperationException();
}
+ public boolean denotesNode() {
+ return true;
+ }
+
public QName getName() {
return name;
}
@@ -319,6 +323,10 @@
}
public boolean isAvailable() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ItemState getItemState() throws NoSuchItemStateException, ItemStateException {
throw new UnsupportedOperationException();
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java Mon Nov 20 00:06:18 2006
@@ -55,7 +55,7 @@
} catch (UnsupportedRepositoryOperationException e) {
// repository does not support observation
}
- this.eventFilter = filter == null ? Collections.EMPTY_LIST : Collections.singletonList(filter);
+ this.eventFilter = (filter == null) ? Collections.EMPTY_LIST : Collections.singletonList(filter);
}
//-------------------------------< InternalEventListener >------------------
@@ -83,7 +83,7 @@
/**
* Retrieve the workspace state(s) affected by the given event and refresh
* them accordingly.
- *
+ *
* @param events
*/
private void pushEvents(Collection events) {
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java?view=auto&rev=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java Mon Nov 20 00:06:18 2006
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jcr2spi.state.entry;
+
+import org.apache.jackrabbit.jcr2spi.state.NoSuchItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.name.QName;
+
+/**
+ * <code>ChildItemEntry</code>...
+ */
+public interface ChildItemEntry {
+
+ /**
+ * True if this ChildItemEntry would resolve to a <code>NodeState</code>.
+ *
+ * @return
+ */
+ public boolean denotesNode();
+
+ /**
+ * @return the name of this child entry.
+ */
+ public QName getName();
+
+ /**
+ * Returns <code>true</code> if the referenced <code>NodeState</code> is
+ * available. That is, the referenced <code>NodeState</code> is already
+ * cached and ready to be returned by {@link #getItemState()}.
+ *
+ * @return <code>true</code> if the <code>NodeState</code> is available;
+ * otherwise <code>false</code>.
+ */
+ public boolean isAvailable();
+
+ /**
+ * @return the referenced <code>ItemState</code>.
+ * @throws NoSuchItemStateException if the <code>ItemState</code> does not
+ * exist anymore.
+ * @throws ItemStateException If an error occurs while retrieving the
+ * <code>ItemState</code>.
+ */
+ public ItemState getItemState() throws NoSuchItemStateException, ItemStateException;
+}
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemEntry.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemReference.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemReference.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemReference.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildItemReference.java Mon Nov 20 00:06:18 2006
@@ -31,7 +31,7 @@
* @see ChildNodeReference
* @see PropertyReference
*/
-abstract class ChildItemReference {
+abstract class ChildItemReference implements ChildItemEntry {
/**
* Cached weak reference to the target NodeState.
@@ -39,14 +39,14 @@
private WeakReference target;
/**
- * The parent that owns this <code>ChildItemReference</code>.
+ * The name of the target item state.
*/
- protected final NodeState parent;
+ private final QName name;
/**
- * The name of the target item state.
+ * The parent that owns this <code>ChildItemReference</code>.
*/
- protected final QName name;
+ protected final NodeState parent;
/**
* The item state factory to create the the item state.
@@ -135,4 +135,20 @@
*/
protected abstract ItemState doResolve()
throws NoSuchItemStateException, ItemStateException;
+
+ /**
+ * @inheritDoc
+ * @see ChildItemEntry#getName()
+ */
+ public QName getName() {
+ return name;
+ }
+
+ /**
+ * @inheritDoc
+ * @see ChildItemEntry#isAvailable()
+ */
+ public boolean isAvailable() {
+ return isResolved();
+ }
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeEntry.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeEntry.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeEntry.java Mon Nov 20 00:06:18 2006
@@ -26,7 +26,7 @@
* <code>ChildNodeEntry</code> specifies the name, index (in the case of
* same-name siblings) and the UUID of a child node entry.
*/
-public interface ChildNodeEntry {
+public interface ChildNodeEntry extends ChildItemEntry {
/**
* @return the <code>NodeId</code> of this child node entry.
@@ -59,14 +59,4 @@
*/
public NodeState getNodeState()
throws NoSuchItemStateException, ItemStateException;
-
- /**
- * Returns <code>true</code> if the referenced <code>NodeState</code> is
- * available. That is, the referenced <code>NodeState</code> is already
- * cached and ready to be returned by {@link #getNodeState()}.
- *
- * @return <code>true</code> if the <code>NodeState</code> is available;
- * otherwise <code>false</code>.
- */
- public boolean isAvailable();
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeReference.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeReference.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeReference.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildNodeReference.java Mon Nov 20 00:06:18 2006
@@ -22,6 +22,7 @@
import org.apache.jackrabbit.jcr2spi.state.ItemStateFactory;
import org.apache.jackrabbit.jcr2spi.state.NoSuchItemStateException;
import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
/**
* <code>ChildNodeReference</code> implements common functionality for child
@@ -105,26 +106,28 @@
/**
* @inheritDoc
- * @see ChildNodeEntry#getName()
+ * @see ChildNodeEntry#getNodeState()
*/
- public QName getName() {
- return name;
+ public NodeState getNodeState()
+ throws NoSuchItemStateException, ItemStateException {
+ return (NodeState) resolve();
}
/**
+ * Returns true.
+ *
* @inheritDoc
- * @see ChildNodeEntry#getNodeState()
+ * @see ChildItemEntry#denotesNode()
*/
- public NodeState getNodeState()
- throws NoSuchItemStateException, ItemStateException {
- return (NodeState) resolve();
+ public boolean denotesNode() {
+ return true;
}
/**
* @inheritDoc
- * @see ChildNodeEntry#isAvailable()
+ * @see ChildItemEntry#getItemState()
*/
- public boolean isAvailable() {
- return isResolved();
+ public ItemState getItemState() throws NoSuchItemStateException, ItemStateException {
+ return getNodeState();
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildPropertyEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildPropertyEntry.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildPropertyEntry.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/ChildPropertyEntry.java Mon Nov 20 00:06:18 2006
@@ -17,7 +17,6 @@
package org.apache.jackrabbit.jcr2spi.state.entry;
import org.apache.jackrabbit.spi.PropertyId;
-import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
import org.apache.jackrabbit.jcr2spi.state.NoSuchItemStateException;
import org.apache.jackrabbit.jcr2spi.state.PropertyState;
@@ -25,7 +24,7 @@
/**
* <code>ChildPropertyEntry</code>...
*/
-public interface ChildPropertyEntry {
+public interface ChildPropertyEntry extends ChildItemEntry {
/**
* @return the <code>NodeId</code> of this child node entry.
@@ -33,11 +32,6 @@
public PropertyId getId();
/**
- * @return the name of this child node entry.
- */
- public QName getName();
-
- /**
* @return the referenced <code>PropertyState</code>.
* @throws NoSuchItemStateException if the <code>PropertyState</code> does not
* exist anymore.
@@ -45,14 +39,4 @@
* <code>PropertyState</code>.
*/
public PropertyState getPropertyState() throws NoSuchItemStateException, ItemStateException;
-
- /**
- * Returns <code>true</code> if the referenced <code>PropertyState</code> is
- * available. That is, the referenced <code>PropertyState</code> is already
- * cached and ready to be returned by {@link #getPropertyState()}.
- *
- * @return <code>true</code> if the <code>PropertyState</code> is available;
- * otherwise <code>false</code>.
- */
- public boolean isAvailable();
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PropertyReference.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PropertyReference.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PropertyReference.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/entry/PropertyReference.java Mon Nov 20 00:06:18 2006
@@ -105,28 +105,31 @@
* @inheritDoc
*/
public PropertyId getId() {
- return idFactory.createPropertyId(parent.getNodeId(), name);
+ return idFactory.createPropertyId(parent.getNodeId(), getName());
}
/**
* @inheritDoc
*/
- public QName getName() {
- return name;
+ public PropertyState getPropertyState() throws NoSuchItemStateException, ItemStateException {
+ return (PropertyState) resolve();
}
/**
+ * Returns false.
+ *
* @inheritDoc
+ * @see ChildItemEntry#denotesNode()
*/
- public PropertyState getPropertyState() throws NoSuchItemStateException, ItemStateException {
- return (PropertyState) resolve();
+ public boolean denotesNode() {
+ return false;
}
/**
* @inheritDoc
- * @see ChildPropertyEntry#isAvailable()
+ * @see ChildItemEntry#getItemState()
*/
- public boolean isAvailable() {
- return isResolved();
+ public ItemState getItemState() throws NoSuchItemStateException, ItemStateException {
+ return getPropertyState();
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java?view=diff&rev=477095&r1=477094&r2=477095
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java Mon Nov 20 00:06:18 2006
@@ -27,14 +27,15 @@
import org.apache.jackrabbit.jcr2spi.operation.Restore;
import org.apache.jackrabbit.jcr2spi.operation.ResolveMergeConflict;
import org.apache.jackrabbit.jcr2spi.operation.Merge;
-import org.apache.jackrabbit.jcr2spi.operation.Remove;
import org.apache.jackrabbit.jcr2spi.operation.AddLabel;
import org.apache.jackrabbit.jcr2spi.operation.RemoveLabel;
+import org.apache.jackrabbit.jcr2spi.operation.RemoveVersion;
import org.apache.jackrabbit.jcr2spi.WorkspaceManager;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.version.VersionException;
import org.apache.jackrabbit.name.QName;
@@ -120,7 +121,7 @@
public void removeVersion(NodeState versionHistoryState, NodeState versionState) throws RepositoryException {
NodeState wspVersionState = getWorkspaceState(versionState);
- Operation op = Remove.create(wspVersionState);
+ Operation op = RemoveVersion.create(wspVersionState);
workspaceManager.execute(op);
}
@@ -157,16 +158,21 @@
public Collection merge(NodeState nodeState, String workspaceName, boolean bestEffort) throws RepositoryException {
NodeState wspState = getWorkspaceState(nodeState);
+ // TODO : needs to be fixed... repository may not support observation
// TODO find better solution to build the mergeFailed-collection
+ EventFilter eventFilter;
+ try {
+ eventFilter = workspaceManager.createEventFilter(Event.ALL_TYPES, nodeState.getQPath(), true, null, null, false);
+ } catch (UnsupportedRepositoryOperationException e) {
+ eventFilter = null;
+ }
final List failedIds = new ArrayList();
- final EventFilter eventFilter = workspaceManager.createEventFilter(
- Event.ALL_TYPES, nodeState.getQPath(), true, null, null, false);
- InternalEventListener mergeFailedCollector = new InternalEventListener() {
+ final Collection fts = (eventFilter == null) ? Collections.EMPTY_LIST : Collections.singletonList(eventFilter);
+ InternalEventListener mergeFailedCollector = new InternalEventListener() {
public Collection getEventFilters() {
- return Collections.singletonList(eventFilter);
+ return fts;
}
-
public void onEvent(EventBundle eventBundle) {
if (eventBundle.isLocal()) {
EventIterator it = eventBundle.getEvents();