001: /*
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ManagerSF.java 9917 2007-01-12 09:56:24Z durieuxp $
023: * --------------------------------------------------------------------------
024: */
025:
026: package org.objectweb.jonas.jtests.beans.bank;
027:
028: import java.rmi.NoSuchObjectException;
029: import java.rmi.RemoteException;
030: import java.util.Collection;
031: import java.util.Iterator;
032:
033: import javax.ejb.CreateException;
034: import javax.ejb.EJBException;
035: import javax.ejb.FinderException;
036: import javax.ejb.NoSuchObjectLocalException;
037: import javax.ejb.RemoveException;
038: import javax.ejb.SessionBean;
039: import javax.ejb.SessionContext;
040: import javax.ejb.SessionSynchronization;
041: import javax.ejb.TransactionRolledbackLocalException;
042: import javax.naming.Context;
043: import javax.naming.InitialContext;
044: import javax.naming.NamingException;
045: import javax.rmi.PortableRemoteObject;
046:
047: import org.objectweb.jonas.common.Log;
048: import org.objectweb.util.monolog.api.BasicLevel;
049: import org.objectweb.util.monolog.api.Logger;
050:
051: /**
052: * Manager Implementation
053: * @author Philippe Durieux
054: */
055: public class ManagerSF implements SessionBean, SessionSynchronization {
056:
057: protected static Logger history = null;
058: SessionContext ejbContext;
059: AccountLocalHome accountLocalHome = null;
060: AccountLocal last = null;
061: int initialValue;
062:
063: // ------------------------------------------------------------------
064: // SessionBean implementation
065: // ------------------------------------------------------------------
066:
067: /**
068: * Set the associated session context. The container calls this method
069: * after the instance creation.
070: * The enterprise Bean instance should store the reference to the context
071: * object in an instance variable.
072: * This method is called with no transaction context.
073: *
074: * @param ctx A SessionContext interface for the instance.
075: * @throws EJBException Thrown by the method to indicate a failure caused by
076: * a system-level error.
077: */
078: public void setSessionContext(SessionContext ctx) {
079: if (history == null) {
080: history = Log
081: .getLogger("org.objectweb.jonas_tests.history");
082: }
083: history.log(BasicLevel.DEBUG, "");
084: ejbContext = ctx;
085: }
086:
087: /**
088: * A container invokes this method before it ends the life of the session object.
089: * This happens as a result of a client's invoking a remove operation, or when a
090: * container decides to terminate the session object after a timeout.
091: * This method is called with no transaction context.
092: *
093: * @throws EJBException Thrown by the method to indicate a failure caused by
094: * a system-level error.
095: */
096: public void ejbRemove() {
097: history.log(BasicLevel.DEBUG, "");
098: }
099:
100: /**
101: * Create a session.
102: * @param ival initial balance value for new accounts.
103: * @throws CreateException Failure to create a session EJB object.
104: */
105: public void ejbCreate(int ival) throws CreateException {
106: history.log(BasicLevel.DEBUG, "");
107:
108: // lookup AccountLocalHome
109: try {
110: Context ictx = new InitialContext();
111: accountLocalHome = (AccountLocalHome) ictx
112: .lookup("java:comp/env/ejb/bank");
113: } catch (NamingException e) {
114: history.log(BasicLevel.ERROR,
115: "Cannot get AccountLocalHome:" + e);
116: throw new CreateException("Cannot get AccountLocalHome");
117: }
118:
119: initialValue = ival;
120: }
121:
122: /**
123: * Create a session.
124: * @param ival initial balance value for new accounts.
125: * @throws CreateException Failure to create a session EJB object.
126: */
127: public void ejbCreate(int ival, boolean prefetch)
128: throws CreateException {
129: history.log(BasicLevel.DEBUG, "");
130:
131: // lookup AccountLocalHome
132: try {
133: Context ictx = new InitialContext();
134: String ejblink = prefetch ? "java:comp/env/ejb/bankpf"
135: : "java:comp/env/ejb/bank";
136: accountLocalHome = (AccountLocalHome) ictx.lookup(ejblink);
137: } catch (NamingException e) {
138: history.log(BasicLevel.ERROR,
139: "Cannot get AccountLocalHome:" + e);
140: throw new CreateException("Cannot get AccountLocalHome");
141: }
142:
143: initialValue = ival;
144: }
145:
146: /**
147: * A container invokes this method on an instance before the instance
148: * becomes disassociated with a specific EJB object.
149: */
150: public void ejbPassivate() {
151: history.log(BasicLevel.DEBUG, "");
152: }
153:
154: /**
155: * A container invokes this method when the instance is taken out of
156: * the pool of available instances to become associated with a specific
157: * EJB object.
158: */
159: public void ejbActivate() {
160: history.log(BasicLevel.DEBUG, "");
161: }
162:
163: // ------------------------------------------------------------------
164: // SessionSynchronization implementation
165: // ------------------------------------------------------------------
166:
167: public void afterBegin() {
168: history.log(BasicLevel.DEBUG, "");
169: }
170:
171: public void beforeCompletion() {
172: history.log(BasicLevel.DEBUG, "");
173: }
174:
175: public void afterCompletion(boolean committed) {
176: if (committed) {
177: history.log(BasicLevel.DEBUG, "TX committed");
178: } else {
179: history.log(BasicLevel.DEBUG, "TX rolled back");
180: }
181: }
182:
183: // ------------------------------------------------------------------
184: // Manager implementation
185: // ------------------------------------------------------------------
186:
187: /**
188: * create a set of Accounts
189: * @param nb nb of Accounts created.
190: */
191: public void createAll(int nb) throws RemoteException,
192: CreateException {
193: // Check if accounts are already created.
194: history.log(BasicLevel.DEBUG, "");
195: try {
196: accountLocalHome.findByNum(nb - 1);
197: } catch (Exception e) {
198: // create accounts
199: for (int i = 0; i < nb; i++) {
200: newAccount(i);
201: }
202: }
203: }
204:
205: /**
206: * reinit all created accounts to their initial value.
207: */
208: public void reinitAll() throws RemoteException {
209: try {
210: Collection coll = accountLocalHome.findAll();
211: for (Iterator it = coll.iterator(); it.hasNext();) {
212: AccountLocal a = (AccountLocal) it.next();
213: a.setBalance(initialValue);
214: }
215: } catch (Exception e) {
216: history.log(BasicLevel.ERROR, "reinitAll:" + e);
217: }
218: }
219:
220: /**
221: * Remove an Account
222: * @param d1 num of the Account.
223: */
224: public void delAccount(int d1) throws RemoteException,
225: RemoveException {
226: try {
227: AccountLocal deb1 = accountLocalHome.findByNum(d1);
228: deb1.remove();
229: history.log(BasicLevel.DEBUG, d1 + "\tREMOVED");
230: } catch (FinderException e) {
231: history.log(BasicLevel.INFO, d1 + "\tNot Found for remove");
232: }
233: }
234:
235: /**
236: * Check all existing Accounts
237: * @return true if all are OK.
238: */
239: public boolean checkAll() throws RemoteException {
240: int count = 0;
241: int total = 0;
242: boolean ret = true;
243: try {
244: Collection coll = accountLocalHome.findAll();
245: for (Iterator it = coll.iterator(); it.hasNext();) {
246: count++;
247: AccountLocal a = (AccountLocal) it.next();
248: int balance = a.getBalance();
249: String name = a.getName();
250: if (balance < 0) {
251: history.log(BasicLevel.ERROR, name
252: + " bad balance: " + balance);
253: ret = false;
254: } else {
255: history.log(BasicLevel.DEBUG, name
256: + " : FINAL BALANCE=" + balance);
257: total += balance;
258: }
259: }
260: } catch (Exception e) {
261: history.log(BasicLevel.ERROR, "checkAllAccounts:" + e);
262: return false;
263: }
264: int exp = initialValue * count;
265: if (total != exp) {
266: history.log(BasicLevel.ERROR,
267: "checkAllAccounts: bad total: " + total
268: + " (expected: " + exp + ")");
269: return false;
270: }
271: history.log(BasicLevel.DEBUG, "CheckAll OK");
272: return ret;
273: }
274:
275: /**
276: * Check an existing Account
277: * @param a num of the Account.
278: * @return true if OK.
279: */
280: public boolean checkAccount(int a) throws RemoteException {
281: boolean ret = false;
282: AccountLocal m = null;
283:
284: // retry several times, because this operation may be rolledback
285: // in case of deadlock.
286: Exception exc = null;
287: int retry;
288: for (retry = 0; retry < 20; retry++) {
289: try {
290: history.log(BasicLevel.DEBUG, "\ta_" + a
291: + "\tCHECKED try #" + retry);
292: m = accountLocalHome.findByNum(a);
293: int b = m.getBalance();
294: if (b >= 0) {
295: ret = true;
296: } else {
297: history.log(BasicLevel.WARN, "bad balance=" + b);
298: }
299: return ret;
300: } catch (Exception e) {
301: exc = e;
302: history.log(BasicLevel.DEBUG, "retrying " + retry);
303: sleep(retry + 1);
304: }
305: }
306: history.log(BasicLevel.WARN, "cannot check account: " + exc);
307: return ret;
308: }
309:
310: /*
311: * read balance for this Account, in a transaction.
312: * @param a num of the Account.
313: * @return balance
314: */
315: public int readBalanceTx(int a) throws RemoteException {
316: return readBalance(a);
317: }
318:
319: /**
320: * read balance for this Account
321: * @param a num of the Account.
322: * @return balance
323: */
324: public int readBalance(int a) throws RemoteException {
325: int ret;
326: try {
327: AccountLocal acc = getAccount(a);
328: if (acc == null) {
329: history.log(BasicLevel.ERROR, "Cannot get account");
330: throw new RemoteException("Cannot get account " + a);
331: }
332: ret = acc.getBalance();
333: } catch (Exception e) {
334: history.log(BasicLevel.ERROR, "Cannot read balance for "
335: + a + ": " + e);
336: throw new RemoteException("Cannot read balance for " + a);
337: }
338: history.log(BasicLevel.DEBUG, "READ " + a + " = " + ret);
339: return ret;
340: }
341:
342: /**
343: * move form an Account to another one.
344: * @param d num of the debit Account.
345: * @param c num of the credit Account.
346: * @param v value to be moved
347: * @param d delay in second for the operation.
348: */
349: public void move(int d, int c, int v, int delay)
350: throws RemoteException {
351: history.log(BasicLevel.DEBUG, "MOVE " + v + " from " + d
352: + " to " + c);
353: try {
354: AccountLocal cred = getAccount(c);
355: AccountLocal deb = getAccount(d);
356: cred.credit(v);
357: sleep(delay);
358: deb.debit(v);
359: } catch (TransactionRolledbackLocalException e) {
360: history.log(BasicLevel.WARN, "move: Rollback transaction");
361: return;
362: } catch (EJBException e) {
363: history.log(BasicLevel.ERROR, "Cannot move:" + e);
364: return;
365: }
366: }
367:
368: /**
369: * Read balance on last accessed account
370: */
371: public int readBalance() throws RemoteException {
372: int ret;
373: try {
374: ret = last.getBalance();
375: } catch (NoSuchObjectLocalException e) {
376: throw new NoSuchObjectException("Account destroyed");
377: } catch (Exception e) {
378: throw new RemoteException("Cannot read last balance");
379: }
380: return ret;
381: }
382:
383: /**
384: * Create an Account, but set rollback only the transaction
385: * @return
386: * @throws RemoteException
387: */
388: public void createRollbackOnly(int i) throws RemoteException {
389: try {
390: last = newAccount(i);
391: } catch (CreateException c) {
392: throw new RemoteException("Cannot create account");
393: }
394: ejbContext.setRollbackOnly();
395: }
396:
397: // ------------------------------------------------------------------
398: // private methods
399: // ------------------------------------------------------------------
400:
401: /**
402: * Create a new Account. The account may exist (for example, when running
403: * tests twice without restarting the Container, or if created by another
404: * session meanwhile)
405: * @param i account number (its PK)
406: */
407: private AccountLocal newAccount(int i) throws RemoteException,
408: CreateException {
409: AccountLocal ml = null;
410: ml = accountLocalHome.create(i, initialValue);
411: history.log(BasicLevel.DEBUG, "New Account has been created\t"
412: + i);
413: return ml;
414: }
415:
416: /**
417: * Create an Account if it does not exist yet.
418: * @param c1 num of the Account.
419: */
420: private AccountLocal getAccount(int c1) throws RemoteException {
421: history.log(BasicLevel.DEBUG, "Get Account\t" + c1);
422: try {
423: last = accountLocalHome.findByNum(c1);
424: } catch (FinderException e) {
425: try {
426: last = newAccount(c1);
427: } catch (CreateException c) {
428: throw new RemoteException("Cannot create account");
429: }
430: }
431: return last;
432: }
433:
434: /**
435: * sleep n seconds
436: * @param n seconds
437: */
438: private void sleep(int n) {
439: try {
440: Thread.sleep(1000 * n);
441: } catch (InterruptedException e) {
442: }
443: }
444:
445: }
|