KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.lang.reflect.Method JavaDoc;
25 import java.rmi.RemoteException JavaDoc;
26 import javax.ejb.EJBObject JavaDoc;
27 import javax.ejb.EJBException JavaDoc;
28 import javax.transaction.Transaction JavaDoc;
29 import javax.transaction.Status JavaDoc;
30
31 import org.jboss.invocation.Invocation;
32 import org.jboss.invocation.InvocationType;
33 import org.jboss.ejb.Container;
34 import org.jboss.ejb.EntityEnterpriseContext;
35 import org.jboss.metadata.EntityMetaData;
36 import org.jboss.ejb.plugins.lock.Entrancy;
37 import org.jboss.ejb.plugins.lock.NonReentrantLock;
38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.CMRInvocation;
39
40 /**
41  * The role of this interceptor is to check for reentrancy.
42  * Per the spec, throw an exception if instance is not marked
43  * as reentrant. We do not check to see if same Tx is
44  * accessing object at the same time as we assume that
45  * any transactional locks will handle this.
46  *
47  * <p><b>WARNING: critical code</b>, get approval from senior developers
48  * before changing.
49  *
50  * @author <a HREF="mailto:bill@burkecentral.com">Bill Burke</a>
51  * @version $Revision: 37459 $
52  */

53 public class EntityReentranceInterceptor
54         extends AbstractInterceptor
55 {
56    protected boolean reentrant = false;
57
58    // Public --------------------------------------------------------
59

60    public void setContainer(Container container)
61    {
62       super.setContainer(container);
63       if (container != null)
64       {
65          EntityMetaData meta = (EntityMetaData) container.getBeanMetaData();
66          reentrant = meta.isReentrant();
67       }
68    }
69
70    protected boolean isTxExpired(Transaction JavaDoc miTx) throws Exception JavaDoc
71    {
72       if (miTx != null && miTx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
73       {
74          return true;
75       }
76       return false;
77    }
78
79    public Object JavaDoc invoke(Invocation mi)
80            throws Exception JavaDoc
81    {
82       // We are going to work with the context a lot
83
EntityEnterpriseContext ctx = (EntityEnterpriseContext) mi.getEnterpriseContext();
84       boolean nonReentrant = !(reentrant || isReentrantMethod(mi));
85
86       // Not a reentrant method like getPrimaryKey
87
NonReentrantLock methodLock = ctx.getMethodLock();
88       Transaction JavaDoc miTx = ctx.getTransaction();
89       boolean locked = false;
90       try
91       {
92          while (!locked)
93          {
94             if (methodLock.attempt(5000, miTx, nonReentrant))
95             {
96                locked = true;
97             }
98             else
99             {
100                if (isTxExpired(miTx))
101                {
102                   log.error("Saw rolled back tx=" + miTx);
103                   throw new RuntimeException JavaDoc("Transaction marked for rollback, possibly a timeout");
104                }
105             }
106          }
107       }
108       catch (NonReentrantLock.ReentranceException re)
109       {
110          if (mi.getType() == InvocationType.REMOTE)
111          {
112             throw new RemoteException JavaDoc("Reentrant method call detected: "
113                     + container.getBeanMetaData().getEjbName() + " "
114                     + ctx.getId().toString());
115          }
116          else
117          {
118             throw new EJBException JavaDoc("Reentrant method call detected: "
119                     + container.getBeanMetaData().getEjbName() + " "
120                     + ctx.getId().toString());
121          }
122       }
123       try
124       {
125          ctx.lock();
126          return getNext().invoke(mi);
127       }
128       finally
129       {
130          ctx.unlock();
131          methodLock.release(nonReentrant);
132       }
133    }
134
135    // Private ------------------------------------------------------
136

137    private static final Method JavaDoc getEJBHome;
138    private static final Method JavaDoc getHandle;
139    private static final Method JavaDoc getPrimaryKey;
140    private static final Method JavaDoc isIdentical;
141    private static final Method JavaDoc remove;
142
143    static
144    {
145       try
146       {
147          Class JavaDoc[] noArg = new Class JavaDoc[0];
148          getEJBHome = EJBObject JavaDoc.class.getMethod("getEJBHome", noArg);
149          getHandle = EJBObject JavaDoc.class.getMethod("getHandle", noArg);
150          getPrimaryKey = EJBObject JavaDoc.class.getMethod("getPrimaryKey", noArg);
151          isIdentical = EJBObject JavaDoc.class.getMethod("isIdentical", new Class JavaDoc[]{EJBObject JavaDoc.class});
152          remove = EJBObject JavaDoc.class.getMethod("remove", noArg);
153       }
154       catch (Exception JavaDoc e)
155       {
156          e.printStackTrace();
157          throw new ExceptionInInitializerError JavaDoc(e);
158       }
159    }
160
161    protected boolean isReentrantMethod(Invocation mi)
162    {
163       // is this a known non-entrant method
164
Method JavaDoc m = mi.getMethod();
165       if (m != null && (
166               m.equals(getEJBHome) ||
167               m.equals(getHandle) ||
168               m.equals(getPrimaryKey) ||
169               m.equals(isIdentical) ||
170               m.equals(remove)))
171       {
172          return true;
173       }
174
175       // if this is a non-entrant message to the container let it through
176
if (mi instanceof CMRInvocation)
177       {
178          Entrancy entrancy = ((CMRInvocation) mi).getEntrancy();
179          if (entrancy == Entrancy.NON_ENTRANT)
180          {
181             log.trace("NON_ENTRANT invocation");
182             return true;
183          }
184       }
185
186       return false;
187    }
188
189 }
190
Popular Tags