KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > core > stateful > StatefulContainer


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: StatefulContainer.java 2495 2006-02-23 07:30:53Z dblevins $
44  */

45
46
47 package org.openejb.core.stateful;
48
49 import java.lang.reflect.Method JavaDoc;
50 import java.rmi.RemoteException JavaDoc;
51 import java.util.HashMap JavaDoc;
52 import java.util.Properties JavaDoc;
53
54 import javax.ejb.EJBHome JavaDoc;
55 import javax.ejb.EJBLocalHome JavaDoc;
56 import javax.ejb.EJBLocalObject JavaDoc;
57 import javax.ejb.EJBObject JavaDoc;
58 import javax.ejb.EnterpriseBean JavaDoc;
59 import javax.ejb.SessionBean JavaDoc;
60
61 import org.openejb.Container;
62 import org.openejb.DeploymentInfo;
63 import org.openejb.OpenEJB;
64 import org.openejb.OpenEJBException;
65 import org.openejb.ProxyInfo;
66 import org.openejb.SystemException;
67 import org.openejb.core.EnvProps;
68 import org.openejb.core.Operations;
69 import org.openejb.core.ThreadContext;
70 import org.openejb.core.transaction.TransactionContainer;
71 import org.openejb.core.transaction.TransactionContext;
72 import org.openejb.core.transaction.TransactionPolicy;
73 import org.openejb.util.Logger;
74 import org.openejb.util.SafeProperties;
75 import org.openejb.util.SafeToolkit;
76
77 /**
78  * Stateful SessionBean container
79  *
80  * @author <a HREF="mailto:Richard@Monson-Haefel.com">Richard Monson-Haefel</a>
81  * @author <a HREF="mailto:david.blevins@visi.com">David Blevins</a>
82  * @version $Revision: 2495 $ $Date: 2006-02-22 23:30:53 -0800 (Wed, 22 Feb 2006) $
83  */

84 public class StatefulContainer implements org.openejb.RpcContainer, TransactionContainer {
85
86     // managed bean instances; passivation and cache
87
StatefulInstanceManager instanceManager;
88     // contains deployment information for each by deployed to this container
89
HashMap JavaDoc deploymentRegistry;
90     // the server unique id for this container
91
Object JavaDoc containerID = null;
92
93     // the remove method is used repeatedly in the removeEJBObject method.
94
Method JavaDoc EJB_REMOVE_METHOD = null;
95
96     final static protected Logger logger = Logger.getInstance("OpenEJB", "org.openejb.util.resources");
97
98     // manages the transactional scope according to the bean's transaction attributes
99
//StatefulTransactionScopeHandler txScopeHandle;
100

101     /*
102      * Construct this container with the specified container id, deployments, container manager and properties.
103      * The properties can include the class name of the preferred InstanceManager, org.openejb.core.entity.EntityInstanceManager
104      * is the default. The properties should also include the properties for the instance manager.
105      *
106      * @param id the unique id to identify this container in the ContainerSystem
107      * @param registry a hashMap of bean delpoyments that this container will be responsible for
108      * @param mngr the ContainerManager for this container
109      * @param properties the properties this container needs to initialize and run
110      * @throws OpenEJBException if there is a problem constructing the container
111      * @see org.openejb.Container
112      */

113     public void init(Object JavaDoc id, HashMap JavaDoc registry, Properties JavaDoc properties)
114     throws org.openejb.OpenEJBException{
115         containerID = id;
116         deploymentRegistry = registry;
117
118         if ( properties == null )properties = new Properties JavaDoc();
119
120         SafeToolkit toolkit = SafeToolkit.getToolkit("StatefulContainer");
121         SafeProperties safeProps = toolkit.getSafeProperties(properties);
122         try {
123             String JavaDoc className = safeProps.getProperty(EnvProps.IM_CLASS_NAME, "org.openejb.core.stateful.StatefulInstanceManager");
124             ClassLoader JavaDoc cl = OpenEJB.getContextClassLoader();
125             instanceManager =(StatefulInstanceManager)Class.forName(className, true, cl).newInstance();
126         } catch ( Exception JavaDoc e ) {
127             throw new org.openejb.SystemException("Initialization of InstanceManager for the \""+containerID+"\" stateful container failed",e);
128         }
129         instanceManager.init(properties);
130
131 // txScopeHandle = new StatefulTransactionScopeHandler(this,instanceManager);
132

133         /*
134         * This block of code is necessary to avoid a chicken and egg problem. The DeploymentInfo
135         * objects must have a reference to their container during this assembly process, but the
136         * container is created after the DeploymentInfo necessitating this loop to assign all
137         * deployment info object's their containers.
138         */

139         org.openejb.DeploymentInfo [] deploys = this.deployments();
140         for ( int x = 0; x < deploys.length; x++ ) {
141             org.openejb.core.DeploymentInfo di = (org.openejb.core.DeploymentInfo)deploys[x];
142             di.setContainer(this);
143         }
144
145         try {
146             EJB_REMOVE_METHOD = javax.ejb.SessionBean JavaDoc.class.getMethod("ejbRemove", new Class JavaDoc [0]);
147         } catch ( NoSuchMethodException JavaDoc nse ) {
148             throw new SystemException("Fixed remove method can not be initated", nse);
149         }
150
151     }
152
153     //===============================
154
// begin Container Implementation
155
//
156

157     /**
158      * Gets the <code>DeploymentInfo</code> objects for all the beans deployed in this container.
159      *
160      * @return an array of DeploymentInfo objects
161      * @see org.openejb.DeploymentInfo
162      */

163     public DeploymentInfo [] deployments() {
164         return(DeploymentInfo [])deploymentRegistry.values().toArray(new DeploymentInfo[deploymentRegistry.size()]);
165     }
166
167     /**
168      * Gets the <code>DeploymentInfo</code> object for the bean with the specified deployment id.
169      *
170      * @param deploymentID the deployment id of the deployed bean.
171      * @return the DeploymentInfo object associated with the bean.
172      * @see org.openejb.DeploymentInfo
173      * @see org.openejb.DeploymentInfo#getDeploymentID()
174      */

175     public DeploymentInfo getDeploymentInfo(Object JavaDoc deploymentID) {
176         return(DeploymentInfo)deploymentRegistry.get(deploymentID);
177     }
178     /**
179      * Gets the type of container (STATELESS, STATEFUL, ENTITY, or MESSAGE_DRIVEN
180      *
181      * @return id type bean container
182      */

183     public int getContainerType( ) {
184         return Container.STATEFUL;
185     }
186     /**
187      * Gets the id of this container.
188      *
189      * @return the id of this container.
190      */

191     public Object JavaDoc getContainerID() {
192         return containerID;
193     }
194
195     /**
196      * Adds a bean to this container.
197      * @param deploymentID the deployment id of the bean to deploy.
198      * @param info the DeploymentInfo object associated with the bean.
199      * @throws org.openejb.OpenEJBException
200      * Occurs when the container is not able to deploy the bean for some
201      * reason.
202      */

203     public void deploy(Object JavaDoc deploymentID, DeploymentInfo info) throws OpenEJBException {
204         HashMap JavaDoc registry = (HashMap JavaDoc)deploymentRegistry.clone();
205         registry.put(deploymentID, info);
206         deploymentRegistry = registry;
207     }
208
209     /**
210      * Invokes a method on an instance of the specified bean deployment.
211      * (processes all business methods on an remote interface)
212      *
213      * @param deployID the dployment id of the bean deployment
214      * @param callMethod the method to be called on the bean instance
215      * @param args the arguments to use when invoking the specified method
216      * @param primKey the primary key class of the bean or null if the bean does not need a primary key
217      * @param securityIdentity identity
218      * @return the result of invoking the specified method on the bean instance
219      * @throws org.openejb.OpenEJBException
220      * @see org.openejb.core.stateless.StatelessContainer#invoke StatelessContainer.invoke
221      */

222     public Object JavaDoc invoke(Object JavaDoc deployID, Method JavaDoc callMethod,Object JavaDoc [] args,Object JavaDoc primKey, Object JavaDoc securityIdentity) throws org.openejb.OpenEJBException{
223         try {
224
225             org.openejb.core.DeploymentInfo deployInfo = (org.openejb.core.DeploymentInfo)this.getDeploymentInfo(deployID);
226
227             ThreadContext callContext = ThreadContext.getThreadContext();
228             callContext.set(deployInfo, primKey, securityIdentity);
229
230             // check authorization to invoke
231
boolean authorized = OpenEJB.getSecurityService().isCallerAuthorized(securityIdentity, deployInfo.getAuthorizedRoles(callMethod));
232             if ( !authorized )
233                 throw new org.openejb.ApplicationException(new RemoteException JavaDoc("Unauthorized Access by Principal Denied"));
234
235             // use special methods for remove and create requests
236
Class JavaDoc declaringClass = callMethod.getDeclaringClass();
237             String JavaDoc methodName = callMethod.getName();
238             
239             if(EJBHome JavaDoc.class.isAssignableFrom(declaringClass) || EJBLocalHome JavaDoc.class.isAssignableFrom(declaringClass) ){
240                 if ( methodName.equals("create") ) {
241                     return createEJBObject(callMethod, args, callContext);
242                 } else if ( methodName.equals("remove") ) {
243                     removeEJBObject(callMethod,args,callContext);
244                     return null;
245                 }
246             } else if((EJBObject JavaDoc.class == declaringClass || EJBLocalObject JavaDoc.class == declaringClass) && methodName.equals("remove") ) {
247                 removeEJBObject(callMethod,args,callContext);
248                 return null;
249             }
250
251
252             SessionBean JavaDoc bean = null;
253
254             // retreive instance from instance manager
255
bean = instanceManager.obtainInstance(primKey, callContext);
256             callContext.setCurrentOperation(Operations.OP_BUSINESS);
257             Object JavaDoc returnValue = null;
258             Method JavaDoc runMethod = deployInfo.getMatchingBeanMethod(callMethod);
259
260             returnValue = this.invoke(callMethod,runMethod, args, bean, callContext);
261
262             // DMB: If an exception is thrown, this bean will not be put back in the
263
// pool.
264
instanceManager.poolInstance(primKey, bean);
265
266             // see comments in org.openejb.core.DeploymentInfo.
267
return deployInfo.convertIfLocalReference(callMethod, returnValue);
268
269         } finally {
270             /*
271                 The thread context must be stripped from the thread before returning or throwing an exception
272                 so that an object outside the container does not have access to a
273                 bean's JNDI ENC. In addition, its important for the
274                 org.openejb.core.ivm.java.javaURLContextFactory, which determines the context
275                 of a JNDI lookup based on the presence of a ThreadContext object. If no ThreadContext
276                 object is available, then the request is assumed to be made from outside the container
277                 system and is given the global OpenEJB JNDI name space instead. If there is a thread context,
278                 then the request is assumed to be made from within the container system and so the
279                 javaContextFactory must return the JNDI ENC of the current enterprise bean which it
280                 obtains from the DeploymentInfo object associated with the current thread context.
281             */

282             ThreadContext.setThreadContext(null);
283         }
284
285     }
286
287     //
288
// end ContainerManager Implementation
289
//====================================
290

291
292     //============================================
293
// begin methods unique to this implementation
294
//
295

296     protected Object JavaDoc invoke(Method JavaDoc callMethod, Method JavaDoc runMethod, Object JavaDoc [] args, EnterpriseBean JavaDoc bean, ThreadContext callContext)
297     throws org.openejb.OpenEJBException{
298
299         //OLD:Transaction originalTx = txScopeHandle.beforeInvoke(callMethod, bean, callContext);
300
// txScopeHandler.afterInvoke( ) peformed in the finally clause
301
TransactionPolicy txPolicy = callContext.getDeploymentInfo().getTransactionPolicy( callMethod );
302         TransactionContext txContext = new TransactionContext( callContext );
303         txContext.context.put(StatefulInstanceManager.class, instanceManager);
304         try {
305             txPolicy.beforeInvoke( bean, txContext );
306         } catch ( org.openejb.ApplicationException e ) {
307             if ( e.getRootCause() instanceof javax.transaction.TransactionRequiredException JavaDoc ||
308                  e.getRootCause() instanceof java.rmi.RemoteException JavaDoc ) {
309                 // SR: this handles the case where the CMT attribute is "mandatory"
310
// but there was no client transaction, or "never" with a transaction.
311
// The session bean should not be destroyed because it is still in a valid state.
312
instanceManager.poolInstance(callContext.getPrimaryKey(), bean);
313             }
314             throw e;
315         }
316
317         Object JavaDoc returnValue = null;
318         try {
319             returnValue = runMethod.invoke(bean, args);
320         } catch ( java.lang.reflect.InvocationTargetException JavaDoc ite ) {// handle enterprise bean exception
321
if ( ite.getTargetException() instanceof RuntimeException JavaDoc ) {
322                 /* System Exception ****************************/
323                 //OLD:txScopeHandle.handleSystemException(callMethod,bean,callContext, originalTx,ite.getTargetException());
324
txPolicy.handleSystemException( ite.getTargetException(), bean, txContext );
325             } else {
326                 /* Application Exception ***********************/
327                 instanceManager.poolInstance(callContext.getPrimaryKey(), bean);
328                 //OLD:txScopeHandle.handleApplicationException(callMethod,bean,callContext, originalTx,ite.getTargetException());
329
txPolicy.handleApplicationException( ite.getTargetException(), txContext );
330             }
331         } catch ( Throwable JavaDoc re ) {// handle reflection exception
332
/*
333               Any exception thrown by reflection; not by the enterprise bean. Possible
334               Exceptions are:
335                 IllegalAccessException - if the underlying method is inaccessible.
336                 IllegalArgumentException - if the number of actual and formal parameters differ, or if an unwrapping conversion fails.
337                 NullPointerException - if the specified object is null and the method is an instance method.
338                 ExceptionInitializerError - if the initialization provoked by this method fails.
339             */

340             //OLD:txScopeHandle.handleSystemException(callMethod,bean,callContext, originalTx,re);
341
txPolicy.handleSystemException( re, bean, txContext );
342
343         } finally {
344             //OLD:txScopeHandle.afterInvoke(callMethod, bean,callContext, originalTx);
345
txPolicy.afterInvoke( bean, txContext );
346         }
347
348         return returnValue;
349     }
350
351     public StatefulInstanceManager getInstanceManager( ) {
352         return instanceManager;
353     }
354
355     // EJBObject and EJBHome remove methods processed here. Primarykey in the ThreadContext will be that
356
// of the target instance even if the remove method orgininated on the home interface.
357
protected void removeEJBObject(Method JavaDoc callMethod, Object JavaDoc [] args, ThreadContext callContext)
358     throws org.openejb.OpenEJBException{
359
360         // ejbRemoved could be invoked from the EJBHome or EJBObject, so need a special MethodInvocation that specifies the ejbRemove on the SessionBean interface with no arguments
361
try {
362             EnterpriseBean JavaDoc bean = instanceManager.obtainInstance(callContext.getPrimaryKey(), callContext);
363             if ( bean!=null ) {
364                 // ejbRemove is invoked with the TX_NOT_SUPPORTS
365
callContext.setCurrentOperation(Operations.OP_REMOVE);
366                 invoke(callMethod,this.EJB_REMOVE_METHOD,null,bean,callContext);
367             }
368         } finally {
369             instanceManager.freeInstance(callContext.getPrimaryKey());
370         }
371
372     }
373
374     // create methods from home interface
375
protected ProxyInfo createEJBObject(Method JavaDoc callMethod, Object JavaDoc [] args, ThreadContext callContext)
376     throws org.openejb.OpenEJBException {
377         org.openejb.core.DeploymentInfo deploymentInfo = (org.openejb.core.DeploymentInfo)callContext.getDeploymentInfo();
378         Class JavaDoc beanType = deploymentInfo.getBeanClass();
379         Object JavaDoc primaryKey = this.newPrimaryKey();
380         callContext.setPrimaryKey(primaryKey);
381
382         EnterpriseBean JavaDoc bean = instanceManager.newInstance(primaryKey,beanType);
383
384         Method JavaDoc runMethod = deploymentInfo.getMatchingBeanMethod(callMethod);
385
386         callContext.setCurrentOperation(Operations.OP_CREATE);
387         invoke(callMethod, runMethod, args, bean,callContext);
388
389         instanceManager.poolInstance(primaryKey, bean);
390
391         Class JavaDoc callingClass = callMethod.getDeclaringClass();
392         boolean isLocalInterface = EJBLocalHome JavaDoc.class.isAssignableFrom(callingClass);
393         return new ProxyInfo(deploymentInfo, primaryKey, isLocalInterface, this);
394     }
395
396
397     // autogenerate stateful primary key. may need a more sophisticated algo.
398
protected Object JavaDoc newPrimaryKey() {
399         return new java.rmi.dgc.VMID JavaDoc();
400     }
401
402     //
403
// end other methods unique to this implementation
404
//================================================
405

406     public void discardInstance(EnterpriseBean JavaDoc bean, ThreadContext threadContext) {
407         try {
408             Object JavaDoc primaryKey = threadContext.getPrimaryKey();
409             instanceManager.freeInstance(primaryKey);
410         } catch ( Throwable JavaDoc t ) {
411             logger.error("", t);
412         }
413     }
414 }
415
Popular Tags