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 2007/02/13 10:31:53 UTC
svn commit: r506927 [5/8] - in /jackrabbit/trunk/contrib/spi: jcr2spi/
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/
jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/lock/ jcr2spi...
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java?view=auto&rev=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java Tue Feb 13 01:31:36 2007
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * <code>AbstractItemStateFactory</code>...
+ */
+public abstract class AbstractItemStateFactory implements ItemStateFactory {
+
+ private static Logger log = LoggerFactory.getLogger(AbstractItemStateFactory.class);
+
+ private final Set creationListeners = new HashSet();
+
+ //---------------------------------------------------< ItemStateFactory >---
+ /**
+ * @inheritDoc
+ * @see ItemStateFactory#addCreationListener(ItemStateCreationListener)
+ */
+ public void addCreationListener(ItemStateCreationListener listener) {
+ synchronized (creationListeners) {
+ creationListeners.add(listener);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemStateFactory#removeCreationListener(ItemStateCreationListener)
+ */
+ public void removeCreationListener(ItemStateCreationListener listener) {
+ synchronized (creationListeners) {
+ creationListeners.remove(listener);
+ }
+ }
+
+ //------------------------------------------------< private | protected >---
+ /**
+ *
+ * @return
+ */
+ private ItemStateCreationListener[] getListeners() {
+ synchronized (creationListeners) {
+ return (ItemStateCreationListener[]) creationListeners.toArray(new ItemStateCreationListener[creationListeners.size()]);
+ }
+ }
+
+ /**
+ *
+ * @param createdState
+ */
+ void notifyCreated(ItemState createdState) {
+ ItemStateCreationListener[] listeners = getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ // notify listeners when this item state is saved or invalidated
+ createdState.addListener(listeners[i]);
+ // now inform about creation
+ listeners[i].created(createdState);
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/AbstractItemStateFactory.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java Tue Feb 13 01:31:36 2007
@@ -19,7 +19,10 @@
import org.apache.jackrabbit.jcr2spi.operation.Operation;
import org.apache.jackrabbit.jcr2spi.operation.AddNode;
import org.apache.jackrabbit.jcr2spi.operation.AddProperty;
+import org.apache.jackrabbit.jcr2spi.operation.SetMixin;
import org.apache.jackrabbit.jcr2spi.config.CacheBehaviour;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.name.QName;
import javax.jcr.nodetype.ConstraintViolationException;
import java.util.Iterator;
@@ -237,15 +240,35 @@
deletedStates.remove(state);
// remove operations performed on the removed state
removeAffectedOperations(state);
- // remove add-operation (parent affected) as well
- NodeState parent = state.getParent();
- if (parent != null && parent.getStatus() != Status.REMOVED) {
- for (Iterator it = operations.iterator(); it.hasNext();) {
- Operation op = (Operation) it.next();
- if ((op instanceof AddNode || op instanceof AddProperty)
- && op.getAffectedItemStates().contains(parent)) {
- it.remove();
+ /* remove the add-operation as well:
+ since the affected state of an 'ADD' operation is the parent
+ instead of the added-state, the set of operations
+ need to be searched for the parent state && the proper
+ operation type.
+ SET_MIXIN can be is a special case of adding a property */
+ NodeEntry parentEntry = state.getHierarchyEntry().getParent();
+ if (parentEntry != null && parentEntry.isAvailable()) {
+ try {
+ NodeState parent = parentEntry.getNodeState();
+ if (parent.getStatus() != Status.REMOVED) {
+ for (Iterator it = operations.iterator(); it.hasNext();) {
+ Operation op = (Operation) it.next();
+ if (op instanceof AddNode && ((AddNode)op).getParentState() == parent) {
+ it.remove();
+ break;
+ } else if (op instanceof AddProperty && ((AddProperty)op).getParentState() == parent) {
+ it.remove();
+ break;
+ } else if (op instanceof SetMixin &&
+ QName.JCR_MIXINTYPES.equals(state.getQName()) &&
+ ((SetMixin)op).getNodeState() == parent) {
+ it.remove();
+ break;
+ }
+ }
}
+ } catch (ItemStateException e) {
+ // should never occur -> ignore
}
}
} else if (previousStatus == Status.EXISTING_REMOVED) {
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java?view=auto&rev=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java Tue Feb 13 01:31:36 2007
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.util.IteratorHelper;
+
+import java.util.Iterator;
+
+/**
+ * <code>EmptyNodeReferences</code>...
+ */
+class EmptyNodeReferences implements NodeReferences {
+
+ private static Logger log = LoggerFactory.getLogger(EmptyNodeReferences.class);
+ private static NodeReferences INSTANCE;
+
+ private EmptyNodeReferences() {
+
+ }
+
+ static NodeReferences getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new EmptyNodeReferences();
+ }
+ return INSTANCE;
+ }
+
+ public boolean isEmpty() {
+ return true;
+ }
+
+ public Iterator iterator() {
+ return IteratorHelper.EMPTY;
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/EmptyNodeReferences.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java Tue Feb 13 01:31:36 2007
@@ -18,16 +18,20 @@
import org.apache.jackrabbit.util.WeakIdentityCollection;
import org.apache.jackrabbit.spi.ItemId;
-import org.apache.jackrabbit.spi.IdFactory;
-import org.apache.jackrabbit.spi.Event;
-import org.apache.jackrabbit.name.Path;
-import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.PropertyId;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.Path;
import org.apache.jackrabbit.jcr2spi.config.CacheBehaviour;
+import org.apache.jackrabbit.jcr2spi.hierarchy.HierarchyEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeConflictException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import java.util.Collection;
import java.util.Iterator;
@@ -44,8 +48,7 @@
private static Logger log = LoggerFactory.getLogger(ItemState.class);
/**
- * Flag used to distinguish workspace states from session states. The first
- * accepts call to {@link #refresh(Event)}, while the latter
+ * Flag used to distinguish workspace states from session states. The latter
* will be able to handle the various methods related to transient
* modifications.
*/
@@ -62,21 +65,13 @@
private final transient Collection listeners = new WeakIdentityCollection(5);
/**
- * IdFactory used to build id of the states
- */
- final IdFactory idFactory;
-
- /**
* The <code>ItemStateFactory</code> which is used to create new
* <code>ItemState</code> instances.
*/
final ItemStateFactory isf;
- /**
- * The parent <code>NodeState</code> or <code>null</code> if this
- * instance represents the root node.
- */
- NodeState parent;
+ // TODO: find better solution..... needed to retrieve definition.
+ final NodeTypeRegistry ntReg;
/**
* the backing persistent item state (may be null)
@@ -86,11 +81,11 @@
/**
* Constructs a new unconnected item state
*
- * @param parent
- * @param initialStatus the initial status of the item state object
+ * @param initialStatus
+ * @param isWorkspaceState
*/
- protected ItemState(NodeState parent, int initialStatus, ItemStateFactory isf,
- IdFactory idFactory, boolean isWorkspaceState) {
+ protected ItemState(int initialStatus, boolean isWorkspaceState,
+ ItemStateFactory isf, NodeTypeRegistry ntReg) {
switch (initialStatus) {
case Status.EXISTING:
case Status.NEW:
@@ -101,11 +96,10 @@
log.debug(msg);
throw new IllegalArgumentException(msg);
}
- this.parent = parent;
overlayedState = null;
- this.idFactory = idFactory;
this.isf = isf;
+ this.ntReg = ntReg;
this.isWorkspaceState = isWorkspaceState;
}
@@ -113,11 +107,10 @@
* Constructs a new item state that is initially connected to an overlayed
* state.
*
- * @param overlayedState the backing item state being overlayed
- * @param initialStatus the initial status of the new <code>ItemState</code> instance
+ * @param overlayedState
+ * @param initialStatus
*/
- protected ItemState(ItemState overlayedState, NodeState parent,
- int initialStatus, ItemStateFactory isf, IdFactory idFactory) {
+ protected ItemState(ItemState overlayedState, int initialStatus, ItemStateFactory isf) {
switch (initialStatus) {
case Status.EXISTING:
case Status.EXISTING_MODIFIED:
@@ -129,16 +122,21 @@
log.debug(msg);
throw new IllegalArgumentException(msg);
}
- this.parent = parent;
- this.idFactory = idFactory;
this.isf = isf;
this.isWorkspaceState = false;
-
+ this.ntReg = overlayedState.ntReg;
connect(overlayedState);
}
//----------------------------------------------------------< ItemState >---
/**
+ * The <code>HierarchyEntry</code> corresponding to this <code>ItemState</code>.
+ *
+ * @return The <code>HierarchyEntry</code> corresponding to this <code>ItemState</code>.
+ */
+ public abstract HierarchyEntry getHierarchyEntry();
+
+ /**
* Returns <code>true</code> if this item state is valid, that is its status
* is one of:
* <ul>
@@ -153,6 +151,7 @@
}
/**
+ * Utility method:
* Determines if this item state represents a node.
*
* @return true if this item state represents a node, otherwise false.
@@ -160,86 +159,48 @@
public abstract boolean isNode();
/**
- * Returns the name of this state.
+ * Utility method:
+ * Returns the name of this state. Shortcut for calling 'getQName' on the
+ * {@link ItemState#getHierarchyEntry() hierarchy entry}.
*
* @return name of this state
*/
- public abstract QName getQName();
+ public QName getQName() {
+ return getHierarchyEntry().getQName();
+ }
/**
- * Returns the identifier of this item state.
+ * Utility method:
+ * Returns the identifier of this item state. Shortcut for calling 'getId'
+ * on the {@link ItemState#getHierarchyEntry() hierarchy entry}.
*
* @return the identifier of this item state..
*/
public abstract ItemId getId();
/**
- * Returns the qualified path of this item state.
- *
- * @return qualified path
- * @throws ItemNotFoundException
- * @throws RepositoryException
- */
- public Path getQPath() throws ItemNotFoundException, RepositoryException {
- // shortcut for root state
- if (parent == null) {
- return Path.ROOT;
- }
-
- // build path otherwise
- try {
- Path.PathBuilder builder = new Path.PathBuilder();
- buildPath(builder, this);
- return builder.getPath();
- } catch (MalformedPathException e) {
- String msg = "Failed to build path of " + this;
- throw new RepositoryException(msg, e);
- }
- }
-
- /**
- * Adds the path element of an item id to the path currently being built.
- * On exit, <code>builder</code> contains the path of <code>state</code>.
+ * Utility method:
+ * Returns the qualified path of this item state. Shortcut for calling
+ * 'getPath' on the {@link ItemState#getHierarchyEntry() hierarchy entry}.
*
- * @param builder builder currently being used
- * @param state item to find path of
+ * @return
+ * @throws RepositoryException if an error occurs
*/
- private void buildPath(Path.PathBuilder builder, ItemState state)
- throws ItemNotFoundException {
- NodeState parentState = state.getParent();
- // shortcut for root state
- if (parentState == null) {
- builder.addRoot();
- return;
- }
-
- // recursively build path of parent
- buildPath(builder, parentState);
-
- QName name = state.getQName();
- if (state.isNode()) {
- int index = ((NodeState)state).getIndex();
- // add to path
- if (index == Path.INDEX_DEFAULT) {
- builder.addLast(name);
- } else {
- builder.addLast(name, index);
- }
- } else {
- // property-state: add to path
- builder.addLast(name);
- }
+ public Path getQPath() throws RepositoryException {
+ return getHierarchyEntry().getPath();
}
/**
- * Returns the parent <code>NodeState</code> or <code>null</code>
- * if either this item state represents the root node or this item state is
- * 'free floating', i.e. not attached to the repository's hierarchy.
+ * Utility method: Shortcut for calling
+ * 'getParent().getNodeState()' on the {@link ItemState#getHierarchyEntry()
+ * hierarchy entry}.
*
- * @return the parent <code>NodeState</code>
+ * @return
+ * @throws NoSuchItemStateException
+ * @throws ItemStateException
*/
- public NodeState getParent() {
- return parent;
+ public NodeState getParent() throws NoSuchItemStateException, ItemStateException {
+ return getHierarchyEntry().getParent().getNodeState();
}
/**
@@ -256,7 +217,7 @@
*
* @param newStatus the new status
*/
- void setStatus(int newStatus) {
+ public void setStatus(int newStatus) {
int oldStatus = status;
if (oldStatus == newStatus) {
return;
@@ -292,14 +253,6 @@
}
/**
- * Reloads this item state recursively. If '<code>keepChanges</code>' is
- * true, states with transient changes are left untouched. Otherwise this
- * state gets its data reloaded from the persistent state.
- * todo throw exception in case of error?
- */
- public abstract void reload(boolean keepChanges);
-
- /**
* Merge all data from the given state into this state. If
* '<code>keepChanges</code>' is true, transient modifications present on
* this state are not touched. Otherwise this state is completely reset
@@ -309,15 +262,7 @@
* @param keepChanges
* @return true if this state has been modified
*/
- abstract boolean merge(ItemState another, boolean keepChanges);
-
- /**
- * Invalidates this item state recursively. In contrast to {@link #refresh}
- * this method only sets the status of this item state to {@link
- * Status#INVALIDATED} and does not acutally update it with the persistent
- * state in the repository.
- */
- public abstract void invalidate(boolean recursive);
+ public abstract boolean merge(ItemState another, boolean keepChanges);
/**
* Add an <code>ItemStateLifeCycleListener</code>
@@ -353,26 +298,21 @@
//-----------------------------------------< ItemStateLifeCycleListener >---
/**
*
- * @param state
+ * @param overlayed
* @param previousStatus
*/
- public void statusChanged(ItemState state, int previousStatus) {
+ public void statusChanged(ItemState overlayed, int previousStatus) {
checkIsSessionState();
- state.checkIsWorkspaceState();
+ overlayed.checkIsWorkspaceState();
// the given state is the overlayed state this state (session) is listening to.
- if (state == overlayedState) {
- switch (state.getStatus()) {
+ if (overlayed == overlayedState) {
+ switch (overlayed.getStatus()) {
case Status.MODIFIED:
// underlying state has been modified by external changes
if (status == Status.EXISTING || status == Status.INVALIDATED) {
- synchronized (this) {
- if (merge(state, false) || status == Status.INVALIDATED) {
- // temporarily set the state to MODIFIED in order
- // to inform listeners.
- setStatus(Status.MODIFIED);
- }
- }
+ // temporarily set the state to MODIFIED in order to inform listeners.
+ setStatus(Status.MODIFIED);
} else if (status == Status.EXISTING_MODIFIED) {
// TODO: try to merge changes
setStatus(Status.STALE_MODIFIED);
@@ -395,7 +335,7 @@
break;
default:
// Should never occur, since 'setStatus(int)' already validates
- log.error("Workspace state cannot have its state changed to " + state.getStatus());
+ log.error("Workspace state cannot have its state changed to " + overlayed.getStatus());
break;
}
}
@@ -449,36 +389,6 @@
return overlayedState != null;
}
- //--------------------------------------------------< Workspace - State >---
- /**
- * Used on 'workspace' states in order to update the state according to
- * an external modification indicated by the given event.
- *
- * @param event
- * @throws IllegalStateException if this state is a 'session' state.
- */
- abstract void refresh(Event event);
-
- /**
- * Returns the overlaying item state or <code>null</code> if that state
- * has not been created yet or has been disconnected.
- *
- * @return
- */
- ItemState getSessionState() {
- checkIsWorkspaceState();
- ItemStateLifeCycleListener[] la;
- synchronized (listeners) {
- la = (ItemStateLifeCycleListener[]) listeners.toArray(new ItemStateLifeCycleListener[listeners.size()]);
- }
- for (int i = 0; i < la.length; i++) {
- if (la[i] instanceof ItemState) {
- return (ItemState) la[i];
- }
- }
- return null;
- }
-
//----------------------------------------------------< Session - State >---
/**
@@ -493,111 +403,65 @@
/**
* Connect this state to some underlying overlayed state.
*/
- void connect(ItemState overlayedState) {
+ private void connect(ItemState overlayedState) {
checkIsSessionState();
overlayedState.checkIsWorkspaceState();
- if (this.overlayedState != null && this.overlayedState != overlayedState) {
+ if (this.overlayedState == null) {
+ setOverLayedState(overlayedState);
+ } else if (this.overlayedState != overlayedState) {
throw new IllegalStateException("Item state already connected to another underlying state: " + this);
- }
- this.overlayedState = overlayedState;
- this.overlayedState.addListener(this);
+ } // attempt to connect state to its ol-state again -> nothing to do.
}
/**
- * Removes this item state. This will change the status of this property
- * state to either {@link Status#EXISTING_REMOVED} or {@link
- * Status#REMOVED} depending on the current status.
+ * Replaces the overlayedState with a new instance retrieved from the
+ * persistent layer thus forcing a reload of this ItemState or in case
+ * of a NEW state, retrieves the overlayed state after the state has been
+ * persisted and connects the NEW state. Note, that in the latter case,
+ * the parent must already be connected to its overlayed state.
*
- * @throws ItemStateException if an error occurs while removing this item
- * state. e.g. this item state is not valid anymore.
+ * @param keepChanges
+ * @throws NoSuchItemStateException
+ * @throws ItemStateException
*/
- void remove() throws ItemStateException {
+ public void reconnect(boolean keepChanges) throws NoSuchItemStateException, ItemStateException {
checkIsSessionState();
- if (!isValid()) {
- throw new ItemStateException("Cannot remove an invalid ItemState");
- }
- int oldStatus = getStatus();
- if (oldStatus == Status.NEW) {
- setStatus(Status.REMOVED);
+ // Need to use the workspace-ISF in order not to create yet another
+ // session-state.
+ ItemStateFactory wspIsf;
+ if (overlayedState != null) {
+ wspIsf = overlayedState.isf;
} else {
- setStatus(Status.EXISTING_REMOVED);
+ wspIsf = getParent().overlayedState.isf;
}
- // now inform parent
- getParent().childStatusChanged(this, oldStatus);
- }
-
- /**
- * Reverts this item state to its initial status (i.e. removing any transient
- * modifications.
- */
- void revert() throws ItemStateException {
- checkIsSessionState();
- switch (getStatus()) {
- case Status.EXISTING_MODIFIED:
- case Status.STALE_MODIFIED:
- // revert state from overlayed
- merge(overlayedState, false);
- setStatus(Status.EXISTING);
- break;
- case Status.EXISTING_REMOVED:
- // revert state from overlayed
- merge(overlayedState, false);
- setStatus(Status.EXISTING);
- parent.childStatusChanged(this, Status.EXISTING_REMOVED);
- break;
- case Status.NEW:
- remove();
- break;
- case Status.STALE_DESTROYED:
- // overlayed does not exist any more
- // cannot call 'remove' on invalid state -> manuall remove
- setStatus(Status.REMOVED);
- parent.childStatusChanged(this, Status.STALE_DESTROYED);
- break;
- default:
- // Cannot revert EXISTING, REMOVED, INVALIDATED, MODIFIED states.
- // State was implicitely reverted
- log.debug("State with status " + getStatus() + " cannot be reverted.");
+ ItemState overlayed;
+ if (isNode()) {
+ overlayed = wspIsf.createNodeState((NodeId) getId(), (NodeEntry) getHierarchyEntry());
+ } else {
+ overlayed = wspIsf.createPropertyState((PropertyId) getId(), (PropertyEntry) getHierarchyEntry());
+ }
+ setOverLayedState(overlayed);
+ boolean modified = merge(overlayed, keepChanges);
+ if (status == Status.NEW || status == Status.INVALIDATED) {
+ setStatus(Status.EXISTING);
+ } else if (modified) {
+ // start notification by marking ol-state modified.
+ overlayed.setStatus(Status.MODIFIED);
}
}
/**
- * Checks if this <code>ItemState</code> is transiently modified, new or stale
- * modified. and adds itself to the <code>ChangeLog</code>.
- * If this <code>ItemState</code> has children it will call
- * {@link #collectStates(ChangeLog, boolean)} recursively.
*
- * @param changeLog the <code>ChangeLog</code> collecting the transient
- * item states present in a given tree.
- * @param throwOnStale If the given flag is true, this methods throws
- * StaleItemStateException if this state is stale.
- * @throws StaleItemStateException if <code>throwOnStale</code> is true and
- * this state is stale.
+ * @param overlayedState
*/
- void collectStates(ChangeLog changeLog, boolean throwOnStale) throws StaleItemStateException {
- checkIsSessionState();
- if (throwOnStale && Status.isStale(getStatus())) {
- String msg = "Cannot save changes: " + getId() + " has been modified externally.";
- log.debug(msg);
- throw new StaleItemStateException(msg);
- }
- // only interested in transient modifications or stale-modified states
- switch (getStatus()) {
- case Status.NEW:
- changeLog.added(this);
- break;
- case Status.EXISTING_MODIFIED:
- case Status.STALE_MODIFIED:
- changeLog.modified(this);
- break;
- case Status.EXISTING_REMOVED:
- changeLog.deleted(this);
- break;
- default:
- log.debug("Collecting states: Ignored ItemState with status " + getStatus());
+ private void setOverLayedState(ItemState overlayedState) {
+ if (this.overlayedState != null) {
+ this.overlayedState.removeListener(this);
}
+ this.overlayedState = overlayedState;
+ this.overlayedState.addListener(this);
}
/**
@@ -627,5 +491,20 @@
String msg = "Cannot mark item state with status " + status + " modified.";
throw new IllegalStateException(msg);
}
+ }
+
+ EffectiveNodeType getEffectiveNodeType() throws RepositoryException {
+ try {
+ EffectiveNodeType ent = getNodeTypeRegistry().getEffectiveNodeType(getParent().getNodeTypeNames());
+ return ent;
+ } catch (ItemStateException e) {
+ throw new RepositoryException("Error while accessing Definition ", e);
+ } catch (NodeTypeConflictException e) {
+ throw new RepositoryException("Error while accessing Definition ", e);
+ }
+ }
+
+ NodeTypeRegistry getNodeTypeRegistry() {
+ return ntReg;
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateFactory.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateFactory.java Tue Feb 13 01:31:36 2007
@@ -18,6 +18,10 @@
import org.apache.jackrabbit.spi.NodeId;
import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
+
+import java.util.Iterator;
/**
* <code>ItemStateFactory</code> provides methods to create child
@@ -28,68 +32,96 @@
/**
*
- * @param ism
+ * @param entry
* @return
* @throws ItemStateException
*/
- public NodeState createRootState(ItemStateManager ism) throws ItemStateException;
+ public NodeState createRootState(NodeEntry entry) throws ItemStateException;
/**
* Creates the child <code>NodeState</code> with the given
* <code>nodeId</code>.
*
* @param nodeId the id of the <code>NodeState</code> to create.
- * @param ism the item state manager to retrievev the parent of the
- * <code>NodeState</code> to create.
+ * @param entry the <code>HierarchyEntry</code> the new state should
+ * be attached to.
* @return the created <code>NodeState</code>.
* @throws NoSuchItemStateException if there is no such <code>NodeState</code>.
- * @throws ItemStateException if an error occurs while retrieving the
- * <code>NodeState</code>.
+ * @throws ItemStateException if an error occurs while retrieving the <code>NodeState</code>.
*/
- public NodeState createNodeState(NodeId nodeId, ItemStateManager ism)
- throws NoSuchItemStateException, ItemStateException;
+ public NodeState createNodeState(NodeId nodeId, NodeEntry entry)
+ throws NoSuchItemStateException, ItemStateException;
+
/**
- * Creates the child <code>NodeState</code> with the given
- * <code>nodeId</code>.
+ * Tries to retrieve the <code>NodeState</code> with the given <code>NodeId</code>
+ * and if the state exists, fills in the NodeEntries missing between the
+ * last known NodeEntry marked by <code>anyParent</code>.
*
- * @param nodeId the id of the <code>NodeState</code> to create.
- * @param parent the parent of the <code>NodeState</code> to create.
+ * @param nodeId
+ * @param anyParent
* @return the created <code>NodeState</code>.
* @throws NoSuchItemStateException if there is no such <code>NodeState</code>.
- * @throws ItemStateException if an error occurs while retrieving the
- * <code>NodeState</code>.
+ * @throws ItemStateException if an error occurs while retrieving the <code>NodeState</code>.
*/
- public NodeState createNodeState(NodeId nodeId, NodeState parent)
- throws NoSuchItemStateException, ItemStateException;
+ public NodeState createDeepNodeState(NodeId nodeId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException;
+
/**
* Creates the <code>PropertyState</code> with the given
* <code>propertyId</code>.
*
* @param propertyId the id of the <code>PropertyState</code> to create.
- * @param parent the parent of the <code>PropertyState</code> to create.
+ * @param entry the <code>HierarchyEntry</code> the new state should
+ * be attached to.
* @return the created <code>PropertyState</code>.
* @throws NoSuchItemStateException if there is no such <code>PropertyState</code>.
* @throws ItemStateException if an error occurs while retrieving the
* <code>PropertyState</code>.
*/
- public PropertyState createPropertyState(PropertyId propertyId,
- NodeState parent)
- throws NoSuchItemStateException, ItemStateException;
+ public PropertyState createPropertyState(PropertyId propertyId, PropertyEntry entry)
+ throws NoSuchItemStateException, ItemStateException;
+
+
+ /**
+ * Tries to retrieve the <code>PropertyState</code> with the given <code>PropertyId</code>
+ * and if the state exists, fills in the HierarchyEntries missing between the
+ * last known NodeEntry marked by <code>anyParent</code>.
+ *
+ * @param propertyId
+ * @param anyParent
+ * @return
+ * @throws NoSuchItemStateException if there is no such <code>NodeState</code>.
+ * @throws ItemStateException if an error occurs while retrieving the <code>NodeState</code>.
+ */
+ public PropertyState createDeepPropertyState(PropertyId propertyId, NodeEntry anyParent) throws NoSuchItemStateException, ItemStateException;
+ /**
+ * Returns an Iterator over <code>ChildInfo</code>s for the given <code>NodeState</code>.
+ *
+ * @param nodeId
+ */
+ public Iterator getChildNodeInfos(NodeId nodeId) throws NoSuchItemStateException, ItemStateException;
/**
+ * Returns the NodeReferences for the NodeState with the given ID.
*
* @param nodeState
+ * @return NodeReferences
+ */
+ public NodeReferences getNodeReferences(NodeState nodeState);
+
+ /**
+ * Adds the given <code>ItemStateCreationListener</code>.
+ *
+ * @param listener
*/
- public ChildNodeEntries getChildNodeEntries(NodeState nodeState) throws NoSuchItemStateException, ItemStateException;
+ public void addCreationListener(ItemStateCreationListener listener);
/**
- * Set the cache used to retrieve item states that have already been
- * built before.
+ * Removes the given <code>ItemStateCreationListener</code>.
*
- * @param cache
+ * @param listener
*/
- public void setCache(ItemStateCache cache);
+ public void removeCreationListener(ItemStateCreationListener listener);
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemStateValidator.java Tue Feb 13 01:31:36 2007
@@ -20,7 +20,8 @@
import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
import org.apache.jackrabbit.jcr2spi.ManagerProvider;
-import org.apache.jackrabbit.jcr2spi.state.entry.ChildNodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry;
+import org.apache.jackrabbit.jcr2spi.hierarchy.PropertyEntry;
import org.apache.jackrabbit.jcr2spi.util.LogUtil;
import org.apache.jackrabbit.jcr2spi.security.AccessManager;
import org.slf4j.LoggerFactory;
@@ -84,16 +85,10 @@
* option for <code>{@link #checkRemoveItem}</code> method:<p/>
* check that target node is not being referenced
*/
- public static final int CHECK_REFERENCES = 16;
-
- /**
- * option for <code>{@link #checkRemoveItem}</code> method:<p/>
- * check that target node is not being referenced
- */
public static final int CHECK_COLLISION = 32;
public static final int CHECK_NONE = 0;
- public static final int CHECK_ALL = CHECK_ACCESS | CHECK_LOCK | CHECK_VERSIONING | CHECK_CONSTRAINTS | CHECK_COLLISION | CHECK_REFERENCES;
+ public static final int CHECK_ALL = CHECK_ACCESS | CHECK_LOCK | CHECK_VERSIONING | CHECK_CONSTRAINTS | CHECK_COLLISION;
/**
* node type registry
@@ -132,8 +127,8 @@
* @throws ConstraintViolationException if any of the validations fail
* @throws RepositoryException if another error occurs
*/
- public void validate(NodeState nodeState)
- throws ConstraintViolationException, RepositoryException {
+ public void validate(NodeState nodeState) throws ConstraintViolationException,
+ RepositoryException {
// effective primary node type
EffectiveNodeType entPrimary = ntReg.getEffectiveNodeType(nodeState.getNodeTypeName());
// effective node type (primary type incl. mixins)
@@ -167,7 +162,7 @@
QNodeDefinition[] cnda = entPrimaryAndMixins.getMandatoryNodeDefs();
for (int i = 0; i < cnda.length; i++) {
QNodeDefinition cnd = cnda[i];
- if (!nodeState.hasChildNodeEntry(cnd.getQName())) {
+ if (!nodeState.getNodeEntry().hasNodeEntry(cnd.getQName())) {
String msg = safeGetJCRPath(nodeState)
+ ": mandatory child node " + cnd.getQName()
+ " does not exist";
@@ -376,8 +371,15 @@
VersionException, LockException, ItemNotFoundException,
ItemExistsException, PathNotFoundException, RepositoryException {
- QPropertyDefinition def = propState.getDefinition();
- checkWriteProperty(propState.getParent(), propState.getQName(), def, options);
+ try {
+ NodeState parent = propState.getParent();
+ QPropertyDefinition def = propState.getDefinition();
+ checkWriteProperty(parent, propState.getQName(), def, options);
+ } catch (NoSuchItemStateException e) {
+ throw new ItemNotFoundException(e);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
}
/**
@@ -432,7 +434,7 @@
* @throws PathNotFoundException
* @throws RepositoryException
*/
- public void checkWriteProperty(NodeState parentState, QName propertyName, QPropertyDefinition definition, int options)
+ private void checkWriteProperty(NodeState parentState, QName propertyName, QPropertyDefinition definition, int options)
throws ConstraintViolationException, AccessDeniedException,
VersionException, LockException, ItemNotFoundException,
ItemExistsException, PathNotFoundException, RepositoryException {
@@ -534,8 +536,6 @@
* parent node is checked-out</li>
* <li><code>{@link #CHECK_CONSTRAINTS}</code>:
* make sure no node type constraints would be violated</li>
- * <li><code>{@link #CHECK_REFERENCES}</code>:
- * make sure no references exist on target node</li>
* </ul>
* @throws ConstraintViolationException
* @throws AccessDeniedException
@@ -551,26 +551,28 @@
ReferentialIntegrityException, RepositoryException {
// TODO: missing check if all affected child-states can be removed as well
- // NOTE: referencial integrity should be asserted for all child-nodes.
- NodeState parentState = targetState.getParent();
- if (parentState == null) {
+ if (targetState.isNode() && ((NodeState)targetState).isRoot()) {
// root node
throw new ConstraintViolationException("Cannot remove root node.");
}
// check parent
- checkIsWritable(parentState, options);
+ try {
+ checkIsWritable(targetState.getParent(), options);
+ } catch (NoSuchItemStateException e) {
+ throw new ItemNotFoundException(e);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
// access rights
if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
try {
// make sure current session is allowed to remove target node
if (!mgrProvider.getAccessManager().canRemove(targetState)) {
- throw new AccessDeniedException(safeGetJCRPath(targetState)
- + ": not allowed to remove node");
+ throw new AccessDeniedException(safeGetJCRPath(targetState) + ": not allowed to remove node");
}
} catch (ItemNotFoundException infe) {
- String msg = "internal error: failed to check access rights for "
- + safeGetJCRPath(targetState);
+ String msg = "internal error: failed to check access rights for " + safeGetJCRPath(targetState);
log.debug(msg);
throw new RepositoryException(msg, infe);
}
@@ -581,10 +583,6 @@
// check if target not protected and not mandatory
checkRemoveConstraints(targetState);
}
- // check referential integrity of state to be deleted
- if ((options & CHECK_REFERENCES) == CHECK_REFERENCES) {
- checkReferences(targetState);
- }
}
/**
@@ -603,8 +601,14 @@
*/
private void checkIsCheckedOut(ItemState itemState)
throws PathNotFoundException, VersionException, RepositoryException {
- NodeState nodeState = (itemState.isNode()) ? (NodeState)itemState : itemState.getParent();
- mgrProvider.getVersionManager().checkIsCheckedOut(nodeState);
+ try {
+ NodeState nodeState = (itemState.isNode()) ? (NodeState)itemState : itemState.getParent();
+ mgrProvider.getVersionManager().checkIsCheckedOut(nodeState);
+ } catch (NoSuchItemStateException e) {
+ throw new ItemNotFoundException(e);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
}
/**
@@ -616,12 +620,17 @@
* @throws LockException if write access to the specified path is not allowed
* @throws RepositoryException if another error occurs
*/
- private void checkLock(ItemState itemState)
- throws LockException, RepositoryException {
- // make sure there's no foreign lock present the node (or the parent node
- // in case the state represents a PropertyState).
- NodeState nodeState = (itemState.isNode()) ? ((NodeState)itemState) : itemState.getParent();
- mgrProvider.getLockManager().checkLock(nodeState);
+ private void checkLock(ItemState itemState) throws LockException, RepositoryException {
+ try {
+ // make sure there's no foreign lock present the node (or the parent node
+ // in case the state represents a PropertyState).
+ NodeState nodeState = (itemState.isNode()) ? ((NodeState)itemState) : itemState.getParent();
+ mgrProvider.getLockManager().checkLock(nodeState);
+ } catch (NoSuchItemStateException e) {
+ throw new ItemNotFoundException(e);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
}
/**
@@ -686,22 +695,23 @@
* @throws RepositoryException
*/
private void checkCollision(NodeState parentState, QName propertyName) throws ItemExistsException, RepositoryException {
+ NodeEntry parentEntry = (NodeEntry) parentState.getHierarchyEntry();
// check for name collisions with existing child nodes
- if (parentState.hasChildNodeEntry(propertyName)) {
- String msg = "there's already a child node with name " + propertyName;
+ if (parentEntry.hasNodeEntry(propertyName)) {
+ String msg = "Child node with name '" + propertyName + "' already exists.";
log.debug(msg);
throw new RepositoryException(msg);
}
// check for name collisions with existing properties
- if (parentState.hasPropertyName(propertyName)) {
- PropertyState errorState = null;
+ PropertyEntry pe = parentEntry.getPropertyEntry(propertyName);
+ if (pe != null) {
try {
- errorState = parentState.getPropertyState(propertyName);
+ pe.getPropertyState();
} catch (ItemStateException e) {
// should not occur. existance has been asserted before
throw new RepositoryException(e);
}
- throw new ItemExistsException(safeGetJCRPath(errorState));
+ throw new ItemExistsException("Property '" + pe.getQName() + "' already exists.");
}
}
@@ -721,12 +731,10 @@
+ nodeName.getLocalName() + "' to " + safeGetJCRPath(parentState)
+ ": colliding with same-named existing property");
- } else if (parentState.hasChildNodeEntry(nodeName)) {
+ } else if (parentState.hasChildNodeEntry(nodeName, Path.INDEX_DEFAULT)) {
// retrieve the existing node state that ev. conflicts with the new one.
try {
- ChildNodeEntry cne = parentState.getChildNodeEntry(nodeName, Path.INDEX_DEFAULT);
- // cne must not be null, since existence has been checked before
- NodeState conflictingState = cne.getNodeState();
+ NodeState conflictingState = parentState.getChildNodeState(nodeName, Path.INDEX_DEFAULT);
QNodeDefinition conflictDef = conflictingState.getDefinition();
QNodeDefinition newDef = getApplicableNodeDefinition(nodeName, nodeTypeName, parentState);
@@ -740,28 +748,6 @@
} catch (ItemStateException e) {
// should not occur, since existence has been asserted before
throw new RepositoryException(e);
- }
- }
- }
-
- /**
- *
- * @param toDelete
- * @throws ReferentialIntegrityException
- * @throws RepositoryException
- */
- private void checkReferences(ItemState toDelete) throws ReferentialIntegrityException, RepositoryException {
- if (!toDelete.isNode()) {
- // PropertyState: nothing to do.
- return;
- }
-
- NodeState targetState = (NodeState)toDelete;
- EffectiveNodeType ent = getEffectiveNodeType(targetState);
- if (ent.includesNodeType(QName.MIX_REFERENCEABLE)) {
- ItemStateManager stateMgr = mgrProvider.getItemStateManager();
- if (stateMgr.hasReferingStates(targetState)) {
- throw new ReferentialIntegrityException(safeGetJCRPath(targetState) + ": cannot remove node with references");
}
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeReferences.java?view=diff&rev=506927&r1=506926&r2=506927
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeReferences.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeReferences.java Tue Feb 13 01:31:36 2007
@@ -21,7 +21,7 @@
/**
* <code>NodeReferences</code>...
*/
-interface NodeReferences {
+public interface NodeReferences {
/**
* Returns a flag indicating whether the <code>Node</code> identified by this