KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb3 > cache > tree > StatefulTreeCache


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.ejb3.cache.tree;
23
24 import java.util.Map JavaDoc;
25
26 import javax.ejb.EJBException JavaDoc;
27 import javax.ejb.NoSuchEJBException JavaDoc;
28 import javax.management.MBeanServer JavaDoc;
29 import javax.management.ObjectName JavaDoc;
30
31 import org.jboss.aop.Advisor;
32 import org.jboss.cache.eviction.EvictionPolicyConfig;
33 import org.jboss.cache.eviction.LRUConfiguration;
34 import org.jboss.cache.jmx.CacheJmxWrapperMBean;
35 import org.jboss.cache.AbstractCacheListener;
36 import org.jboss.cache.Cache;
37 import org.jboss.cache.CacheException;
38 import org.jboss.cache.CacheSPI;
39 import org.jboss.cache.InvocationContext;
40 import org.jboss.cache.Region;
41 import org.jboss.ejb3.Container;
42 import org.jboss.ejb3.Pool;
43 import org.jboss.ejb3.cache.ClusteredStatefulCache;
44 import org.jboss.ejb3.stateful.StatefulBeanContext;
45 import org.jboss.mx.util.MBeanProxyExt;
46 import org.jboss.mx.util.MBeanServerLocator;
47 import org.jboss.logging.Logger;
48 import org.jboss.annotation.ejb.cache.tree.CacheConfig;
49
50 import org.jboss.cache.Fqn;
51 import org.jboss.cache.config.Option;
52
53 /**
54  * Comment
55  *
56  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
57  * @version $Revision: 58552 $
58  */

59 public class StatefulTreeCache implements ClusteredStatefulCache
60 {
61    protected static Logger log = Logger.getLogger(StatefulTreeCache.class);
62    static int FQN_SIZE = 2; // depth of fqn that we store the session in.
63

64    private static Option BYPASS_OPTION = new Option();
65    private static Option LOCAL_ONLY_OPTION = new Option();
66    static
67    {
68       BYPASS_OPTION.setBypassInterceptorChain(true);
69       LOCAL_ONLY_OPTION.setCacheModeLocal(true);
70    }
71    
72    private Pool pool;
73    private Cache cache;
74    private Fqn cacheNode;
75    private Region region;
76    private ClusteredStatefulCacheListener listener;
77    
78    public static long MarkInUseWaitTime = 15000;
79
80    public StatefulBeanContext create()
81    {
82       StatefulBeanContext ctx = null;
83       try
84       {
85          ctx = (StatefulBeanContext) pool.get();
86          cache.put(new Fqn(cacheNode, ctx.getId()), "bean", ctx);
87          ctx.inUse = true;
88          ctx.lastUsed = System.currentTimeMillis();
89       }
90       catch (EJBException JavaDoc e)
91       {
92          throw e;
93       }
94       catch (Exception JavaDoc e)
95       {
96          throw new EJBException JavaDoc(e);
97       }
98       return ctx;
99    }
100
101    public StatefulBeanContext create(Class JavaDoc[] initTypes, Object JavaDoc[] initValues)
102    {
103       StatefulBeanContext ctx = null;
104       try
105       {
106          ctx = (StatefulBeanContext) pool.get(initTypes, initValues);
107          Fqn id = new Fqn(cacheNode, ctx.getId());
108          cache.put(id, "bean", ctx);
109          ctx.inUse = true;
110          ctx.lastUsed = System.currentTimeMillis();
111       }
112       catch (EJBException JavaDoc e)
113       {
114          throw e;
115       }
116       catch (Exception JavaDoc e)
117       {
118          throw new EJBException JavaDoc(e);
119       }
120       return ctx;
121    }
122
123    public StatefulBeanContext get(Object JavaDoc key) throws EJBException JavaDoc
124    {
125       StatefulBeanContext entry = null;
126       Fqn id = new Fqn(cacheNode, key);
127       try
128       {
129          Object JavaDoc obj = cache.get(id, "bean");
130          entry = (StatefulBeanContext) obj;
131       }
132       catch (CacheException e)
133       {
134          throw new RuntimeException JavaDoc(e);
135       }
136       if (entry == null)
137       {
138          throw new NoSuchEJBException JavaDoc("Could not find Stateful bean: " + key);
139       }
140       entry.inUse = true;
141       // Mark it to eviction thread that don't passivate it yet.
142
// Note the Fqn we use is relative to the region!
143
region.markNodeCurrentlyInUse(new Fqn(key), MarkInUseWaitTime);
144       if(log.isDebugEnabled())
145       {
146          log.debug("get: retrieved bean with cache id " +id.toString());
147       }
148
149       entry.lastUsed = System.currentTimeMillis();
150       return entry;
151    }
152
153    public void remove(Object JavaDoc key)
154    {
155       Fqn id = new Fqn(cacheNode, key);
156       try
157       {
158          if(log.isDebugEnabled())
159          {
160             log.debug("remove: cache id " +id.toString());
161          }
162          cache.removeNode(id);
163       }
164       catch (CacheException e)
165       {
166          throw new RuntimeException JavaDoc(e);
167       }
168    }
169
170    public void finished(StatefulBeanContext ctx)
171    {
172       synchronized (ctx)
173       {
174          ctx.inUse = false;
175          ctx.lastUsed = System.currentTimeMillis();
176          // OK, it is free to passivate now.
177
// Note the Fqn we use is relative to the region!
178
region.unmarkNodeCurrentlyInUse(new Fqn(ctx.getId()));
179       }
180    }
181
182    public void replicate(StatefulBeanContext ctx)
183    {
184       try
185       {
186          cache.put(new Fqn(cacheNode, ctx.getId()), "bean", ctx);
187       }
188       catch (CacheException e)
189       {
190          throw new RuntimeException JavaDoc(e);
191       }
192    }
193
194    public void initialize(Container container) throws Exception JavaDoc
195    {
196       Advisor advisor = (Advisor) container;
197       this.pool = container.getPool();
198       CacheConfig config = (CacheConfig) advisor.resolveAnnotation(CacheConfig.class);
199       MBeanServer JavaDoc server = MBeanServerLocator.locateJBoss();
200       ObjectName JavaDoc cacheON = new ObjectName JavaDoc(config.name());
201       CacheJmxWrapperMBean mbean = (CacheJmxWrapperMBean) MBeanProxyExt.create(CacheJmxWrapperMBean.class, cacheON, server);
202       cache = mbean.getCache();
203
204       cacheNode = Fqn.fromString("/" + container.getEjbName() + "/");
205
206       // Try to create an eviction region per ejb
207
region = cache.getRegion(cacheNode, true);
208       EvictionPolicyConfig epc = getEvictionPolicyConfig((int) config.idleTimeoutSeconds(),
209             config.maxSize());
210       region.setEvictionPolicy(epc);
211       // BES 11/16/2006 uncomment if we switch to per-region marshalling
212
// region.registerContextClassLoader(Thread.currentThread().getContextClassLoader());
213
// region.activate();
214
log.debug("initialize(): created eviction region: " +region + " for ejb: " +container.getEjbName());
215    }
216    
217    protected EvictionPolicyConfig getEvictionPolicyConfig(int timeToLiveSeconds, int maxNodes)
218    {
219       LRUConfiguration epc = new LRUConfiguration();
220       epc.setTimeToLiveSeconds(timeToLiveSeconds);
221       epc.setMaxNodes(maxNodes);
222       return epc;
223    }
224
225    public void start()
226    {
227       // register to listen for cache event
228
// TODO this approach may not be scalable when there are many beans since then we will need to go thru
229
// N listeners to figure out which this event this belongs to.
230
listener = new ClusteredStatefulCacheListener();
231       cache.addCacheListener(listener);
232    }
233
234    public void stop()
235    {
236       // Remove the listener
237
cache.removeCacheListener(listener);
238       
239       // BES 11/16/2006 uncomment if we switch to per-region marshalling
240
// If we do, we don't need to remove the node below; deactivate() does it
241
// if (region != null)
242
// {
243
// region.deactivate();
244
// region.unregisterContextClassLoader();
245
// }
246

247       // FIXME this method needs to be in Cache
248
((CacheSPI) cache).getRegionManager().removeRegion(region.getFqn());
249       // Clear any queues
250
region.resetEvictionQueues();
251       region = null;
252       
253       try {
254          // remove locally.
255
InvocationContext ctx = cache.getInvocationContext();
256          ctx.setOptionOverrides(getLocalOnlyOption());
257          cache.removeNode(cacheNode);
258       }
259       catch (CacheException e)
260       {
261          log.error("Stop(): can't remove bean from the underlying distributed cache");
262       }
263
264       log.debug("stop(): StatefulTreeCache stopped successfully for " +cacheNode);
265    }
266
267    /**
268     * A TreeCacheListener. Note that extends it from AbstractTreeCacheListener is a bit heavy since
269     * it will get all the treecache events (instead of just passivation/activation). But we will have to
270     * wait untill JBossCache2.0 for the refactoring then.
271     */

272    public class ClusteredStatefulCacheListener extends AbstractCacheListener
273    {
274       protected Logger log = Logger.getLogger(ClusteredStatefulCacheListener.class);
275
276       // BES 11/18/2006 this was causing stack overflow; switched to nodeLoaded,
277
// which gives direct access to the data
278
// @Override
279
// public void nodeActivated(Fqn fqn, boolean pre) {
280
// if(pre) return; // we are not interested in preActivate event
281
// if(fqn.size() != FQN_SIZE) return;
282
// if(!fqn.isChildOrEquals(cacheNode)) return; // don't care about fqn that doesn't belong to me.
283
//
284
// StatefulBeanContext bean = null;
285
// try {
286
// // TODO Can this cause deadlock in the cache level? Should be ok but need review.
287
// bean = (StatefulBeanContext) cache.get(fqn, "bean");
288
// } catch (CacheException e) {
289
// log.error("nodeActivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
290
// return;
291
// }
292
//
293
// if(bean == null)
294
// {
295
// throw new IllegalStateException("nodeActivate(): null bean instance.");
296
// }
297
//
298
//// log.debug("nodeActivate(): send postActivate event on fqn: " +fqn);
299
// if(log.isTraceEnabled())
300
// {
301
// log.trace("nodeActivate(): send postActivate event on fqn: " +fqn);
302
// }
303
//
304
// bean.postActivate();
305
// }
306

307       @Override JavaDoc
308       public void nodeLoaded(Fqn fqn, boolean pre, Map JavaDoc nodeData)
309       {
310          if(pre) return; // we are not interested in preActivate event
311
if(fqn.size() != FQN_SIZE) return;
312          if(!fqn.isChildOrEquals(cacheNode)) return; // don't care about fqn that doesn't belong to me.
313
if (nodeData == null) return;
314          
315          StatefulBeanContext bean = (StatefulBeanContext) nodeData.get("bean");
316          
317          if(bean == null)
318          {
319             throw new IllegalStateException JavaDoc("nodeActivate(): null bean instance.");
320          }
321
322 // log.debug("nodeActivate(): send postActivate event on fqn: " +fqn);
323
if(log.isTraceEnabled())
324          {
325             log.trace("nodeActivate(): send postActivate event on fqn: " +fqn);
326          }
327
328          bean.postActivate();
329          
330       }
331
332       @Override JavaDoc
333       public void nodePassivated(Fqn fqn, boolean pre) {
334          if(!pre) return; // we are not interested in postPassivate event
335
if(fqn.size() != FQN_SIZE) return;
336          if(!fqn.isChildOrEquals(cacheNode)) return; // don't care about fqn that doesn't belong to me.
337

338          
339          try {
340             InvocationContext ctx = cache.getInvocationContext();
341             ctx.setOptionOverrides(getBypassOption());
342             StatefulBeanContext bean = (StatefulBeanContext) cache.get(fqn, "bean");
343             if (bean != null && !bean.inUse)
344                bean.prePassivate();
345
346          } catch (CacheException e) {
347             log.error("nodePassivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
348             return;
349          }
350
351 // log.debug("nodePassivate(): send prePassivate event on fqn: " +fqn);
352
if(log.isTraceEnabled())
353          {
354             log.trace("nodePassivate(): send prePassivate event on fqn: " +fqn);
355          }
356
357       }
358    }
359    
360    private Option getBypassOption()
361    {
362       try
363       {
364          return BYPASS_OPTION.clone();
365       }
366       catch (CloneNotSupportedException JavaDoc e)
367       {
368          throw new RuntimeException JavaDoc(e);
369       }
370    }
371    
372    private Option getLocalOnlyOption()
373    {
374       try
375       {
376          return LOCAL_ONLY_OPTION.clone();
377       }
378       catch (CloneNotSupportedException JavaDoc e)
379       {
380          throw new RuntimeException JavaDoc(e);
381       }
382    }
383 }
384
Popular Tags