/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.cache;


import org.jboss.cache.lock.IdentityLock;
import org.jgroups.blocks.MethodCall;

import javax.transaction.Transaction;
import java.util.*;


/**
 * This is the value (key being the {@link GlobalTransaction}) in the transaction table
 * of TreeCache.
 * <br>A TransactionEntry maintains
 * <ul>
 * <li>Handle to local Transactions: there can be more than 1 local TX associated with a GlobalTransaction
 * <li>List of modifications (Modification)
 * <li>List of nodes that were created as part of lock acquisition. These nodes can be
 * safely deleted when a transaction is rolled back
 * <li>List of locks ({@link IdentityLock}) that have been acquired by
 * this transaction so far
 * </ul>
 *
 * @author <a href="mailto:bela@jboss.org">Bela Ban</a> Apr 14, 2003
 * @version $Revision: 1.10.2.8 $
 */
public class TransactionEntry {

   /**
    * Local transaction
    */
   protected Transaction ltx=null;

   /**
    * List<MethodCall> of modifications ({@link MethodCall}). They will be replicated on TX commit
    */
   protected List modification_list=new LinkedList();

   /**
    * List<MethodCall>. List of compensating {@link org.jgroups.blocks.MethodCall} objects
    * which revert the ones in <tt>modification_list</tt>. For each entry in the modification list,
    * we have a corresponding entry in this list. A rollback will simply iterate over this list in
    * reverse to undo the modifications. Note that these undo-ops will never be replicated.
    */
   protected List undo_list=new LinkedList();

   /**
    * List<Fqn> of nodes created. Elements are fully qualified names (Fqns)
    */
   protected List nodes=new LinkedList();

   /**
    * List<IdentityLock> of locks acquired by the transaction ({@link IdentityLock})
    */
   protected List locks=new LinkedList();




   public TransactionEntry() {
      ;
   }

   public void addModification(MethodCall m) {
      if(m == null) return;
      modification_list.add(m);
   }

   public List getModifications() {
      return modification_list;
   }

   public void addUndoOperation(MethodCall m) {
      undo_list.add(m);
   }

   public List getUndoOperations() {
      return undo_list;
   }

   public void addNode(Fqn fqn) {
      if(fqn != null)
         nodes.add(fqn);
   }

   public List getNodes() {
      return nodes;
   }

   public void setTransaction(Transaction tx) {
      ltx=tx;
   }

   /**
    * Returns a list of local transactions associated with this TransactionEntry
    * @return
    */
   public Transaction getTransaction() {
      return ltx;
   }

   public void addLock(IdentityLock l) {
      if(l != null) {
         synchronized(locks) {
            if(!locks.contains(l))
               locks.add(l);
         }
      }
   }

   /**
    *
    * @param newLocks Collection<IdentityLock>
    */
   public void addLocks(Collection newLocks) {
      if(newLocks != null) {
         IdentityLock tmp;
         synchronized(locks) {
            for(Iterator it=newLocks.iterator(); it.hasNext();) {
               tmp=(IdentityLock)it.next();
               if(!locks.contains(tmp))
                  locks.add(tmp);
            }
         }
      }
   }


   public List getLocks() {
      return locks;
   }

   public void releaseAllLocks(Object owner) {
      IdentityLock lock;
      synchronized(locks) {
         for(Iterator it=locks.iterator(); it.hasNext();) {
            lock=(IdentityLock)it.next();
            lock.release(owner);
         }
         locks.clear();
      }
   }


   public String toString() {
      StringBuffer sb=new StringBuffer();
      if(modification_list != null)
         sb.append("\nmodification_list: ").append(modification_list);
      if(undo_list != null)
         sb.append("\nundo_list: ").append(undo_list);
      if(locks != null)
         sb.append("\nlocks: ").append(locks);
      if(nodes != null)
         sb.append("\nnodes: ").append(nodes);
      return sb.toString();
   }


}
