Hello Folks,
Took a wild shot at the
Option D, timed cache invalidation. Have put it in a separate interceptor that
sits before the EntitySynchronizationInterceptor and invalidates the
EntityEnterpriseContext at regular preset intervals.
1. There is an invalidation timer task per
entity bean [I persum per-EntityEnterpriseContext maps to per bean and not per
bean instance]
2. The refersh rate is currently set at 60secs
but could be moved elsewhere to the jboss config xml
3. The Configuration Metadat now has an entry
for option D.
4. The interceptor does NOT reload the entity.
It just invalidates the cache. The entity reload is managed by the
EntitySynchronizationInterceptor.
Does anyone want to go thru this and get back to
me? It is a first cut code using this method [the previous one had some code
that was junked!]. What I'd like someone to point out is
1. Do we need to take care of any transaction
related issues in the invoke method?
2. Am adding to a hashset. Now the Context
object is removed from the hashset only when the if(ctx.getId()) evaluates to
null. Do we need to have any other place where we remove the context from the
list of items to be invalidated? We will have the underlying database updated
by other programs that are not linked into Jboss.
If the code is a complete pile of crap let me
know and would appreciate if you could give some pointers as well as to what
is incorrect and how it could be improved. At the moment it is pretty much a
crude piece of code!
Regards
Vinay
/*
* JBoss, the OpenSource EJB
server
*
* Distributable under LGPL license.
* See terms of license
at gnu.org.
*/
package org.jboss.ejb.plugins;
import java.lang.reflect.Method;
import
java.rmi.RemoteException;
import java.rmi.ServerException;
import java.util.Timer;
import
java.util.TimerTask;
import java.util.HashSet;
import
java.util.Iterator;
import javax.ejb.EJBObject;
import
javax.ejb.CreateException;
import javax.ejb.EJBException;
import
javax.ejb.NoSuchEntityException;
import
javax.ejb.RemoveException;
import javax.ejb.EntityBean;
import
javax.transaction.Status;
import
javax.transaction.Synchronization;
import
javax.transaction.Transaction;
import
javax.transaction.TransactionManager;
import
javax.transaction.RollbackException;
import
javax.transaction.SystemException;
import org.jboss.ejb.Container;
import
org.jboss.ejb.EntityContainer;
import
org.jboss.ejb.EntityPersistenceManager;
import
org.jboss.ejb.EntityEnterpriseContext;
import
org.jboss.ejb.EnterpriseContext;
import
org.jboss.ejb.InstanceCache;
import org.jboss.ejb.InstancePool;
import
org.jboss.ejb.MethodInvocation;
import
org.jboss.metadata.ConfigurationMetaData;
import
org.jboss.logging.Logger;
public class SoftBallInterceptor
extends
AbstractInterceptor
{
protected int
commitOption;
protected EntityContainer
container;
protected HashSet ctxToInvalidate = new
HashSet();
private static int REFRESH_RATE =
60000;
public void
setContainer(Container container)
{
this.container =
(EntityContainer)container;
}
public void
init()
throws Exception
{
commitOption =
container.getBeanMetaData().getContainerConfiguration().getCommitOption();
if(commitOption ==
ConfigurationMetaData.D_COMMIT_OPTION)
{
//Start
Timer Task
Now!
new
Timer().schedule(new
ForceSynchronization(),0,REFRESH_RATE);
}
}
public Container
getContainer()
{
return container;
}
private void
register(EntityEnterpriseContext ctx, Transaction tx)
{
}
private void
deregister(EntityEnterpriseContext ctx)
{
}
// Interceptor implementation
--------------------------------------
public Object
invokeHome(MethodInvocation mi)
throws
Exception
{
try
{
return
getNext().invokeHome(mi);
} finally
{
// Anonymous was sent
in, so if it has an id it was
created
EntityEnterpriseContext ctx =
(EntityEnterpriseContext)mi.getEnterpriseContext();
if (ctx.getId() != null)
{
Transaction tx =
mi.getTransaction();
if (tx != null
&& tx.getStatus() ==
Status.STATUS_ACTIVE)
register(ctx, tx); // Set tx
// Currently
synched with underlying
storage
ctx.setValid(true);
}
}
}
public Object
invoke(MethodInvocation mi)
throws
Exception
{
if(commitOption ==
ConfigurationMetaData.D_COMMIT_OPTION)
{
EntityEnterpriseContext ctx =
(EntityEnterpriseContext)mi.getEnterpriseContext();
if(ctx.getId()!=null)
{
synchronized(ctxToInvalidate)
{
this.ctxToInvalidate.add(ctx);
}
}
else
{
synchronized(ctxToInvalidate)
{
this.ctxToInvalidate.remove(ctx);
}
}
}
return
getNext().invoke(mi);
}
private class
ForceSynchronization
extends
TimerTask
{
ForceSynchronization()
{
}
public void
run()
{
synchronized(ctxToInvalidate)
{
Iterator it = ctxToInvalidate.iterator();
while(it.hasNext())
{
EntityEnterpriseContext ctx =
(EntityEnterpriseContext)it.next();
ctx.setValid(false);
}
}
}
}
}