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