You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2006/01/11 15:24:32 UTC
svn commit: r368026 [3/3] - in /incubator/jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/lock/
main/java/org/apache/jackrabbit/core/observation/
main/java/org/apache/jackrabbit/core/state/ ma...
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java?rev=368026&r1=368025&r2=368026&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java Wed Jan 11 06:22:57 2006
@@ -20,12 +20,11 @@
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.PropertyImpl;
import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.observation.DelegatingObservationDispatcher;
-import org.apache.jackrabbit.core.observation.EventState;
+import org.apache.jackrabbit.core.observation.EventStateCollectionFactory;
+import org.apache.jackrabbit.core.observation.EventStateCollection;
import org.apache.jackrabbit.core.state.ChangeLog;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.LocalItemStateManager;
@@ -37,17 +36,12 @@
import org.apache.jackrabbit.core.state.SharedItemStateManager;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
-import org.apache.jackrabbit.name.Path;
import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.uuid.UUID;
import org.apache.log4j.Logger;
-import javax.jcr.NodeIterator;
-import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.Value;
import javax.jcr.ReferentialIntegrityException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
@@ -56,12 +50,13 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
-import java.util.LinkedList;
+import java.util.Collection;
/**
* This Class implements a VersionManager.
*/
-public class VersionManagerImpl implements VersionManager {
+public class VersionManagerImpl extends AbstractVersionManager
+ implements EventStateCollectionFactory {
/**
* the default logger
@@ -79,9 +74,9 @@
private final PersistenceManager pMgr;
/**
- * the state manager for the version storage
+ * the shared state manager for the version storage
*/
- private LocalItemStateManager stateMgr;
+ private SharedItemStateManager sharedStateMgr;
/**
* the virtual item state provider that exposes the version storage
@@ -89,11 +84,6 @@
private final VersionItemStateProvider versProvider;
/**
- * the persistent root node of the version histories
- */
- private final NodeStateEx historyRoot;
-
- /**
* the node type manager
*/
private NodeTypeRegistry ntReg;
@@ -106,12 +96,12 @@
/**
* Map of returned items. this is kept for invalidating
*/
- //private ReferenceMap items = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+ private ReferenceMap versionItems = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
/**
- * Map of returned items. this is kept for invalidating
+ * Session to be used when creating observation events.
*/
- private ReferenceMap versionItems = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+ private transient SessionImpl eventSource;
/**
* Creates a bew vesuion manager
@@ -145,9 +135,9 @@
cl.added(pt);
pMgr.store(cl);
}
- SharedItemStateManager sharedStateMgr =
+ sharedStateMgr =
new VersionItemStateManager(pMgr, VERSION_STORAGE_NODE_UUID, ntReg);
- stateMgr = new LocalItemStateManager(sharedStateMgr, null);
+ stateMgr = new LocalItemStateManager(sharedStateMgr, this);
NodeState nodeState = (NodeState) stateMgr.getItemState(new NodeId(VERSION_STORAGE_NODE_UUID));
historyRoot = new NodeStateEx(stateMgr, ntReg, nodeState, QName.JCR_VERSIONSTORAGE);
@@ -167,212 +157,47 @@
}
/**
- * Close this version manager. After having closed a persistence
- * manager, further operations on this object are treated as illegal
- * and throw
- *
- * @throws Exception if an error occurs
+ * {@inheritDoc}
*/
public void close() throws Exception {
pMgr.close();
}
/**
- * Creates a new version history. This action is needed either when creating
- * a new 'mix:versionable' node or when adding the 'mix:versionalbe' mixin
- * to a node.
- *
- * @param node
- * @return
- * @throws javax.jcr.RepositoryException
+ * {@inheritDoc}
+ * <p/>
+ * This method needs to be synchronized since it sets the event source
+ * to be used when creating the events to be dispatched later on.
*/
- public VersionHistory createVersionHistory(Session session, NodeState node)
+ public synchronized VersionHistory createVersionHistory(Session session,
+ NodeState node)
throws RepositoryException {
- List created = new LinkedList();
- InternalVersionHistory history = createVersionHistory(created, node);
+ eventSource = (SessionImpl) session;
+
+ InternalVersionHistory history = createVersionHistory(node);
if (history == null) {
throw new VersionException("History already exists for node " + node.getUUID());
}
- VersionHistoryImpl vh = (VersionHistoryImpl) session.getNodeByUUID(history.getId());
-
- // generate observation events
- List events = new ArrayList();
- Iterator iter = created.iterator();
- while (iter.hasNext()) {
- String uuid = (String) iter.next();
- NodeImpl child = (NodeImpl) ((SessionImpl) session).getItemManager().getItem(new NodeId(uuid));
- generateAddedEvents(events, (NodeImpl) child.getParent(), child, false);
- }
- obsMgr.dispatch(events, (SessionImpl) session);
- return vh;
+ return (VersionHistory) session.getNodeByUUID(history.getId());
}
/**
* {@inheritDoc}
*/
- public VersionHistory getVersionHistory(Session session, NodeState node)
- throws RepositoryException {
-
- String vhId = getVersionHistoryId(node);
- if (vhId == null) {
- return null;
- }
- return (VersionHistoryImpl) session.getNodeByUUID(vhId);
- }
-
- /**
- * Creates a new Version History.
- *
- * @param created a list for adding the uuids of the newly created nodes
- * @param node the node for which the version history is to be initialized
- * @return the newly created version history.
- * @throws RepositoryException
- */
- private InternalVersionHistory createVersionHistory(List created, NodeState node)
- throws RepositoryException {
-
- try {
- stateMgr.edit();
- } catch (IllegalStateException e) {
- throw new RepositoryException("Unable to start edit operation", e);
- }
-
- boolean succeeded = false;
-
- try {
- // create deep path
- String uuid = node.getUUID();
- NodeStateEx root = historyRoot;
- for (int i = 0; i < 3; i++) {
- QName name = new QName(QName.NS_DEFAULT_URI, uuid.substring(i * 2, i * 2 + 2));
- if (!root.hasNode(name)) {
- NodeStateEx n = root.addNode(name, QName.REP_VERSIONSTORAGE, null, false);
- created.add(n.getUUID());
- root.store();
- }
- root = root.getNode(name, 1);
- }
- QName historyNodeName = new QName(QName.NS_DEFAULT_URI, uuid);
- if (root.hasNode(historyNodeName)) {
- // already exists
- return null;
- }
-
- // create new history node in the persistent state
- InternalVersionHistoryImpl hist = InternalVersionHistoryImpl.create(this, root, UUID.randomUUID().toString(), historyNodeName, node, created);
-
- // end update
- stateMgr.update();
- succeeded = true;
-
- log.info("Created new version history " + hist.getId() + " for " + node + ".");
- return hist;
-
- } catch (ItemStateException e) {
- throw new RepositoryException(e);
- } finally {
- if (!succeeded) {
- // update operation failed, cancel all modifications
- stateMgr.cancel();
- }
- }
- }
-
- /**
- * Returns the id of the version history associated with the given node
- * or <code>null</code> if that node doesn't have a version history.
- *
- * @param node the node whose version history's id is to be returned.
- * @return the the id of the version history associated with the given node
- * or <code>null</code> if that node doesn't have a version history.
- * @throws RepositoryException if an error occurs
- */
- private String getVersionHistoryId(NodeState node)
- throws RepositoryException {
-
- // build and traverse path
- String uuid = node.getUUID();
- NodeStateEx n = historyRoot;
- for (int i = 0; i < 3; i++) {
- QName name = new QName(QName.NS_DEFAULT_URI, uuid.substring(i * 2, i * 2 + 2));
- if (!n.hasNode(name)) {
- return null;
- }
- n = n.getNode(name, 1);
- }
- QName historyNodeName = new QName(QName.NS_DEFAULT_URI, uuid);
- if (!n.hasNode(historyNodeName)) {
- return null;
- }
- return n.getNode(historyNodeName, 1).getUUID();
- }
-
- /**
- * Checks if the version history with the given id exists
- *
- * @param id
- * @return
- */
- public boolean hasVersionHistory(String id) {
- // todo: probably need to check if this item is really a history
- return hasItem(id);
- }
-
- /**
- * Returns the version history with the given id
- *
- * @param id
- * @return
- * @throws RepositoryException
- */
- public InternalVersionHistory getVersionHistory(String id) throws RepositoryException {
- return (InternalVersionHistory) getItem(id);
- }
-
- /**
- * Checks if the version with the given id exists
- *
- * @param id
- * @return
- */
- public boolean hasVersion(String id) {
- // todo: probably need to check if this item is really a version
- return hasItem(id);
- }
-
- /**
- * Returns the version with the given id
- *
- * @param id
- * @return
- * @throws RepositoryException
- */
- public InternalVersion getVersion(String id) throws RepositoryException {
- return (InternalVersion) getItem(id);
- }
-
- /**
- * checks, if the node with the given id exists
- *
- * @param id
- * @return
- */
public boolean hasItem(String id) {
return versionItems.containsKey(id) || stateMgr.hasItemState(new NodeId(id));
}
/**
- * Returns the item with the given persistent id
- *
- * @param uuid
- * @return
- * @throws RepositoryException
+ * {@inheritDoc}
*/
- synchronized InternalVersionItem getItem(String uuid) throws RepositoryException {
+ protected synchronized InternalVersionItem getItem(String uuid)
+ throws RepositoryException {
+
NodeId id = new NodeId(uuid);
try {
- InternalVersionItem item = (InternalVersionItem) versionItems.get(id);
+ InternalVersionItem item = (InternalVersionItem) versionItems.get(uuid);
if (item == null) {
if (stateMgr.hasItemState(id)) {
NodeState state = (NodeState) stateMgr.getItemState(id);
@@ -394,7 +219,7 @@
}
}
if (item != null) {
- versionItems.put(id, item);
+ versionItems.put(uuid, item);
}
}
return item;
@@ -404,310 +229,113 @@
}
/**
- * invokes the checkin() on the persistent version manager and remaps the
- * newly created version objects.
- *
- * @param node
- * @return
- * @throws RepositoryException
+ * {@inheritDoc}
+ * <p/>
+ * This method needs to be synchronized since it sets the event source
+ * to be used when creating the events to be dispatched later on.
*/
- public Version checkin(NodeImpl node) throws RepositoryException {
- SessionImpl session = (SessionImpl) node.getSession();
- InternalVersion version = internalCheckin(node);
-
- VersionImpl v = (VersionImpl) session.getNodeByUUID(version.getId());
+ public synchronized Version checkin(NodeImpl node) throws RepositoryException {
+ eventSource = (SessionImpl) node.getSession();
- // generate observation events
- List events = new ArrayList();
+ String histUUID = node.getProperty(QName.JCR_VERSIONHISTORY).getString();
+ InternalVersion version = checkin(
+ (InternalVersionHistoryImpl) getVersionHistory(histUUID), node);
- generateAddedEvents(events, (NodeImpl) v.getParent(), v, true);
+ AbstractVersion v = (AbstractVersion) eventSource.getNodeByUUID(version.getId());
- // invalidate predecessors successor property
+ // invalidate predecessors successor properties
InternalVersion[] preds = version.getPredecessors();
- for (int i=0; i<preds.length; i++) {
+ for (int i = 0; i < preds.length; i++) {
PropertyId propId = new PropertyId(preds[i].getId(), QName.JCR_SUCCESSORS);
versProvider.onPropertyChanged(propId);
}
- obsMgr.dispatch(events, session);
-
return v;
}
/**
- * Checks in a node
- *
- * @param node
- * @return
- * @throws RepositoryException
- * @see javax.jcr.Node#checkin()
- */
- private synchronized InternalVersion internalCheckin(NodeImpl node) throws RepositoryException {
- // assuming node is versionable and checkout (check in nodeimpl)
- // To create a new version of a versionable node N, the client calls N.checkin.
- // This causes the following series of events:
- String histUUID = node.getProperty(QName.JCR_VERSIONHISTORY).getString();
- InternalVersionHistoryImpl history = (InternalVersionHistoryImpl) getVersionHistory(histUUID);
-
- // 0. resolve the predecessors
- Value[] values = node.getProperty(QName.JCR_PREDECESSORS).getValues();
- InternalVersion[] preds = new InternalVersion[values.length];
- for (int i = 0; i < values.length; i++) {
- preds[i] = history.getVersion(values[i].getString());
- }
-
- // 0.1 search a predecessor, suitable for generating the new name
- String versionName = null;
- int maxDots = Integer.MAX_VALUE;
- for (int i = 0; i < preds.length; i++) {
- // take the first pred. without a successor
- if (preds[i].getSuccessors().length == 0) {
- versionName = preds[i].getName().getLocalName(); //assuming no namespaces in version names
- // need to count the dots
- int pos = -1;
- int numDots = 0;
- while (versionName.indexOf('.', pos + 1) >= 0) {
- pos = versionName.indexOf('.', pos + 1);
- numDots++;
- }
- if (numDots < maxDots) {
- maxDots = numDots;
- if (pos < 0) {
- versionName = "1.0";
- } else {
- versionName = versionName.substring(0, pos + 1)
- + (Integer.parseInt(versionName.substring(pos + 1)) + 1);
- }
- }
- break;
- }
- }
- // if no empty found, generate new name
- if (versionName == null) {
- versionName = preds[0].getName().getLocalName();
- do {
- versionName += ".1";
- } while (history.hasVersion(new QName("", versionName)));
- }
-
- try {
- stateMgr.edit();
- } catch (IllegalStateException e) {
- throw new RepositoryException("Unable to start edit operation.");
- }
-
- boolean succeeded = false;
-
- try {
- InternalVersionImpl v = history.checkin(new QName("", versionName), node);
- stateMgr.update();
- succeeded = true;
-
- return v;
- } catch (ItemStateException e) {
- throw new RepositoryException(e);
- } finally {
- if (!succeeded) {
- // update operation failed, cancel all modifications
- stateMgr.cancel();
- }
- }
- }
-
-
- /**
- * Removes the specified version from the history
- *
- * @param history the version history from where to remove the version.
- * @param name the name of the version to remove.
- * @throws VersionException if the version <code>history</code> does
- * not have a version with <code>name</code>.
- * @throws RepositoryException if any other error occurs.
+ * {@inheritDoc}
+ * <p/>
+ * This method needs to be synchronized since it sets the event source
+ * to be used when creating the events to be dispatched later on.
*/
- public void removeVersion(VersionHistory history, QName name)
+ public synchronized void removeVersion(VersionHistory history, QName name)
throws VersionException, RepositoryException {
- if (!((VersionHistoryImpl) history).hasNode(name)) {
+
+ AbstractVersionHistory historyImpl = (AbstractVersionHistory) history;
+ if (!historyImpl.hasNode(name)) {
throw new VersionException("Version with name " + name.toString()
+ " does not exist in this VersionHistory");
}
- // generate observation events
- SessionImpl session = (SessionImpl) history.getSession();
- VersionImpl version = (VersionImpl) ((VersionHistoryImpl) history).getNode(name);
- List events = new ArrayList();
- generateRemovedEvents(events, (NodeImpl) history, version, true);
+ eventSource = (SessionImpl) history.getSession();
- InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
- ((VersionHistoryImpl) history).getInternalVersionHistory();
+ // save away predecessors before removing version
+ AbstractVersion version = (AbstractVersion) historyImpl.getNode(name);
+ InternalVersion preds[] = version.getInternalVersion().getPredecessors();
- try {
- stateMgr.edit();
- } catch (IllegalStateException e) {
- throw new VersionException("Unable to start edit operation", e);
- }
- boolean succeeded = false;
- try {
- vh.removeVersion(name);
- stateMgr.update();
- succeeded = true;
- } catch (ItemStateException e) {
- log.error("Error while storing: " + e.toString());
- } finally {
- if (!succeeded) {
- // update operation failed, cancel all modifications
- stateMgr.cancel();
- }
- }
+ InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
+ historyImpl.getInternalVersionHistory();
+ removeVersion(vh, name);
// invalidate predecessors successor properties
- InternalVersion preds[] = version.getInternalVersion().getPredecessors();
- for (int i=0; i<preds.length; i++) {
+ for (int i = 0; i < preds.length; i++) {
PropertyId propId = new PropertyId(preds[i].getId(), QName.JCR_SUCCESSORS);
versProvider.onPropertyChanged(propId);
}
- obsMgr.dispatch(events, session);
}
/**
* {@inheritDoc}
- */
- public Version setVersionLabel(VersionHistory history, QName version,
- QName label, boolean move)
+ * <p/>
+ * This method needs to be synchronized since it sets the event source
+ * to be used when creating the events to be dispatched later on.
+ */
+ public synchronized Version setVersionLabel(VersionHistory history,
+ QName version, QName label,
+ boolean move)
throws RepositoryException {
- SessionImpl session = (SessionImpl) history.getSession();
-
- InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
- ((VersionHistoryImpl) history).getInternalVersionHistory();
- NodeImpl labelNode = ((VersionHistoryImpl) history).getNode(QName.JCR_VERSIONLABELS);
- try {
- stateMgr.edit();
- } catch (IllegalStateException e) {
- throw new VersionException("Unable to start edit operation", e);
- }
- InternalVersion v = null;
- boolean success = false;
- try {
- v = vh.setVersionLabel(version, label, move);
- stateMgr.update();
- success = true;
- } catch(ItemStateException e) {
- log.error("Error while storing: " + e.toString());
- } finally {
- if (!success) {
- // update operation failed, cancel all modifications
- stateMgr.cancel();
- }
- }
+ AbstractVersionHistory historyImpl = (AbstractVersionHistory) history;
+ eventSource = (SessionImpl) history.getSession();
- // collect observation events
- List events = new ArrayList();
- if (version == null && v != null) {
- // label removed
- events.add(EventState.propertyRemoved(
- labelNode.internalGetUUID(),
- labelNode.getPrimaryPath(),
- Path.PathElement.fromString(label.toString()),
- (NodeTypeImpl) labelNode.getPrimaryNodeType(),
- labelNode.getMixinTypeNames(),
- labelNode.getSession()
- ));
- } else if (v == null) {
- // label added
- events.add(EventState.propertyAdded(
- labelNode.internalGetUUID(),
- labelNode.getPrimaryPath(),
- Path.PathElement.fromString(label.toString()),
- (NodeTypeImpl) labelNode.getPrimaryNodeType(),
- labelNode.getMixinTypeNames(),
- labelNode.getSession()
- ));
- } else {
- // label modified
- events.add(EventState.propertyChanged(
- labelNode.internalGetUUID(),
- labelNode.getPrimaryPath(),
- Path.PathElement.fromString(label.toString()),
- (NodeTypeImpl) labelNode.getPrimaryNodeType(),
- labelNode.getMixinTypeNames(),
- labelNode.getSession()
- ));
- }
- obsMgr.dispatch(events, session);
+ InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
+ historyImpl.getInternalVersionHistory();
+ InternalVersion v = setVersionLabel(vh, version, label, move);
if (v == null) {
return null;
} else {
- return (VersionImpl) session.getNodeByUUID(v.getId());
+ return (Version) eventSource.getNodeByUUID(v.getId());
}
}
/**
- * Adds a subtree of itemstates as 'added' to a list of events
- *
- * @param events
- * @param parent
- * @param node
- * @throws RepositoryException
+ * Invoked by some external source to indicate that some items in the
+ * versions tree were updated. Version manager should flush its own
+ * caches.
+ * @param items items updated
*/
- private void generateAddedEvents(List events, NodeImpl parent, NodeImpl node,
- boolean recursive)
- throws RepositoryException {
-
- events.add(EventState.childNodeAdded(
- parent.internalGetUUID(),
- parent.getPrimaryPath(),
- node.internalGetUUID(),
- node.getPrimaryPath().getNameElement(),
- (NodeTypeImpl) parent.getPrimaryNodeType(),
- parent.getMixinTypeNames(),
- node.getSession()
- ));
-
- PropertyIterator iter = node.getProperties();
+ public void itemsUpdated(Collection items) {
+ Iterator iter = items.iterator();
while (iter.hasNext()) {
- PropertyImpl prop = (PropertyImpl) iter.nextProperty();
- events.add(EventState.propertyAdded(
- node.internalGetUUID(),
- node.getPrimaryPath(),
- prop.getPrimaryPath().getNameElement(),
- (NodeTypeImpl) node.getPrimaryNodeType(),
- node.getMixinTypeNames(),
- node.getSession()
- ));
- }
- if (recursive) {
- NodeIterator niter = node.getNodes();
- while (niter.hasNext()) {
- NodeImpl n = (NodeImpl) niter.nextNode();
- generateAddedEvents(events, node, n, true);
- }
+ itemUpdated((InternalVersionItem) iter.next());
}
}
/**
- * Adds a subtree of itemstates as 'removed' to a list of events
- *
- * @param events
- * @param parent
- * @param node
- * @throws RepositoryException
+ * Update internal version item. Version histories are reloaded if possible.
+ * Matching items are removed from the cache.
+ * @param item item updated
*/
- private void generateRemovedEvents(List events, NodeImpl parent,
- NodeImpl node, boolean recursive)
- throws RepositoryException {
-
- events.add(EventState.childNodeRemoved(
- parent.internalGetUUID(),
- parent.getPrimaryPath(),
- node.internalGetUUID(),
- node.getPrimaryPath().getNameElement(),
- (NodeTypeImpl) parent.getPrimaryNodeType(),
- parent.getMixinTypeNames(),
- node.getSession()
- ));
- if (recursive) {
- NodeIterator niter = node.getNodes();
- while (niter.hasNext()) {
- NodeImpl n = (NodeImpl) niter.nextNode();
- generateRemovedEvents(events, node, n, true);
+ private void itemUpdated(InternalVersionItem item) {
+ InternalVersionItem cached = (InternalVersionItem) versionItems.remove(item.getId());
+ if (cached != null) {
+ if (cached instanceof InternalVersionHistoryImpl) {
+ InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl) cached;
+ try {
+ vh.reload();
+ versionItems.put(vh.getId(), vh);
+ } catch (RepositoryException e) {
+ log.warn("Unable to update version history: " + e.toString());
+ }
}
}
}
@@ -742,7 +370,7 @@
/**
* {@inheritDoc}
*/
- public List getItemReferences(InternalVersionItem item) {
+ protected List getItemReferences(InternalVersionItem item) {
try {
NodeReferences refs = pMgr.load(new NodeReferencesId(item.getId()));
return refs.getReferences();
@@ -776,6 +404,32 @@
return (NodeId) historyRoot.getState().getId();
}
+ /**
+ * Return the shared item state manager.
+ */
+ SharedItemStateManager getSharedStateMgr() {
+ return sharedStateMgr;
+ }
+
+ //------------------------------------------< EventStateCollectionFactory >
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * This object uses one instance of a <code>LocalItemStateManager</code>
+ * to update data on behalf of many sessions. In order to maintain the
+ * association between update operation and session who actually invoked
+ * the update, an internal event source is used.
+ */
+ public synchronized EventStateCollection createEventStateCollection()
+ throws RepositoryException {
+
+ if (eventSource == null) {
+ throw new RepositoryException("Unknown event source.");
+ }
+ return obsMgr.createEventStateCollection(eventSource);
+ }
+
//--------------------------------------------------------< inner classes >
/**
* Spezialized SharedItemStateManager that filters out NodeReferences to
@@ -787,7 +441,7 @@
String rootNodeUUID,
NodeTypeRegistry ntReg)
throws ItemStateException {
- super(persistMgr, rootNodeUUID, ntReg);
+ super(persistMgr, rootNodeUUID, ntReg, false);
}
protected void checkReferentialIntegrity(ChangeLog changes)
Added: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java?rev=368026&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java Wed Jan 11 06:22:57 2006
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.core.version;
+
+import org.apache.jackrabbit.core.ItemLifeCycleListener;
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.RepositoryException;
+import javax.jcr.InvalidItemStateException;
+
+/**
+ * Implementation of a {@link javax.jcr.version.Version} that works in an
+ * XA environment.
+ */
+public class XAVersion extends AbstractVersion {
+
+ /**
+ * Internal version. Gets fetched again from the version manager if
+ * needed.
+ */
+ private InternalVersion version;
+
+ /**
+ * XA Version manager.
+ */
+ private final XAVersionManager vMgr;
+
+ /**
+ * Create a new instance of this class.
+ * @param itemMgr item manager
+ * @param session session
+ * @param id node id
+ * @param state node state
+ * @param definition node definition
+ * @param listeners life cycle listeners
+ */
+ public XAVersion(ItemManager itemMgr, SessionImpl session, NodeId id,
+ NodeState state, NodeDefinition definition,
+ ItemLifeCycleListener[] listeners,
+ InternalVersion version) {
+ super(itemMgr, session, id, state, definition, listeners);
+
+ this.version = version;
+ this.vMgr = (XAVersionManager) session.getVersionManager();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected InternalVersion getInternalVersion() throws RepositoryException {
+ ensureUpToDate();
+ sanityCheck();
+ return version;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void sanityCheck() throws RepositoryException {
+ super.sanityCheck();
+
+ if (version == null) {
+ throw new InvalidItemStateException(id + ": the item does not exist anymore");
+ }
+ }
+
+ /**
+ * Ensure the internal version is up-to-date.
+ */
+ private synchronized void ensureUpToDate() throws RepositoryException {
+ if (version != null) {
+ if (vMgr.differentXAEnv((InternalVersionImpl) version)) {
+ version = vMgr.getVersion(version.getId());
+ }
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersion.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java?rev=368026&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java Wed Jan 11 06:22:57 2006
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.core.version;
+
+import org.apache.jackrabbit.core.ItemLifeCycleListener;
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.state.NodeState;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.nodetype.NodeDefinition;
+
+/**
+ * Implementation of a {@link javax.jcr.version.VersionHistory} that works in an
+ * XA environment.
+ */
+public class XAVersionHistory extends AbstractVersionHistory {
+
+ /**
+ * Internal version history. Gets fetched again from the version manager if
+ * needed.
+ */
+ private InternalVersionHistory history;
+
+ /**
+ * XA Version manager.
+ */
+ private final XAVersionManager vMgr;
+
+ /**
+ * Create a new instance of this class.
+ * @param itemMgr item manager
+ * @param session session
+ * @param id node id
+ * @param state node state
+ * @param definition node definition
+ * @param listeners life cycle listeners
+ * @param history internal version history
+ */
+ public XAVersionHistory(ItemManager itemMgr, SessionImpl session, NodeId id,
+ NodeState state, NodeDefinition definition,
+ ItemLifeCycleListener[] listeners,
+ InternalVersionHistory history) {
+ super(itemMgr, session, id, state, definition, listeners);
+
+ this.history = history;
+ this.vMgr = (XAVersionManager) session.getVersionManager();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected InternalVersionHistory getInternalVersionHistory()
+ throws RepositoryException {
+
+ ensureUpToDate();
+ sanityCheck();
+ return history;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void sanityCheck() throws RepositoryException {
+ super.sanityCheck();
+
+ if (history == null) {
+ throw new InvalidItemStateException(id + ": the item does not exist anymore");
+ }
+ }
+
+ /**
+ * Ensure the internal version is up-to-date.
+ */
+ private synchronized void ensureUpToDate() throws RepositoryException {
+ if (history != null) {
+ if (vMgr.differentXAEnv(((InternalVersionHistoryImpl) history))) {
+ history = vMgr.getVersionHistory(history.getId());
+ }
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionHistory.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java?rev=368026&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java Wed Jan 11 06:22:57 2006
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.core.version;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.core.TransactionContext;
+import org.apache.jackrabbit.core.TransactionException;
+import org.apache.jackrabbit.core.InternalXAResource;
+import org.apache.jackrabbit.core.observation.EventStateCollectionFactory;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeReferencesId;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.XAItemStateManager;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
+import org.apache.jackrabbit.core.virtual.VirtualPropertyState;
+import org.apache.jackrabbit.core.virtual.VirtualNodeState;
+import org.apache.jackrabbit.name.QName;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Implementation of a {@link VersionManager} that works in an XA environment.
+ * Works as a filter between a version manager client and the global version
+ * manager.
+ */
+public class XAVersionManager extends AbstractVersionManager
+ implements VirtualItemStateProvider, InternalXAResource {
+
+ /**
+ * Attribute name for associated change log.
+ */
+ private static final String CHANGE_LOG_ATTRIBUTE_NAME = "XAVersionManager.ChangeLog";
+
+ /**
+ * Attribute name for items.
+ */
+ private static final String ITEMS_ATTRIBUTE_NAME = "VersionItems";
+
+ /**
+ * Repository version manager.
+ */
+ private final VersionManagerImpl vMgr;
+
+ /**
+ * Node type registry.
+ */
+ private NodeTypeRegistry ntReg;
+
+ /**
+ * Items that have been modified and are part of the XA environment.
+ */
+ private Map xaItems;
+
+ /**
+ * Creates a new instance of this class.
+ */
+ public XAVersionManager(VersionManagerImpl vMgr, NodeTypeRegistry ntReg,
+ EventStateCollectionFactory factory)
+ throws RepositoryException {
+
+ this.vMgr = vMgr;
+ this.ntReg = ntReg;
+ this.stateMgr = new XAItemStateManager(vMgr.getSharedStateMgr(),
+ factory, CHANGE_LOG_ATTRIBUTE_NAME);
+
+ NodeState state;
+ try {
+ state = (NodeState) stateMgr.getItemState(vMgr.getHistoryRootId());
+ } catch (ItemStateException e) {
+ throw new RepositoryException("Unable to retrieve history root", e);
+ }
+ this.historyRoot = new NodeStateEx(stateMgr, ntReg, state, QName.JCR_VERSIONSTORAGE);
+ }
+
+ //-------------------------------------------------------< VersionManager >
+
+ /**
+ * {@inheritDoc}
+ */
+ public VirtualItemStateProvider getVirtualItemStateProvider() {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public VersionHistory createVersionHistory(Session session, NodeState node)
+ throws RepositoryException {
+
+ if (isInXA()) {
+ InternalVersionHistory history = createVersionHistory(node);
+ xaItems.put(history.getId(), history);
+ return (VersionHistory) session.getNodeByUUID(history.getId());
+ }
+ return vMgr.createVersionHistory(session, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version checkin(NodeImpl node) throws RepositoryException {
+ if (isInXA()) {
+ String histUUID = node.getProperty(QName.JCR_VERSIONHISTORY).getString();
+ InternalVersion version = checkin(
+ (InternalVersionHistoryImpl) getVersionHistory(histUUID), node);
+ return (Version) node.getSession().getNodeByUUID(version.getId());
+ }
+ return vMgr.checkin(node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeVersion(VersionHistory history, QName versionName)
+ throws RepositoryException {
+
+ if (isInXA()) {
+ InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
+ ((AbstractVersionHistory) history).getInternalVersionHistory();
+ removeVersion(vh, versionName);
+ return;
+ }
+ vMgr.removeVersion(history, versionName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version setVersionLabel(VersionHistory history, QName version,
+ QName label, boolean move)
+ throws RepositoryException {
+
+ if (isInXA()) {
+ InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
+ ((AbstractVersionHistory) history).getInternalVersionHistory();
+ InternalVersion v = setVersionLabel(vh, version, label, move);
+ if (v == null) {
+ return null;
+ } else {
+ return (Version) history.getSession().getNodeByUUID(v.getId());
+ }
+ }
+ return vMgr.setVersionLabel(history, version, label, move);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws Exception {
+ }
+
+ //---------------------------------------------< VirtualItemStateProvider >
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isVirtualRoot(ItemId id) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeId getVirtualRootId() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public VirtualPropertyState createPropertyState(VirtualNodeState parent,
+ QName name, int type,
+ boolean multiValued)
+ throws RepositoryException {
+
+ throw new IllegalStateException("Read-only");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public VirtualNodeState createNodeState(VirtualNodeState parent, QName name,
+ String uuid, QName nodeTypeName)
+ throws RepositoryException {
+
+ throw new IllegalStateException("Read-only");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean setNodeReferences(NodeReferences refs) {
+ ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
+ if (changeLog != null) {
+ changeLog.modified(refs);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Return item states for changes only. Global version manager will return
+ * other items.
+ */
+ public ItemState getItemState(ItemId id)
+ throws NoSuchItemStateException, ItemStateException {
+
+ ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
+ if (changeLog != null) {
+ return changeLog.get(id);
+ }
+ throw new NoSuchItemStateException("State not in change log: " + id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasItemState(ItemId id) {
+ ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
+ if (changeLog != null) {
+ return changeLog.has(id);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeReferences getNodeReferences(NodeReferencesId id)
+ throws NoSuchItemStateException, ItemStateException {
+
+ ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
+ if (changeLog != null) {
+ return changeLog.get(id);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNodeReferences(NodeReferencesId id) {
+ ChangeLog changeLog = ((XAItemStateManager) stateMgr).getChangeLog();
+ if (changeLog != null) {
+ return changeLog.get(id) != null;
+ }
+ return false;
+ }
+
+ //-----------------------------------------------< AbstractVersionManager >
+
+ /**
+ * {@inheritDoc}
+ */
+ protected InternalVersionItem getItem(String uuid) throws RepositoryException {
+ InternalVersionItem item = null;
+ if (xaItems != null) {
+ item = (InternalVersionItem) xaItems.get(uuid);
+ }
+ if (item == null) {
+ item = vMgr.getItem(uuid);
+ }
+ return item;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected boolean hasItem(String uuid) {
+ if (xaItems != null && xaItems.containsKey(uuid)) {
+ return true;
+ }
+ return vMgr.hasItem(uuid);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected List getItemReferences(InternalVersionItem item) {
+ return vMgr.getItemReferences(item);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Before modifying version history given, make a local copy of it.
+ */
+ protected InternalVersion checkin(InternalVersionHistoryImpl history,
+ NodeImpl node)
+ throws RepositoryException {
+
+ if (history.getVersionManager() != this) {
+ history = makeLocalCopy(history);
+ xaItems.put(history.getId(), history);
+ }
+ return super.checkin(history, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Before modifying version history given, make a local copy of it.
+ */
+ protected void removeVersion(InternalVersionHistoryImpl history, QName name)
+ throws VersionException, RepositoryException {
+
+ if (history.getVersionManager() != this) {
+ history = makeLocalCopy(history);
+ xaItems.put(history.getId(), history);
+ }
+ super.removeVersion(history, name);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Before modifying version history given, make a local copy of it.
+ */
+ protected InternalVersion setVersionLabel(InternalVersionHistoryImpl history,
+ QName version, QName label,
+ boolean move)
+ throws RepositoryException {
+
+ if (history.getVersionManager() != this) {
+ history = makeLocalCopy(history);
+ xaItems.put(history.getId(), history);
+ }
+ return super.setVersionLabel(history, version, label, move);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Put the version object into our cache.
+ */
+ protected void versionCreated(InternalVersion version) {
+ xaItems.put(version.getId(), version);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Remove the version object from our cache.
+ */
+ protected void versionDestroyed(InternalVersion version) {
+ xaItems.remove(version.getId());
+ }
+
+ //-------------------------------------------------------------------< XA >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void associate(TransactionContext tx) {
+ ((XAItemStateManager) stateMgr).associate(tx);
+
+ Map xaItems = null;
+ if (tx != null) {
+ xaItems = (Map) tx.getAttribute(ITEMS_ATTRIBUTE_NAME);
+ if (xaItems == null) {
+ xaItems = new HashMap();
+ tx.setAttribute(ITEMS_ATTRIBUTE_NAME, xaItems);
+ }
+ }
+ this.xaItems = xaItems;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Delegate the call to our XA item state manager.
+ */
+ public void beforeOperation(TransactionContext tx) {
+ ((XAItemStateManager) stateMgr).beforeOperation(tx);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Delegate the call to our XA item state manager.
+ */
+ public void prepare(TransactionContext tx) throws TransactionException {
+ ((XAItemStateManager) stateMgr).prepare(tx);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Delegate the call to our XA item state manager. If successful, inform
+ * global repository manager to update its caches.
+ */
+ public void commit(TransactionContext tx) throws TransactionException {
+ ((XAItemStateManager) stateMgr).commit(tx);
+
+ Map xaItems = (Map) tx.getAttribute(ITEMS_ATTRIBUTE_NAME);
+ vMgr.itemsUpdated(xaItems.values());
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Delegate the call to our XA item state manager.
+ */
+ public void rollback(TransactionContext tx) {
+ ((XAItemStateManager) stateMgr).rollback(tx);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Delegate the call to our XA item state manager.
+ */
+ public void afterOperation(TransactionContext tx) {
+ ((XAItemStateManager) stateMgr).afterOperation(tx);
+ }
+
+ //-------------------------------------------------------< implementation >
+
+ /**
+ * Return a flag indicating whether this version manager is currently
+ * associated with an XA transaction.
+ */
+ private boolean isInXA() {
+ return xaItems != null;
+ }
+
+ /**
+ * Make a local copy of an internal version item. This will recreate the
+ * (global) version item with state information from our own state
+ * manager.
+ */
+ private InternalVersionHistoryImpl makeLocalCopy(InternalVersionHistoryImpl history)
+ throws RepositoryException {
+
+ NodeState state;
+ try {
+ state = (NodeState) stateMgr.getItemState(new NodeId(history.getId()));
+ } catch (ItemStateException e) {
+ throw new RepositoryException("Unable to make local copy", e);
+ }
+ NodeStateEx stateEx = new NodeStateEx(stateMgr, ntReg, state, null);
+ return new InternalVersionHistoryImpl(this, stateEx);
+ }
+
+ /**
+ * Return a flag indicating whether an internal version item belongs to
+ * a different XA environment.
+ */
+ boolean differentXAEnv(InternalVersionItemImpl item) {
+ if (item.getVersionManager() == this) {
+ if (xaItems == null || !xaItems.containsKey(item.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java?rev=368026&r1=368025&r2=368026&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/AbstractVISProvider.java Wed Jan 11 06:22:57 2006
@@ -32,6 +32,7 @@
import org.apache.jackrabbit.core.state.NodeReferencesId;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.ItemStateReferenceMap;
+import org.apache.jackrabbit.core.state.ItemStateListener;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.uuid.UUID;
import org.apache.log4j.Logger;
@@ -44,7 +45,7 @@
* This Class implements a virtual item state provider, in order to expose the
* versions to the version storage.
*/
-public abstract class AbstractVISProvider implements VirtualItemStateProvider {
+public abstract class AbstractVISProvider implements VirtualItemStateProvider, ItemStateListener {
/**
* the default logger
*/
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java?rev=368026&r1=368025&r2=368026&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualItemStateProvider.java Wed Jan 11 06:22:57 2006
@@ -28,7 +28,7 @@
/**
* This Interface defines a virtual item state provider.
*/
-public interface VirtualItemStateProvider extends ItemStateManager, ItemStateListener {
+public interface VirtualItemStateProvider extends ItemStateManager {
/**
* Checks if the id refers to the root of a virtual tree.
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java?rev=368026&r1=368025&r2=368026&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/virtual/VirtualNodeState.java Wed Jan 11 06:22:57 2006
@@ -56,7 +56,7 @@
* @param mixins
* @throws RepositoryException
*/
- public VirtualNodeState(VirtualItemStateProvider stateMgr,
+ public VirtualNodeState(AbstractVISProvider stateMgr,
String parentUUID,
String uuid,
QName nodeTypeName,
Modified: incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java?rev=368026&r1=368025&r2=368026&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java Wed Jan 11 06:22:57 2006
@@ -22,6 +22,9 @@
import javax.jcr.Node;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.VersionException;
+import javax.jcr.version.Version;
import javax.jcr.lock.Lock;
import javax.transaction.UserTransaction;
import javax.transaction.RollbackException;
@@ -33,6 +36,30 @@
public class XATest extends AbstractJCRTest {
/**
+ * Other superuser.
+ */
+ private Session otherSuperuser;
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ otherSuperuser = helper.getSuperuserSession();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void tearDown() throws Exception {
+ if (otherSuperuser != null) {
+ otherSuperuser.logout();
+ }
+ super.tearDown();
+ }
+
+ /**
* @see junit.framework#runTest
*
* Make sure that tested repository supports transactions
@@ -44,28 +71,6 @@
}
}
- public void testCheckin() throws Exception {
- // get user transaction object
- UserTransaction utx = new UserTransactionImpl(superuser);
-
- // start transaction
- utx.begin();
-
- // add node and save
- Node n = testRootNode.addNode(nodeName1, testNodeType);
- n.addMixin(mixVersionable);
- testRootNode.save();
-
- n.checkin();
-
- assertFalse("Node must be checked-in", n.isCheckedOut());
-
- // commit
- utx.commit();
-
- assertFalse("Node must be checked-in", n.isCheckedOut());
- }
-
/**
* Add a node inside a transaction and commit changes. Make sure
* node exists for other sessions only after commit.
@@ -557,6 +562,8 @@
otherSuperuser.logout();
}
+ //--------------------------------------------------------------< locking >
+
/**
* Test locking a node in one session. Verify that node is not locked
* in other session until commit.
@@ -692,7 +699,7 @@
* Test locking a new node inside a transaction.
* @throws Exception
*/
- public void testLockNewNode() throws Exception {
+ public void xxxtestLockNewNode() throws Exception {
// get user transaction object, start
UserTransaction utx = new UserTransactionImpl(superuser);
utx.begin();
@@ -802,5 +809,162 @@
// verify lock is live again
assertTrue("Lock live", lock.isLive());
+ }
+
+ //-----------------------------------------------------------< versioning >
+
+ /**
+ * Checkin inside tx should not be visible to other users.
+ */
+ public void testCheckin() throws Exception {
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // add node and save
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ n.addMixin(mixVersionable);
+ testRootNode.save();
+
+ // reference node in other session
+ Node nOther = otherSuperuser.getNodeByUUID(n.getUUID());
+
+ // start transaction
+ utx.begin();
+
+ // checkin node
+ n.checkin();
+
+ // assert: base versions must differ
+ assertNotSame("Base versions must differ",
+ n.getBaseVersion().getName(), nOther.getBaseVersion().getName());
+
+ // assert: version must not be visible to other session
+ try {
+ nOther.getVersionHistory().getVersion(n.getBaseVersion().getName());
+ fail("Version must not be visible to other session.");
+ } catch (VersionException e) {
+ // expected.
+ }
+
+ // commit
+ utx.commit();
+
+ // assert: base versions must be equal
+ assertSame("Base versions must be equal",
+ n.getBaseVersion().getName(), nOther.getBaseVersion().getName());
+ }
+
+ /**
+ * Checkin from two sessions simultaneously should throw when committing.
+ * @throws Exception
+ */
+ public void testConflictingCheckin() throws Exception {
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // add node and save
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ n.addMixin(mixVersionable);
+ testRootNode.save();
+
+ // reference node in other session
+ Node nOther = otherSuperuser.getNodeByUUID(n.getUUID());
+
+ // start transaction
+ utx.begin();
+
+ // checkin node inside tx
+ n.checkin();
+
+ // checkin node outside tx
+ nOther.checkin();
+
+ // commit
+ try {
+ utx.commit();
+ fail("Commit failing with modified version history.");
+ } catch (RollbackException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test removed version gets invalid for other users on commit.
+ */
+ public void testRemoveVersion() throws Exception {
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // add node and save
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ n.addMixin(mixVersionable);
+ testRootNode.save();
+
+ // reference node in other session
+ Node nOther = otherSuperuser.getNodeByUUID(n.getUUID());
+
+ // create two versions, reference first version in other session
+ n.checkin();
+ Version vOther = nOther.getBaseVersion();
+ n.checkout();
+ n.checkin();
+
+ // start transaction
+ utx.begin();
+
+ // remove version and commit
+ n.getVersionHistory().removeVersion(vOther.getName());
+
+ // commit
+ utx.commit();
+
+ // assert: version has become invalid
+ try {
+ vOther.getPredecessors();
+ fail("Removed version still operational.");
+ } catch (RepositoryException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test new version label becomes available to other sessions on commit.
+ */
+ public void testSetVersionLabel() throws Exception {
+ final String versionLabel = "myVersion";
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // add node and save
+ Node n = testRootNode.addNode(nodeName1, testNodeType);
+ n.addMixin(mixVersionable);
+ testRootNode.save();
+
+ // reference node in other session
+ Node nOther = otherSuperuser.getNodeByUUID(n.getUUID());
+
+ // create another version
+ Version v = n.checkin();
+
+ // start transaction
+ utx.begin();
+
+ // add new version label
+ n.getVersionHistory().addVersionLabel(v.getName(), versionLabel, false);
+
+ // assert: version label unknown in other session
+ try {
+ nOther.getVersionHistory().getVersionByLabel(versionLabel);
+ fail("Version label visible outside tx.");
+ } catch (VersionException e) {
+ // expected
+ }
+
+ // commit
+ utx.commit();
+
+ // assert: version label known in other session
+ nOther.getVersionHistory().getVersionByLabel(versionLabel);
}
}