KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > EntityInstanceInterceptor


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins;
23
24 import org.jboss.ejb.BeanLock;
25 import org.jboss.ejb.Container;
26 import org.jboss.ejb.EntityContainer;
27 import org.jboss.ejb.EntityEnterpriseContext;
28 import org.jboss.ejb.InstanceCache;
29 import org.jboss.ejb.AllowedOperationsAssociation;
30 import org.jboss.ejb.InstancePool;
31 import org.jboss.invocation.Invocation;
32 import org.jboss.invocation.InvocationType;
33 import org.jboss.util.NestedRuntimeException;
34
35 import javax.ejb.EJBException JavaDoc;
36 import javax.ejb.NoSuchObjectLocalException JavaDoc;
37 import javax.ejb.TimedObject JavaDoc;
38 import javax.ejb.Timer JavaDoc;
39 import javax.transaction.Transaction JavaDoc;
40 import java.lang.reflect.Method JavaDoc;
41 import java.rmi.NoSuchObjectException JavaDoc;
42 import java.rmi.RemoteException JavaDoc;
43
44 /**
45  * The instance interceptors role is to acquire a context representing the
46  * target object from the cache.
47  *
48  * <p>This particular container interceptor implements pessimistic locking on
49  * the transaction that is associated with the retrieved instance. If there is
50  * a transaction associated with the target component and it is different from
51  * the transaction associated with the Invocation coming in then the policy is
52  * to wait for transactional commit.
53  *
54  * <p>We also implement serialization of calls in here (this is a spec
55  * requirement). This is a fine grained notify, notifyAll mechanism. We notify
56  * on ctx serialization locks and notifyAll on global transactional locks.
57  *
58  * <p><b>WARNING: critical code</b>, get approval from senior developers before
59  * changing.
60  * @author <a HREF="mailto:marc.fleury@jboss.org">Marc Fleury</a>
61  * @author <a HREF="mailto:Scott.Stark@jboss.org">Scott Stark</a>
62  * @author <a HREF="mailto:bill@burkecentral.com">Bill Burke</a>
63  * @author <a HREF="mailto:mkgarnek@hotmail.com">Jamie Burns</a>
64  * @version $Revision: 37459 $
65  */

66 public class EntityInstanceInterceptor
67    extends AbstractInterceptor
68 {
69    // Constants -----------------------------------------------------
70

71    // Attributes ----------------------------------------------------
72

73    protected EntityContainer container;
74
75    // Static --------------------------------------------------------
76

77    /** A reference to {@link javax.ejb.TimedObject#ejbTimeout}. */
78    protected static final Method JavaDoc ejbTimeout;
79
80    static
81    {
82       try
83       {
84          ejbTimeout = TimedObject JavaDoc.class.getMethod("ejbTimeout", new Class JavaDoc[]{Timer JavaDoc.class});
85       }
86       catch (Exception JavaDoc e)
87       {
88          throw new ExceptionInInitializerError JavaDoc(e);
89       }
90    }
91
92    // Constructors --------------------------------------------------
93

94    // Public --------------------------------------------------------
95

96    public void setContainer(Container container)
97    {
98       this.container = (EntityContainer) container;
99    }
100
101    public Container getContainer()
102    {
103       return container;
104    }
105
106    // Interceptor implementation --------------------------------------
107

108    public Object JavaDoc invokeHome(Invocation mi)
109       throws Exception JavaDoc
110    {
111       // Get context
112
EntityContainer container = (EntityContainer) getContainer();
113       EntityEnterpriseContext ctx = (EntityEnterpriseContext) container.getInstancePool().get();
114       InstancePool pool = container.getInstancePool();
115
116       // Pass it to the method invocation
117
mi.setEnterpriseContext(ctx);
118    
119       // Give it the transaction
120
ctx.setTransaction(mi.getTransaction());
121    
122       // Set the current security information
123
ctx.setPrincipal(mi.getPrincipal());
124
125       AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_HOME);
126       
127       // Invoke through interceptors
128

129       Object JavaDoc obj = null;
130       Exception JavaDoc exception = null;
131
132       try
133       {
134          obj = getNext().invokeHome(mi);
135           
136          // Is the context now with an identity? in which case we need to insert
137
if (ctx.getId() != null)
138          {
139             BeanLock lock = container.getLockManager().getLock(ctx.getCacheKey());
140             lock.sync(); // lock all access to BeanLock
141
try
142             {
143                // Check there isn't a context already in the cache
144
// e.g. commit-option B where the entity was
145
// created then removed externally
146
InstanceCache cache = container.getInstanceCache();
147                cache.remove(ctx.getCacheKey());
148        
149                // marcf: possible race on creation and usage
150
// insert instance in cache,
151
cache.insert(ctx);
152             }
153             finally
154             {
155                lock.releaseSync();
156                container.getLockManager().removeLockRef(ctx.getCacheKey());
157             }
158              
159             // we are all done
160
return obj;
161          }
162       }
163       catch (Exception JavaDoc e)
164       {
165          exception = e;
166       }
167       finally
168       {
169          AllowedOperationsAssociation.popInMethodFlag();
170       }
171
172       ctx.setTransaction(null);
173       // EntityCreateInterceptor will access ctx if it is not null and call postCreate
174
mi.setEnterpriseContext(null);
175       
176       // if we get to here with a null exception then our invocation is
177
// just a home invocation. Return our instance to the instance pool
178
if (exception == null)
179       {
180          container.getInstancePool().free(ctx);
181          return obj;
182       }
183       
184       if (exception instanceof RuntimeException JavaDoc)
185       {
186          // if we get to here with a RuntimeException, we have a system exception.
187
// EJB 2.1 section 18.3.1 says we need to discard our instance.
188
pool.discard(ctx);
189       }
190       else
191       {
192          // if we get to here with an Exception, we have an application exception.
193
// EJB 2.1 section 18.3.1 says we can keep the instance. We need to return
194
// our instance to the instance pool so we dont get a memory leak.
195
pool.free(ctx);
196       }
197       
198       throw exception;
199    }
200
201
202    public Object JavaDoc invoke(Invocation mi)
203       throws Exception JavaDoc
204    {
205       boolean trace = log.isTraceEnabled();
206
207       // The key
208
Object JavaDoc key = mi.getId();
209
210       // The context
211
EntityEnterpriseContext ctx;
212       try
213       {
214          ctx = (EntityEnterpriseContext) container.getInstanceCache().get(key);
215       }
216       catch (NoSuchObjectException JavaDoc e)
217       {
218          if (mi.isLocal())
219             throw new NoSuchObjectLocalException JavaDoc(e.getMessage());
220          else
221             throw e;
222       }
223       catch (EJBException JavaDoc e)
224       {
225          throw e;
226       }
227       catch (RemoteException JavaDoc e)
228       {
229          throw e;
230       }
231       catch (Exception JavaDoc e)
232       {
233          InvocationType type = mi.getType();
234          boolean isLocal = (type == InvocationType.LOCAL || type == InvocationType.LOCALHOME);
235          if (isLocal)
236             throw new EJBException JavaDoc("Unable to get an instance from the pool/cache", e);
237          else
238             throw new RemoteException JavaDoc("Unable to get an intance from the pool/cache", e);
239       }
240
241       if (trace) log.trace("Begin invoke, key=" + key);
242
243       // Associate transaction, in the new design the lock already has the transaction from the
244
// previous interceptor
245

246       // Don't set the transction if a read-only method. With a read-only method, the ctx can be shared
247
// between multiple transactions.
248
Transaction JavaDoc tx = mi.getTransaction();
249       if (!container.isReadOnly())
250       {
251          Method JavaDoc method = mi.getMethod();
252          if (method == null ||
253             !container.getBeanMetaData().isMethodReadOnly(method.getName()))
254          {
255             ctx.setTransaction(tx);
256          }
257       }
258
259       // Set the current security information
260
ctx.setPrincipal(mi.getPrincipal());
261       // Set the JACC EnterpriseBean PolicyContextHandler data
262
EnterpriseBeanPolicyContextHandler.setEnterpriseBean(ctx.getInstance());
263
264       // Set context on the method invocation
265
mi.setEnterpriseContext(ctx);
266
267       if (ejbTimeout.equals(mi.getMethod()))
268          AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_TIMEOUT);
269       else
270          AllowedOperationsAssociation.pushInMethodFlag(IN_BUSINESS_METHOD);
271
272       Throwable JavaDoc exceptionThrown = null;
273       boolean discardContext = false;
274       try
275       {
276          Object JavaDoc obj = getNext().invoke(mi);
277          return obj;
278       }
279       catch (RemoteException JavaDoc e)
280       {
281          exceptionThrown = e;
282          discardContext = true;
283          throw e;
284       }
285       catch (RuntimeException JavaDoc e)
286       {
287          exceptionThrown = e;
288          discardContext = true;
289          throw e;
290       }
291       catch (Error JavaDoc e)
292       {
293          exceptionThrown = e;
294          discardContext = true;
295          throw e;
296       }
297       catch (Exception JavaDoc e)
298       {
299          exceptionThrown = e;
300          throw e;
301       }
302       catch (Throwable JavaDoc e)
303       {
304          exceptionThrown = e;
305          discardContext = true;
306          throw new NestedRuntimeException(e);
307       }
308       finally
309       {
310          AllowedOperationsAssociation.popInMethodFlag();
311
312          // Make sure we clear the transaction on an error before synchronization.
313
// But avoid a race with a transaction rollback on a synchronization
314
// that may have moved the context onto a different transaction
315
if (exceptionThrown != null && tx != null)
316          {
317             Transaction JavaDoc ctxTx = ctx.getTransaction();
318             if (tx.equals(ctxTx) && ctx.hasTxSynchronization() == false)
319                ctx.setTransaction(null);
320          }
321
322          // If an exception has been thrown,
323
if (exceptionThrown != null &&
324             // if tx, the ctx has been registered in an InstanceSynchronization.
325
// that will remove the context, so we shouldn't.
326
// if no synchronization then we need to do it by hand
327
// But not for application exceptions
328
!ctx.hasTxSynchronization() && discardContext)
329          {
330             // Discard instance
331
// EJB 1.1 spec 12.3.1
332
container.getInstanceCache().remove(key);
333
334             if (trace) log.trace("Ending invoke, exceptionThrown, ctx=" + ctx, exceptionThrown);
335          }
336          else if (ctx.getId() == null)
337          {
338             // The key from the Invocation still identifies the right cachekey
339
container.getInstanceCache().remove(key);
340
341             if (trace) log.trace("Ending invoke, cache removal, ctx=" + ctx);
342             // no more pool return
343
}
344
345          if (trace) log.trace("End invoke, key=" + key + ", ctx=" + ctx);
346
347       } // end invoke
348
}
349 }
350
351
Popular Tags