You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/02/25 11:44:56 UTC
svn commit: r155314 - in incubator/jackrabbit/trunk/src:
java/org/apache/jackrabbit/core/ java/org/apache/jackrabbit/core/state/
test/org/apache/jackrabbit/core/
Author: mreutegg
Date: Fri Feb 25 02:44:52 2005
New Revision: 155314
URL: http://svn.apache.org/viewcvs?view=rev&rev=155314
Log:
Transaction patch submitted by Dominique.
Moved test classes out of api.xa package because the UserTransactionImpl class uses the implementation specifc XASessionImpl class.
Added:
incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java (with props)
incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java (with props)
Modified:
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/XASessionImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ChangeLog.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionContext.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionListener.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java
incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/TestAll.java
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java Fri Feb 25 02:44:52 2005
@@ -235,25 +235,6 @@
}
/**
- * Notify the listeners that this instance has been resurrected
- * (i.e. it has been rendered 'valid' again).
- */
- protected void notifyResurrected() {
- // copy listeners to array to avoid ConcurrentModificationException
- ItemLifeCycleListener[] la = new ItemLifeCycleListener[listeners.size()];
- Iterator iter = listeners.values().iterator();
- int cnt = 0;
- while (iter.hasNext()) {
- la[cnt++] = (ItemLifeCycleListener) iter.next();
- }
- for (int i = 0; i < la.length; i++) {
- if (la[i] != null) {
- la[i].itemResurrected(this);
- }
- }
- }
-
- /**
* Notify the listeners that this instance has been destroyed
* (i.e. it has been permanently rendered 'invalid').
*/
@@ -966,12 +947,6 @@
state = persistentState;
state.addListener(this);
- if (status == STATUS_INVALIDATED) {
- // resurrect this instance
- status = STATUS_NORMAL;
- // notify the listeners
- notifyResurrected();
- }
return;
/**
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java Fri Feb 25 02:44:52 2005
@@ -46,14 +46,6 @@
public void itemInvalidated(ItemId id, ItemImpl item);
/**
- * Called when a previously invalidated <code>ItemImpl</code> instance
- * has been resurrected (i.e. it has been rendered 'valid' again).
- *
- * @param item the instance which has been resurrected
- */
- public void itemResurrected(ItemImpl item);
-
- /**
* Called when an <code>ItemImpl</code> instance has been destroyed
* (i.e. it has been permanently rendered 'invalid').
* <p/>
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemManager.java Fri Feb 25 02:44:52 2005
@@ -628,27 +628,6 @@
return createPropertyInstance(state, def);
}
- /**
- * Removes the specified item from the cache and renders it
- * 'invalid'.
- *
- * @param id
- * @throws ItemNotFoundException
- * @throws RepositoryException
- */
- void removeItem(ItemId id)
- throws ItemNotFoundException, RepositoryException {
- // the removed instance is not directly removed from the cache;
- // it will be removed when the instance notifies the item manager
- // that it has been invalidated (see itemInvalidated method)
- ItemImpl item = retrieveItem(id);
- if (item == null) {
- // need to instantiate item first
- item = createItemInstance(id);
- }
- item.setRemoved();
- }
-
//---------------------------------------------------< item cache methods >
/**
* Checks if there's a cache entry for the specified id.
@@ -748,15 +727,6 @@
log.debug("invalidated item " + id);
// remove instance from cache
evictItem(id);
- }
-
- /**
- * @see ItemLifeCycleListener#itemResurrected
- */
- public void itemResurrected(ItemImpl item) {
- log.debug("resurrected item " + item.getId());
- // add instance to cache
- cacheItem(item);
}
/**
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java Fri Feb 25 02:44:52 2005
@@ -537,16 +537,16 @@
// modify the state of 'this', i.e. the parent node
NodeState thisState = (NodeState) getOrCreateTransientItemState();
- // remove property
- PropertyId propId = new PropertyId(thisState.getUUID(), propName);
- itemMgr.removeItem(propId);
-
// remove the property entry
if (!thisState.removePropertyEntry(propName)) {
String msg = "failed to remove property " + propName + " of " + safeGetJCRPath();
log.debug(msg);
throw new RepositoryException(msg);
}
+
+ // remove property
+ PropertyId propId = new PropertyId(thisState.getUUID(), propName);
+ itemMgr.getItem(propId).setRemoved();
}
protected void removeChildNode(QName nodeName, int index) throws RepositoryException {
@@ -624,7 +624,7 @@
if (orphaned) {
// remove this node
- itemMgr.removeItem(id);
+ itemMgr.getItem(id).setRemoved();
}
}
@@ -2689,7 +2689,7 @@
} catch (RepositoryException e) {
session.refresh(false);
throw e;
- }
+ }
session.save();
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/XASessionImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/XASessionImpl.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/XASessionImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/XASessionImpl.java Fri Feb 25 02:44:52 2005
@@ -21,7 +21,6 @@
import org.apache.jackrabbit.core.state.TransactionContext;
import org.apache.jackrabbit.core.state.TransactionException;
import org.apache.jackrabbit.core.state.TransactionListener;
-import org.apache.jackrabbit.core.state.TransactionalItemStateManager;
import org.apache.log4j.Logger;
import javax.jcr.Credentials;
@@ -193,7 +192,6 @@
disassociate();
} else if (flags == TMFAIL) {
disassociate();
- tx.setRollbackOnly();
} else if (flags == TMSUSPEND) {
disassociate();
} else {
@@ -220,12 +218,7 @@
if (tx == null) {
throw new XAException(XAException.XAER_NOTA);
}
- try {
- tx.rollback();
- } catch (TransactionException e) {
- log.error("Unable to rollback transaction.", e);
- throw new XAException(XAException.XAER_RMERR);
- }
+ wsp.getItemStateManager().rollback(tx);
}
/**
@@ -238,10 +231,10 @@
}
try {
- tx.commit();
+ wsp.getItemStateManager().commit(tx);
} catch (TransactionException e) {
log.error("Unable to commit transaction.", e);
- throw new XAException(XAException.XAER_RMERR);
+ throw new XAException(XAException.XA_RBOTHER);
}
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ChangeLog.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ChangeLog.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ChangeLog.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/ChangeLog.java Fri Feb 25 02:44:52 2005
@@ -57,7 +57,10 @@
}
/**
- * A state has been modified
+ * A state has been modified. If the state is not a new state
+ * (not in the collection of added ones), then disconnect
+ * the local state from its underlying shared state and add
+ * it to the modified states collection.
* @param state state that has been modified
*/
public void modified(ItemState state) {
@@ -68,7 +71,11 @@
}
/**
- * A state has been deleted
+ * A state has been deleted. If the state is not a new state
+ * (not in the collection of added ones), then disconnect
+ * the local state from its underlying shared state, remove
+ * it from the modified states collection and add it to the
+ * deleted states collection.
* @param state state that has been deleted
*/
public void deleted(ItemState state) {
@@ -220,32 +227,14 @@
}
/**
- * Reset this change log, removing all members inside.
+ * Reset this change log, removing all members inside the
+ * maps we built.
*/
public void reset() {
addedStates.clear();
modifiedStates.clear();
deletedStates.clear();
modifiedRefs.clear();
- }
-
- /**
- * Discard all items contained in this change log
- */
- public void discard() {
- Iterator iter = addedStates();
- while (iter.hasNext()) {
- ((ItemState) iter.next()).discard();
- }
- iter = modifiedStates();
- while (iter.hasNext()) {
- ((ItemState) iter.next()).discard();
- }
- iter = deletedStates();
- while (iter.hasNext()) {
- ((ItemState) iter.next()).discard();
- }
- reset();
}
/**
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SessionItemStateManager.java Fri Feb 25 02:44:52 2005
@@ -33,8 +33,19 @@
private static Logger log = Logger.getLogger(SessionItemStateManager.class);
+ /**
+ * Root node id
+ */
private final NodeId rootNodeId;
+
+ /**
+ * State manager that allows updates
+ */
private final UpdatableItemStateManager persistentStateMgr;
+
+ /**
+ * Virtual item state providers
+ */
private VirtualItemStateProvider[] virtualProviders = new VirtualItemStateProvider[0];
private final TransientItemStateManager transientStateMgr;
private HierarchyManager hierMgr;
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Fri Feb 25 02:44:52 2005
@@ -301,11 +301,33 @@
ChangeLog shared = new ChangeLog();
/**
+ * Validate modified references. Target node of references may
+ * have been deleted in the meantime.
+ */
+ Iterator iter = local.modifiedRefs();
+ while (iter.hasNext()) {
+ NodeReferences refs = (NodeReferences) iter.next();
+ NodeId id = new NodeId(refs.getUUID());
+
+ if (refs.hasReferences()) {
+ try {
+ if (local.get(id) == null && !hasItemState(id)) {
+ throw new NoSuchItemStateException();
+ }
+ } catch (NoSuchItemStateException e) {
+ String msg = "Target node " + id + " of REFERENCE property does not exist";
+ throw new ItemStateException(msg);
+ }
+ }
+ shared.modified(refs);
+ }
+
+ /**
* Reconnect all items contained in the change log to their
* respective shared item and add the shared items to a
* new change log.
*/
- Iterator iter = local.addedStates();
+ iter = local.addedStates();
while (iter.hasNext()) {
ItemState state = (ItemState) iter.next();
state.connect(createInstance(state));
@@ -322,10 +344,6 @@
ItemState state = (ItemState) iter.next();
state.connect(getItemState(state.getId()));
shared.deleted(state.getOverlayedState());
- }
- iter = local.modifiedRefs();
- while (iter.hasNext()) {
- shared.modified((NodeReferences) iter.next());
}
/* Push all changes from the local items to the shared items */
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionContext.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionContext.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionContext.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionContext.java Fri Feb 25 02:44:52 2005
@@ -38,43 +38,6 @@
private final Map attributes = new HashMap();
/**
- * Flag indicating whether rollback only is allowed
- */
- private boolean rollbackOnly;
-
- /**
- * Commit this transaction. Commits all changes to items contained in the
- * transaction. After having successfully committed the transaction, it
- * may no longer be used.
- *
- * @throws org.apache.jackrabbit.core.state.TransactionException if an error occurs
- */
- public void commit() throws TransactionException {
- if (rollbackOnly) {
- throw new TransactionException("Transaction set to rollback only.");
- }
- notifyCommitted();
- }
-
- /**
- * Set outcome of this transaction to rollback only.
- */
- public void setRollbackOnly() {
- rollbackOnly = true;
- }
-
- /**
- * Rollback this transaction. Rollbacks all changes to items contained in
- * the transaction. After having successfully rolled back the transaction,
- * it may no longer be used.
- *
- * @throws org.apache.jackrabbit.core.state.TransactionException if an error occurs
- */
- public void rollback() throws TransactionException {
- notifyRolledBack();
- }
-
- /**
* Set an attribute on this transaction. If the value specified is
* <code>null</code>, it is semantically equivalent to
* {@link #removeAttribute}.
@@ -137,7 +100,7 @@
* one commit and one rollback event to be reported, the listeners can
* safely be cleared at the same time.
*/
- private void notifyCommitted() throws TransactionException {
+ void notifyCommitted() {
TransactionListener[] al;
synchronized (listeners) {
@@ -156,7 +119,7 @@
* one commit and one rollback event to be reported, the listeners can
* safely be cleared at the same time.
*/
- private void notifyRolledBack() throws TransactionException {
+ void notifyRolledBack() {
TransactionListener[] al;
synchronized (listeners) {
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionListener.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionListener.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionListener.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionListener.java Fri Feb 25 02:44:52 2005
@@ -29,14 +29,12 @@
*
* @param tx transaction that was committed
*/
- public void transactionCommitted(TransactionContext tx)
- throws TransactionException;
+ public void transactionCommitted(TransactionContext tx);
/**
* Transaction was rolled back
*
* @param tx transaction that was rolled back
*/
- public void transactionRolledBack(TransactionContext tx)
- throws TransactionException;
+ public void transactionRolledBack(TransactionContext tx);
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/TransactionalItemStateManager.java Fri Feb 25 02:44:52 2005
@@ -24,8 +24,7 @@
* multiple save() requests and commits them only when an associated transaction
* is itself committed.
*/
-public class TransactionalItemStateManager extends LocalItemStateManager
- implements TransactionListener {
+public class TransactionalItemStateManager extends LocalItemStateManager {
/**
* Logger instance
@@ -38,14 +37,9 @@
private static final String ATTRIBUTE_CHANGE_LOG = "ChangeLog";
/**
- * Currently associated transaction
+ * Current transactional change log
*/
- private transient TransactionContext tx;
-
- /**
- * Current change log
- */
- private transient ChangeLog changeLog;
+ private transient ChangeLog txLog;
/**
* Creates a new <code>LocalItemStateManager</code> instance.
@@ -61,15 +55,46 @@
* @param tx transaction context.
*/
public void setTransactionContext(TransactionContext tx) {
+ txLog = null;
+
if (tx != null) {
- changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
- if (changeLog == null) {
- changeLog = new ChangeLog();
- tx.setAttribute(ATTRIBUTE_CHANGE_LOG, changeLog);
- tx.addListener(this);
+ txLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
+ if (txLog == null) {
+ txLog = new ChangeLog();
+ tx.setAttribute(ATTRIBUTE_CHANGE_LOG, txLog);
+ }
+ }
+ }
+
+ /**
+ * Commit changes made within a transaction
+ * @param tx transaction context
+ * @throws TransactionException if an error occurs
+ */
+ public void commit(TransactionContext tx) throws TransactionException {
+ ChangeLog changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
+ if (changeLog != null) {
+ try {
+ super.update(changeLog);
+ } catch (ItemStateException e) {
+ changeLog.undo(sharedStateMgr);
+ throw new TransactionException("Unable to end update.", e);
}
+ changeLog.reset();
+ tx.notifyCommitted();
}
- this.tx = tx;
+ }
+
+ /**
+ * Rollback changes made within a transaction
+ * @param tx transaction context
+ */
+ public void rollback(TransactionContext tx) {
+ ChangeLog changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
+ if (changeLog != null) {
+ changeLog.undo(sharedStateMgr);
+ }
+ tx.notifyRolledBack();
}
//-----------------------------------------------------< ItemStateManager >
@@ -83,9 +108,9 @@
public ItemState getItemState(ItemId id)
throws NoSuchItemStateException, ItemStateException {
- if (tx != null) {
+ if (txLog != null) {
// check items in change log
- ItemState state = changeLog.get(id);
+ ItemState state = txLog.get(id);
if (state != null) {
return state;
}
@@ -100,10 +125,10 @@
* change log first.
*/
public boolean hasItemState(ItemId id) {
- if (tx != null) {
+ if (txLog != null) {
// check items in change log
try {
- ItemState state = changeLog.get(id);
+ ItemState state = txLog.get(id);
if (state != null) {
return true;
}
@@ -123,9 +148,9 @@
public NodeReferences getNodeReferences(NodeReferencesId id)
throws NoSuchItemStateException, ItemStateException {
- if (tx != null) {
+ if (txLog != null) {
// check change log
- NodeReferences refs = changeLog.get(id);
+ NodeReferences refs = txLog.get(id);
if (refs != null) {
return refs;
}
@@ -141,40 +166,10 @@
* then again deleted).
*/
protected void update(ChangeLog changeLog) throws ItemStateException {
- if (tx != null) {
- this.changeLog.merge(changeLog);
+ if (txLog != null) {
+ txLog.merge(changeLog);
} else {
super.update(changeLog);
- }
- }
-
-
- //--------------------------------------------------< TransactionListener >
-
- /**
- * @see TransactionListener#transactionCommitted
- */
- public void transactionCommitted(TransactionContext tx)
- throws TransactionException {
-
- ChangeLog changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
- if (changeLog != null) {
- try {
- super.update(changeLog);
- changeLog.reset();
- } catch (ItemStateException e) {
- throw new TransactionException("Unable to end update.", e);
- }
- }
- }
-
- /**
- * @see TransactionListener#transactionRolledBack
- */
- public void transactionRolledBack(TransactionContext tx) {
- ChangeLog changeLog = (ChangeLog) tx.getAttribute(ATTRIBUTE_CHANGE_LOG);
- if (changeLog != null) {
- changeLog.undo(sharedStateMgr);
}
}
}
Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/TestAll.java?view=diff&r1=155313&r2=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/TestAll.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/TestAll.java Fri Feb 25 02:44:52 2005
@@ -37,6 +37,7 @@
suite.addTestSuite(PathTest.class);
suite.addTestSuite(QNameTest.class);
+ suite.addTestSuite(XATest.class);
return suite;
}
Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java?view=auto&rev=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java Fri Feb 25 02:44:52 2005
@@ -0,0 +1,211 @@
+/*
+ * 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;
+
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+import javax.transaction.xa.XAException;
+import javax.transaction.UserTransaction;
+import javax.transaction.Status;
+import javax.transaction.NotSupportedException;
+import javax.transaction.SystemException;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.RollbackException;
+import javax.jcr.Session;
+
+/**
+ * Internal {@link javax.transaction.UserTransaction} implementation.
+ */
+class UserTransactionImpl implements UserTransaction {
+
+ /**
+ * Global transaction id counter
+ */
+ private static byte counter = 0;
+
+ /**
+ * XAResource
+ */
+ private final XAResource xares;
+
+ /**
+ * Xid
+ */
+ private Xid xid;
+
+ /**
+ * Status
+ */
+ private int status = Status.STATUS_NO_TRANSACTION;
+
+ /**
+ * Create a new instance of this class. Takes a session as parameter.
+ * @param session session. If session is not of type
+ * {@link XASession}, an <code>IllegalArgumentException</code>
+ * is thrown
+ */
+ public UserTransactionImpl(Session session) {
+ if (session instanceof XASession) {
+ xares = ((XASession) session).getXAResource();
+ } else {
+ throw new IllegalArgumentException("Session not of type XASession");
+ }
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#begin
+ */
+ public void begin() throws NotSupportedException, SystemException {
+ if (status != Status.STATUS_NO_TRANSACTION) {
+ throw new IllegalStateException("Transaction already active");
+ }
+
+ try {
+ xid = new XidImpl(counter++);
+ xares.start(xid, XAResource.TMNOFLAGS);
+ status = Status.STATUS_ACTIVE;
+
+ } catch (XAException e) {
+
+ throw new SystemException("Unable to begin transaction: " +
+ "XA_ERR=" + e.errorCode);
+ }
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#commit
+ */
+ public void commit() throws HeuristicMixedException,
+ HeuristicRollbackException, IllegalStateException,
+ RollbackException, SecurityException, SystemException {
+
+ if (status != Status.STATUS_ACTIVE) {
+ throw new IllegalStateException("Transaction not active");
+ }
+
+ try {
+ xares.end(xid, XAResource.TMSUCCESS);
+
+ status = Status.STATUS_PREPARING;
+ xares.prepare(xid);
+ status = Status.STATUS_PREPARED;
+
+ status = Status.STATUS_COMMITTING;
+ xares.commit(xid, false);
+ status = Status.STATUS_COMMITTED;
+
+ } catch (XAException e) {
+
+ if (e.errorCode >= XAException.XA_RBBASE &&
+ e.errorCode <= XAException.XA_RBEND) {
+ throw new RollbackException();
+ } else {
+ throw new SystemException("Unable to commit transaction: " +
+ "XA_ERR=" + e.errorCode);
+ }
+ }
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#getStatus
+ */
+ public int getStatus() throws SystemException {
+ return status;
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#rollback
+ */
+ public void rollback() throws IllegalStateException, SecurityException,
+ SystemException {
+
+ if (status != Status.STATUS_ACTIVE &&
+ status != Status.STATUS_MARKED_ROLLBACK) {
+
+ throw new IllegalStateException("Transaction not active");
+ }
+
+ try {
+ xares.end(xid, XAResource.TMFAIL);
+
+ status = Status.STATUS_ROLLING_BACK;
+ xares.rollback(xid);
+ status = Status.STATUS_ROLLEDBACK;
+
+ } catch (XAException e) {
+
+ throw new SystemException("Unable to rollback transaction: " +
+ "XA_ERR=" + e.errorCode);
+ }
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#setRollbackOnly()
+ */
+ public void setRollbackOnly() throws IllegalStateException, SystemException {
+ if (status != Status.STATUS_ACTIVE) {
+ throw new IllegalStateException("Transaction not active");
+ }
+ status = Status.STATUS_MARKED_ROLLBACK;
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#setTransactionTimeout
+ */
+ public void setTransactionTimeout(int seconds) throws SystemException {}
+
+
+ /**
+ * Internal {@link Xid} implementation.
+ */
+ class XidImpl implements Xid {
+
+ /** Global transaction id */
+ private final byte[] globalTxId;
+
+ /**
+ * Create a new instance of this class. Takes a global
+ * transaction number as parameter
+ * @param globalTxNumber global transaction number
+ */
+ public XidImpl(byte globalTxNumber) {
+ this.globalTxId = new byte[] { globalTxNumber };
+ }
+
+ /**
+ * @see javax.transaction.xa.Xid#getFormatId()
+ */
+ public int getFormatId() {
+ return 0;
+ }
+
+ /**
+ * @see javax.transaction.xa.Xid#getBranchQualifier()
+ */
+ public byte[] getBranchQualifier() {
+ return new byte[0];
+ }
+
+ /**
+ * @see javax.transaction.xa.Xid#getGlobalTransactionId()
+ */
+ public byte[] getGlobalTransactionId() {
+ return globalTxId;
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/UserTransactionImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java?view=auto&rev=155314
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java Fri Feb 25 02:44:52 2005
@@ -0,0 +1,328 @@
+/*
+ * 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;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+import javax.jcr.Repository;
+import javax.jcr.Node;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Session;
+import javax.transaction.UserTransaction;
+import javax.transaction.RollbackException;
+
+/**
+ * <code>XATest</code> contains the test cases for the methods
+ * inside {@link org.apache.jackrabbit.core.XASession}.
+ */
+public class XATest extends AbstractJCRTest {
+
+ /**
+ * @see junit.framework#runTest
+ *
+ * Make sure that tested repository supports transactions
+ */
+ protected void runTest() throws Throwable {
+ Repository rep = helper.getRepository();
+ if (rep.getDescriptor(Repository.OPTION_TRANSACTIONS_SUPPORTED) != null) {
+ super.runTest();
+ }
+ }
+
+ /**
+ * Add a node inside a transaction and commit changes. Make sure
+ * node exists for other sessions only after commit.
+ * @throws Exception
+ */
+ public void testAddNodeCommit() 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(mixReferenceable);
+ testRootNode.save();
+
+ // assertion: node exists in this session
+ try {
+ superuser.getNodeByUUID(n.getUUID());
+ } catch (ItemNotFoundException e) {
+ fail("New node not visible after save()");
+ }
+
+ // assertion: node does not exist in other session
+ Session otherSuperuser = helper.getSuperuserSession();
+
+ try {
+ otherSuperuser.getNodeByUUID(n.getUUID());
+ fail("Uncommitted node visible for other session");
+ } catch (ItemNotFoundException e) {
+ /* expected */
+ }
+
+ // commit
+ utx.commit();
+
+ // assertion: node exists in this session
+ try {
+ otherSuperuser.getNodeByUUID(n.getUUID());
+ } catch (ItemNotFoundException e) {
+ fail("Committed node not visible in this session");
+ }
+
+ // assertion: node also exists in other session
+ try {
+ otherSuperuser.getNodeByUUID(n.getUUID());
+ } catch (ItemNotFoundException e) {
+ fail("Committed node not visible in other session");
+ }
+
+ // logout
+ otherSuperuser.logout();
+ }
+
+ /**
+ * Set a property inside a transaction and commit changes. Make sure
+ * property exists for other sessions only after commit.
+ * @throws Exception
+ */
+ public void testSetPropertyCommit() throws Exception {
+ // prerequisite: non-existing property
+ if (testRootNode.hasProperty(propertyName1)) {
+ testRootNode.getProperty(propertyName1).remove();
+ testRootNode.save();
+ }
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // start transaction
+ utx.begin();
+
+ // set property and save
+ testRootNode.setProperty(propertyName1, "0");
+ testRootNode.save();
+
+ // assertion: property exists in this session
+ assertTrue(testRootNode.hasProperty(propertyName1));
+
+ // assertion: property does not exist in other session
+ Session otherSuperuser = helper.getSuperuserSession();
+ Node otherRootNode = otherSuperuser.getRootNode().getNode(testPath);
+ assertFalse(otherRootNode.hasProperty(propertyName1));
+
+ // commit
+ utx.commit();
+
+ // assertion: property exists in this session
+ assertTrue(testRootNode.hasProperty(propertyName1));
+
+ // assertion: property also exists in other session
+ assertTrue(otherRootNode.hasProperty(propertyName1));
+
+ // logout
+ otherSuperuser.logout();
+ }
+
+ /**
+ * Add a node inside a transaction and rollback changes.
+ * @throws Exception
+ */
+ public void testAddNodeRollback() 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(mixReferenceable);
+ testRootNode.save();
+
+ // assertion: node exists in this session
+ String uuid = n.getUUID();
+
+ try {
+ superuser.getNodeByUUID(uuid);
+ } catch (ItemNotFoundException e) {
+ fail("New node not visible after save()");
+ }
+
+ // rollback
+ utx.rollback();
+
+ // assertion: node does not exist in this session
+ try {
+ superuser.getNodeByUUID(uuid);
+ fail("Node still visible after rollback()");
+ } catch (ItemNotFoundException e) {
+ /* expected */
+ }
+ }
+
+ /**
+ * Set a property inside a transaction and rollback changes.
+ * @throws Exception
+ */
+ public void testSetPropertyRollback() throws Exception {
+ // prerequisite: non-existing property
+ if (testRootNode.hasProperty(propertyName1)) {
+ testRootNode.getProperty(propertyName1).remove();
+ testRootNode.save();
+ }
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // start transaction
+ utx.begin();
+
+ // set property and save
+ testRootNode.setProperty(propertyName1, "0");
+ testRootNode.save();
+
+ // assertion: property exists in this session
+ assertTrue(testRootNode.hasProperty(propertyName1));
+
+ // rollback
+ utx.rollback();
+
+ // assertion: property does not exist in this session
+ assertFalse(testRootNode.hasProperty(propertyName1));
+ }
+
+ /**
+ * Remove a node inside a transaction and rollback changes. Check
+ * that the node reference may again be used after having rolled
+ * back changes.
+ * @throws Exception
+ */
+ public void testRemoveNodeRollback() throws Exception {
+ // prerequisite: existing node
+ Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+ n1.addMixin(mixReferenceable);
+ testRootNode.save();
+
+ String uuid = n1.getUUID();
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // start transaction
+ utx.begin();
+
+ // remove node and save
+ Node n2 = superuser.getNodeByUUID(uuid);
+ n2.remove();
+ testRootNode.save();
+
+ // assertion: node no longer exists
+ try {
+ superuser.getNodeByUUID(uuid);
+ fail("Removed node still exists after save()");
+ } catch (ItemNotFoundException e) {
+ /* expected */
+ }
+
+ // rollback
+ utx.rollback();
+
+ // assertion: node exists again
+ try {
+ superuser.getNodeByUUID(uuid);
+ } catch (ItemNotFoundException e) {
+ fail("Removed node not visible after rollback()");
+ }
+ }
+
+ /**
+ * Remove a property inside a transaction and rollback changes.
+ * Check that the property reference may again be used after
+ * having rolled back changes.
+ * @throws Exception
+ */
+ public void testRemovePropertyRollback() throws Exception {
+ // prerequisite: existing property
+ if (!testRootNode.hasProperty(propertyName1)) {
+ testRootNode.setProperty(propertyName1, "0");
+ testRootNode.save();
+ }
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // start transaction
+ utx.begin();
+
+ // remove property and save
+ testRootNode.getProperty(propertyName1).remove();
+ testRootNode.save();
+
+ // assertion: property no longer exists
+ assertFalse(testRootNode.hasProperty(propertyName1));
+
+ // rollback
+ utx.rollback();
+
+ // assertion: property exists and reference valid
+ assertTrue(testRootNode.hasProperty(propertyName1));
+ }
+
+ /**
+ * Add reference to some node in one session while removing
+ * the node in another.
+ * @throws Exception
+ */
+ public void testAddReference() throws Exception {
+ // add two nodes, second one referenceable
+ Node n1 = testRootNode.addNode(nodeName1);
+ Node n2 = testRootNode.addNode(nodeName2);
+ n2.addMixin(mixReferenceable);
+ testRootNode.save();
+
+ // get user transaction object
+ UserTransaction utx = new UserTransactionImpl(superuser);
+
+ // start transaction
+ utx.begin();
+
+ // add reference and save
+ n1.setProperty(propertyName1, n2);
+ testRootNode.save();
+
+ // remove referenced node in other session
+ Session otherSuperuser = helper.getSuperuserSession();
+ Node otherRootNode = otherSuperuser.getRootNode().getNode(testPath);
+ otherSuperuser.getNodeByUUID(n2.getUUID()).remove();
+ otherRootNode.save();
+
+ // assertion: commit must fail since integrity violated
+ try {
+ utx.commit();
+ fail("Commit succeeds with violated integrity");
+ } catch (RollbackException e) {
+ /* expected */
+ }
+
+ // logout
+ otherSuperuser.logout();
+ }
+}
Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/XATest.java
------------------------------------------------------------------------------
svn:eol-style = native