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