You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2006/08/15 12:59:04 UTC
svn commit: r431572 - in
/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi:
./ state/
Author: mreutegg
Date: Tue Aug 15 03:59:04 2006
New Revision: 431572
URL: http://svn.apache.org/viewvc?rev=431572&view=rev
Log:
- Rename TransientChangeLog to TransientItemStateManager.
- ChangeLog does not disconnect ItemStates anymore
- Added WorkspaceItemStateManager which extends CachingItemStateManager. CachingItemStateManager is now more generic.
- TransientItemStateManager implements TransientItemStateFactory
Added:
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java (with props)
Removed:
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientChangeLog.java
Modified:
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ChangeLog.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/SessionItemStateManager.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/WorkspaceManager.java Tue Aug 15 03:59:04 2006
@@ -28,11 +28,11 @@
import org.apache.jackrabbit.jcr2spi.state.ChangeLog;
import org.apache.jackrabbit.jcr2spi.state.UpdatableItemStateManager;
import org.apache.jackrabbit.jcr2spi.state.NodeReferences;
-import org.apache.jackrabbit.jcr2spi.state.CachingItemStateManager;
import org.apache.jackrabbit.jcr2spi.state.ItemStateFactory;
import org.apache.jackrabbit.jcr2spi.state.WorkspaceItemStateFactory;
import org.apache.jackrabbit.jcr2spi.state.NodeState;
import org.apache.jackrabbit.jcr2spi.state.ItemStateManager;
+import org.apache.jackrabbit.jcr2spi.state.WorkspaceItemStateManager;
import org.apache.jackrabbit.jcr2spi.operation.OperationVisitor;
import org.apache.jackrabbit.jcr2spi.operation.AddNode;
import org.apache.jackrabbit.jcr2spi.operation.AddProperty;
@@ -116,7 +116,7 @@
private final SessionInfo sessionInfo;
// TODO: TO-BE-FIXED. Major refactoring of caching mechanism with change to SPI ids
- private final CachingItemStateManager cache;
+ private final WorkspaceItemStateManager cache;
private final NamespaceRegistryImpl nsRegistry;
private final NodeTypeRegistry ntRegistry;
@@ -140,7 +140,7 @@
this.sessionInfo = sessionInfo;
ItemStateFactory isf = createItemStateFactory();
- cache = new CachingItemStateManager(isf, service.getIdFactory());
+ cache = new WorkspaceItemStateManager(isf, service.getIdFactory());
addEventListener(cache);
nsRegistry = createNamespaceRegistry();
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/CachingItemStateManager.java Tue Aug 15 03:59:04 2006
@@ -19,27 +19,19 @@
import org.apache.jackrabbit.name.Path;
import org.apache.jackrabbit.spi.ItemId;
import org.apache.jackrabbit.spi.NodeId;
-import org.apache.jackrabbit.spi.EventIterator;
-import org.apache.jackrabbit.spi.Event;
import org.apache.jackrabbit.spi.IdFactory;
-import org.apache.jackrabbit.jcr2spi.observation.InternalEventListener;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.commons.collections.map.LRUMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Iterator;
/**
* <code>CachingItemStateManager</code> implements an {@link ItemStateManager}
* and decorates it with a caching facility.
*/
-public class CachingItemStateManager implements ItemStateManager, InternalEventListener {
+public class CachingItemStateManager implements ItemStateManager, ItemStateLifeCycleListener {
/**
* The logger instance for this class.
@@ -89,6 +81,7 @@
this.recentlyUsed = new LRUMap(1000); // TODO: make configurable
// initialize root
root = isf.createNodeState(idFactory.createNodeId((String) null, Path.ROOT), this);
+ root.addListener(this);
}
//---------------------------------------------------< ItemStateManager >---
@@ -137,87 +130,31 @@
return false;
}
- //-------------------------------< InternalEventListener >------------------
+ //------------------------< ItemStateListener >-----------------------------
- /**
- * Processes <code>events</code> and invalidates cached <code>ItemState</code>s
- * accordingly.
- * @param events
- * @param isLocal
- */
- public void onEvent(EventIterator events, boolean isLocal) {
- // if events origin from local changes then
- // cache does not need invalidation
- if (isLocal) {
- return;
+ public void statusChanged(ItemState state, int previousStatus) {
+ if (state.getStatus() == ItemState.STATUS_REMOVED ||
+ state.getStatus() == ItemState.STATUS_STALE_DESTROYED) {
+ recentlyUsed.remove(state);
+ if (state.isNode()) {
+ NodeState nodeState = (NodeState) state;
+ if (nodeState.getUUID() != null) {
+ uuid2NodeState.remove(nodeState.getUUID());
+ }
+ }
}
+ }
- // collect set of removed node ids
- Set removedNodeIds = new HashSet();
- List eventList = new ArrayList();
- while (events.hasNext()) {
- Event e = events.nextEvent();
- eventList.add(e);
- }
+ public void stateCreated(ItemState created) {
+ }
- for (Iterator it = eventList.iterator(); it.hasNext(); ) {
- Event e = (Event) it.next();
- ItemId itemId = e.getItemId();
- NodeId parentId = e.getParentId();
- ItemState state;
- NodeState parent;
- switch (e.getType()) {
- case Event.NODE_ADDED:
- case Event.PROPERTY_ADDED:
- state = lookup(itemId);
- if (state != null) {
- // TODO: item already exists ???
- // remove from cache and invalidate
- recentlyUsed.remove(state);
- state.discard();
- }
- parent = (NodeState) lookup(parentId);
- if (parent != null) {
- // discard and let wsp manager reload state when accessed next time
- recentlyUsed.remove(parent);
- parent.discard();
- }
- break;
- case Event.NODE_REMOVED:
- case Event.PROPERTY_REMOVED:
- state = lookup(itemId);
- if (state != null) {
- if (itemId.denotesNode()) {
- if (itemId.getRelativePath() == null) {
- // also remove mapping from uuid
- uuid2NodeState.remove(itemId.getUUID());
- }
- }
- recentlyUsed.remove(state);
- state.notifyStateDestroyed();
- }
- state = lookup(parentId);
- if (state != null) {
- parent = (NodeState) state;
- // check if removed as well
- if (removedNodeIds.contains(parent.getId())) {
- // do not invalidate here
- } else {
- // discard and let wsp manager reload state when accessed next time
- recentlyUsed.remove(parent);
- parent.discard();
- }
- }
- break;
- case Event.PROPERTY_CHANGED:
- state = lookup(itemId);
- // discard and let wsp manager reload state when accessed next time
- if (state != null) {
- recentlyUsed.remove(state);
- state.discard();
- }
- }
- }
+ public void stateModified(ItemState modified) {
+ }
+
+ public void stateDestroyed(ItemState destroyed) {
+ }
+
+ public void stateDiscarded(ItemState discarded) {
}
//------------------------------< internal >--------------------------------
@@ -228,7 +165,7 @@
*
* @param state the touched state.
*/
- private void touch(ItemState state) {
+ protected void touch(ItemState state) {
recentlyUsed.put(state, state);
}
@@ -245,7 +182,8 @@
String uuid = id.getUUID();
Path relPath = id.getRelativePath();
- NodeState nodeState = null;
+ // start with root node if no uuid part in id
+ NodeState nodeState = root;
// resolve uuid part
if (uuid != null) {
nodeState = (NodeState) uuid2NodeState.get(uuid);
@@ -253,6 +191,7 @@
// state identified by the uuid is not yet cached -> get from ISM
NodeId refId = (relPath == null) ? (NodeId) id : idFactory.createNodeId(uuid);
nodeState = isf.createNodeState(refId, this);
+ nodeState.addListener(this);
uuid2NodeState.put(uuid, nodeState);
}
}
@@ -273,7 +212,7 @@
* @return the cached <code>ItemState</code> or <code>null</code> if it is not
* present in the cache.
*/
- private ItemState lookup(ItemId id) {
+ protected ItemState lookup(ItemId id) {
ItemState state;
// resolve UUID
if (id.getUUID() != null) {
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?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- 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 Aug 15 03:59:04 2006
@@ -19,8 +19,6 @@
import org.apache.jackrabbit.jcr2spi.operation.Operation;
import java.util.Iterator;
-import java.util.List;
-import java.util.ArrayList;
import java.util.Set;
import java.util.LinkedHashSet;
@@ -53,7 +51,7 @@
/**
* Type of operation this changelog is collection state modifications for.
*/
- private List operations = new ArrayList();
+ private Set operations = new LinkedHashSet();
//-----------------------------------------------< Inform the ChangeLog >---
// DIFF JR: method added
@@ -78,23 +76,20 @@
/**
* A state has been modified. If the state is not a new state
- * (not in the collection of added ones), then disconnect
- * the local state from its underlying shared state and add
+ * (not in the collection of added ones), then add
* it to the modified states collection.
*
* @param state state that has been modified
*/
public void modified(ItemState state) {
if (!addedStates.contains(state)) {
- state.disconnect();
modifiedStates.add(state);
}
}
/**
* A state has been deleted. If the state is not a new state
- * (not in the collection of added ones), then disconnect
- * the local state from its underlying shared state, remove
+ * (not in the collection of added ones), then remove
* it from the modified states collection and add it to the
* deleted states collection.
*
@@ -102,7 +97,6 @@
*/
public void deleted(ItemState state) {
if (addedStates.remove(state)) {
- state.disconnect();
modifiedStates.remove(state);
deletedStates.add(state);
}
@@ -307,7 +301,6 @@
* @return <code>true</code> if the operation was removed.
*/
protected boolean removeOperation(Operation operation) {
- // @todo optimize
return operations.remove(operation);
}
}
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?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- 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 Tue Aug 15 03:59:04 2006
@@ -192,6 +192,22 @@
}
//--------------------< 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;
+ }
+
/**
* Determines if this item state represents a node.
*
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?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- 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 Tue Aug 15 03:59:04 2006
@@ -103,7 +103,7 @@
* State manager for the transient items
*/
// DIFF JACKRABBIT: private final TransientItemStateManager transientStateMgr;
- private final TransientChangeLog transientStateMgr;
+ private final TransientItemStateManager transientStateMgr;
/**
* Hierarchy manager
@@ -115,6 +115,11 @@
private final ItemStateValidator validator;
/**
+ * The root node state or <code>null</code> if it hasn't been retrieved yet.
+ */
+ private NodeState rootNodeState;
+
+ /**
* Creates a new <code>SessionItemStateManager</code> instance.
*
* @param workspaceItemStateMgr
@@ -126,7 +131,7 @@
NamespaceResolver nsResolver) {
this.workspaceItemStateMgr = workspaceItemStateMgr;
// DIFF JACKRABBIT: this.transientStateMgr = new TransientItemStateManager();
- this.transientStateMgr = new TransientChangeLog(idFactory, workspaceItemStateMgr);
+ this.transientStateMgr = new TransientItemStateManager(idFactory, workspaceItemStateMgr);
// DIFF JR: validator added
this.validator = validator;
// DIFF JR: idFactory added
@@ -328,7 +333,7 @@
}
// list of transient items that should be discarded
- ChangeLog changeLog = new TransientChangeLog(idFactory, workspaceItemStateMgr);
+ ChangeLog changeLog = new ChangeLog();
// check status of current item's state
if (itemState.isTransient()) {
@@ -622,7 +627,7 @@
* @throws ItemStateException
*/
private ChangeLog getChangeLog(ItemState itemState) throws StaleItemStateException, ItemStateException {
- ChangeLog changeLog = new TransientChangeLog(idFactory, workspaceItemStateMgr);
+ ChangeLog changeLog = new ChangeLog();
if (itemState.getParent() == null) {
// root state -> get all item states
for (Iterator it = transientStateMgr.addedStates(); it.hasNext(); ) {
@@ -1385,7 +1390,9 @@
// remove property entry
parent.removePropertyName(target.getQName());
// destroy property state
- destroy(target);
+ // DIFF JR: notification of transient item state manager is done using ItemStateLifeCycleListener
+ //destroy(target);
+ target.notifyStateDiscarded();
}
/**
@@ -1436,10 +1443,6 @@
// TODO: check if correct
}
}
-
- // destroy target state
- // DIFF JR: destroy targetState (not overlayed state)
- destroy(targetState);
}
/**
@@ -1482,19 +1485,6 @@
propState.setValues(iva);
propState.setType(valueType);
}
-
- /**
- * Destroy an item state.
- *
- * @param state item state that should be destroyed
- */
- private void destroy(ItemState state) {
- // DIFF JACKRABBIT: persistentStateMgr.destroy(state);
- transientStateMgr.deleted(state);
- // todo correct?
- state.notifyStateDiscarded();
- }
-
/**
* Computes the values of well-known system (i.e. protected) properties
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?rev=431572&r1=431571&r2=431572&view=diff
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Tue Aug 15 03:59:04 2006
@@ -18,52 +18,232 @@
import org.apache.jackrabbit.jcr2spi.operation.Operation;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
import javax.jcr.ItemExistsException;
import java.util.Iterator;
/**
- * <code>TransientItemStateManager</code> ...
+ * <code>TransientItemStateManager</code> implements a {@link ItemStateManager}
+ * and adds more methods that support transient changes (e.g. resurrect deleted
+ * state).
*/
-interface TransientItemStateManager extends ItemStateManager {
+public class TransientItemStateManager
+ implements ItemStateManager, TransientItemStateFactory, ItemStateLifeCycleListener {
/**
- * @return the number of entries
+ * Logger instance for this class.
*/
- public int getEntriesCount();
+ private static final Logger log = LoggerFactory.getLogger(TransientItemStateManager.class);
/**
- * @return <code>true</code> if there are any entries in attic.
+ * The change log which keeps track of changes and maintains hard references
+ * to changed item states.
*/
- public boolean hasEntriesInAttic();
+ private final ChangeLog changeLog;
/**
- * @return an iterator over all entries
+ *
*/
- public Iterator getEntries();
+ private final IdFactory idFactory;
/**
- * @return an iterator over all entries in attic
+ * The parent item state manager, which return item states that are then
+ * overlayed by transient item states created by this TransientItemStateManager.
*/
- public Iterator getEntriesInAttic();
+ private final ItemStateManager parent;
/**
- * Adds an operation to this transient item state manager.
+ * ItemStateManager view of the states in the attic; lazily instantiated
+ * in {@link #getAttic()}
+ */
+ private AtticItemStateManager attic;
+
+ TransientItemStateManager(IdFactory idFactory, ItemStateManager parent) {
+ this.changeLog = new ChangeLog();
+ this.idFactory = idFactory;
+ this.parent = parent;
+ }
+
+ //-----------------------< ItemStateManager >-------------------------------
+
+ /**
+ * Return the root node state or <code>null</code> if the root state has
+ * not been modified yet.
+ *
+ * @return
+ * @throws ItemStateException
+ * @see ItemStateManager#getRootState()
+ */
+ public NodeState getRootState() throws ItemStateException {
+ // TODO
+ return null;
+ }
+
+ /**
+ * Return an item state given its id. Returns <code>null</code>
+ * if the item state is neither in the added nor in the modified
+ * section. Throws a <code>NoSuchItemStateException</code> if
+ * the item state is in the deleted section.
+ *
+ * @return item state or <code>null</code>
+ * @throws NoSuchItemStateException if the item has been deleted
+ * @see ItemStateManager#getItemState(ItemId)
+ */
+ public ItemState getItemState(ItemId id) throws NoSuchItemStateException, ItemStateException {
+ // TODO: this is expensive. Improvement: Lookup item, then check its state
+ ItemState state = null;
+ for (Iterator it = changeLog.addedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ state = s;
+ break;
+ }
+ }
+ if (state == null) {
+ for (Iterator it = changeLog.modifiedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ state = s;
+ break;
+ }
+ }
+ if (state == null) {
+ for (Iterator it = changeLog.deletedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ throw new NoSuchItemStateException("State has been marked destroyed: " + id);
+ }
+ }
+ }
+ }
+ return state;
+ }
+
+ /**
+ * Return a flag indicating whether a given item state exists.
+ *
+ * @return <code>true</code> if item state exists within this
+ * log; <code>false</code> otherwise
+ * @see ItemStateManager#hasItemState(ItemId)
+ */
+ public boolean hasItemState(ItemId id) {
+ // TODO: too expensive. lookup item and check status
+ for (Iterator it = changeLog.addedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ return true;
+ }
+ }
+ for (Iterator it = changeLog.modifiedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return a node references object given its id. Returns
+ * <code>null</code> if the node reference is not in the modified
+ * section.
*
- * @param operationType the operation.
- * @throws IllegalStateException if <code>operationType</code> is not
- * compatible with the previously executed operation (invalid sequence of
- * operations).
+ * @return node references or <code>null</code>
+ * @see ItemStateManager#getNodeReferences(NodeId)
+ */
+ public NodeReferences getNodeReferences(NodeId id) {
+ // TODO: improve
+ for (Iterator it = changeLog.modifiedRefs(); it.hasNext(); ) {
+ NodeReferences refs = (NodeReferences) it.next();
+ if (refs.getId().equals(id)) {
+ return refs;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns <code>false</code> if the node reference is not in the modified
+ * section.
+ *
+ * @return false if no references are present in this changelog for the
+ * given id.
+ * @see ItemStateManager#hasNodeReferences(NodeId)
+ */
+ public boolean hasNodeReferences(NodeId id) {
+ return getNodeReferences(id) != null;
+ }
+
+ /**
+ * @return the operations that have been recorded until now.
+ */
+ public Iterator getOperations() {
+ return changeLog.getOperations();
+ }
+
+ /**
+ * Add the given operation to the list of operations to be recorded within
+ * this TransientItemStateManager.
+ *
+ * @param operation
+ */
+ void addOperation(Operation operation) {
+ changeLog.addOperation(operation);
+ }
+
+ /**
+ * Removes the <code>operation</code> from the list of operations.
+ * @param operation the Operation to remove.
+ * @return <code>true</code> if the operation was removed.
+ */
+ boolean removeOperation(Operation operation) {
+ return changeLog.removeOperation(operation);
+ }
+
+ /**
+ * @return the number of entries
*/
- public void addOperation(Operation operationType) throws IllegalStateException;
+ public int getEntriesCount() {
+ return changeLog.addedStates.size() + changeLog.modifiedStates.size();
+ }
- //----------------< methods for creating & discarding ItemState instances >
+ /**
+ * @return <code>true</code> if there are any entries in attic.
+ */
+ public boolean hasEntriesInAttic() {
+ return changeLog.deletedStates.size() > 0;
+ }
+
+ /**
+ * @return an iterator over all entries
+ */
+ public Iterator getEntries() {
+ IteratorChain it = new IteratorChain();
+ it.addIterator(changeLog.modifiedStates());
+ it.addIterator(changeLog.addedStates());
+ return it;
+ }
/**
+ * @return an iterator over all entries in attic
+ */
+ public Iterator getEntriesInAttic() {
+ return changeLog.deletedStates();
+ }
+
+ /**
+ * TODO: throw ItemExistsException? how to check?
* Creates a new transient {@link NodeState} that does not overlay any other
* {@link NodeState}.
*
- * @param name the name of the <code>NodeState</code> to create.
+ * @param nodeName the name of the <code>NodeState</code> to create.
* @param uuid the uuid of the <code>NodeState</code> to create or
* <code>null</code> if the created <code>NodeState</code>
* cannot be identified by a UUID.
@@ -71,10 +251,17 @@
* @param parent the parent of the new node state.
* @return a new transient {@link NodeState}.
*/
- NodeState createNodeState(QName name,
- String uuid,
- QName nodeTypeName,
- NodeState parent);
+ public NodeState createNodeState(QName nodeName,
+ String uuid,
+ QName nodeTypeName,
+ NodeState parent) {
+ NodeState nodeState = createNewNodeState(nodeName, uuid, parent);
+ nodeState.setNodeTypeName(nodeTypeName);
+ parent.addChildNodeState(nodeState, uuid);
+ changeLog.added(nodeState);
+ nodeState.addListener(this);
+ return nodeState;
+ }
/**
* Creates a new transient property state for a given <code>parent</code>
@@ -86,39 +273,74 @@
* @throws ItemExistsException if <code>parent</code> already has a property
* with the given name.
*/
- PropertyState createPropertyState(NodeState parent, QName propName)
- throws ItemExistsException;
+ public PropertyState createPropertyState(NodeState parent, QName propName)
+ throws ItemExistsException {
+ PropertyState propState = createNewPropertyState(propName, parent);
+ parent.addPropertyState(propState);
+ changeLog.added(propState);
+ propState.addListener(this);
+ return propState;
+ }
/**
- * Disposes the specified instance, i.e. discards it and removes it from
- * the map.
+ * Disposes a single item <code>state</code>. The state is discarded removed
+ * from the map of added or modified states and disconnected from the
+ * underlying state. This method does not take states into account that are
+ * marked as deleted.
*
- * @param state the <code>ItemState</code> instance that should be disposed
- * @see ItemState#discard()
+ * @param state the item state to dispose.
*/
- public void disposeItemState(ItemState state);
+ public void disposeItemState(ItemState state) {
+ state.discard();
+ if (changeLog.addedStates.remove(state)) {
+ changeLog.modifiedStates.remove(state);
+ }
+ state.onDisposed();
+ }
/**
- * Transfers the specified instance from the 'active' map to the attic.
+ * A state has been deleted. If the state is not a new state
+ * (not in the collection of added ones), then remove
+ * it from the modified states collection.
+ * The state is added to the deleted states collection in any case.
*
- * @param state the <code>ItemState</code> instance that should be moved to
- * the attic
+ * @param state state that has been deleted
*/
- public void moveItemStateToAttic(ItemState state);
+ public void moveItemStateToAttic(ItemState state) {
+ if (changeLog.addedStates.remove(state)) {
+ changeLog.modifiedStates.remove(state);
+ }
+ changeLog.deleted(state);
+ }
/**
- * Disposes the specified instance in the attic, i.e. discards it and
- * removes it from the attic.
+ * Disposes a single item <code>state</code> that is marked as deleted. The
+ * state is discarded removed from the map of removed states and
+ * disconnected from the underlying state.
*
- * @param state the <code>ItemState</code> instance that should be disposed
- * @see ItemState#discard()
+ * @param state the item state to dispose.
*/
- public void disposeItemStateInAttic(ItemState state);
+ public void disposeItemStateInAttic(ItemState state) {
+ state.discard();
+ changeLog.deletedStates.remove(state);
+ state.onDisposed();
+ }
/**
* Disposes all transient item states in the cache and in the attic.
*/
- public void disposeAllItemStates();
+ public void disposeAllItemStates() {
+ IteratorChain it = new IteratorChain();
+ it.addIterator(changeLog.modifiedStates());
+ it.addIterator(changeLog.addedStates());
+ it.addIterator(changeLog.deletedStates());
+ while (it.hasNext()) {
+ ItemState state = (ItemState) it.next();
+ state.discard();
+ state.onDisposed();
+ }
+ changeLog.reset();
+ }
/**
* Return the attic item state provider that holds all items
@@ -126,14 +348,315 @@
*
* @return attic
*/
- public ItemStateManager getAttic();
-
- //-----------------------------------< methods for controlling operations >
+ public ItemStateManager getAttic() {
+ if (attic == null) {
+ attic = new AtticItemStateManager();
+ }
+ return attic;
+ }
/**
* Disposes a collection of {@link org.apache.jackrabbit.jcr2spi.operation.Operation}s.
*
* @param operations the operations.
*/
- public void disposeOperations(Iterator operations);
+ public void disposeOperations(Iterator operations) {
+ while (operations.hasNext()) {
+ changeLog.removeOperation((Operation) operations.next());
+ }
+ }
+
+ /**
+ * TODO: remove this method when not used anymore
+ * Return an iterator over all added states.
+ *
+ * @return iterator over all added states.
+ */
+ public Iterator addedStates() {
+ return changeLog.addedStates();
+ }
+
+ /**
+ * TODO: remove this method when not used anymore
+ * Return an iterator over all modified states.
+ *
+ * @return iterator over all modified states.
+ */
+ public Iterator modifiedStates() {
+ return changeLog.modifiedStates();
+ }
+
+ /**
+ * TODO: remove this method when not used anymore
+ * Return an iterator over all deleted states.
+ *
+ * @return iterator over all deleted states.
+ */
+ public Iterator deletedStates() {
+ return changeLog.deletedStates();
+ }
+
+ //----------------------< TransientItemStateFactory >-----------------------
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createNewNodeState(QName, String, NodeState)
+ */
+ public NodeState createNewNodeState(QName name, String uuid, NodeState parent) {
+ NodeState nodeState = new NodeState(name, uuid, parent, null,
+ ItemState.STATUS_NEW, true, this, idFactory);
+ // get a notification when this item state is saved or invalidated
+ nodeState.addListener(this);
+ changeLog.added(nodeState);
+ return nodeState;
+ }
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createNewPropertyState(QName, NodeState)
+ */
+ public PropertyState createNewPropertyState(QName name, NodeState parent) {
+ PropertyState propState = new PropertyState(name, parent,
+ ItemState.STATUS_NEW, true, idFactory);
+ // get a notification when this item state is saved or invalidated
+ propState.addListener(this);
+ changeLog.added(propState);
+ return propState;
+ }
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createNodeState(NodeId, ItemStateManager)
+ */
+ public NodeState createNodeState(NodeId nodeId, ItemStateManager ism)
+ throws NoSuchItemStateException, ItemStateException {
+ // retrieve state to overlay
+ NodeState overlayedState = (NodeState) parent.getItemState(nodeId);
+ NodeId parentId = overlayedState.getParent().getNodeId();
+ NodeState parentState = (NodeState) ism.getItemState(parentId);
+ NodeState nodeState = new NodeState(overlayedState, parentState,
+ ItemState.STATUS_EXISTING, true, this, idFactory);
+ nodeState.addListener(this);
+ return nodeState;
+ }
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createNodeState(NodeId, NodeState)
+ */
+ public NodeState createNodeState(NodeId nodeId, NodeState parentState)
+ throws NoSuchItemStateException, ItemStateException {
+ // retrieve state to overlay
+ NodeState overlayedState = (NodeState) parent.getItemState(nodeId);
+ NodeState nodeState = new NodeState(overlayedState, parentState,
+ ItemState.STATUS_EXISTING, true, this, idFactory);
+ nodeState.addListener(this);
+ return nodeState;
+ }
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createPropertyState(PropertyId, ItemStateManager)
+ */
+ public PropertyState createPropertyState(PropertyId propertyId,
+ ItemStateManager ism)
+ throws NoSuchItemStateException, ItemStateException {
+ // retrieve state to overlay
+ PropertyState overlayedState = (PropertyState) parent.getItemState(propertyId);
+ NodeId parentId = overlayedState.getParent().getNodeId();
+ NodeState parentState = (NodeState) ism.getItemState(parentId);
+ PropertyState propState = new PropertyState(overlayedState, parentState,
+ ItemState.STATUS_EXISTING, true, idFactory);
+ propState.addListener(this);
+ return propState;
+ }
+
+ /**
+ * @inheritDoc
+ * @see TransientItemStateFactory#createPropertyState(PropertyId, NodeState)
+ */
+ public PropertyState createPropertyState(PropertyId propertyId,
+ NodeState parentState)
+ throws NoSuchItemStateException, ItemStateException {
+ // retrieve state to overlay
+ PropertyState overlayedState = (PropertyState) parent.getItemState(propertyId);
+ PropertyState propState = new PropertyState(overlayedState, parentState,
+ ItemState.STATUS_EXISTING, true, idFactory);
+ propState.addListener(this);
+ return propState;
+ }
+
+ //-----------------------< ItemStateLifeCycleListener >---------------------
+
+ /**
+ * @inheritDoc
+ * @see ItemStateListener#stateCreated(ItemState)
+ */
+ public void stateCreated(ItemState created) {
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemStateListener#stateModified(ItemState)
+ */
+ public void stateModified(ItemState modified) {
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemStateListener#stateDestroyed(ItemState)
+ */
+ public void stateDestroyed(ItemState destroyed) {
+ changeLog.deletedStates.remove(destroyed);
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemStateListener#stateDiscarded(ItemState)
+ */
+ public void stateDiscarded(ItemState discarded) {
+ // TODO: remove from modified (and deleted?) set of change log
+ }
+
+ /**
+ * @inheritDoc
+ * @see ItemStateLifeCycleListener#statusChanged(ItemState, int)
+ */
+ public void statusChanged(ItemState state, int previousStatus) {
+ // TODO: depending on status of state adapt change log
+ // e.g. a revert on states will reset the status from
+ // 'existing modified' to 'existing'.
+ // a state which changes from 'existing' to 'existing modified' will
+ // go into the modified set of the change log, etc.
+ switch (state.getStatus()) {
+ case ItemState.STATUS_EXISTING:
+ if (previousStatus == ItemState.STATUS_EXISTING_MODIFIED) {
+ // was modified and is now refreshed
+ changeLog.modifiedStates.remove(state);
+ } else if (previousStatus == ItemState.STATUS_EXISTING_REMOVED) {
+ // was removed and is now refreshed
+ changeLog.deletedStates.remove(state);
+ } else if (previousStatus == ItemState.STATUS_STALE_MODIFIED) {
+ // was modified and state and is now refreshed
+ changeLog.modifiedStates.remove(state);
+ } else if (previousStatus == ItemState.STATUS_NEW) {
+ // was new and has been saved now
+ changeLog.addedStates.remove(state);
+ }
+ break;
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ changeLog.modified(state);
+ break;
+ case ItemState.STATUS_EXISTING_REMOVED:
+ // check if modified earlier
+ if (previousStatus == ItemState.STATUS_EXISTING_MODIFIED) {
+ changeLog.modifiedStates.remove(state);
+ }
+ changeLog.deleted(state);
+ break;
+ case ItemState.STATUS_REMOVED:
+ if (previousStatus == ItemState.STATUS_NEW) {
+ // was new and now removed again
+ changeLog.addedStates.remove(state);
+ } else if (previousStatus == ItemState.STATUS_EXISTING_REMOVED) {
+ // was removed and is now saved
+ changeLog.deletedStates.remove(state);
+ }
+ break;
+ case ItemState.STATUS_STALE_DESTROYED:
+ // state is now stale. remove from modified
+ changeLog.modifiedStates.remove(state);
+ break;
+ case ItemState.STATUS_STALE_MODIFIED:
+ // state is now stale. keep in modified. wait until refreshed
+ break;
+ case ItemState.STATUS_NEW:
+ // should never happen
+ log.warn("ItemState changed status to 'new'");
+ break;
+ case ItemState.STATUS_UNDEFINED:
+ // should never happen
+ log.warn("ItemState changed status to 'undefined'");
+ break;
+ default:
+ log.warn("ItemState has invalid status: " + state.getStatus());
+ }
+ }
+
+ //--------------------------------------------------------< inner classes >
+
+ /**
+ * ItemStateManager view of the states in the attic
+ *
+ * @see TransientItemStateManager#getAttic()
+ */
+ private class AtticItemStateManager implements ItemStateManager {
+
+ AtticItemStateManager() {
+ }
+
+ /**
+ * Since the root node may never be removed, this method always returns
+ * <code>null</code>.
+ *
+ * @return <code>null</code> since the root node cannot be removed.
+ * @throws ItemStateException
+ * @see ItemStateManager#getRootState()
+ */
+ public NodeState getRootState() throws ItemStateException {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemState getItemState(ItemId id)
+ throws NoSuchItemStateException, ItemStateException {
+
+ // TODO: too expensive. rather lookup item and check state
+ ItemState state = null;
+ for (Iterator it = changeLog.deletedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ state = s;
+ }
+ }
+ if (state != null) {
+ return state;
+ } else {
+ throw new NoSuchItemStateException(id.toString());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasItemState(ItemId id) {
+ // TODO: too expensive. rather lookup item and check state
+ for (Iterator it = changeLog.deletedStates(); it.hasNext(); ) {
+ ItemState s = (ItemState) it.next();
+ if (s.getId().equals(id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeReferences getNodeReferences(NodeId id)
+ throws NoSuchItemStateException, ItemStateException {
+ // n/a
+ throw new ItemStateException("getNodeReferences() not implemented");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNodeReferences(NodeId id) {
+ // n/a
+ return false;
+ }
+ }
}
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java?rev=431572&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java Tue Aug 15 03:59:04 2006
@@ -0,0 +1,115 @@
+/*
+ * 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.apache.jackrabbit.jcr2spi.observation.InternalEventListener;
+import org.apache.jackrabbit.spi.EventIterator;
+import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.IdFactory;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * <code>WorkspaceItemStateManager</code>
+ */
+public class WorkspaceItemStateManager
+ extends CachingItemStateManager
+ implements InternalEventListener {
+
+ public WorkspaceItemStateManager(ItemStateFactory isf, IdFactory idFactory)
+ throws ItemStateException, NoSuchItemStateException {
+ super(isf, idFactory);
+ }
+
+ //-------------------------------< InternalEventListener >------------------
+
+ /**
+ * Processes <code>events</code> and invalidates cached <code>ItemState</code>s
+ * accordingly.
+ * @param events
+ * @param isLocal
+ */
+ public void onEvent(EventIterator events, boolean isLocal) {
+ // if events origin from local changes then
+ // cache does not need invalidation
+ if (isLocal) {
+ return;
+ }
+
+ // collect set of removed node ids
+ Set removedNodeIds = new HashSet();
+ List eventList = new ArrayList();
+ while (events.hasNext()) {
+ Event e = events.nextEvent();
+ eventList.add(e);
+ }
+
+ for (Iterator it = eventList.iterator(); it.hasNext(); ) {
+ Event e = (Event) it.next();
+ ItemId itemId = e.getItemId();
+ NodeId parentId = e.getParentId();
+ ItemState state;
+ NodeState parent;
+ switch (e.getType()) {
+ case Event.NODE_ADDED:
+ case Event.PROPERTY_ADDED:
+ state = lookup(itemId);
+ if (state != null) {
+ // TODO: item already exists ???
+ // invalidate
+ state.discard();
+ }
+ parent = (NodeState) lookup(parentId);
+ if (parent != null) {
+ // discard and let wsp manager reload state when accessed next time
+ parent.discard();
+ }
+ break;
+ case Event.NODE_REMOVED:
+ case Event.PROPERTY_REMOVED:
+ state = lookup(itemId);
+ if (state != null) {
+ state.notifyStateDestroyed();
+ }
+ state = lookup(parentId);
+ if (state != null) {
+ parent = (NodeState) state;
+ // check if removed as well
+ if (removedNodeIds.contains(parent.getId())) {
+ // do not invalidate here
+ } else {
+ // discard and let wsp manager reload state when accessed next time
+ parent.discard();
+ }
+ }
+ break;
+ case Event.PROPERTY_CHANGED:
+ state = lookup(itemId);
+ // discard and let wsp manager reload state when accessed next time
+ if (state != null) {
+ state.discard();
+ }
+ }
+ }
+ }
+}
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateManager.java
------------------------------------------------------------------------------
svn:eol-style = native