Return-Path: Delivered-To: apmail-incubator-jackrabbit-commits-archive@www.apache.org Received: (qmail 51646 invoked from network); 11 Jan 2006 14:25:10 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 11 Jan 2006 14:25:10 -0000 Received: (qmail 96759 invoked by uid 500); 11 Jan 2006 14:25:08 -0000 Mailing-List: contact jackrabbit-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: jackrabbit-dev@incubator.apache.org Delivered-To: mailing list jackrabbit-commits@incubator.apache.org Received: (qmail 96719 invoked by uid 500); 11 Jan 2006 14:25:07 -0000 Delivered-To: apmail-incubator-jackrabbit-cvs@incubator.apache.org Received: (qmail 96712 invoked by uid 99); 11 Jan 2006 14:25:07 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 11 Jan 2006 06:25:07 -0800 X-ASF-Spam-Status: No, hits=-8.6 required=10.0 tests=ALL_TRUSTED,INFO_TLD,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 11 Jan 2006 06:25:03 -0800 Received: (qmail 51409 invoked by uid 65534); 11 Jan 2006 14:24:43 -0000 Message-ID: <20060111142443.51407.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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... Date: Wed, 11 Jan 2006 14:24:32 -0000 To: jackrabbit-cvs@incubator.apache.org From: dpfister@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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} + *

+ * 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 null 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 null 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} + *

+ * 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= 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 history does - * not have a version with name. - * @throws RepositoryException if any other error occurs. + * {@inheritDoc} + *

+ * 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 + * 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} + *

+ * This object uses one instance of a LocalItemStateManager + * 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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * Put the version object into our cache. + */ + protected void versionCreated(InternalVersion version) { + xaItems.put(version.getId(), version); + } + + /** + * {@inheritDoc} + *

+ * 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} + *

+ * Delegate the call to our XA item state manager. + */ + public void beforeOperation(TransactionContext tx) { + ((XAItemStateManager) stateMgr).beforeOperation(tx); + } + + /** + * {@inheritDoc} + *

+ * Delegate the call to our XA item state manager. + */ + public void prepare(TransactionContext tx) throws TransactionException { + ((XAItemStateManager) stateMgr).prepare(tx); + } + + /** + * {@inheritDoc} + *

+ * 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} + *

+ * Delegate the call to our XA item state manager. + */ + public void rollback(TransactionContext tx) { + ((XAItemStateManager) stateMgr).rollback(tx); + } + + /** + * {@inheritDoc} + *

+ * 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); } }