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/10/09 18:46:18 UTC
svn commit: r454423 [2/3] - in /jackrabbit/trunk/contrib/spi:
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/
jcr2spi/src/main/jav...
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=454423&r1=454422&r2=454423
==============================================================================
--- 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 Oct 9 09:46:16 2006
@@ -27,6 +27,11 @@
import org.apache.jackrabbit.spi.ItemId;
import org.apache.jackrabbit.spi.Event;
import org.apache.jackrabbit.spi.PropertyId;
+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.ChildNodeReference;
+import org.apache.jackrabbit.value.QValue;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
@@ -140,8 +145,8 @@
protected NodeState(QName name, String uuid, NodeState parent,
QName nodeTypeName, QNodeDefinition definition,
int initialStatus, ItemStateFactory isf,
- IdFactory idFactory) {
- super(parent, initialStatus, idFactory);
+ IdFactory idFactory, boolean isWorkspaceState) {
+ super(parent, initialStatus, idFactory, isWorkspaceState);
this.name = name;
this.uuid = uuid;
this.nodeTypeName = nodeTypeName;
@@ -164,7 +169,7 @@
IdFactory idFactory) {
super(overlayedState, parent, initialStatus, idFactory);
this.isf = isf;
- pull();
+ reset();
}
void init(QName[] mixinTypeNames, Collection childEntries, Collection propertyNames, NodeReferences references) {
@@ -173,14 +178,14 @@
}
// re-create property references
propertiesInAttic.clear();
- properties.clear(); // TODO: any more cleanup work to do? try some kind of merging?
+ properties.clear();
Iterator it = propertyNames.iterator();
while (it.hasNext()) {
QName propName = (QName) it.next();
- properties.put(propName, new PropertyReference(this, propName, isf, idFactory));
+ properties.put(propName, PropertyReference.create(this, propName, isf, idFactory));
}
// re-create child node entries
- childNodeEntries.removeAll(); // TODO: any mre cleanup work to do? try some kind of merging?
+ childNodeEntries.removeAll();
it = childEntries.iterator();
while (it.hasNext()) {
ChildNodeEntry cne = (ChildNodeEntry) it.next();
@@ -190,119 +195,7 @@
this.references = references;
}
- /**
- * {@inheritDoc}
- */
- protected synchronized void pull() {
- if (overlayedState != null) {
- synchronized (overlayedState) {
- NodeState nodeState = (NodeState) overlayedState;
- name = nodeState.name;
- uuid = nodeState.uuid;
- nodeTypeName = nodeState.nodeTypeName;
- definition = nodeState.definition;
-
- init(nodeState.getMixinTypeNames(), nodeState.getChildNodeEntries(), nodeState.getPropertyNames(), nodeState.getNodeReferences());
- }
- }
- }
-
- protected synchronized void refresh(Event event, ChangeLog changeLog) {
- NodeId id = getNodeId();
- switch (event.getType()) {
- case Event.NODE_ADDED:
- case Event.PROPERTY_ADDED:
- if (id.equals(event.getParentId())) {
- ItemId evId = event.getItemId();
- ItemState newState = null;
-
- if (evId.denotesNode()) {
- QName name = event.getQPath().getNameElement().getName();
- String uuid = (((NodeId)evId).getRelativePath() != null) ? null : ((NodeId)evId).getUUID();
- ChildNodeEntry cne = childNodeEntries.add(name, uuid);
- try {
- newState = cne.getNodeState();
- } catch (ItemStateException e) {
- log.error("Internal error", e);
- }
- } else {
- PropertyId pId = (PropertyId) event.getItemId();
- PropertyReference re = new PropertyReference(this, pId.getQName(), isf, idFactory);
- properties.put(pId.getQName(), re);
- try {
- newState = re.getPropertyState();
- } catch (ItemStateException e) {
- log.error("Internal error", e);
- }
- }
-
- // connect the transient state to this state and make
- // sure its data are updated
- if (newState != null && changeLog != null) {
- for (Iterator it = changeLog.addedStates(); it.hasNext();) {
- ItemState added = (ItemState) it.next();
- if (added.getId().equals(evId)) {
- added.connect(newState);
- added.pull();
- break;
- }
- }
- }
- } else {
- // ILLEGAL
- throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
- }
- break;
-
- case Event.NODE_REMOVED:
- if (id.equals(event.getParentId())) {
- QName qName = event.getQPath().getNameElement().getName();
- int index = event.getQPath().getNameElement().getNormalizedIndex();
- childNodeEntries.remove(qName, index);
- setStatus(STATUS_MODIFIED);
- } else if (id.equals(event.getItemId())) {
- setStatus(STATUS_REMOVED);
- } else {
- // ILLEGAL
- throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
- }
- break;
-
- case Event.PROPERTY_REMOVED:
- if (id.equals(event.getParentId())) {
- PropertyId pId = (PropertyId) event.getItemId();
- properties.remove(pId.getQName());
- setStatus(STATUS_MODIFIED);
- } else {
- // ILLEGAL
- throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
- }
- break;
-
- case Event.PROPERTY_CHANGED:
- default:
- // ILLEGAL
- throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
- }
- }
-
- //--------------------< public READ methods and package private Setters >---
-
- /**
- * @return the name of this node state.
- */
- public final QName getName() {
- return name;
- }
-
- /**
- * @return the UUID of this node state or <code>null</code> if this
- * node cannot be identified with a UUID.
- */
- public final String getUUID() {
- return uuid;
- }
-
+ //----------------------------------------------------------< ItemState >---
/**
* Determines if this item state represents a node.
*
@@ -314,12 +207,21 @@
}
/**
+ * @see ItemState#getQName()
+ */
+ public final QName getQName() {
+ return name;
+ }
+
+ /**
* {@inheritDoc}
+ * @see ItemState#getId()
*/
public ItemId getId() {
return getNodeId();
}
+ //----------------------------------------------------------< NodeState >---
/**
* Returns the id of this node state.
*
@@ -350,6 +252,14 @@
}
/**
+ * @return the UUID of this node state or <code>null</code> if this
+ * node cannot be identified with a UUID.
+ */
+ public final String getUUID() {
+ return uuid;
+ }
+
+ /**
* Returns the name of this node's node type.
*
* @return the name of this node's node type.
@@ -368,20 +278,6 @@
}
/**
- * Sets the names of this node's mixin types.
- *
- * @param mixinTypeNames set of names of mixin types
- */
- synchronized void setMixinTypeNames(QName[] mixinTypeNames) {
- if (mixinTypeNames != null) {
- this.mixinTypeNames = mixinTypeNames;
- } else {
- this.mixinTypeNames = new QName[0];
- }
- markModified();
- }
-
- /**
* Return all nodetype names that apply to this <code>NodeState</code>
* including the primary nodetype and the mixins.
*
@@ -389,8 +285,9 @@
*/
public synchronized QName[] getNodeTypeNames() {
// mixin types
- QName[] types = new QName[mixinTypeNames.length + 1];
- System.arraycopy(mixinTypeNames, 0, types, 0, mixinTypeNames.length);
+ QName[] mixinNames = getMixinTypeNames();
+ QName[] types = new QName[mixinNames.length + 1];
+ System.arraycopy(mixinNames, 0, types, 0, mixinNames.length);
// primary type
types[types.length - 1] = getNodeTypeName();
return types;
@@ -407,6 +304,21 @@
return definition;
}
+
+ /**
+ * Return the <code>NodeReferences</code> present on this state or
+ * <code>null</code>.
+ *
+ * @return references
+ */
+ NodeReferences getNodeReferences() {
+ if (getStatus() == Status.NEW) {
+ return null;
+ } else {
+ return references;
+ }
+ }
+
/**
* Determines if there are any child node entries.
*
@@ -493,73 +405,401 @@
}
/**
- * TODO: move this method to a node state implementation which contains all transient related methods?
+ * Determines if there is a property entry with the specified
+ * <code>QName</code>.
*
- * Adds a child node state to this node state.
+ * @param propName <code>QName</code> object specifying a property name
+ * @return <code>true</code> if there is a property entry with the specified
+ * <code>QName</code>.
+ */
+ public synchronized boolean hasPropertyName(QName propName) {
+ ChildPropertyEntry entry = (ChildPropertyEntry) properties.get(propName);
+ if (entry == null) {
+ return false;
+ }
+ if (entry.isAvailable()) {
+ try {
+ return entry.getPropertyState().isValid();
+ } catch (ItemStateException e) {
+ // probably deleted in the meantime
+ return false;
+ }
+ } else {
+ // then it must be valid
+ return true;
+ }
+ }
+
+ /**
+ * Returns the names of this node's properties as a set of
+ * <code>QNames</code> objects.
*
- * @param child the node state to add.
- * @param uuid the uuid of the child node state or <code>null</code> if
- * <code>child</code> cannot be identified with a uuid.
- * @throws IllegalArgumentException if <code>this</code> is not the parent
- * of <code>child</code>.
+ * @return set of <code>QNames</code> objects
*/
- synchronized void addChildNodeState(NodeState child, String uuid) {
- if (child.getParent() != this) {
- throw new IllegalArgumentException("This NodeState is not the parent of child");
+ public synchronized Collection getPropertyNames() {
+ Collection names;
+ if (getStatus() == Status.EXISTING_MODIFIED) {
+ names = new ArrayList();
+ for (Iterator it = getPropertyEntries().iterator(); it.hasNext(); ) {
+ names.add(((ChildPropertyEntry) it.next()).getName());
+ }
+ } else {
+ // this node state is unmodified, return all
+ names = properties.keySet();
}
- ChildNodeEntry cne = ChildNodeReference.create(child, isf, idFactory);
- childNodeEntries.add(cne);
- markModified();
+ return Collections.unmodifiableCollection(names);
}
/**
- * Renames this node to <code>newName</code>.
+ * Returns the complete collection of {@link ChildPropertyEntry}s.
*
- * @param newName the new name for this node state.
- * @throws IllegalStateException if this is the root node.
+ * @return unmodifiable collection of <code>ChildPropertyEntry</code> objects
*/
- private synchronized void rename(QName newName) {
- if (parent == null) {
- throw new IllegalStateException("root node cannot be renamed");
+ public synchronized Collection getPropertyEntries() {
+ Collection props;
+ if (getStatus() == Status.EXISTING_MODIFIED) {
+ // filter out removed properties
+ props = new ArrayList();
+ for (Iterator it = properties.values().iterator(); it.hasNext(); ) {
+ ChildPropertyEntry propEntry = (ChildPropertyEntry) it.next();
+ if (propEntry.isAvailable()) {
+ try {
+ if (propEntry.getPropertyState().isValid()) {
+ props.add(propEntry);
+ }
+ } catch (ItemStateException e) {
+ // removed in the meantime -> ignore
+ }
+ } else {
+ // never been accessed before, assume valid
+ props.add(propEntry);
+ }
+ }
+ } else {
+ // no need to filter out properties, there are no removed properties
+ props = properties.values();
+ }
+ return Collections.unmodifiableCollection(props);
+ }
+
+ /*
+ * Returns the property state with the given name.
+ *
+ * @param propertyName the name of the property state to return.
+ * @throws NoSuchItemStateException if there is no property state with the
+ * given name.
+ * @throws ItemStateException if an error occurs while retrieving the
+ * property state.
+ */
+ public synchronized PropertyState getPropertyState(QName propertyName)
+ throws NoSuchItemStateException, ItemStateException {
+ PropertyState propState = getAnyPropertyState(propertyName);
+ if (propState.isValid()) {
+ return propState;
+ } else {
+ throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString());
}
- name = newName;
}
/**
- * Notifies this node state that a child node state has been removed.
+ * Returns the property state with the given name and also takes removed
+ * property states into account.
*
- * @param nodeState the node state that has been removed.
- * @throws IllegalArgumentException if <code>this</code> is not the parent
- * of <code>nodeState</code>.
+ * @param propertyName the name of the property state to return.
+ * @throws NoSuchItemStateException if there is no property state with the
+ * given name.
+ * @throws ItemStateException if an error occurs while retrieving the
+ * property state.
*/
- private synchronized void childNodeStateRemoved(NodeState nodeState) {
- if (nodeState.getParent() != this) {
- throw new IllegalArgumentException("This NodeState is not the parent of nodeState");
+ public synchronized PropertyState getAnyPropertyState(QName propertyName)
+ throws NoSuchItemStateException, ItemStateException {
+ ChildPropertyEntry propEntry = (ChildPropertyEntry) properties.get(propertyName);
+ if (propEntry == null) {
+ throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString());
}
- // if nodeState does not exist anymore remove its child node entry
- if (nodeState.getStatus() == STATUS_REMOVED) {
- List entries = getChildNodeEntries(nodeState.getName());
- for (Iterator it = entries.iterator(); it.hasNext(); ) {
- ChildNodeEntry cne = (ChildNodeEntry) it.next();
+ return propEntry.getPropertyState();
+ }
+
+ /**
+ * TODO: find a better way to provide the index of a child node entry
+ * Returns the index of the given <code>ChildNodeEntry</code> and with
+ * <code>name</code>.
+ *
+ * @param name the name of the child node.
+ * @param cne the <code>ChildNodeEntry</code> instance.
+ * @return the index of the child node entry or <code>0</code> if it is not
+ * found in this <code>NodeState</code>.
+ */
+ public int getChildNodeIndex(QName name, ChildNodeEntry cne) {
+ List sns = childNodeEntries.get(name);
+ // index is one based
+ int index = 1;
+ for (Iterator it = sns.iterator(); it.hasNext(); ) {
+ ChildNodeEntry e = (ChildNodeEntry) it.next();
+ if (e == cne) {
+ return index;
+ }
+ // skip removed entries
+ try {
+ if (e.isAvailable() && e.getNodeState().isValid()) {
+ index++;
+ }
+ } catch (ItemStateException ex) {
+ // probably removed or stale
+ }
+ }
+ // not found
+ return Path.INDEX_UNDEFINED;
+ }
+ //--------------------------------------------------< Workspace - State >---
+ /**
+ *
+ * @param event
+ * @param changeLog
+ * @see ItemState#refresh(Event, ChangeLog)
+ */
+ synchronized void refresh(Event event, ChangeLog changeLog) {
+ checkIsWorkspaceState();
+
+ NodeId id = getNodeId();
+ switch (event.getType()) {
+ case Event.NODE_ADDED:
+ case Event.PROPERTY_ADDED:
+ if (id.equals(event.getParentId())) {
+ ItemId evId = event.getItemId();
+ ItemState newState = null;
+
+ if (evId.denotesNode()) {
+ QName name = event.getQPath().getNameElement().getName();
+ String uuid = (((NodeId)evId).getPath() != null) ? null : ((NodeId)evId).getUUID();
+ ChildNodeEntry cne = childNodeEntries.add(name, uuid);
+ try {
+ newState = cne.getNodeState();
+ } catch (ItemStateException e) {
+ log.error("Internal error", e);
+ }
+ } else {
+ QName pName = ((PropertyId) event.getItemId()).getQName();
+ ChildPropertyEntry re = PropertyReference.create(this, pName, isf, idFactory);
+ properties.put(pName, re);
+ try {
+ newState = re.getPropertyState();
+ } catch (ItemStateException e) {
+ log.error("Internal error", e);
+ }
+ // make sure this state is up to date (uuid/mixins)
+ refresh(pName, event.getType());
+ }
+
+ // connect the added state from the transient layer to the
+ // new workspaceState and make sure its data are updated.
+ if (newState != null && changeLog != null) {
+ for (Iterator it = changeLog.addedStates(); it.hasNext();) {
+ ItemState added = (ItemState) it.next();
+ if (added.getId().equals(evId)) {
+ added.connect(newState);
+ added.merge();
+ break;
+ }
+ }
+ }
+ // and let the transiently modified session state now, that
+ // its workspace state has been touched.
+ setStatus(Status.MODIFIED);
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
+ }
+ break;
+
+ case Event.NODE_REMOVED:
+ if (id.equals(event.getParentId())) {
+ QName qName = event.getQPath().getNameElement().getName();
+ int index = event.getQPath().getNameElement().getNormalizedIndex();
+ childNodeEntries.remove(qName, index);
+ setStatus(Status.MODIFIED);
+ } else if (id.equals(event.getItemId())) {
+ setStatus(Status.REMOVED);
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
+ }
+ break;
+
+ case Event.PROPERTY_REMOVED:
+ if (id.equals(event.getParentId())) {
+ QName pName = ((PropertyId) event.getItemId()).getQName();
+ properties.remove(pName);
+ // make sure this state is up to date (uuid/mixins)
+ refresh(pName, event.getType());
+ setStatus(Status.MODIFIED);
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
+ }
+ break;
+
+ case Event.PROPERTY_CHANGED:
+ if (id.equals(event.getParentId())) {
+ QName pName = ((PropertyId) event.getItemId()).getQName();
+ if (refresh(pName, event.getType())) {
+ setStatus(Status.MODIFIED);
+ }
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
+ }
+ break;
+ default:
+ // ILLEGAL
+ throw new IllegalArgumentException("Illegal event type " + event.getType() + " for NodeState.");
+ }
+ }
+
+ /**
+ * Returns true, if the uuid or the mixin types of this state have been
+ * modified.
+ *
+ * @param propertyName
+ * @param eventType
+ * @return
+ */
+ private boolean refresh(QName propertyName, int eventType) {
+ if (QName.JCR_UUID.equals(propertyName)) {
+ // TODO: to be fixed.
+ } else if (QName.JCR_MIXINTYPES.equals(propertyName)) {
+ if (eventType == Event.PROPERTY_REMOVED) {
+ mixinTypeNames = QName.EMPTY_ARRAY;
+ } else { // added or changed
try {
- if (cne.getNodeState() == nodeState) {
- childNodeEntries.remove(cne);
- break;
+ PropertyState ps = getPropertyState(propertyName);
+ QValue[] values = ps.getValues();
+ QName[] newMixins = new QName[values.length];
+ for (int i = 0; i < values.length; i++) {
+ newMixins[i] = QName.valueOf(values[i].getString());
}
+ mixinTypeNames = newMixins;
} catch (ItemStateException e) {
- // does not exist anymore? TODO: better error handling
- log.warn("child node entry does not exist anymore", e);
+ // should never occur.
+ log.error("Internal error while updating mixin types.", e);
+ } catch (RepositoryException e) {
+ // should never occur.
+ log.error("Internal error while updating mixin types.", e);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ //----------------------------------------------------< Session - State >---
+ /**
+ * {@inheritDoc}
+ * @see ItemState#reset()
+ */
+ synchronized void reset() {
+ checkIsSessionState();
+
+ if (overlayedState != null) {
+ synchronized (overlayedState) {
+ NodeState wspState = (NodeState) overlayedState;
+ name = wspState.name;
+ uuid = wspState.uuid;
+ nodeTypeName = wspState.nodeTypeName;
+ definition = wspState.definition;
+
+ init(wspState.getMixinTypeNames(), wspState.getChildNodeEntries(), wspState.getPropertyNames(), wspState.getNodeReferences());
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see ItemState#merge()
+ */
+ synchronized void merge() {
+ checkIsSessionState();
+
+ if (overlayedState != null) {
+ synchronized (overlayedState) {
+ NodeState wspState = (NodeState) overlayedState;
+ name = wspState.name;
+ uuid = wspState.uuid;
+ nodeTypeName = wspState.nodeTypeName;
+ definition = wspState.definition;
+
+ mixinTypeNames = wspState.mixinTypeNames;
+ references = wspState.getNodeReferences();
+
+ // search for removed properties
+ Collection wspProps = wspState.getPropertyNames();
+ for (Iterator it = properties.keySet().iterator(); it.hasNext();) {
+ ChildPropertyEntry pe = (ChildPropertyEntry) properties.get((QName) it.next());
+ if (pe.isAvailable()) {
+ try {
+ PropertyState ps = getPropertyState(pe.getName());
+ if (ps.getStatus() == Status.REMOVED || ps.getStatus() == Status.STALE_DESTROYED) {
+ it.remove();
+ }
+ } catch (ItemStateException e) {
+ log.error("Internal error while merging item node states.", e);
+ }
+ } else if (!wspProps.contains(pe.getName())) {
+ // not available and not present in wsp-layer any more.
+ it.remove();
+ }
+ }
+ // add missing property entries
+ for (Iterator it = wspProps.iterator(); it.hasNext();) {
+ QName propName = (QName) it.next();
+ if (!hasPropertyName(propName)) {
+ properties.put(propName, PropertyReference.create(this, propName, isf, idFactory));
+ } // else property is already listed
+ }
+
+ Collection wspEntries = wspState.getChildNodeEntries();
+ // remove child entries, that are 'REMOVED' in the wsp layer
+ for (Iterator it = getChildNodeEntries().iterator(); it.hasNext();) {
+ ChildNodeEntry cne = (ChildNodeEntry) it.next();
+ if (cne.isAvailable()) {
+ try {
+ NodeState ns = cne.getNodeState();
+ if (ns.getStatus() == Status.REMOVED) {
+ childNodeEntries.remove(cne.getName(), cne.getIndex());
+ }
+ } catch (ItemStateException e) {
+ // should not occur
+ log.error("Internal error while merging item node states.", e);
+ }
+ } else if (wspState.getChildNodeEntries(cne.getName()).isEmpty()) {
+ childNodeEntries.remove(cne.getName(), cne.getIndex());
+ } // TODO: clean up same-named siblings
+ }
+
+ // add missing child entries
+
+ for (Iterator it = wspEntries.iterator(); it.hasNext();) {
+ ChildNodeEntry wspEntry = (ChildNodeEntry) it.next();
+ List namedEntries = getChildNodeEntries(wspEntry.getName());
+ if (namedEntries.isEmpty()) {
+ // simple case: no cne with the given name
+ childNodeEntries.add(wspEntry.getName(), wspEntry.getUUID());
+ } else {
+ List wspCnes = wspState.getChildNodeEntries(wspEntry.getName());
+ // TODO: compare sn-siblings an add missing ones
+ }
}
}
}
- markModified();
}
/**
* @inheritDoc
* @see ItemState#remove()
*/
- public void remove() throws ItemStateException {
+ void remove() throws ItemStateException {
+ checkIsSessionState();
+
if (!isValid()) {
throw new ItemStateException("cannot remove an invalid NodeState");
}
@@ -586,10 +826,10 @@
// already removed
}
}
- if (getStatus() == STATUS_EXISTING || getStatus() == STATUS_EXISTING_MODIFIED) {
- setStatus(STATUS_EXISTING_REMOVED);
- } else if (getStatus() == STATUS_NEW) {
- setStatus(STATUS_REMOVED);
+ if (getStatus() == Status.EXISTING || getStatus() == Status.EXISTING_MODIFIED) {
+ setStatus(Status.EXISTING_REMOVED);
+ } else if (getStatus() == Status.NEW) {
+ setStatus(Status.REMOVED);
}
// now inform parent
parent.childNodeStateRemoved(this);
@@ -602,20 +842,17 @@
* @inheritDoc
* @see ItemState#revert(Set)
*/
- public void revert(Set affectedItemStates) {
- // all states except for 'new' ones must have an overlayed state in order
- // to be 'reverted'.
- if (getStatus() != STATUS_NEW && overlayedState == null) {
- throw new IllegalStateException("revert cannot be called on workspace state");
- }
+ 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(); ) {
- PropertyReference ref = (PropertyReference) it.next();
- if (ref.isResolved()) {
+ ChildPropertyEntry entry = (ChildPropertyEntry) it.next();
+ if (entry.isAvailable()) {
try {
- PropertyState propState = ref.getPropertyState();
+ PropertyState propState = entry.getPropertyState();
propState.revert(affectedItemStates);
} catch (ItemStateException e) {
// should not happen because PropertyReference is resolved
@@ -644,10 +881,10 @@
// now revert child node states
List children = new ArrayList(childNodeEntries);
for (Iterator it = children.iterator(); it.hasNext(); ) {
- ChildNodeReference ref = (ChildNodeReference) it.next();
- if (ref.isResolved()) {
+ ChildNodeEntry entry = (ChildNodeEntry) it.next();
+ if (entry.isAvailable()) {
try {
- NodeState nodeState = ref.getNodeState();
+ NodeState nodeState = entry.getNodeState();
nodeState.revert(affectedItemStates);
} catch (ItemStateException e) {
// should not happen because ChildNodeReference is resolved
@@ -660,31 +897,31 @@
// now revert this node state
switch (getStatus()) {
- case STATUS_EXISTING:
+ case Status.EXISTING:
// nothing to do
break;
- case STATUS_EXISTING_MODIFIED:
- case STATUS_EXISTING_REMOVED:
- case STATUS_STALE_MODIFIED:
+ case Status.EXISTING_MODIFIED:
+ case Status.EXISTING_REMOVED:
+ case Status.STALE_MODIFIED:
// revert state from overlayed
- pull();
- setStatus(STATUS_EXISTING);
+ reset();
+ setStatus(Status.EXISTING);
affectedItemStates.add(this);
break;
- case STATUS_NEW:
+ case Status.NEW:
// set removed
- setStatus(STATUS_REMOVED);
+ setStatus(Status.REMOVED);
// remove from parent
parent.childNodeStateRemoved(this);
affectedItemStates.add(this);
break;
- case STATUS_REMOVED:
+ 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");
parent.childNodeStateRemoved(this);
break;
- case STATUS_STALE_DESTROYED:
+ case Status.STALE_DESTROYED:
// overlayed state does not exist anymore
parent.childNodeStateRemoved(this);
affectedItemStates.add(this);
@@ -696,21 +933,23 @@
* @inheritDoc
* @see ItemState#collectTransientStates(Set)
*/
- public void collectTransientStates(Set transientStates) {
+ void collectTransientStates(Set transientStates) {
+ checkIsSessionState();
+
switch (getStatus()) {
- case STATUS_EXISTING_MODIFIED:
- case STATUS_EXISTING_REMOVED:
- case STATUS_NEW:
- case STATUS_STALE_DESTROYED:
- case STATUS_STALE_MODIFIED:
+ 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(); ) {
- PropertyReference ref = (PropertyReference) it.next();
- if (ref.isAvailable()) {
+ ChildPropertyEntry entry = (ChildPropertyEntry) it.next();
+ if (entry.isAvailable()) {
try {
- ref.getPropertyState().collectTransientStates(transientStates);
+ entry.getPropertyState().collectTransientStates(transientStates);
} catch (ItemStateException e) {
// should not happen because ref is available
}
@@ -732,86 +971,74 @@
}
/**
- * Determines if there is a property entry with the specified
- * <code>QName</code>.
+ * Sets the names of this node's mixin types.
*
- * @param propName <code>QName</code> object specifying a property name
- * @return <code>true</code> if there is a property entry with the specified
- * <code>QName</code>.
+ * @param mixinTypeNames set of names of mixin types
*/
- public synchronized boolean hasPropertyName(QName propName) {
- PropertyReference ref = (PropertyReference) properties.get(propName);
- if (ref == null) {
- return false;
- }
- if (ref.isResolved()) {
- try {
- return ref.getPropertyState().isValid();
- } catch (ItemStateException e) {
- // probably deleted in the meantime
- return false;
- }
+ synchronized void setMixinTypeNames(QName[] mixinTypeNames) {
+ checkIsSessionState();
+
+ if (mixinTypeNames != null) {
+ this.mixinTypeNames = mixinTypeNames;
} else {
- // then it must be valid
- return true;
+ this.mixinTypeNames = new QName[0];
}
+ markModified();
}
/**
- * Returns the names of this node's properties as a set of
- * <code>QNames</code> objects.
+ * Adds a child node state to this node state.
*
- * @return set of <code>QNames</code> objects
+ * @param child the node state to add.
+ * @param uuid the uuid of the child node state or <code>null</code> if
+ * <code>child</code> cannot be identified with a uuid.
+ * @throws IllegalArgumentException if <code>this</code> is not the parent
+ * of <code>child</code>.
*/
- public synchronized Collection getPropertyNames() {
- Collection names;
- if (getStatus() == STATUS_EXISTING_MODIFIED) {
- names = new ArrayList();
- for (Iterator it = getPropertyEntries().iterator(); it.hasNext(); ) {
- names.add(((ChildPropertyEntry) it.next()).getName());
- }
- } else {
- // this node state is unmodified, return all
- names = properties.keySet();
+ synchronized void addChildNodeState(NodeState child, String uuid) {
+ checkIsSessionState();
+
+ if (child.getParent() != this) {
+ throw new IllegalArgumentException("This NodeState is not the parent of child");
}
- return Collections.unmodifiableCollection(names);
+ ChildNodeEntry cne = ChildNodeReference.create(child, isf, idFactory);
+ childNodeEntries.add(cne);
+ markModified();
}
/**
- * Returns the complete collection of {@link ChildPropertyEntry}s.
+ * Notifies this node state that a child node state has been removed.
*
- * @return unmodifiable collection of <code>ChildPropertyEntry</code> objects
+ * @param nodeState the node state that has been removed.
+ * @throws IllegalArgumentException if <code>this</code> is not the parent
+ * of <code>nodeState</code>.
*/
- public synchronized Collection getPropertyEntries() {
- Collection props;
- if (getStatus() == STATUS_EXISTING_MODIFIED) {
- // filter out removed properties
- props = new ArrayList();
- for (Iterator it = properties.values().iterator(); it.hasNext(); ) {
- ChildPropertyEntry propEntry = (ChildPropertyEntry) it.next();
- if (propEntry.isAvailable()) {
- try {
- if (propEntry.getPropertyState().isValid()) {
- props.add(propEntry);
- }
- } catch (ItemStateException e) {
- // removed in the meantime -> ignore
+ private synchronized void childNodeStateRemoved(NodeState nodeState) {
+ checkIsSessionState();
+
+ if (nodeState.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 (nodeState.getStatus() == Status.REMOVED) {
+ List entries = getChildNodeEntries(nodeState.getQName());
+ for (Iterator it = entries.iterator(); it.hasNext(); ) {
+ ChildNodeEntry cne = (ChildNodeEntry) it.next();
+ try {
+ if (cne.getNodeState() == nodeState) {
+ childNodeEntries.remove(cne.getName(), cne.getIndex());
+ break;
}
- } else {
- // never been accessed before, assume valid
- props.add(propEntry);
+ } catch (ItemStateException e) {
+ // does not exist anymore? TODO: better error handling
+ log.warn("child node entry does not exist anymore", e);
}
}
- } else {
- // no need to filter out properties, there are no removed properties
- props = properties.values();
}
- return Collections.unmodifiableCollection(props);
+ markModified();
}
/**
- * TODO: move this method to a node state implementation which contains all transient related methods?
- *
* Adds a property state to this node state.
*
* @param propState the property state to add.
@@ -822,6 +1049,7 @@
* of <code>propState</code>.
*/
synchronized void addPropertyState(PropertyState propState) throws ItemExistsException {
+ checkIsSessionState();
if (propState.getParent() != this) {
throw new IllegalArgumentException("This NodeState is not the parent of propState");
}
@@ -837,7 +1065,7 @@
properties.remove(propertyName);
}
if (existingState != null) {
- if (existingState.getStatus() == STATUS_EXISTING_REMOVED) {
+ if (existingState.getStatus() == Status.EXISTING_REMOVED) {
// move to attic
propertiesInAttic.put(propertyName, ref);
} else {
@@ -845,7 +1073,7 @@
}
}
}
- properties.put(propertyName, new PropertyReference(propState, isf, idFactory));
+ properties.put(propertyName, PropertyReference.create(propState, isf, idFactory));
markModified();
}
@@ -857,53 +1085,85 @@
* of <code>propState</code>.
*/
synchronized void propertyStateRemoved(PropertyState propState) {
+ checkIsSessionState();
if (propState.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) {
+ if (propState.getStatus() == Status.REMOVED) {
properties.remove(propState.getQName());
}
markModified();
}
- /*
- * Returns the property state with the given name.
+ /**
+ * Reorders the child node <code>insertNode</code> before the child node
+ * <code>beforeNode</code>.
*
- * @param propertyName the name of the property state to return.
- * @throws NoSuchItemStateException if there is no property state with the
- * given name.
- * @throws ItemStateException if an error occurs while retrieving the
- * property state.
+ * @param insertNode the child node to reorder.
+ * @param beforeNode the child node where to insert the node before. If
+ * <code>null</code> the child node <code>insertNode</code>
+ * is moved to the end of the child node entries.
+ * @throws NoSuchItemStateException if <code>insertNode</code> or
+ * <code>beforeNode</code> is not a child
+ * node of this <code>NodeState</code>.
*/
- public synchronized PropertyState getPropertyState(QName propertyName)
- throws NoSuchItemStateException, ItemStateException {
- PropertyState propState = getAnyPropertyState(propertyName);
- if (propState.isValid()) {
- return propState;
+ synchronized void reorderChildNodeEntries(NodeState insertNode, NodeState beforeNode)
+ throws NoSuchItemStateException {
+ checkIsSessionState();
+
+ childNodeEntries.reorder(insertNode, beforeNode);
+ // mark this state as modified
+ markModified();
+ }
+
+ /**
+ * Moves a <code>ChildNodeEntry</code> to a new parent. If the new parent
+ * is this <code>NodeState</code>, the child state is renamed and moved
+ * to the end of the child entries collection.
+ *
+ * @param newParent
+ * @param childState
+ * @param newName
+ * @param newName <code>QName</code> object specifying the entry's new name
+ * @throws RepositoryException if the given child state is not a child
+ * of this node state.
+ */
+ synchronized void moveChildNodeEntry(NodeState newParent, NodeState childState, QName newName, QNodeDefinition newDefinition)
+ throws RepositoryException {
+ checkIsSessionState();
+
+ ChildNodeEntry oldEntry = childNodeEntries.remove(childState);
+ if (oldEntry != null) {
+ childState.rename(newName);
+ // re-parent target node
+ childState.parent = newParent;
+ // set definition according to new definition required by the new parent
+ childState.definition = newDefinition;
+ // add child node entry to new parent
+ newParent.childNodeEntries.add(childState);
} else {
- throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString());
+ throw new RepositoryException("Unexpected error: Child state to be renamed does not exist.");
}
+ // mark both this and newParent modified
+ markModified();
+ newParent.markModified();
}
/**
- * Returns the property state with the given name and also takes removed
- * property states into account.
+ * Renames this node to <code>newName</code>.
*
- * @param propertyName the name of the property state to return.
- * @throws NoSuchItemStateException if there is no property state with the
- * given name.
- * @throws ItemStateException if an error occurs while retrieving the
- * property state.
+ * @param newName the new name for this node state.
+ * @throws IllegalStateException if this is the root node.
*/
- public synchronized PropertyState getAnyPropertyState(QName propertyName)
- throws NoSuchItemStateException, ItemStateException {
- PropertyReference propRef = (PropertyReference) properties.get(propertyName);
- if (propRef == null) {
- throw new NoSuchItemStateException(idFactory.createPropertyId(getNodeId(), propertyName).toString());
+ private synchronized void rename(QName newName) {
+ checkIsSessionState();
+
+ if (parent == null) {
+ throw new IllegalStateException("root node cannot be renamed");
}
- return propRef.getPropertyState();
+ name = newName;
}
//---------------------------------------------------------< diff methods >
@@ -917,11 +1177,14 @@
* been added.
*/
public synchronized Set getAddedPropertyNames() {
- if (!hasOverlayedState()) {
+ checkIsSessionState();
+
+ if (getStatus() == Status.NEW) {
+ // state is new -> all
return Collections.unmodifiableSet(properties.keySet());
}
- NodeState other = (NodeState) getOverlayedState();
+ NodeState other = (NodeState) getWorkspaceState();
HashSet set = new HashSet(properties.keySet());
set.removeAll(other.properties.keySet());
return set;
@@ -934,7 +1197,10 @@
* @return collection of added child node entries
*/
public synchronized Collection getAddedChildNodeEntries() {
- if (!hasOverlayedState()) {
+ checkIsSessionState();
+
+ if (getStatus() == Status.NEW) {
+ // state is new -> all child nodes are new too
return childNodeEntries;
}
@@ -942,7 +1208,7 @@
for (Iterator it = childNodeEntries.iterator(); it.hasNext(); ) {
ChildNodeEntry cne = (ChildNodeEntry) it.next();
try {
- if (cne.getNodeState().getStatus() == STATUS_NEW) {
+ if (cne.getNodeState().getStatus() == Status.NEW) {
added.add(cne);
}
} catch (ItemStateException e) {
@@ -961,11 +1227,13 @@
* been removed.
*/
public synchronized Set getRemovedPropertyNames() {
- if (!hasOverlayedState()) {
+ checkIsSessionState();
+
+ if (getStatus() == Status.NEW) {
return Collections.EMPTY_SET;
}
- NodeState other = (NodeState) getOverlayedState();
+ NodeState other = (NodeState) getWorkspaceState();
HashSet set = new HashSet(other.properties.keySet());
set.removeAll(properties.keySet());
return set;
@@ -978,7 +1246,9 @@
* @return collection of removed child node entries
*/
public synchronized Collection getRemovedChildNodeEntries() {
- if (!hasOverlayedState()) {
+ checkIsSessionState();
+
+ if (getStatus() == Status.NEW) {
return Collections.EMPTY_LIST;
}
@@ -986,7 +1256,7 @@
for (Iterator it = childNodeEntries.iterator(); it.hasNext(); ) {
ChildNodeEntry cne = (ChildNodeEntry) it.next();
try {
- if (cne.getNodeState().getStatus() == STATUS_EXISTING_REMOVED) {
+ if (cne.getNodeState().getStatus() == Status.EXISTING_REMOVED) {
removed.add(cne);
}
} catch (ItemStateException e) {
@@ -996,116 +1266,7 @@
return removed;
}
- /**
- * Reorders the child node <code>insertNode</code> before the child node
- * <code>beforeNode</code>.
- *
- * @param insertNode the child node to reorder.
- * @param beforeNode the child node where to insert the node before. If
- * <code>null</code> the child node <code>insertNode</code>
- * is moved to the end of the child node entries.
- * @throws NoSuchItemStateException if <code>insertNode</code> or
- * <code>beforeNode</code> is not a child
- * node of this <code>NodeState</code>.
- */
- synchronized void reorderChildNodeEntries(NodeState insertNode, NodeState beforeNode)
- throws NoSuchItemStateException {
- childNodeEntries.reorder(insertNode, beforeNode);
- // mark this state as modified
- markModified();
- }
-
- /**
- * Moves a <code>ChildNodeEntry</code> to a new parent. If the new parent
- * is this <code>NodeState</code>, the child state is renamed and moved
- * to the end of the child entries collection.
- *
- * @param newParent
- * @param childState
- * @param newName
- * @param newName <code>QName</code> object specifying the entry's new name
- * @throws RepositoryException if the given child state is not a child
- * of this node state.
- */
- synchronized void moveChildNodeEntry(NodeState newParent, NodeState childState, QName newName, QNodeDefinition newDefinition)
- throws RepositoryException {
- ChildNodeEntry oldEntry = childNodeEntries.remove(childState);
- if (oldEntry != null) {
- childState.rename(newName);
- // re-parent target node
- childState.parent = newParent;
- // set definition according to new definition required by the new parent
- childState.definition = newDefinition;
- // add child node entry to new parent
- newParent.childNodeEntries.add(childState);
- } else {
- throw new RepositoryException("Unexpected error: Child state to be renamed does not exist.");
- }
- // mark both this and newParent modified
- markModified();
- newParent.markModified();
- }
-
- /**
- * Return the <code>NodeReferences</code> present on this state or
- * <code>null</code>.
- *
- * @return references
- */
- NodeReferences getNodeReferences() {
- if (hasOverlayedState()) {
- return ((NodeState)getOverlayedState()).references;
- } else {
- return references;
- }
- }
-
- /**
- * Set the <code>NodeReferences</code> for this state.
- *
- * @param references
- */
- void setNodeReferences(NodeReferences references) {
- if (getOverlayedState() != null) {
- throw new UnsupportedOperationException("Cannot set references to a transient node state.");
- }
- this.references = references;
- }
-
- /**
- * TODO: find a better way to provide the index of a child node entry
- * Returns the index of the given <code>ChildNodeEntry</code> and with
- * <code>name</code>.
- *
- * @param name the name of the child node.
- * @param cne the <code>ChildNodeEntry</code> instance.
- * @return the index of the child node entry or <code>0</code> if it is not
- * found in this <code>NodeState</code>.
- */
- int getChildNodeIndex(QName name, ChildNodeEntry cne) {
- List sns = childNodeEntries.get(name);
- // index is one based
- int index = 1;
- for (Iterator it = sns.iterator(); it.hasNext(); ) {
- ChildNodeEntry e = (ChildNodeEntry) it.next();
- if (e == cne) {
- return index;
- }
- // skip removed entries
- try {
- if (e.isAvailable() && e.getNodeState().isValid()) {
- index++;
- }
- } catch (ItemStateException ex) {
- // probably removed or stale
- }
- }
- // not found
- return Path.INDEX_UNDEFINED;
- }
-
//-------------------------------< internal >-------------------------------
-
/**
* Returns <code>true</code> if the collection of child node
* <code>entries</code> contains at least one valid <code>ChildNodeEntry</code>.
@@ -1134,7 +1295,6 @@
}
//------------------------------------------------------< inner classes >---
-
/**
* <code>ChildNodeEntries</code> represents an insertion-ordered
* collection of <code>ChildNodeEntry</code>s that also maintains
@@ -1166,7 +1326,7 @@
* is no <code>ChildNodeEntry</code> for <code>nodeState</code>.
*/
ChildNodeEntry get(NodeState nodeState) {
- Object o = nameMap.get(nodeState.getName());
+ Object o = nameMap.get(nodeState.getQName());
if (o == null) {
// no matching child node entry
return null;
@@ -1330,7 +1490,7 @@
}
}
- ChildNodeEntry entry = createChildNodeEntry(nodeName, uuid);
+ ChildNodeEntry entry = ChildNodeReference.create(NodeState.this, nodeName, uuid, isf, idFactory);
LinkedEntries.LinkNode ln = entries.add(entry);
if (siblings != null) {
@@ -1466,7 +1626,7 @@
*/
ChildNodeEntry remove(NodeState nodeState) {
ChildNodeEntry entry = null;
- for (Iterator it = get(nodeState.getName()).iterator(); it.hasNext(); ) {
+ for (Iterator it = get(nodeState.getQName()).iterator(); it.hasNext(); ) {
ChildNodeEntry tmp = (ChildNodeEntry) it.next();
try {
if (tmp.isAvailable() && tmp.getNodeState() == nodeState) {
@@ -1484,16 +1644,6 @@
}
/**
- * Removes the given child node entry.
- *
- * @param entry entry to be removed.
- * @return the removed entry or <code>null</code> if there is no such entry.
- */
- public ChildNodeEntry remove(ChildNodeEntry entry) {
- return remove(entry.getName(), entry.getIndex());
- }
-
- /**
* Removes all child node entries
*/
public void removeAll() {
@@ -1522,18 +1672,18 @@
// the link node where insertLN is ordered before
LinkedEntries.LinkNode beforeLN = null;
- Object insertObj = nameMap.get(insertNode.getName());
+ Object insertObj = nameMap.get(insertNode.getQName());
if (insertObj == null) {
// no matching child node entry
- throw new NoSuchItemStateException(insertNode.getName().toString());
+ throw new NoSuchItemStateException(insertNode.getQName().toString());
}
insertLN = getLinkNode(insertObj, insertNode);
// now retrieve LinkNode for beforeNode
if (beforeNode != null) {
- Object beforeObj = nameMap.get(beforeNode.getName());
+ Object beforeObj = nameMap.get(beforeNode.getQName());
if (beforeObj == null) {
- throw new NoSuchItemStateException(beforeNode.getName().toString());
+ throw new NoSuchItemStateException(beforeNode.getQName().toString());
}
beforeLN = getLinkNode(beforeObj, beforeNode);
}
@@ -1550,7 +1700,7 @@
// count our same name siblings until we reach beforeLN
int snsCount = 0;
- QName insertName = insertNode.getName();
+ QName insertName = insertNode.getQName();
for (Iterator it = entries.linkNodeIterator(); it.hasNext(); ) {
LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
if (ln == beforeLN) {
@@ -1573,25 +1723,6 @@
}
/**
- * Creates a <code>ChildNodeEntry</code> instance based on
- * <code>nodeName</code> and an optional <code>uuid</code>.
- *
- * @param nodeName the name of the child node.
- * @param uuid the UUID of the child node. If <code>null</code> the
- * child node cannot be identified with a UUID.
- * @return the created child node entry.
- */
- private ChildNodeEntry createChildNodeEntry(QName nodeName, String uuid) {
- if (uuid == null) {
- return new PathElementReference(NodeState.this, nodeName,
- isf, idFactory);
- } else {
- return new UUIDReference(NodeState.this,
- idFactory.createNodeId(uuid), isf, nodeName);
- }
- }
-
- /**
* Returns the matching <code>LinkNode</code> from a list or a single
* <code>LinkNode</code>.
*
@@ -1631,7 +1762,7 @@
log.warn("error retrieving a child node state", e);
}
}
- throw new NoSuchItemStateException(nodeState.getName().toString());
+ throw new NoSuchItemStateException(nodeState.getQName().toString());
}
//--------------------------------------< unmodifiable Collection view >
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java?view=diff&rev=454423&r1=454422&r2=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PathResolver.java Mon Oct 9 09:46:16 2006
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.jcr2spi.state;
import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
/**
* <code>PathResolver</code> resolves a relative Path starting at a given
@@ -32,7 +33,7 @@
/**
* The path to resolve.
*/
- private final Path relPath;
+ private final Path path;
/**
* Internal constructor.
@@ -48,47 +49,47 @@
"not contain parent path elements");
}
this.start = start;
- this.relPath = relPath;
+ this.path = relPath;
}
/**
* Resolves the path starting at <code>start</code>.
*
* @param start the starting point.
- * @param relPath the path to resolve.
+ * @param path the path to resolve.
* @return the resolved item state.
* @throws NoSuchItemStateException the the referenced item state does not
* exist.
* @throws ItemStateException if an error occurs while retrieving the
* item state.
- * @throws IllegalArgumentException if relPath is absolute or not normalized
+ * @throws IllegalArgumentException if path is absolute or not normalized
* or starts with a parent ('..') path
* element.
*/
- public static ItemState resolve(ItemState start, Path relPath)
+ public static ItemState resolve(ItemState start, Path path)
throws NoSuchItemStateException, ItemStateException {
- return new PathResolver(start, relPath).resolve();
+ return new PathResolver(start, path).resolve();
}
/**
- * Looks up the <code>ItemState</code> at <code>relPath</code> starting at
+ * Looks up the <code>ItemState</code> at <code>path</code> starting at
* <code>start</code>.
*
* @param start the starting point.
- * @param relPath the path to resolve.
+ * @param path the path to resolve.
* @return the resolved item state or <code>null</code> if the item is not
* available.
* @throws NoSuchItemStateException the the referenced item state does not
* exist.
* @throws ItemStateException if an error occurs while retrieving the
* item state.
- * @throws IllegalArgumentException if relPath is absolute or not normalized
+ * @throws IllegalArgumentException if path is absolute or not normalized
* or starts with a parent ('..') path
* element.
*/
- public static ItemState lookup(ItemState start, Path relPath)
+ public static ItemState lookup(ItemState start, Path path)
throws NoSuchItemStateException, ItemStateException {
- return new PathResolver(start, relPath).lookup();
+ return new PathResolver(start, path).lookup();
}
/**
@@ -102,15 +103,15 @@
private ItemState resolve()
throws NoSuchItemStateException, ItemStateException {
if (!start.isNode()) {
- throw new NoSuchItemStateException(relPath.toString());
+ throw new NoSuchItemStateException(path.toString());
}
NodeState state = (NodeState) start;
- for (int i = 0; i < relPath.getLength(); i++) {
- Path.PathElement elem = relPath.getElement(i);
+ for (int i = 0; i < path.getLength(); i++) {
+ Path.PathElement elem = path.getElement(i);
// check for root element
if (elem.denotesRoot()) {
if (start.getParent() != null) {
- throw new NoSuchItemStateException(relPath.toString());
+ throw new NoSuchItemStateException(path.toString());
} else {
continue;
}
@@ -122,10 +123,10 @@
elem.getNormalizedIndex()).getNodeState();
} else if (elem.getIndex() == 0 // property must not have index
&& state.hasPropertyName(elem.getName())
- && i == relPath.getLength() - 1) { // property must be final path element
+ && i == path.getLength() - 1) { // property must be final path element
return state.getPropertyState(elem.getName());
} else {
- throw new NoSuchItemStateException(relPath.toString());
+ throw new NoSuchItemStateException(path.toString());
}
}
return state;
@@ -144,11 +145,11 @@
private ItemState lookup()
throws NoSuchItemStateException, ItemStateException {
if (!start.isNode()) {
- throw new NoSuchItemStateException(relPath.toString());
+ throw new NoSuchItemStateException(path.toString());
}
NodeState state = (NodeState) start;
- for (int i = 0; i < relPath.getLength(); i++) {
- Path.PathElement elem = relPath.getElement(i);
+ for (int i = 0; i < path.getLength(); i++) {
+ Path.PathElement elem = path.getElement(i);
// first try to resolve node
if (state.hasChildNodeEntry(elem.getName(), elem.getNormalizedIndex())) {
ChildNodeEntry cne = state.getChildNodeEntry(elem.getName(), elem.getNormalizedIndex());
@@ -159,11 +160,11 @@
}
} else if (elem.getIndex() == 0 // property must not have index
&& state.hasPropertyName(elem.getName())
- && i == relPath.getLength() - 1) { // property must be final path element
+ && i == path.getLength() - 1) { // property must be final path element
// TODO: check if available
return state.getPropertyState(elem.getName());
} else {
- throw new NoSuchItemStateException(relPath.toString());
+ throw new NoSuchItemStateException(path.toString());
}
}
return state;
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=454423&r1=454422&r2=454423
==============================================================================
--- 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 Oct 9 09:46:16 2006
@@ -73,7 +73,7 @@
protected PropertyState(PropertyState overlayedState, NodeState parent,
int initialStatus, IdFactory idFactory) {
super(overlayedState, parent, initialStatus, idFactory);
- pull();
+ reset();
}
/**
@@ -86,8 +86,8 @@
* @param idFactory
*/
protected PropertyState(QName name, NodeState parent, QPropertyDefinition definition,
- int initialStatus, IdFactory idFactory) {
- super(parent, initialStatus, idFactory);
+ int initialStatus, IdFactory idFactory, boolean isWorkspaceState) {
+ super(parent, initialStatus, idFactory, isWorkspaceState);
this.name = name;
this.def = definition;
@@ -105,128 +105,7 @@
this.values = (values == null) ? QValue.EMPTY_ARRAY : values;
}
- /**
- * @inheritDoc
- */
- public void remove() {
- if (getStatus() == STATUS_NEW) {
- setStatus(STATUS_REMOVED);
- } else {
- setStatus(STATUS_EXISTING_REMOVED);
- }
- parent.propertyStateRemoved(this);
- }
-
- /**
- * @inheritDoc
- * @see ItemState#revert(Set)
- */
- public void revert(Set affectedItemStates) {
- // all states except for 'new' ones must have an overlayed state in order
- // to be 'reverted'.
- if (getStatus() != STATUS_NEW && overlayedState == null) {
- throw new IllegalStateException("revert cannot be called on workspace 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
- pull();
- setStatus(STATUS_EXISTING);
- affectedItemStates.add(this);
- break;
- case STATUS_NEW:
- // set removed
- setStatus(STATUS_REMOVED);
- // and remove from parent
- parent.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");
- parent.propertyStateRemoved(this);
- break;
- case STATUS_STALE_DESTROYED:
- // overlayed does not exist anymore
- parent.propertyStateRemoved(this);
- affectedItemStates.add(this);
- break;
- }
- }
-
- /**
- * @inheritDoc
- * @see ItemState#collectTransientStates(Set)
- */
- public void collectTransientStates(Set transientStates) {
- 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());
- }
- }
-
- /**
- * {@inheritDoc}
- */
- protected synchronized void pull() {
- if (overlayedState != null) {
- synchronized (overlayedState) {
- PropertyState propState = (PropertyState) overlayedState;
- name = propState.name;
- type = propState.type;
- def = propState.def;
- values = propState.values;
- }
- }
- }
-
- protected synchronized void refresh(Event event, ChangeLog changeLog) {
- switch (event.getType()) {
- case Event.PROPERTY_REMOVED:
- if (event.getItemId().equals(getId())) {
- setStatus(STATUS_REMOVED);
- } else {
- // ILLEGAL
- throw new IllegalArgumentException("EventId " + event.getItemId() + " does not match id of this property state.");
- }
- break;
-
- case Event.PROPERTY_CHANGED:
- if (event.getItemId().equals(getId())) {
- setStatus(STATUS_MODIFIED);
- } else {
- // ILLEGAL
- throw new IllegalArgumentException("EventId " + event.getItemId() + " does not match id of this property state.");
- }
- break;
-
- case Event.PROPERTY_ADDED:
- case Event.NODE_ADDED:
- case Event.NODE_REMOVED:
- default:
- throw new IllegalArgumentException("Event type " + event.getType() + " cannot be applied to a PropertyState");
- }
- }
-
- //--------------------< public READ methods and package private Setters >---
+ //----------------------------------------------------------< ItemState >---
/**
* Always returns false.
*
@@ -238,12 +117,24 @@
}
/**
+ * Returns the name of this property.
+ *
+ * @return the name of this property.
+ * @see ItemState#getQName()
+ */
+ public QName getQName() {
+ return name;
+ }
+
+ /**
* {@inheritDoc}
+ * @see ItemState#getId()
*/
public ItemId getId() {
return getPropertyId();
}
+ //------------------------------------------------------< PropertyState >---
/**
* Returns the identifier of this property.
*
@@ -254,15 +145,6 @@
}
/**
- * Returns the name of this property.
- *
- * @return the name of this property.
- */
- public QName getQName() {
- return name;
- }
-
- /**
* Returns the type of the property value(s).
*
* @return the type of the property value(s).
@@ -305,20 +187,6 @@
}
/**
- * Sets the value(s) of this property.
- *
- * @param values the new values
- */
- void setValues(QValue[] values, int type) throws RepositoryException {
- // make sure the arguements are consistent and do not violate the
- // given property definition.
- validate(values, type, this.def);
- this.values = values;
- this.type = type;
- markModified();
- }
-
- /**
* Convenience method for single valued property states.
*
* @return
@@ -333,6 +201,158 @@
} else {
return values[0];
}
+ }
+
+ //----------------------------------------------------< Workspace State >---
+ /**
+ * @see ItemState#refresh(Event, ChangeLog)
+ */
+ synchronized void refresh(Event event, ChangeLog changeLog) {
+ checkIsWorkspaceState();
+
+ switch (event.getType()) {
+ case Event.PROPERTY_REMOVED:
+ if (event.getItemId().equals(getId())) {
+ setStatus(Status.REMOVED);
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("EventId " + event.getItemId() + " does not match id of this property state.");
+ }
+ break;
+
+ case Event.PROPERTY_CHANGED:
+ if (event.getItemId().equals(getId())) {
+ setStatus(Status.MODIFIED);
+ } else {
+ // ILLEGAL
+ throw new IllegalArgumentException("EventId " + event.getItemId() + " does not match id of this property state.");
+ }
+ break;
+
+ case Event.PROPERTY_ADDED:
+ case Event.NODE_ADDED:
+ case Event.NODE_REMOVED:
+ default:
+ throw new IllegalArgumentException("Event type " + event.getType() + " cannot be applied to a PropertyState");
+ }
+ }
+
+ //----------------------------------------------------< Session - State >---
+ /**
+ * {@inheritDoc}
+ * @see ItemState#reset()
+ */
+ synchronized void reset() {
+ checkIsSessionState();
+ if (overlayedState != null) {
+ synchronized (overlayedState) {
+ PropertyState wspState = (PropertyState) overlayedState;
+ name = wspState.name;
+ type = wspState.type;
+ def = wspState.def;
+ values = wspState.values;
+ }
+ }
+ }
+
+ synchronized void merge() {
+ reset();
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemState#remove()
+ */
+ void remove() {
+ checkIsSessionState();
+
+ if (getStatus() == Status.NEW) {
+ setStatus(Status.REMOVED);
+ } else {
+ setStatus(Status.EXISTING_REMOVED);
+ }
+ parent.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
+ parent.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");
+ parent.propertyStateRemoved(this);
+ break;
+ case Status.STALE_DESTROYED:
+ // overlayed does not exist anymore
+ parent.propertyStateRemoved(this);
+ affectedItemStates.add(this);
+ break;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemState#collectTransientStates(Set)
+ */
+ void collectTransientStates(Set 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.
+ *
+ * @param values the new values
+ */
+ void setValues(QValue[] values, int type) throws RepositoryException {
+ checkIsSessionState();
+
+ // make sure the arguements are consistent and do not violate the
+ // given property definition.
+ validate(values, type, this.def);
+ this.values = values;
+ this.type = type;
+ markModified();
}
/**
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=454423&r1=454422&r2=454423
==============================================================================
--- 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 Oct 9 09:46:16 2006
@@ -18,6 +18,8 @@
import org.apache.jackrabbit.jcr2spi.HierarchyManager;
import org.apache.jackrabbit.jcr2spi.HierarchyManagerImpl;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildPropertyEntry;
+import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
import org.apache.jackrabbit.jcr2spi.util.ReferenceChangeTracker;
import org.apache.jackrabbit.jcr2spi.util.LogUtil;
import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
@@ -366,7 +368,7 @@
throws StaleItemStateException, ItemStateException {
// fail-fast test: check status of this item's state
switch (state.getStatus()) {
- case ItemState.STATUS_NEW:
+ case Status.NEW:
{
String msg = LogUtil.safeGetJCRPath(state, nsResolver) + ": cannot save a new item.";
log.debug(msg);
@@ -375,13 +377,13 @@
}
if (throwOnStale) {
switch (state.getStatus()) {
- case ItemState.STATUS_STALE_MODIFIED:
+ case Status.STALE_MODIFIED:
{
String msg = LogUtil.safeGetJCRPath(state, nsResolver) + ": the item cannot be saved because it has been modified externally.";
log.debug(msg);
throw new StaleItemStateException(msg);
}
- case ItemState.STATUS_STALE_DESTROYED:
+ case Status.STALE_DESTROYED:
{
String msg = LogUtil.safeGetJCRPath(state, nsResolver) + ": the item cannot be saved because it has been deleted externally.";
log.debug(msg);
@@ -398,16 +400,16 @@
ItemState transientState = (ItemState) it.next();
// fail-fast test: check status of transient state
switch (transientState.getStatus()) {
- case ItemState.STATUS_NEW:
+ case Status.NEW:
changeLog.added(transientState);
break;
- case ItemState.STATUS_EXISTING_MODIFIED:
+ case Status.EXISTING_MODIFIED:
changeLog.modified(transientState);
break;
- case ItemState.STATUS_EXISTING_REMOVED:
+ case Status.EXISTING_REMOVED:
changeLog.deleted(transientState);
break;
- case ItemState.STATUS_STALE_MODIFIED:
+ case Status.STALE_MODIFIED:
if (throwOnStale) {
String msg = transientState.getId() + ": the item cannot be saved because it has been modified externally.";
log.debug(msg);
@@ -415,7 +417,7 @@
} else {
changeLog.modified(transientState);
}
- case ItemState.STATUS_STALE_DESTROYED:
+ case Status.STALE_DESTROYED:
if (throwOnStale) {
String msg = transientState.getId() + ": the item cannot be saved because it has been deleted externally.";
log.debug(msg);
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java?view=auto&rev=454423
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java Mon Oct 9 09:46:16 2006
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ *
+ * Copyright 1997-2005 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+package org.apache.jackrabbit.jcr2spi.state;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>Status</code>...
+ */
+public class Status {
+
+ private static Logger log = LoggerFactory.getLogger(Status.class);
+
+ /**
+ * 'existing', i.e. persistent state
+ */
+ public static final int EXISTING = 1;
+ /**
+ * 'existing', i.e. persistent state that has been transiently modified (copy-on-write)
+ */
+ public static final int EXISTING_MODIFIED = 2;
+ /**
+ * 'existing', i.e. persistent state that has been transiently removed (copy-on-write)
+ */
+ public static final int EXISTING_REMOVED = 3;
+ /**
+ * 'new' state
+ */
+ public static final int NEW = 4;
+ /**
+ * 'existing', i.e. persistent state that has been persistently modified by somebody else
+ */
+ public static final int STALE_MODIFIED = 5;
+ /**
+ * 'existing', i.e. persistent state that has been destroyed by somebody else
+ */
+ public static final int STALE_DESTROYED = 6;
+
+ /**
+ * a state is permanently modified either by saving transient changes or
+ * by wsp operations or be external modification
+ * TODO: improve. status only temporarily used to indicate to a SessionISM-state to copy changes
+ */
+ public static final int MODIFIED = 7;
+
+ /**
+ * a new state was deleted and is now 'removed'
+ * or an existing item has been removed by a workspace operation or
+ * by an external modification.
+ */
+ public static final int REMOVED = 8;
+
+
+ public static boolean isTerminalStatus(int status) {
+ return status == REMOVED || status == STALE_DESTROYED;
+ }
+
+}
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/Status.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url