KickJava   Java API By Example, From Geeks To Geeks.

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


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.Constructor JavaDoc;
25 import java.rmi.NoSuchObjectException JavaDoc;
26 import java.rmi.RemoteException JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.jboss.deployment.DeploymentException;
30 import org.jboss.ejb.BeanLock;
31 import org.jboss.ejb.BeanLockExt;
32 import org.jboss.ejb.Container;
33 import org.jboss.ejb.EnterpriseContext;
34 import org.jboss.ejb.InstanceCache;
35 import org.jboss.logging.Logger;
36 import org.jboss.metadata.MetaData;
37 import org.jboss.metadata.XmlLoadable;
38 import org.jboss.monitor.MetricsConstants;
39 import org.jboss.monitor.Monitorable;
40 import org.jboss.monitor.client.BeanCacheSnapshot;
41 import org.jboss.util.CachePolicy;
42 import org.w3c.dom.Element JavaDoc;
43
44 /**
45  * Base class for caches of entity and stateful beans. <p>
46  * It manages the cache entries through a {@link CachePolicy} object;
47  * the implementation of the cache policy object must respect the following
48  * requirements:
49  * <ul>
50  * <li> Have a public constructor that takes a single argument of type
51  * AbstractInstanceCache.class or a subclass
52  * </ul>
53  *
54  * @author <a HREF="mailto:simone.bordet@compaq.com">Simone Bordet</a>
55  * @author <a HREF="bill@burkecentral.com">Bill Burke</a>
56  * @author <a HREF="marc.fleury@jboss.org">Marc Fleury</a>
57  * @author Scott.Stark@jboss.org
58  * @version $Revision: 43998 $
59  * @jmx:mbean
60  */

61 public abstract class AbstractInstanceCache
62    implements InstanceCache, XmlLoadable, Monitorable, MetricsConstants,
63       AbstractInstanceCacheMBean
64 {
65    // Constants -----------------------------------------------------
66

67    // Attributes ----------------------------------------------------
68
protected static Logger log = Logger.getLogger(AbstractInstanceCache.class);
69
70    /* The object that is delegated to implement the desired caching policy */
71    private CachePolicy m_cache;
72    /* The mutex object for the cache */
73    private final Object JavaDoc m_cacheLock = new Object JavaDoc();
74
75    // Static --------------------------------------------------------
76

77    // Constructors --------------------------------------------------
78

79    // Monitorable implementation ------------------------------------
80
public void sample(Object JavaDoc s)
81    {
82       if( m_cache == null )
83          return;
84
85       synchronized (getCacheLock())
86       {
87          BeanCacheSnapshot snapshot = (BeanCacheSnapshot)s;
88          snapshot.m_passivatingBeans = 0;
89          CachePolicy policy = getCache();
90          if (policy instanceof Monitorable)
91          {
92             ((Monitorable)policy).sample(s);
93          }
94       }
95    }
96    public Map JavaDoc retrieveStatistic()
97    {
98       return null;
99    }
100    public void resetStatistic()
101    {
102    }
103
104    // Public --------------------------------------------------------
105
/* From InstanceCache interface */
106    public EnterpriseContext get(Object JavaDoc id)
107       throws RemoteException JavaDoc, NoSuchObjectException JavaDoc
108    {
109       if (id == null) throw new IllegalArgumentException JavaDoc("Can't get an object with a null key");
110
111       EnterpriseContext ctx;
112
113       synchronized (getCacheLock())
114       {
115          CachePolicy cache = getCache();
116          ctx = (EnterpriseContext)cache.get(id);
117          if (ctx == null)
118          {
119             try
120             {
121                ctx = acquireContext();
122                setKey(id, ctx);
123                if (doActivate(ctx) == false)
124                   // This is a recursive activation
125
return ctx;
126                logActivation(id);
127                // the cache will throw an IllegalStateException if we try to insert
128
// something that is in the cache already, so we don't check here
129
cache.insert(id, ctx);
130             }
131             catch (Throwable JavaDoc x)
132             {
133                log.debug("Activation failure", x);
134                throw new NoSuchObjectException JavaDoc(x.getMessage());
135             }
136          }
137       }
138
139       return ctx;
140    }
141
142    /* From InstanceCache interface */
143    public void insert(EnterpriseContext ctx)
144    {
145       if (ctx == null) throw new IllegalArgumentException JavaDoc("Can't insert a null object in the cache");
146
147       Object JavaDoc key = getKey(ctx);
148       synchronized (getCacheLock())
149       {
150          // the cache will throw an IllegalStateException if we try to insert
151
// something that is in the cache already, so we don't check here
152
getCache().insert(key, ctx);
153       }
154    }
155
156    /**
157     * Tries to passivate the instance. If the instance is in use then the instance
158     * will be passivated later according to the container's commit option and max age.
159     */

160    protected void tryToPassivate(EnterpriseContext ctx)
161    {
162       tryToPassivate(ctx, false);
163    }
164
165    /**
166     * Tries to passivate the instance. If the instance is in use and passivateAfterCommit
167     * parameter is true then the instance will passivated after the transaction commits.
168     * Otherwise, the instance will be passivated later according to the container's
169     * commit option and max age.
170     */

171    protected void tryToPassivate(EnterpriseContext ctx, boolean passivateAfterCommit)
172    {
173       Object JavaDoc id = ctx.getId();
174       if (id == null) return;
175       BeanLock lock = getContainer().getLockManager().getLock(id);
176       boolean lockedBean = false;
177       try
178       {
179          /* If this is a BeanLockExt only attempt the lock as the call to
180          remove is going to have to acquire the cache lock, but this may already
181          be held since this method is called by passivation policies without
182          the cache lock. This can lead to a deadlock as in the case of a size based
183          eviction during a cache get attempts to lock the bean that has been
184          locked by an age based background thread as seen in bug 987389 on
185          sourceforge.
186          */

187          if( lock instanceof BeanLockExt )
188          {
189             BeanLockExt lock2 = (BeanLockExt) lock;
190             lockedBean = lock2.attemptSync();
191             if( lockedBean == false )
192             {
193                unableToPassivateDueToCtxLock(ctx, passivateAfterCommit);
194                return;
195             }
196          }
197          else
198          {
199             // Use the blocking sync
200
lock.sync();
201             lockedBean = true;
202          }
203
204          if (canPassivate(ctx))
205          {
206             try
207             {
208                remove(id);
209                passivate(ctx);
210                freeContext(ctx);
211             }
212             catch (Exception JavaDoc ignored)
213             {
214                log.warn("failed to passivate, id="+id, ignored);
215             }
216          }
217          else
218          {
219             // Touch the entry to make it MRU
220
synchronized (getCacheLock())
221             {
222                getCache().get(id);
223             }
224
225             unableToPassivateDueToCtxLock(ctx, passivateAfterCommit);
226          }
227       }
228       finally
229       {
230          if( lockedBean )
231             lock.releaseSync();
232          getContainer().getLockManager().removeLockRef(id);
233       }
234    }
235
236    /**
237     * Passivates and removes the instance from the cache.
238     * If the instance is in use then removal and passivation will be scheduled until
239     * after transaction ends
240     */

241    public void release(EnterpriseContext ctx)
242    {
243       if (ctx == null) throw new IllegalArgumentException JavaDoc("Can't release a null object");
244
245       // Here I remove the bean; call to remove(id) is wrong
246
// cause will remove also the cache lock that is needed
247
// by the passivation, that eventually will remove it.
248
/* the removal should only be done if the instance is not in use.
249          this is taken care of in tryToPassivate
250       Object id = getKey(ctx);
251       synchronized (getCacheLock())
252       {
253          if (getCache().peek(id) != null)
254             getCache().remove(id);
255       }
256       */

257       tryToPassivate(ctx, true);
258    }
259
260    /**
261     * From InstanceCache interface
262     * @jmx:managed-operation
263     */

264    public void remove(Object JavaDoc id)
265    {
266       if (id == null) throw new IllegalArgumentException JavaDoc("Can't remove an object using a null key");
267
268       synchronized (getCacheLock())
269       {
270          if (getCache().peek(id) != null)
271          {
272             getCache().remove(id);
273          }
274       }
275    }
276
277    public boolean isActive(Object JavaDoc id)
278    {
279       // Check whether an object with the given id is available in the cache
280
synchronized (getCacheLock())
281       {
282          return getCache().peek(id) != null;
283       }
284    }
285
286    /** Get the current cache size
287     * @jmx:managed-attribute
288     * @return the size of the cache
289     */

290    public long getCacheSize()
291    {
292       int cacheSize = m_cache != null ? m_cache.size() : 0;
293       return cacheSize;
294    }
295    /** Flush the cache.
296     * @jmx:managed-operation
297     */

298    public void flush()
299    {
300       if( m_cache != null )
301          m_cache.flush();
302    }
303    /** Get the passivated count.
304     * @jmx:managed-attribute
305     * @return the number of passivated instances.
306     */

307    public long getPassivatedCount()
308    {
309       return 0;
310    }
311
312    /**
313     * Display the cache policy.
314     *
315     * @jmx:managed-attribute
316     * @return the cache policy as a string.
317     */

318    public String JavaDoc getCachePolicyString()
319    {
320       return m_cache.toString();
321    }
322    
323    // XmlLoadable implementation ----------------------------------------------
324
public void importXml(Element JavaDoc element) throws DeploymentException
325    {
326       // This one is mandatory
327
String JavaDoc p = MetaData.getElementContent(MetaData.getUniqueChild(element, "cache-policy"));
328       try
329       {
330          Class JavaDoc cls = SecurityActions.getContextClassLoader().loadClass(p);
331          Constructor JavaDoc ctor = cls.getConstructor(new Class JavaDoc[] {AbstractInstanceCache.class});
332          m_cache = (CachePolicy)ctor.newInstance(new Object JavaDoc[] {this});
333       }
334       catch (Exception JavaDoc x)
335       {
336          throw new DeploymentException("Can't create cache policy", x);
337       }
338
339       Element JavaDoc policyConf = MetaData.getOptionalChild(element, "cache-policy-conf");
340       if (policyConf != null)
341       {
342          if (m_cache instanceof XmlLoadable)
343          {
344             try
345             {
346                ((XmlLoadable)m_cache).importXml(policyConf);
347             }
348             catch (Exception JavaDoc x)
349             {
350                throw new DeploymentException("Can't import policy configuration", x);
351             }
352          }
353       }
354    }
355
356    /* From Service interface*/
357    public void create() throws Exception JavaDoc
358    {
359       getCache().create();
360    }
361    /* From Service interface*/
362    public void start() throws Exception JavaDoc
363    {
364       getCache().start();
365    }
366    /* From Service interface*/
367    public void stop()
368    {
369       // Empty the cache
370
synchronized (getCacheLock())
371       {
372          getCache().stop();
373       }
374    }
375    /* From Service interface*/
376    public void destroy()
377    {
378       synchronized (getCacheLock())
379       {
380          getCache().destroy();
381       }
382       this.m_cache = null;
383    }
384
385    // Y overrides ---------------------------------------------------
386

387    // Package protected ---------------------------------------------
388

389    // Protected -----------------------------------------------------
390
protected void logActivation(Object JavaDoc id)
391    {
392       if( log.isTraceEnabled() )
393       {
394          StringBuffer JavaDoc m_buffer=new StringBuffer JavaDoc(100);
395          m_buffer.append("Activated bean ");
396          m_buffer.append(getContainer().getBeanMetaData().getEjbName());
397          m_buffer.append(" with id = ");
398          m_buffer.append(id);
399          log.trace(m_buffer.toString());
400       }
401    }
402
403    protected void logPassivation(Object JavaDoc id)
404    {
405       if( log.isTraceEnabled() )
406       {
407          StringBuffer JavaDoc m_buffer=new StringBuffer JavaDoc(100);
408          m_buffer.append("Passivated bean ");
409          m_buffer.append(getContainer().getBeanMetaData().getEjbName());
410          m_buffer.append(" with id = ");
411          m_buffer.append(id);
412          log.trace(m_buffer.toString());
413       }
414    }
415
416    protected void unableToPassivateDueToCtxLock(EnterpriseContext ctx, boolean passivateAfterCommit)
417    {
418       log.warn("Unable to passivate due to ctx lock, id="+ctx.getId());
419    }
420
421    /**
422     * Returns the container for this cache.
423     */

424    protected abstract Container getContainer();
425    /**
426     * Returns the cache policy used for this cache.
427     */

428    protected CachePolicy getCache() {return m_cache;}
429    /**
430     * Returns the mutex used to sync access to the cache policy object
431     */

432    public Object JavaDoc getCacheLock()
433    {
434       return m_cacheLock;
435    }
436    /**
437     * Passivates the given EnterpriseContext
438     */

439    protected abstract void passivate(EnterpriseContext ctx) throws RemoteException JavaDoc;
440    /**
441     * Activates the given EnterpriseContext
442     */

443    protected abstract void activate(EnterpriseContext ctx) throws RemoteException JavaDoc;
444    /**
445     * Activate the given EnterpriseContext
446     *
447     * @param ctx the context
448     * @return false if we recursively activating
449     * @throws RemoteException for any error
450     */

451    protected boolean doActivate(EnterpriseContext ctx) throws RemoteException JavaDoc
452    {
453       activate(ctx);
454       return true;
455    }
456    /**
457     * Acquires an EnterpriseContext from the pool
458     */

459    protected abstract EnterpriseContext acquireContext() throws Exception JavaDoc;
460    /**
461     * Frees the given EnterpriseContext to the pool
462     */

463    protected abstract void freeContext(EnterpriseContext ctx);
464    /**
465     * Returns the key used by the cache to map the given context
466     */

467    protected abstract Object JavaDoc getKey(EnterpriseContext ctx);
468    /**
469     * Sets the given id as key for the given context
470     */

471    protected abstract void setKey(Object JavaDoc id, EnterpriseContext ctx);
472    /**
473     * Returns whether the given context can be passivated or not
474     *
475     */

476    protected abstract boolean canPassivate(EnterpriseContext ctx);
477
478    // Private -------------------------------------------------------
479

480    // Inner classes -------------------------------------------------
481
}
482
Popular Tags