001    /*
002      Copyright (C) 2001 Renaud Pawlak
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
017    
018    package org.objectweb.jac.aspects.transaction;
019    
020    
021    
022    import java.util.Hashtable;
023    import java.util.Vector;
024    import org.aopalliance.intercept.ConstructorInvocation;
025    import org.aopalliance.intercept.MethodInvocation;
026    import org.apache.log4j.Logger;
027    import org.objectweb.jac.core.AspectComponent;
028    import org.objectweb.jac.core.Interaction;
029    import org.objectweb.jac.core.Wrappee;
030    import org.objectweb.jac.core.Wrapper;
031    import org.objectweb.jac.core.Wrapping;
032    import org.objectweb.jac.util.Log;
033    
034    /**
035     * This wrapper wraps all JAC objects that can be part of a
036     * transaction in order to dispatch the transactions to local clones
037     * and to commit them. */
038    
039    public class DispatchTransactionWrapper extends Wrapper {
040        static Logger logger = Logger.getLogger("transaction");
041    
042        Hashtable clones = new Hashtable();
043        Hashtable originals = new Hashtable();
044    
045        public DispatchTransactionWrapper(AspectComponent ac) {
046            super(ac);
047        }
048    
049        /**
050         * Dispatches a call on a wrappee transaction-clone depending on
051         * the current transaction if any (if not, it performs a regular
052         * call). */
053    
054        public Object dispatch(Interaction interaction) {
055            Integer id = (Integer)attr("Transaction.id");
056            Integer commit = (Integer)attr("Transaction.commit");
057            Integer rollback = (Integer)attr("Transaction.rollback");
058            // none transaction is active => local call
059            if( id == null ) {
060                return proceed(interaction);
061            } else if( commit != null ) {
062                if( commit.equals( id ) ) {
063                    // this transaction is committing...
064                    return proceed(interaction);
065                }
066            } else if( rollback != null ) {
067                if( rollback.equals( id ) ) {
068                    // this transaction is rollbacking...
069                    return proceed(interaction);
070                }
071            } else {
072                if( ! clones.containsKey(id) ) {
073                    logger.debug("creating a new clone for transaction "+id);
074                    // creates a new original object
075                    originals.put(id,Wrapping.clone(interaction.wrappee));
076                    // creates a new clone
077                    clones.put(id,Wrapping.clone(interaction.wrappee));
078                    // memorize that the object is part of the transaction
079                    logger.debug(interaction.wrappee+" is part of a transaction");
080                    Vector affectedObjects = (Vector)attr("Transaction"+id+".affectedObjects");
081                    affectedObjects.add(interaction.wrappee);
082                }
083                logger.debug("delegating to the clone "+id);
084                // delegate to the transaction's clone
085                return interaction.invoke(clones.get(id));
086            }
087            return proceed(interaction);
088        }
089    
090        /**
091         * Commits the transaction on the wrappee (role method).
092         *
093         * <p>This method copies the transaction-clone state to the
094         * original object.
095         * 
096         * @param transactionId the transaction to be commited */
097    
098        public void commit(Wrappee wrappee, Integer transactionId) throws Exception {
099            logger.debug("committing transaction "+transactionId+
100                         " on object "+wrappee);
101            if( clones.containsKey(transactionId) ) {
102                // remove the transaction state
103                Wrappee clone = (Wrappee)clones.get(transactionId);
104                Wrappee original = (Wrappee)originals.get(transactionId);
105                clones.remove(transactionId);
106                originals.remove(transactionId);
107                Merging.merge(wrappee,original,clone);
108            }
109        }
110    
111        /**
112         * Rollbacks the transaction on the wrappee (role method).
113         *
114         * @param transactionId the transaction to be rollbacked */
115    
116        public void rollback(Wrappee wrappee, Integer transactionId) {
117            logger.debug("rollbacking transaction "+transactionId+
118                         " on object "+wrappee);
119            if( clones.containsKey(transactionId) ) {
120                // remove the transaction state
121                clones.remove(transactionId);
122                originals.remove(transactionId);
123            }            
124        }
125    
126        /* (non-Javadoc)
127         * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
128         */
129        public Object invoke(MethodInvocation invocation) throws Throwable {
130            // TODO Auto-generated method stub
131            throw new Exception("Unimplemented method: invoke(MethodInvocation invocation)");
132        }
133    
134        /* (non-Javadoc)
135         * @see org.aopalliance.intercept.ConstructorInterceptor#construct(org.aopalliance.intercept.ConstructorInvocation)
136         */
137        public Object construct(ConstructorInvocation invocation) throws Throwable {
138            // TODO Auto-generated method stub
139            throw new Exception("Unimplemented method: construct(MethodInvocation invocation)");
140        }
141    
142    } 
143    
144