KickJava   Java API By Example, From Geeks To Geeks.

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


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: EjbObjectProxyHandler.java 1921 2005-06-19 22:40:34Z jlaskowski $
44  */

45 package org.openejb.core.ivm;
46
47 import java.io.ObjectStreamException JavaDoc;
48 import java.lang.reflect.Method JavaDoc;
49 import java.rmi.RemoteException JavaDoc;
50
51 import org.openejb.RpcContainer;
52
53 /**
54  * This InvocationHandler and its proxy are serializable and can be used by
55  * HomeHandle, Handle, and MetaData to persist and revive handles. It maintains
56  * its original client identity which allows the container to be more discerning about
57  * allowing the revieed proxy to be used. See StatefulContaer manager for more details.
58  *
59  * @author <a HREF="mailto:david.blevins@visi.com">David Blevins</a>
60  * @author <a HREF="mailto:Richard@Monson-Haefel.com">Richard Monson-Haefel</a>
61  */

62 public abstract class EjbObjectProxyHandler extends BaseEjbProxyHandler {
63                      
64     protected final static org.apache.log4j.Category logger = org.apache.log4j.Category.getInstance("OpenEJB");
65     static final java.util.HashMap JavaDoc dispatchTable;
66     
67     // this table helps dispatching in constant time, instead of many expensive equals() calls
68
static {
69         dispatchTable = new java.util.HashMap JavaDoc();
70         dispatchTable.put("getHandle", new Integer JavaDoc(1));
71         dispatchTable.put("getPrimaryKey", new Integer JavaDoc(2));
72         dispatchTable.put("isIdentical", new Integer JavaDoc(3));
73         dispatchTable.put("remove", new Integer JavaDoc(4));
74         dispatchTable.put("getEJBHome", new Integer JavaDoc(5));
75     }
76     
77     public EjbObjectProxyHandler(RpcContainer container, Object JavaDoc pk, Object JavaDoc depID){
78         super(container, pk, depID);
79     }
80     
81     /**
82     * The Registry id is a logical identifier that is used as a key when placing EjbObjectProxyHanlders into
83     * the BaseEjbProxyHanlder's liveHandleRegistry. EjbObjectProxyHanlders that represent the same
84     * bean identity (keyed by the registry id) will be stored together so that they can be removed together
85     * when the BaseEjbProxyHandler.invalidateAllHandlers is invoked.
86     *
87     * This method is implemented by the subclasses to return an id that logically identifies
88     * bean identity for a specific deployment id and container. For example, the EntityEjbObjectHandler
89     * overrides this method to return a compound key composed of the bean's primary key, deployment id, and
90     * container id. This uniquely identifies the bean identity that is proxied by this handler. Another example
91     * is the StatefulEjbObjectHanlder which overrides this method to return the stateful bean's hidden primary key,
92     * which is a java.rmi.dgc.VMID.
93     */

94     public abstract Object JavaDoc getRegistryId();
95
96     // This method has been "desynchronized", because:
97
// 1. It is a common super class, and session beans don't need to be synchronized.
98
// stateless session bean requests will be dispatched concurrently anyway,
99
// and the statefull session container already has concurrent access protection.
100
// 2. It is a HUGE scalability problem if multiple clients access stateless session beans
101
// through only one handler, because then all access is serialzed, which is unnrecessary
102
// 3. The scheme was broken anyway, because the handler instance was locked, which didn't
103
// prevent access to the same bean using two different handlers.
104
public Object JavaDoc _invoke(Object JavaDoc p, Method JavaDoc m, Object JavaDoc[] a) throws Throwable JavaDoc{
105         java.lang.Object JavaDoc retValue=null;
106         java.lang.Throwable JavaDoc exc=null;
107         
108         try{
109             if (logger.isInfoEnabled()) {
110                 logger.info("invoking method "+m.getName()+" on "+deploymentID+" with identity "+primaryKey);
111             }
112             Integer JavaDoc operation = (Integer JavaDoc)dispatchTable.get(m.getName());
113             
114             if(operation==null) {
115                 retValue = businessMethod(m,a,p);
116             }else {
117                 switch(operation.intValue()) {
118                     case 1: retValue = getHandle(m,a,p); break;
119                     case 2: retValue = getPrimaryKey(m,a,p); break;
120                     case 3: retValue = isIdentical(m,a,p); break;
121                     case 4: retValue = remove(m,a,p); break;
122                     case 5: retValue = getEJBHome(m,a,p); break;
123                     default:
124                         throw new RuntimeException JavaDoc("Inconsistent internal state");
125                 }
126             }
127             /*
128             * Business methods that return EJBHome or EJBObject references to local
129             * beans (beans in the same container system) must have the return value
130             * converted to a ProxyInfo object, so that the server can provide the client
131             * with a proper remote reference. Local remote references are implemented using
132             * the org.openejb.core.ivm.BaseEjbProxyHandler types, which should not be returned
133             * to the client. Non-local remote references are assumed to be serializable and valid
134             * return types for the clients.
135             *
136             * If the reference is a local remote reference a subtype of ProxyInfo is returned. The subtype
137             * is a org.openejb.core.ivm.SpecialProxyInfo. This class type is useful when the calling server
138             * is the IntraVM server. Instead of creating a new remote ref from the proxy the IntraVM takes
139             * a short cut and reuses the original local remote reference -- they are thread safe with no synchronization.
140             *
141             * See Section 2.2.1.2.5 Remote References of the OpenEJB specification.
142             */

143                 
144             if(retValue instanceof SpecialProxyInfo)
145                 retValue = ((SpecialProxyInfo)retValue).getProxy();
146         
147             return retValue;
148
149         /*
150          * The ire is thrown by the container system and propagated by
151          * the server to the stub.
152          */

153         }catch ( org.openejb.InvalidateReferenceException ire ) {
154             invalidateAllHandlers(getRegistryId());
155             exc = (ire.getRootCause() != null )? ire.getRootCause(): ire;
156             throw exc;
157         /*
158          * Application exceptions must be reported dirctly to the client. They
159          * do not impact the viability of the proxy.
160          */

161         } catch ( org.openejb.ApplicationException ae ) {
162             exc = (ae.getRootCause() != null )? ae.getRootCause(): ae;
163             throw exc;
164
165         /*
166          * A system exception would be highly unusual and would indicate a sever
167          * problem with the container system.
168          */

169         } catch ( org.openejb.SystemException se ) {
170             invalidateReference();
171             exc = (se.getRootCause() != null )? se.getRootCause(): se;
172             logger.error("The container received an unexpected exception: ", exc);
173             throw new RemoteException JavaDoc("Container has suffered a SystemException", exc);
174         } catch ( org.openejb.OpenEJBException oe ) {
175             exc = (oe.getRootCause() != null )? oe.getRootCause(): oe;
176             logger.warn("The container received an unexpected exception: ", exc);
177             throw new RemoteException JavaDoc("Unknown Container Exception",oe.getRootCause());
178         }finally {
179             if(logger.isDebugEnabled()) {
180                 if(exc==null) {
181                     logger.debug("finished invoking method "+m.getName()+". Return value:"+retValue);
182                 } else {
183                     logger.debug("finished invoking method "+m.getName()+" with exception "+exc);
184                 }
185             } else if (logger.isInfoEnabled()) {
186                 if(exc==null) {
187                     logger.debug("finished invoking method "+m.getName());
188                 } else {
189                     logger.debug("finished invoking method "+m.getName()+" with exception "+exc);
190                 }
191             }
192         }
193     }
194     
195
196     protected Object JavaDoc getEJBHome(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
197         checkAuthorization(method);
198         return deploymentInfo.getEJBHome();
199     }
200     
201     protected Object JavaDoc getHandle(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
202         checkAuthorization(method);
203         return new IntraVmHandle(proxy);
204     }
205     public org.openejb.ProxyInfo getProxyInfo(){
206         return new org.openejb.ProxyInfo(deploymentInfo, primaryKey, isLocal(), container);
207     }
208     
209     /**
210      * The writeReplace method is invoked on the proxy when it enters the
211      * serialization process. The call is passed to the handler, then delegated
212      * to this method.
213      *
214      * If the proxy is being copied between bean instances in a RPC
215      * call we use the IntraVmArtifact. This object is immutable and does not
216      * need to be dereferenced; therefore, we have no need to actually serialize
217      * this object.
218      *
219      * If the proxy is referenced by a stateful bean that is being
220      * passivated by the container we allow this object to be serialized.
221      *
222      * If the proxy is being serialized in any other context, we know that its
223      * destination is outside the core container system. This is the
224      * responsibility of the Application Server and one of its proxies is
225      * serialized to the stream in place of the IntraVmProxy.
226      *
227      * @param proxy
228      * @return Object
229      * @exception ObjectStreamException
230      */

231     protected Object JavaDoc _writeReplace(Object JavaDoc proxy) throws ObjectStreamException JavaDoc{
232         /*
233          * If the proxy is being copied between bean instances in a RPC
234          * call we use the IntraVmArtifact
235          */

236         if(IntraVmCopyMonitor.isIntraVmCopyOperation()){
237             return new IntraVmArtifact( proxy );
238         /*
239          * If the proxy is referenced by a stateful bean that is being
240          * passivated by the container we allow this object to be serialized.
241          */

242         }else if(IntraVmCopyMonitor.isStatefulPassivationOperation()){
243             return proxy;
244         /*
245          * If the proxy is serialized outside the core container system,
246          * we allow the application server to handle it.
247          */

248         } else{
249             return org.openejb.OpenEJB.getApplicationServer().getEJBObject(this.getProxyInfo());
250         }
251     }
252     
253     protected abstract Object JavaDoc getPrimaryKey(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc;
254     
255     protected abstract Object JavaDoc isIdentical(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc;
256
257     protected abstract Object JavaDoc remove(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc;
258     
259     protected Object JavaDoc businessMethod(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc proxy) throws Throwable JavaDoc{
260         checkAuthorization(method);
261         return container.invoke(deploymentID, method, args, primaryKey, getThreadSpecificSecurityIdentity());
262     }
263 }
264
Popular Tags