View Javadoc

1   /*
2    * Copyright (c) 1998-2006 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.test.jini.txn;
20  
21  import java.io.BufferedReader;
22  import java.io.FileNotFoundException;
23  import java.io.FileReader;
24  import java.io.IOException;
25  import java.rmi.RMISecurityManager;
26  import java.util.HashMap;
27  import java.util.Map;
28  import java.util.Random;
29  
30  import jgroup.core.ConfigManager;
31  import jgroup.jini.LookupManager;
32  import net.jini.core.entry.Entry;
33  import net.jini.core.lease.Lease;
34  import net.jini.core.lookup.ServiceTemplate;
35  import net.jini.core.transaction.server.TransactionManager;
36  import net.jini.core.transaction.server.TransactionParticipant;
37  import net.jini.lookup.entry.Name;
38  
39  import org.apache.log4j.Logger;
40  
41  import com.sun.jini.lookup.entry.BasicServiceType;
42  
43  /**
44   * Client for running Jini transactions, using either replicated or non-replicated
45   * transaction components.<p>
46   * 
47   * This client can perform transactions using three different models:
48   * <ol>
49   * <li> Using replicated bank services and a replicated transaction manager.</li>
50   * <li> Using non-replicated bank services and a non-replicated transaction manager. In 
51   *   this model, classic (transient) Jini transactions are performed without replication 
52   *   support at all.</li> 
53   * <li> Using non-replicated bank services and a transaction manager with replication 
54   *   support. In this mode, the state of the transaction manager is transfered to the
55   *   transaction manager replicas, when performing transactions.</li>
56   * </ol>
57   * The different models are set by passing two system properties to TxnClient:
58   * <ul>
59   * <li> tm.replication </li>
60   * <li> banks.replication </li>
61   * </ul>
62   * 
63   * @author Rohnny Moland
64   */
65  public class TxnClient
66  {
67    
68    ////////////////////////////////////////////////////////////////////////////////////////////
69    // Logger
70    ////////////////////////////////////////////////////////////////////////////////////////////
71  
72    /** Obtain logger for this class */
73    private static final Logger log = Logger.getLogger(TxnClient.class);
74  
75  
76    ////////////////////////////////////////////////////////////////////////////////////////////
77    // Fields
78    ////////////////////////////////////////////////////////////////////////////////////////////
79  
80    /** Map holding transaction scenarios */
81    private Map<Integer,TxnData> txnScenarios = new HashMap<Integer,TxnData>();
82  
83    /** Bank service proxies */
84    private Bank bank1;
85    private Bank bank2;
86    
87    /** The local TransactionManager service proxy */
88    private TransactionManager mgr;
89    
90    /** Boolean determining if the current transaction has committed. */
91    private volatile boolean committed;
92    
93    /** Boolean telling if client should lookup bank services with replication support */
94    private boolean banksReplication;
95    
96    /** Boolean telling if client should lookup bank services with passive replication support */
97    private boolean pBanksReplication;
98    
99    /** Boolean telling if client should lookup transaction manager with replication support */
100   private boolean mgrReplication;
101 
102   /** Boolean telling if client should lookup transaction manager with passive replication support */
103   private boolean pMgrReplication;
104   
105   /** Holds the transaction number performed */
106   private int txnNumber = 1;
107   
108   /** measurement instance fields */
109   private long start;
110   private long end;
111   private long totalstart;
112   private long totalend;
113 
114   /** Default path to the txn simulation file */
115   private static final String defaultSimulationPath = "target/resources/simulation/txn-simulation";
116 
117   
118   ////////////////////////////////////////////////////////////////////////////////////////////
119   // Constructor and main
120   ////////////////////////////////////////////////////////////////////////////////////////////
121 
122   /**
123    * Instatiates a TxnClient object
124    */
125   public static void main(String args[])
126     throws Exception
127   {
128     new TxnClient();
129   } 
130   
131   /**
132    * Constructor invoked by main
133    */    
134   public TxnClient()
135     throws Exception 
136   {
137     System.setSecurityManager(new RMISecurityManager());
138     ConfigManager.init();
139     
140     /** get the system properties */
141     banksReplication = Boolean.parseBoolean(System.getProperty("banks.replication", "true"));
142     pBanksReplication = Boolean.parseBoolean(System.getProperty("banks.passive", "false"));
143     mgrReplication = Boolean.parseBoolean(System.getProperty("tm.replication", "true"));
144     pMgrReplication = Boolean.parseBoolean(System.getProperty("tm.passive", "false"));
145     int txns = Integer.getInteger("num.of.txns", 9).intValue();    
146     String simFile = System.getProperty("txn.simulation.file", defaultSimulationPath);  
147     
148     log.debug("banks.replication: " + banksReplication);
149     log.debug("banks.passive: " + pBanksReplication);
150     log.debug("tm.replication: " + mgrReplication);
151     log.debug("tm.passive: " + pMgrReplication);
152     log.debug("txns: " + txns);
153     log.debug("simFile: " + simFile);
154 
155     /** Lookup the services */
156     lookup();    
157     
158     /** load transaction scenarios */
159     loadTxnScenarios(simFile);    
160     
161     /** Perform some random transactions */
162     performTxnScenarios(txns);
163     
164     /** exit from client, to be able to run post experiment */
165     System.exit(0);
166   }
167   
168   
169   /**
170    * Lookup group TM and transaction participants.
171    */
172   private void lookup() 
173   {
174     try {
175       log.debug("try to find bank services...");
176       if (banksReplication) {
177         if (pBanksReplication) {
178           bank1 = (Bank) LookupManager.lookup("Bank/TheLoanBox");
179           log.debug("Try to lookup Bank/LargeFees");
180           bank2 = (Bank) LookupManager.lookup("Bank/LargeFees");           
181         } else {
182           bank1 = (Bank) LookupManager.lookup("NOKAS/RobberyBank");
183           bank2 = (Bank) LookupManager.lookup("Bank/YadaSavings");           
184         }
185      } else {
186         bank1 = (Bank) LookupManager.lookup(new Name("NOKAS/RobberyBank"));
187         bank2 = (Bank) LookupManager.lookup(new Name("Bank/YadaSavings"));
188       }
189       log.debug("bank1 name: " + bank1.getName());
190       log.debug("bank2 name: " + bank2.getName());
191 
192       log.debug("try to find a TM...");
193 
194       if (mgrReplication) {
195         if (pMgrReplication) {
196           mgr = (TransactionManager) LookupManager.lookup("Jgroup/PassiveGroupMahalo");
197         } else {
198           mgr = (TransactionManager) LookupManager.lookup("Jgroup/ActiveGroupMahalo");
199         }
200       } else {
201         Class[] classes = new Class[] { TransactionManager.class };
202         Entry[] attr = new Entry[] {new BasicServiceType("Transaction Manager")};
203         ServiceTemplate template = new ServiceTemplate(null, classes, attr);
204         mgr = (TransactionManager) LookupManager.lookup(template);
205       }
206     } catch (IOException e) {
207       log.error("FAiled to look service", e);
208     }       
209   }
210   
211    
212   /**
213    * Performs a transaction. Could be:
214    * 1. Replicated transaction manager and replicated bank services.
215    * 2. Non-replicated transaction manager and non-replicated bank services.
216    * 3. Replicated transaction manager and non-replicated bank services.
217    */
218   private void performTransaction(int txnnr)
219   {
220     TxnData txnData = txnScenarios.get(new Integer(txnnr));
221 
222     TransactionManager.Created tcs = null;
223     try {
224       tcs = mgr.create(Lease.FOREVER);
225     } catch (Exception e) {
226       log.error("Unable to create transaction", e);
227     }
228     long transactionID = tcs.id;
229     log.debug("-- Created transaction number: " + txnNumber++ + " with txn id=" + transactionID);
230     
231     try {
232       bank1.withdraw(txnData.srcAccount, txnData.credit, transactionID);
233       bank2.deposit(txnData.destAccount, txnData.debit, transactionID);
234       mgr.join(transactionID, (TransactionParticipant) bank1, 0);
235       mgr.join(transactionID, (TransactionParticipant) bank2, 0);      
236     } catch (Exception e) {
237       log.error("Unable to join in participants", e);
238     }
239     
240     try {
241       mgr.commit(transactionID);
242       log.debug("Transaction " + transactionID + " committed");
243     } catch (Exception e) {
244       log.error("Unable to commit transaction", e);
245     }
246   }
247   
248   
249   /**
250    * Loads the txn scenarios.
251    */  
252   private void loadTxnScenarios(String simulationFile)
253   {
254     try {
255       BufferedReader in = new BufferedReader(new FileReader(simulationFile));
256       String txnScenario;
257       log.debug("txnnr. srcAccount destAccount credit debit");
258       log.debug("--------------------------------------------------");      
259       for (int i=0; (txnScenario = in.readLine()) != null; i++) {  
260         String[] txnInfo = txnScenario.split("\\s+");
261         TxnData txnData = new TxnData(Long.parseLong(txnInfo[1]), Long.parseLong(txnInfo[2]), 
262                              Integer.parseInt(txnInfo[3]), Integer.parseInt(txnInfo[4]) );        
263         txnScenarios.put(new Integer(Integer.parseInt(txnInfo[0])), txnData);
264         log.debug(txnInfo[0] + "  " + txnInfo[1] + "  " + txnInfo[2] + "  " + txnInfo[3] + "  " + txnInfo[4]);
265       }
266       in.close();
267     } catch (FileNotFoundException e) {
268       log.error("Could not find the specified file: " + simulationFile, e);
269     } catch (IOException e) {
270       log.error(e.getMessage());
271     }
272   }
273 
274 
275   /**
276    * Perform some random transactions.
277    * 
278    * @param number The number of transactions to perform.
279    * @throws InterruptedException 
280    */
281   private void performTxnScenarios(int number)
282   {
283     Random rnd = new Random(); 
284     for (int i=0; i<number; i++) {
285       
286       /** Ensure that a client can only perform one transaction at once */
287       performTransaction(1+rnd.nextInt(8));
288 
289 //      while (!committed) {
290 //      }
291 //      committed = false;
292     }
293   }
294 
295 
296   ////////////////////////////////////////////////////////////////////////////////////////////
297   // Inner classes
298   ////////////////////////////////////////////////////////////////////////////////////////////  
299   
300   /**
301    * This class holds the txn scenario datas.
302    */
303   private class TxnData 
304   {    
305     private long srcAccount;
306     private long destAccount;
307     private int credit;
308     private int debit;
309      
310     public TxnData(long srcAccount, long destAccount, int credit, int debit)
311     {
312       this.srcAccount = srcAccount;
313       this.destAccount = destAccount;
314       this.credit = credit;
315       this.debit = debit;  
316     }
317   }
318 
319 } // END TxnClient