KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas > stests > manac > ManagerSF


1 /*
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: ManagerSF.java,v 1.12 2004/03/19 11:57:18 benoitf Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas.stests.manac;
27
28 import java.rmi.RemoteException;
29 import java.sql.Connection;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.util.Enumeration;
33 import javax.ejb.CreateException;
34 import javax.ejb.EJBException;
35 import javax.ejb.FinderException;
36 import javax.ejb.RemoveException;
37 import javax.ejb.SessionBean;
38 import javax.ejb.SessionContext;
39 import javax.ejb.SessionSynchronization;
40 import javax.ejb.TransactionRolledbackLocalException;
41 import javax.naming.Context;
42 import javax.naming.InitialContext;
43 import javax.naming.NamingException;
44 import javax.sql.DataSource;
45
46 import org.objectweb.jonas.common.Log;
47 import org.objectweb.util.monolog.api.Logger;
48 import org.objectweb.util.monolog.api.BasicLevel;
49
50 /**
51  * Manager Implementation
52  * @author Philippe Durieux
53  */

54 public class ManagerSF implements SessionBean, SessionSynchronization {
55
56     protected static Logger logger = null;
57     protected static Logger history = null;
58     SessionContext ejbContext;
59     ManacLocalHome manacLocalHome = null;
60     int delay = 0;
61     int c1 = 0;
62     int c2 = 0;
63     int d1 = 0;
64     int d2 = 0;
65     ManacLocal cred1 = null;
66     ManacLocal cred2 = null;
67     ManacLocal deb1 = null;
68     ManacLocal deb2 = null;
69     int initialValue = 1000;
70     int value = 10;
71
72     private void log(String message) {
73         history.log(BasicLevel.INFO, "a_" + d1 + "\ta_" + d2 + "\ta_" + c1 + "\ta_" + c2 + "\tv_" + value + "\t" + message);
74     }
75
76     // ------------------------------------------------------------------
77
// init DataBase for Manac beans
78
// ------------------------------------------------------------------
79
private void initDB() {
80         logger.log(BasicLevel.DEBUG, "");
81
82         // Get my DataSource from JNDI
83
DataSource ds = null;
84         InitialContext ictx = null;
85         String myTable = null;
86         try {
87             ictx = new InitialContext();
88         } catch (Exception e) {
89             logger.log(BasicLevel.ERROR, "new InitialContext() : " + e);
90             throw new EJBException("Cannot get JNDI InitialContext");
91         }
92         try {
93             ds = (DataSource) ictx.lookup("java:comp/env/jdbc/mydb");
94         } catch (Exception e) {
95             logger.log(BasicLevel.ERROR, "cannot lookup datasource " + e);
96             throw new EJBException("cannot lookup datasource");
97         }
98         try {
99             // Create table if specified in dd (in fact, only if CMP1.x)
100
myTable = (String) ictx.lookup("java:comp/env/tablename");
101             createTable(ds, myTable);
102         } catch (Exception e) {
103             logger.log(BasicLevel.WARN, "No init necessary in CMP2");
104         }
105     }
106
107     private void createTable(DataSource ds, String myTable) {
108         // Drop table
109
Connection conn = null;
110         Statement stmt = null;
111         try {
112             conn = ds.getConnection();
113             stmt = conn.createStatement();
114             stmt.execute("drop table " + myTable);
115             stmt.close();
116         } catch (SQLException e) {
117             // The first time, table will not exist.
118
logger.log(BasicLevel.INFO, "Exception in dropTable : " + e);
119         }
120
121         // Create table.
122
try {
123             stmt = conn.createStatement();
124             stmt.execute("create table " + myTable + "(name varchar(30) not null primary key, num integer, balance integer)");
125             stmt.close();
126             conn.close();
127         } catch (SQLException e) {
128             logger.log(BasicLevel.ERROR, "Exception in createTable : " + e);
129             throw new EJBException("Exception in createTable");
130         }
131     }
132
133     // ------------------------------------------------------------------
134
// SessionBean implementation
135
// ------------------------------------------------------------------
136

137     /**
138      * Set the associated session context. The container calls this method
139      * after the instance creation.
140      * The enterprise Bean instance should store the reference to the context
141      * object in an instance variable.
142      * This method is called with no transaction context.
143      *
144      * @param ctx A SessionContext interface for the instance.
145      * @throws EJBException Thrown by the method to indicate a failure caused by
146      * a system-level error.
147      */

148     public void setSessionContext(SessionContext ctx) {
149         if (logger == null) {
150             logger = Log.getLogger(Log.JONAS_TESTS_PREFIX);
151         }
152         if (history == null) {
153             history = Log.getLogger("org.objectweb.jonas_tests.history");
154         }
155         logger.log(BasicLevel.DEBUG, "");
156         ejbContext = ctx;
157     }
158
159     /**
160      * A container invokes this method before it ends the life of the session object.
161      * This happens as a result of a client's invoking a remove operation, or when a
162      * container decides to terminate the session object after a timeout.
163      * This method is called with no transaction context.
164      *
165      * @throws EJBException Thrown by the method to indicate a failure caused by
166      * a system-level error.
167      */

168     public void ejbRemove() {
169         logger.log(BasicLevel.DEBUG, "");
170     }
171
172     /**
173      * Create a session.
174      * @param ival initial balance value for new accounts.
175      * @throws CreateException Failure to create a session EJB object.
176      */

177     public void ejbCreate(int ival) throws CreateException {
178         logger.log(BasicLevel.DEBUG, "");
179
180         // lookup ManacLocalHome
181
try {
182             Context ictx = new InitialContext();
183             manacLocalHome = (ManacLocalHome) ictx.lookup("java:comp/env/ejb/manac");
184         } catch (NamingException e) {
185             logger.log(BasicLevel.ERROR, "Cannot get ManacLocalHome:" + e);
186             throw new CreateException("Cannot get ManacLocalHome");
187         }
188
189         initialValue = ival;
190     }
191
192     /**
193      * A container invokes this method on an instance before the instance
194      * becomes disassociated with a specific EJB object.
195      */

196     public void ejbPassivate() {
197         logger.log(BasicLevel.DEBUG, "");
198     }
199
200     /**
201      * A container invokes this method when the instance is taken out of
202      * the pool of available instances to become associated with a specific
203      * EJB object.
204      */

205     public void ejbActivate() {
206         logger.log(BasicLevel.DEBUG, "");
207     }
208     
209     // ------------------------------------------------------------------
210
// SessionSynchronization implementation
211
// ------------------------------------------------------------------
212

213     public void afterBegin() {
214         log("TX after_begin");
215     }
216
217     public void beforeCompletion() {
218         log("TX before_completion");
219     }
220
221     public void afterCompletion(boolean committed) {
222         if (committed) {
223             log("TX committed");
224         } else {
225             log("TX rolled back");
226         }
227     }
228
229     // ------------------------------------------------------------------
230
// Manager implementation
231
// ------------------------------------------------------------------
232

233     /**
234      * Create a new Account. The account may exist (for example, when running
235      * tests twice without restarting the Container, or if created by another
236      * session meanwhile)
237      * @param i account number (its PK)
238      */

239     private ManacLocal newAccount(int i) throws RemoteException {
240         ManacLocal ml = null;
241         try {
242             ml = manacLocalHome.create(i, initialValue);
243             logger.log(BasicLevel.INFO, "New Account created : " + i);
244             history.log(BasicLevel.INFO, "New Account\t" + i);
245         } catch (CreateException e) {
246             // Sometimes another one has just created it
247
try {
248                 ml = manacLocalHome.findByNum(i);
249                 logger.log(BasicLevel.INFO, "Account was created already : " + i);
250             } catch (FinderException e2) {
251                 logger.log(BasicLevel.ERROR, "newAccount:" + e);
252                 history.log(BasicLevel.INFO, "CANNOT CREATE ACCOUNT\t" + i);
253                 throw new RemoteException("Cannot create Manac", e);
254             }
255         }
256         return ml;
257     }
258
259     /**
260      * Initializes the database by creating a set of accounts.
261      * @param nb number of account created.
262      */

263     public void createAll(int nb) throws RemoteException {
264         logger.log(BasicLevel.DEBUG, "");
265
266         // init database for Manac bean
267
initDB();
268
269         // Check if accounts are already created.
270
try {
271             manacLocalHome.findByNum(nb - 1);
272         } catch (Exception e) {
273             // create accounts
274
for (int i = 0; i < nb; i++) {
275                 newAccount(i);
276             }
277         }
278     }
279
280     /**
281      * Reinit the balances for each created account to its initial value.
282      */

283     public void reinitAll() throws RemoteException {
284         logger.log(BasicLevel.DEBUG, "");
285         try {
286             Enumeration enum = manacLocalHome.findAll();
287             while (enum.hasMoreElements()) {
288                 ManacLocal a = (ManacLocal) enum.nextElement();
289                 a.setBalance(initialValue);
290             }
291         } catch (Exception e) {
292             logger.log(BasicLevel.ERROR, "reinitAll:" + e);
293         }
294     }
295
296     /**
297      * Set a delay value, in seconds, for the transaction.
298      */

299     public void setDelay(int d) throws RemoteException {
300         logger.log(BasicLevel.DEBUG, "delay (sec) = " + d);
301         delay = d;
302     }
303
304     /**
305      * Each operation debits 2 accounts and credits 2 accounts.
306      * Lookup all accounts and create them if they not exist yet
307      * @param d1 first account to credit
308      * @param d2 second account to credit
309      * @param c1 first account to debit
310      * @param c2 second account to debit
311      * @throws RemoteException
312      */

313     public void setAccounts(int d1, int d2, int c1, int c2) throws RemoteException {
314         logger.log(BasicLevel.DEBUG, "d1=" + d1 + " d2=" + d2 + " c1=" + c1 + " c2=" + c2);
315         log("SA beg");
316
317         // debit account d1
318
this.d1 = d1;
319         try {
320             deb1 = manacLocalHome.findByNum(d1);
321         } catch (FinderException e) {
322             deb1 = newAccount(d1);
323         }
324
325         // debit account d2
326
this.d2 = d2;
327         try {
328             deb2 = manacLocalHome.findByNum(d2);
329         } catch (FinderException e) {
330             deb2 = newAccount(d2);
331         }
332
333         // credit account c1
334
this.c1 = c1;
335         try {
336             cred1 = manacLocalHome.findByNum(c1);
337         } catch (FinderException e) {
338             cred1 = newAccount(c1);
339         }
340
341         // credit account c2
342
this.c2 = c2;
343         try {
344             cred2 = manacLocalHome.findByNum(c2);
345         } catch (FinderException e) {
346             cred2 = newAccount(c2);
347         }
348         log("SA end");
349     }
350
351     /**
352      * Find an account and create it if not found.
353      * @param c1 account number
354      */

355     public void getAccount(int c1) throws RemoteException {
356         logger.log(BasicLevel.DEBUG, " c1=" + c1);
357         this.c1 = c1;
358         try {
359             cred1 = manacLocalHome.findByNum(c1);
360         } catch (FinderException e) {
361             cred1 = newAccount(c1);
362         }
363     }
364
365     /**
366      * Find an account and create it if not found.
367      * Then, remove it.
368      * @param d1 account number
369      */

370     public void delAccount(int d1) throws RemoteException, RemoveException {
371         logger.log(BasicLevel.DEBUG, " d1=" + d1);
372         this.d1 = d1;
373         try {
374             deb1 = manacLocalHome.findByNum(d1);
375         } catch (FinderException e) {
376             deb1 = newAccount(d1);
377         }
378         deb1.remove();
379         history.log(BasicLevel.INFO, d1 + "\tREMOVED");
380     }
381
382     /**
383      * Set the value to withdraw.
384      * @param v value to withdraw.
385      */

386     public void setValue(int v) throws RemoteException {
387         logger.log(BasicLevel.DEBUG, "");
388         this.value = v;
389     }
390
391     /**
392      * Do the movement.
393      */

394     public void movement() throws RemoteException {
395         logger.log(BasicLevel.DEBUG, "move " + value + " from " + d1 + "," + d2 + " to " + c1 + "," + c2);
396         log("MV start");
397
398         // credit accounts first because we don't want a rollback if
399
// same account is debited and credited in the same operation.
400
try {
401             cred1.credit(value);
402             cred2.credit(value);
403         } catch (TransactionRolledbackLocalException e) {
404             logger.log(BasicLevel.WARN, "Credit -> Rollback transaction");
405             log("MV rbc1");
406             return;
407         } catch (EJBException e) {
408             logger.log(BasicLevel.ERROR, "Cannot credit account:" + e);
409             log("MV rbc2");
410             return;
411         }
412
413         // wait a little if delay
414
if (delay > 0) {
415             sleep(delay);
416         }
417     
418         // debit accounts
419
try {
420             deb1.debit(value);
421             deb2.debit(value);
422         } catch (TransactionRolledbackLocalException e) {
423             logger.log(BasicLevel.WARN, "Debit -> Rollback transaction");
424             log("MV rbd1");
425             return;
426         } catch (EJBException e) {
427             logger.log(BasicLevel.ERROR, "debit:" + e);
428             log("MV rbd2");
429             return;
430         }
431
432         log("MV commit");
433     }
434
435     /**
436      * Simple withdraw operation, on existing accounts only.
437      */

438     public void withdraw(int wd, int wc, int wv) throws RemoteException {
439         logger.log(BasicLevel.DEBUG, "move " + wv + " from " + wd + " to " + wc);
440         d1 = wd;
441         c1 = wc;
442         log("W move start: ");
443
444         // credit accounts first because we don't want a rollback if
445
// same account is debited and credited in the same operation.
446
// credit account wc
447
try {
448             manacLocalHome.findByNum(wc).credit(wv);
449         } catch (FinderException e) {
450             logger.log(BasicLevel.WARN, "Credit -> Unknown account");
451             log("W cred0");
452             return;
453         } catch (TransactionRolledbackLocalException e) {
454             logger.log(BasicLevel.WARN, "Credit -> Rollback transaction");
455             log("W cred1");
456             return;
457         } catch (EJBException e) {
458             logger.log(BasicLevel.ERROR, "Cannot credit account:" + e);
459             log("W cred2");
460             return;
461         }
462         // debit account
463
try {
464             manacLocalHome.findByNum(wd).debit(wv);
465         } catch (FinderException e) {
466             logger.log(BasicLevel.WARN, "Debit -> Unknown account");
467             log("W ded0");
468             return;
469         } catch (TransactionRolledbackLocalException e) {
470             logger.log(BasicLevel.WARN, "Debit -> Rollback transaction");
471             log("W deb1");
472             return;
473         } catch (EJBException e) {
474             logger.log(BasicLevel.ERROR, "Cannot debit account:" + e);
475             log("W deb2");
476             return;
477         }
478         log("W move end: ");
479     }
480
481     public void sleep(int seconds) {
482         try {
483             Thread.sleep(1000 * seconds);
484         } catch (InterruptedException e) {
485         }
486     }
487
488     /**
489      * This is a read operation, executed outside transaction.
490      */

491     public int readBalances() throws RemoteException {
492         logger.log(BasicLevel.DEBUG, "");
493         int ret = 1000000;
494         int bal;
495         try {
496             bal = deb1.getBalance();
497             if (bal < ret) {
498                 ret = bal;
499             }
500             bal = deb2.getBalance();
501             if (bal < ret) {
502                 ret = bal;
503             }
504             bal = cred1.getBalance();
505             if (bal < ret) {
506                 ret = bal;
507             }
508             bal = cred2.getBalance();
509             if (bal < ret) {
510                 ret = bal;
511             }
512         } catch (Exception e) {
513             logger.log(BasicLevel.ERROR, "cannot read account" + e);
514             throw new RemoteException("cannot read account" + e);
515         }
516         return ret;
517     }
518
519     public boolean checkAccount(int a) throws RemoteException {
520         logger.log(BasicLevel.DEBUG, "");
521
522         boolean ret = false;
523         ManacLocal m = null;
524
525         // retry several times, because this operation may be rolledback
526
// in case of deadlock.
527
Exception exc = null;
528         int retry;
529         for (retry = 0; retry < 20; retry++) {
530             try {
531                 history.log(BasicLevel.INFO, "\ta_" + a + "\tCHECKED try #" + retry);
532                 m = manacLocalHome.findByNum(a);
533                 int b = m.getBalance();
534                 if (b >= 0) {
535                     ret = true;
536                 } else {
537                     logger.log(BasicLevel.WARN, "bad balance=" + b);
538                 }
539                 return ret;
540             } catch (Exception e) {
541                 exc = e;
542                 logger.log(BasicLevel.INFO, "retrying " + retry);
543                 sleep(retry + 1);
544             }
545         }
546         logger.log(BasicLevel.WARN, "cannot check account: " + exc);
547         return ret;
548     }
549
550     public boolean checkAll() throws RemoteException {
551         logger.log(BasicLevel.DEBUG, "");
552
553         int count = 0;
554         int total = 0;
555         try {
556             Enumeration enum = manacLocalHome.findAll();
557             while (enum.hasMoreElements()) {
558                 count++;
559                 ManacLocal a = (ManacLocal) enum.nextElement();
560                 int balance = a.getBalance();
561                 if (balance < 0) {
562                     logger.log(BasicLevel.ERROR, "checkAllAccounts: bad balance: " + balance);
563                     return false;
564                 }
565                 String name = a.getName();
566                 logger.log(BasicLevel.DEBUG, name + " : FINAL BALANCE=" + balance);
567                 history.log(BasicLevel.INFO, name + "\t" + balance);
568                 total += balance;
569             }
570         } catch (Exception e) {
571             logger.log(BasicLevel.ERROR, "checkAllAccounts:" + e);
572             return false;
573         }
574         int exp = initialValue * count;
575         if (total != exp) {
576             logger.log(BasicLevel.ERROR, "checkAllAccounts: bad total: " + total + " (expected: " + exp + ")");
577             history.log(BasicLevel.INFO, "CheckAll ERROR: " + total + "\t" + exp);
578             return false;
579         }
580         logger.log(BasicLevel.DEBUG, "total=" + total);
581         history.log(BasicLevel.INFO, "CheckAll OK");
582         return true;
583     }
584
585 }
586
Popular Tags