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