KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > core > ivm > EjbHomeProxyHandler


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: EjbHomeProxyHandler.java 2118 2005-08-28 08:29:46Z dblevins $
44  */

45
46
47 package org.openejb.core.ivm;
48
49 import java.io.ObjectStreamException JavaDoc;
50 import java.lang.reflect.Method JavaDoc;
51 import java.rmi.RemoteException JavaDoc;
52
53 import javax.ejb.EJBHome JavaDoc;
54 import javax.ejb.EJBException JavaDoc;
55
56 import org.openejb.ProxyInfo;
57 import org.openejb.RpcContainer;
58 import org.openejb.core.ThreadContext;
59 import org.openejb.util.proxy.ProxyManager;
60
61 /**
62  * This is an InvocationHandler that is used only for handling requests from an
63  * EJBHome stub. The EjbHomeProxyHandler handles all in-VM requests from the EJBHome stub.
64  * The EjbHomeProxyHandler is different from the EjbObjectProxyHandler in that it does not need to be synchronized.
65  * One instance of the EjbHomeProxyHandler can be used by all instances of the EJBObject stub in the
66  * same VM as the bean deployment they represent.
67  * This InvocationHandler and its proxy are serializable and can be used by
68  * HomeHandle, Handle, and MetaData to persist and revive handles to the EJBHome. It maintains
69  * its original client identity which allows the container to be more discerning about
70  * allowing the revieed proxy to be used. See StatefulContainer manager for more details.
71  *
72  * @author <a HREF="mailto:david.blevins@visi.com">David Blevins</a>
73  * @author <a HREF="mailto:Richard@Monson-Haefel.com">Richard Monson-Haefel</a>
74  * @see org.openejb.core.ivm.EjbObjectProxyHandler
75  * @see org.openejb.core.stateful.StatefulContainer
76  */

77 public abstract class EjbHomeProxyHandler extends BaseEjbProxyHandler {
78     protected final static org.apache.log4j.Category logger = org.apache.log4j.Category.getInstance("OpenEJB");
79
80     static final java.util.HashMap JavaDoc dispatchTable;
81
82     // this table helps dispatching in constant time, instead of many expensive equals() calls
83
static {
84         dispatchTable = new java.util.HashMap JavaDoc();
85         dispatchTable.put("create", new Integer JavaDoc(1));
86         dispatchTable.put("getEJBMetaData", new Integer JavaDoc(2));
87         dispatchTable.put("getHomeHandle", new Integer JavaDoc(3));
88         dispatchTable.put("remove", new Integer JavaDoc(4));
89     }
90     
91     /**
92      * Constructs an EjbHomeProxyHandler to handle invocations from an EJBHome stub/proxy.
93      *
94      * @param container The Container that the bean deployment this stub hanlder represents is deployed in.
95      * @param pk The primary key of the bean deployment or null if the deployment is a bean type that doesn't require a primary key.
96      * @param depID The unique id of the bean deployment that this stub handler will represent.
97      */

98     public EjbHomeProxyHandler(RpcContainer container, Object JavaDoc pk, Object JavaDoc depID) {
99         super(container, pk, depID);
100     }
101
102     public void invalidateReference(){
103         throw new IllegalStateException JavaDoc("A home reference must never be invalidated!");
104     }
105     
106     protected Object JavaDoc createProxy(ProxyInfo proxyInfo){
107         
108         if (proxyInfo instanceof SpecialProxyInfo) {
109             Object JavaDoc proxy = ((SpecialProxyInfo)proxyInfo).getProxy();
110             if (proxy == null) throw new RuntimeException JavaDoc("Could not create IVM proxy for "+proxyInfo.getInterface()+" interface");
111             return proxy;
112         }
113         
114         Object JavaDoc newProxy = null;
115         try {
116             EjbObjectProxyHandler handler = newEjbObjectHandler(proxyInfo.getBeanContainer(), proxyInfo.getPrimaryKey(), proxyInfo.getDeploymentInfo().getDeploymentID());
117             handler.setLocal(isLocal());
118             handler.doIntraVmCopy = this.doIntraVmCopy;
119             Class JavaDoc[] interfaces = new Class JavaDoc[]{ proxyInfo.getInterface(), IntraVmProxy.class };
120             newProxy = ProxyManager.newProxyInstance( interfaces , handler );
121         } catch (IllegalAccessException JavaDoc iae) {
122             throw new RuntimeException JavaDoc("Could not create IVM proxy for "+proxyInfo.getInterface()+" interface");
123         }
124         if (newProxy == null) throw new RuntimeException JavaDoc("Could not create IVM proxy for "+proxyInfo.getInterface()+" interface");
125     
126         return newProxy;
127     }
128
129     protected abstract EjbObjectProxyHandler newEjbObjectHandler(RpcContainer container, Object JavaDoc pk, Object JavaDoc depID);
130     
131     protected Object JavaDoc _invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc{
132
133         if (logger.isInfoEnabled()) {
134             logger.info("invoking method "+method.getName()+" on "+deploymentID);
135         }
136         
137         String JavaDoc methodName = method.getName();
138         
139         try{
140             java.lang.Object JavaDoc retValue;
141             Integer JavaDoc operation = (Integer JavaDoc)dispatchTable.get(methodName);
142
143             if(operation==null) {
144                 if ( methodName.startsWith("find") ){
145                     retValue = findX(method, args, proxy);
146                 } else {
147                     // Cannot return null. Must throw and exception instead.
148
throw new UnsupportedOperationException JavaDoc("Unkown method: "+method);
149                 }
150             }else {
151                 switch(operation.intValue()) {
152         /*-- CREATE ------------- <HomeInterface>.create(<x>) ---*/
153                     case 1: retValue = create(method, args, proxy); break;
154         /*-- GET EJB METADATA ------ EJBHome.getEJBMetaData() ---*/
155                     case 2: retValue = getEJBMetaData(method, args, proxy); break;
156         /*-- GET HOME HANDLE -------- EJBHome.getHomeHandle() ---*/
157                     case 3: retValue = getHomeHandle(method, args, proxy); break;
158         /*-- REMOVE ------------------------ EJBHome.remove() ---*/
159                     case 4: {
160                         Class JavaDoc type = method.getParameterTypes()[0];
161
162             /*-- HANDLE ------- EJBHome.remove(Handle handle) ---*/
163                         if (javax.ejb.Handle JavaDoc.class.isAssignableFrom(type)) {
164                             retValue = removeWithHandle(method, args, proxy);
165             } else {
166                         /*-- PRIMARY KEY ----- EJBHome.remove(Object key) ---*/
167                             retValue = removeByPrimaryKey(method, args, proxy);
168                         }
169                         break;
170                     }
171                     default:
172                         throw new RuntimeException JavaDoc("Inconsistent internal state: value "+operation.intValue()+" for operation "+methodName);
173                 }
174             }
175
176             if(logger.isDebugEnabled()) {
177                 logger.debug("finished invoking method "+method.getName()+". Return value:"+retValue);
178             } else if (logger.isInfoEnabled()) {
179                 logger.info("finished invoking method "+method.getName());
180             }
181             
182             return retValue;
183
184         /*
185          * The ire is thrown by the container system and propagated by
186          * the server to the stub.
187          */

188         } catch (RemoteException JavaDoc re) {
189             if (isLocal()){
190                 throw new EJBException JavaDoc(re.getMessage(),(Exception JavaDoc)re.detail);
191             } else {
192                 throw re;
193             }
194
195         } catch ( org.openejb.InvalidateReferenceException ire ) {
196             Throwable JavaDoc cause = ire.getRootCause();
197             if (cause instanceof RemoteException JavaDoc && isLocal()){
198                 RemoteException JavaDoc re = (RemoteException JavaDoc)cause;
199                 Throwable JavaDoc detail = (re.detail != null)? re.detail: re;
200                 cause = new EJBException JavaDoc(re.getMessage(), (Exception JavaDoc) detail);
201             }
202             throw cause;
203         /*
204          * Application exceptions must be reported dirctly to the client. They
205          * do not impact the viability of the proxy.
206          */

207         } catch ( org.openejb.ApplicationException ae ) {
208             throw ae.getRootCause();
209         /*
210          * A system exception would be highly unusual and would indicate a sever
211          * problem with the container system.
212          */

213         } catch ( org.openejb.SystemException se ) {
214             if (isLocal()){
215                 throw new EJBException JavaDoc("Container has suffered a SystemException", (Exception JavaDoc)se.getRootCause());
216             } else {
217                 throw new RemoteException JavaDoc("Container has suffered a SystemException",se.getRootCause());
218             }
219         } catch ( org.openejb.OpenEJBException oe ) {
220             if (isLocal()){
221                 throw new EJBException JavaDoc("Unknown Container Exception", (Exception JavaDoc)oe.getRootCause());
222             } else {
223                 throw new RemoteException JavaDoc("Unknown Container Exception",oe.getRootCause());
224             }
225         } catch(Throwable JavaDoc t) {
226             logger.info("finished invoking method "+method.getName()+" with exception:"+t, t);
227             throw t;
228         }
229     }
230
231     /*-------------------------------------------------*/
232     /* Home interface methods */
233     /*-------------------------------------------------*/
234     
235     /**
236      * <P>
237      * Creates a new EJBObject and returns it to the
238      * caller. The EJBObject is a new proxy with a
239      * new handler. This implementation should not be
240      * sent outside the virtual machine.
241      * </P>
242      * <P>
243      * This method propogates to the container
244      * system.
245      * </P>
246      * <P>
247      * The create method is required to be defined
248      * by the bean's home interface.
249      * </P>
250      *
251      * @param method
252      * @param args
253      * @param proxy
254      * @return Returns an new EJBObject proxy and handler
255      * @exception Throwable
256      */

257     protected Object JavaDoc create(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
258         ProxyInfo proxyInfo = (ProxyInfo) container.invoke(deploymentID,method,args,null, getThreadSpecificSecurityIdentity());
259         return createProxy(proxyInfo);
260     }
261
262     /**
263      * <P>
264      * Locates and returns a new EJBObject or a collection
265      * of EJBObjects. The EJBObject(s) is a new proxy with
266      * a new handler. This implementation should not be
267      * sent outside the virtual machine.
268      * </P>
269      * <P>
270      * This method propogates to the container
271      * system.
272      * </P>
273      * <P>
274      * The find method is required to be defined
275      * by the bean's home interface of Entity beans.
276      * </P>
277      *
278      * @param method
279      * @param args
280      * @param proxy
281      * @return Returns an new EJBObject proxy and handler
282      * @exception Throwable
283      */

284     protected abstract Object JavaDoc findX(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc;
285
286     /*-------------------------------------------------*/
287     /* EJBHome methods */
288     /*-------------------------------------------------*/
289
290     /**
291      * <P>
292      * Returns an EJBMetaData implementation that is
293      * valid inside this virtual machine. This
294      * implementation should not be sent outside the
295      * virtual machine.
296      * </P>
297      * <P>
298      * This method does not propogate to the container
299      * system.
300      * </P>
301      * <P>
302      * getMetaData is a method of javax.ejb.EJBHome
303      * </P>
304      * <P>
305      * Checks if the caller is authorized to invoke the
306      * javax.ejb.EJBHome.getMetaData on the EJBHome of the
307      * deployment.
308      * </P>
309      *
310      * @return Returns an IntraVmMetaData
311      * @exception Throwable
312      * @see IntraVmMetaData
313      * @see javax.ejb.EJBHome
314      * @see javax.ejb.EJBHome#getEJBMetaData
315      */

316     protected Object JavaDoc getEJBMetaData(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc {
317         checkAuthorization(method);
318         IntraVmMetaData metaData = new IntraVmMetaData(deploymentInfo.getHomeInterface(), deploymentInfo.getRemoteInterface(),deploymentInfo.getPrimaryKeyClass(), deploymentInfo.getComponentType());
319         metaData.setEJBHome((EJBHome JavaDoc)proxy);
320         return metaData;
321     }
322     
323
324     /**
325      * <P>
326      * Returns a HomeHandle implementation that is
327      * valid inside this virtual machine. This
328      * implementation should not be sent outside the
329      * virtual machine.
330      * </P>
331      * <P>
332      * This method does not propogate to the container
333      * system.
334      * </P>
335      * <P>
336      * getHomeHandle is a method of javax.ejb.EJBHome
337      * </P>
338      * <P>
339      * Checks if the caller is authorized to invoke the
340      * javax.ejb.EJBHome.getHomeHandle on the EJBHome of the
341      * deployment.
342      * </P>
343      *
344      * @param proxy
345      * @return Returns an IntraVmHandle
346      * @exception Throwable
347      * @see IntraVmHandle
348      * @see javax.ejb.EJBHome
349      * @see javax.ejb.EJBHome#getHomeHandle
350      */

351     protected Object JavaDoc getHomeHandle(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
352         checkAuthorization(method);
353         return new IntraVmHandle(proxy);
354     }
355     public org.openejb.ProxyInfo getProxyInfo(){
356         return new org.openejb.ProxyInfo(deploymentInfo, null, deploymentInfo.getHomeInterface(), container);
357     }
358     
359     /**
360      * The writeReplace method is invoked on the proxy when it enters the
361      * serialization process. The call is passed to the handler, then delegated
362      * to this method.
363      *
364      * If the proxy is being copied between bean instances in a RPC
365      * call we use the IntraVmArtifact. This object is immutable and does not
366      * need to be dereferenced; therefore, we have no need to actually serialize
367      * this object.
368      *
369      * If the proxy is referenced by a stateful bean that is being
370      * passivated by the container we allow this object to be serialized.
371      *
372      * If the proxy is being serialized in any other context, we know that its
373      * destination is outside the core container system. This is the
374      * responsibility of the Application Server and one of its proxies is
375      * serialized to the stream in place of the IntraVmProxy.
376      *
377      * @param proxy
378      * @return Object
379      * @exception ObjectStreamException
380      */

381     protected Object JavaDoc _writeReplace(Object JavaDoc proxy) throws ObjectStreamException JavaDoc{
382         /*
383          * If the proxy is being copied between bean instances in a RPC
384          * call we use the IntraVmArtifact
385          */

386         if(IntraVmCopyMonitor.isIntraVmCopyOperation()){
387             return new IntraVmArtifact( proxy );
388         /*
389          * If the proxy is referenced by a stateful bean that is being
390          * passivated by the container we allow this object to be serialized.
391          */

392         }else if(IntraVmCopyMonitor.isStatefulPassivationOperation()){
393             return proxy;
394         /*
395          * If the proxy is serialized outside the core container system,
396          * we allow the application server to handle it.
397          */

398         } else{
399             return org.openejb.OpenEJB.getApplicationServer().getEJBHome(this.getProxyInfo());
400         }
401     }
402     
403     /**
404      * <P>
405      * Attempts to remove an EJBObject from the
406      * container system. The EJBObject to be removed
407      * is represented by the javax.ejb.Handle object passed
408      * into the remove method in the EJBHome.
409      * </P>
410      * <P>
411      * This method propogates to the container system.
412      * </P>
413      * <P>
414      * remove(Handle handle) is a method of javax.ejb.EJBHome
415      * </P>
416      * <P>
417      * Checks if the caller is authorized to invoke the
418      * javax.ejb.EJBHome.remove on the EJBHome of the
419      * deployment.
420      * </P>
421      *
422      * TODO: this method relies on the fact that the handle implementation is a subclass
423      * of IntraVM handle, which isn't neccessarily the case for arbitrary remote protocols.
424      * Also, for all other but IntraVM handles, the stub invalidation doesn't currently work.
425      *
426      * @param method
427      * @param args
428      * @return Returns null
429      * @exception Throwable
430      * @see javax.ejb.EJBHome
431      * @see javax.ejb.EJBHome#remove(javax.ejb.Handle)
432      */

433     protected Object JavaDoc removeWithHandle(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
434
435         // Extract the primary key from the handle
436
IntraVmHandle handle = (IntraVmHandle)args[0];
437         Object JavaDoc primKey = handle.getPrimaryKey();
438         EjbObjectProxyHandler stub;
439         try{
440             stub = (EjbObjectProxyHandler)ProxyManager.getInvocationHandler(handle.getEJBObject());
441         }catch(IllegalArgumentException JavaDoc e) {
442             // a remote proxy, see comment above
443
stub=null;
444         }
445         // invoke remove() on the container
446
container.invoke(deploymentID, method, args, primKey, ThreadContext.getThreadContext().getSecurityIdentity());
447
448         /*
449          * This operation takes care of invalidating all the EjbObjectProxyHanders associated with
450          * the same RegistryId. See this.createProxy().
451          */

452         if(stub!=null) {
453             invalidateAllHandlers(stub.getRegistryId());
454         }
455         return null;
456     }
457     
458     /**
459      * <P>
460      * Attempts to remove an EJBObject from the
461      * container system. The EJBObject to be removed
462      * is represented by the primaryKey passed
463      * into the remove method of the EJBHome.
464      * </P>
465      * <P>
466      * This method propogates to the container system.
467      * </P>
468      * <P>
469      * remove(Object primary) is a method of javax.ejb.EJBHome
470      * </P>
471      * <P>
472      * Checks if the caller is authorized to invoke the
473      * javax.ejb.EJBHome.remove on the EJBHome of the
474      * deployment.
475      * </P>
476      *
477      * @param method
478      * @param args
479      * @return Returns null
480      * @exception Throwable
481      * @see javax.ejb.EJBHome
482      * @see javax.ejb.EJBHome#remove(javax.ejb.Handle)
483      */

484     protected abstract Object JavaDoc removeByPrimaryKey(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc;
485 }
486
Popular Tags