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: JSessionFactory.java 8307 2006-04-27 13:36:00Z durieuxp $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container;
025:
026: import java.rmi.RemoteException;
027: import java.util.ArrayList;
028:
029: import javax.ejb.EJBException;
030: import javax.naming.NamingException;
031: import javax.transaction.SystemException;
032:
033: import org.objectweb.jonas_ejb.deployment.api.SessionDesc;
034:
035: import org.objectweb.util.monolog.api.BasicLevel;
036:
037: /**
038: * This class is a factory for a Session Bean. It is responsible for - managing
039: * Home and LocalHome. - keeping the JNDI context for this component
040: * (java:comp/env)
041: * @author Philippe Durieux
042: */
043: public abstract class JSessionFactory extends JFactory {
044:
045: /**
046: * Timeout for this session.
047: */
048: int timeout = 0;
049:
050: protected JSessionHome home = null;
051:
052: protected JSessionLocalHome localhome = null;
053:
054: protected boolean isSynchro = false;
055:
056: protected boolean isStateful; // set after constructor call
057:
058: /**
059: * Pool of free JSessionSwitch objects
060: * Used if singleswitch=false.
061: */
062: protected ArrayList sessionList = new ArrayList();
063:
064: /**
065: * Unique JSessionSwitch when singleswitch=true
066: */
067: protected JSessionSwitch uniqueSession = null;
068:
069: /**
070: * If no timeout, we can manage only 1 JSessionSwitch for all sessions.
071: * Only used in case of stateless, for load balancing.
072: */
073: protected boolean singleswitch;
074:
075: /**
076: * constructor
077: * @param dd The Session Deployment Descriptor
078: * @param cont The Container where the bean is defined.
079: */
080: public JSessionFactory(SessionDesc dd, JContainer cont) {
081: super (dd, cont);
082: if (TraceEjb.isDebugIc()) {
083: TraceEjb.interp.log(BasicLevel.DEBUG, "");
084: }
085:
086: txbeanmanaged = dd.isBeanManagedTransaction();
087: timeout = dd.getSessionTimeout();
088:
089: // Create the Home if defined in DD
090: Class homeclass = null;
091: String clname = dd.getFullWrpHomeName();
092: if (clname != null) {
093: try {
094: homeclass = cont.getClassLoader().loadClass(clname);
095: } catch (ClassNotFoundException e) {
096: throw new EJBException(ejbname + " Cannot load "
097: + clname, e);
098: }
099: if (TraceEjb.isDebugIc())
100: TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": "
101: + clname + " loaded");
102: try {
103: // new JSessionHome(dd, this)
104: int nbp = 2;
105: Class[] ptype = new Class[nbp];
106: Object[] pobj = new Object[nbp];
107: ptype[0] = org.objectweb.jonas_ejb.deployment.api.SessionDesc.class;
108: pobj[0] = (Object) dd;
109: ptype[1] = org.objectweb.jonas_ejb.container.JSessionFactory.class;
110: pobj[1] = (Object) this ;
111: home = (JSessionHome) homeclass.getConstructor(ptype)
112: .newInstance(pobj);
113: } catch (Exception e) {
114: throw new EJBException(
115: ejbname + " Cannot create home ", e);
116: }
117: // register it in JNDI
118: try {
119: home.register();
120: } catch (Exception e) {
121: throw new EJBException(ejbname
122: + " Cannot register home ", e);
123: }
124: }
125:
126: // Create the LocalHome if defined in DD
127: clname = dd.getFullWrpLocalHomeName();
128: if (clname != null) {
129: try {
130: homeclass = cont.getClassLoader().loadClass(clname);
131: } catch (ClassNotFoundException e) {
132: throw new EJBException(ejbname + " Cannot load "
133: + clname, e);
134: }
135: if (TraceEjb.isDebugIc())
136: TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": "
137: + clname + " loaded");
138: try {
139: // new JSessionLocalHome(dd, this)
140: int nbp = 2;
141: Class[] ptype = new Class[nbp];
142: Object[] pobj = new Object[nbp];
143: ptype[0] = org.objectweb.jonas_ejb.deployment.api.SessionDesc.class;
144: pobj[0] = (Object) dd;
145: ptype[1] = org.objectweb.jonas_ejb.container.JSessionFactory.class;
146: pobj[1] = (Object) this ;
147: localhome = (JSessionLocalHome) homeclass
148: .getConstructor(ptype).newInstance(pobj);
149: } catch (Exception e) {
150: throw new EJBException(ejbname
151: + " Cannot create localhome ", e);
152: }
153: // register it in JNDI
154: try {
155: localhome.register();
156: } catch (Exception e) {
157: throw new EJBException(ejbname
158: + " Cannot register localhome ", e);
159: }
160: }
161:
162: }
163:
164: /**
165: * Return true if singleswitch option is on.
166: * @return
167: */
168: public boolean singleSwitchOn() {
169: return singleswitch;
170: }
171:
172: // ---------------------------------------------------------------
173: // BeanFactory implementation
174: // ---------------------------------------------------------------
175:
176: /**
177: * stop this EJB. Mainly unregister it in JNDI.
178: */
179: public void stop() {
180: if (TraceEjb.isDebugIc()) {
181: TraceEjb.interp.log(BasicLevel.DEBUG, "");
182: }
183: try {
184: if (home != null) {
185: home.unregister();
186: }
187: if (localhome != null) {
188: localhome.unregister();
189: }
190: } catch (NamingException e) {
191: }
192:
193: // Must unexport the unique session now.
194: if (singleswitch) {
195: uniqueSession.noLongerUsed();
196: }
197: stopContainer();
198: }
199:
200: /**
201: * synchronize bean instances if needed
202: */
203: public void syncDirty(boolean notused) {
204: }
205:
206: /**
207: * @return the home if exist
208: */
209: public JHome getHome() {
210: return home;
211: }
212:
213: /**
214: * @return the local home if exist
215: */
216: public JLocalHome getLocalHome() {
217: return localhome;
218: }
219:
220: // ---------------------------------------------------------------
221: // JSessionSwitch pool management
222: // ---------------------------------------------------------------
223:
224: /**
225: * Create a new Session Find one in the pool, or create a new object.
226: * @return a SessionSwitch
227: */
228: public synchronized JSessionSwitch createEJB()
229: throws RemoteException {
230:
231: if (TraceEjb.isDebugIc()) {
232: TraceEjb.interp.log(BasicLevel.DEBUG, "");
233: }
234:
235: if (singleswitch) {
236: if (uniqueSession == null) {
237: uniqueSession = createNewSession();
238: }
239: return uniqueSession;
240: }
241:
242: JSessionSwitch bs = null;
243: if (sessionList.size() > 0) {
244: bs = (JSessionSwitch) sessionList.remove(0);
245: // must re-export the remote object in the Orb since EJBObjects
246: // should be un exported when put in the pool.
247: JSessionRemote remote = bs.getRemote();
248: if (remote != null) {
249: if (remote.exportObject() == false) {
250: TraceEjb.logger.log(BasicLevel.ERROR,
251: "bad JSessionSwitch found in pool.");
252: return null;
253: }
254: }
255: } else {
256: // This depend on subclass (stateless or stateful)
257: // no need to export the EJBObject because it is basically a
258: // RemoteObject
259: bs = createNewSession();
260: }
261:
262: // Start a timer for this new session
263: if (timeout > 0) {
264: bs.startTimer(timeout * 1000);
265: }
266: return bs;
267: }
268:
269: /**
270: * remove a Session. This may be called also on timeout. put it back in the
271: * pool for later use.
272: * @param bs The Bean Session Switch to put back in the pool.
273: */
274: public synchronized void removeEJB(JSessionSwitch bs) {
275:
276: if (TraceEjb.isDebugIc()) {
277: TraceEjb.interp.log(BasicLevel.DEBUG, "");
278: }
279:
280: if (singleswitch) {
281: uniqueSession = null;
282: } else {
283: sessionList.add(bs);
284: }
285: }
286:
287: // ---------------------------------------------------------------
288: // other public methods
289: // ---------------------------------------------------------------
290:
291: /**
292: * Session beans can be container managed or bean managed transaction
293: * Session home don't check transactional context.
294: * @param rctx The Request Context
295: */
296: public void checkTransaction(RequestCtx rctx) {
297: if (txbeanmanaged) {
298: try {
299: rctx.clientTx = tm.suspend();
300: if (TraceEjb.isDebugTx()) {
301: TraceEjb.tx.log(BasicLevel.DEBUG, "suspending tx:"
302: + rctx.clientTx);
303: }
304: } catch (SystemException e) {
305: throw new EJBException("cannot suspend transaction", e);
306: }
307: } else {
308: checkTransactionContainer(rctx);
309: }
310: }
311:
312: /**
313: * @return True if this Session implements SessionSynchronization
314: */
315: public boolean isSessionSynchro() {
316: return isSynchro;
317: }
318:
319: /**
320: * @return the current timeout value in seconds for Jmx
321: */
322: public int getTimeout() {
323: return timeout;
324: }
325:
326: /**
327: * set the current timeout value for Jmx
328: * @param timeout in seconds
329: */
330: public void setTimeout(int t) {
331: if (TraceEjb.isDebugTx()) {
332: TraceEjb.tx.log(BasicLevel.DEBUG, "");
333: }
334: timeout = t;
335: }
336:
337: /**
338: * @return true if this Session is Stateful. Will be used internally by
339: * EJBObject or EJBLocalObject because they are common to both
340: * types.
341: */
342: public boolean isStateful() {
343: return isStateful;
344: }
345:
346: /**
347: * @return a JSessionContext
348: */
349: public abstract JSessionContext getJContext(JSessionSwitch ss);
350:
351: // ---------------------------------------------------------------
352: // private methods
353: // ---------------------------------------------------------------
354:
355: abstract protected JSessionSwitch createNewSession()
356: throws RemoteException;
357: }
|