package org.jboss.ejb.txtimer;
import org.jboss.ejb.ContainerMBean;
import org.jboss.logging.Logger;
import org.jboss.mx.util.MBeanProxy;
import org.jboss.mx.util.ObjectNameFactory;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.system.server.Server;
import org.jboss.tm.TxManager;
import javax.ejb.TimerService;
import javax.management.InstanceNotFoundException;
import javax.management.Notification;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class DatabasePersistencePolicy extends ServiceMBeanSupport
implements NotificationListener, DatabasePersistencePolicyMBean
{
private static Logger log = Logger.getLogger(DatabasePersistencePolicy.class);
private DatabasePersistencePlugin dbpPlugin;
private ObjectName dataSource;
private String dbpPluginClassName;
private TransactionManager tm;
private List timersToRestore;
public void startService() throws Exception
{
try
{
InitialContext iniCtx = new InitialContext();
tm = (TransactionManager)iniCtx.lookup("java:/TransactionManager");
}
catch (Exception e)
{
log.warn("Cannot obtain TransactionManager from JNDI: " + e.toString());
tm = TxManager.getInstance();
}
if (dbpPluginClassName != null)
{
Class dbpPolicyClass = Thread.currentThread().getContextClassLoader().loadClass(dbpPluginClassName);
dbpPlugin = (DatabasePersistencePlugin)dbpPolicyClass.newInstance();
}
else
{
dbpPlugin = new GeneralPurposeDatabasePersistencePlugin();
}
dbpPlugin.init(server, dataSource);
dbpPlugin.createTableIfNotExists();
timersToRestore = dbpPlugin.selectTimers();
log.debug("Found " + timersToRestore.size() + " timer(s)");
if (timersToRestore.size() > 0)
{
dbpPlugin.clearTimers();
}
registerNotificationListener();
}
public void handleNotification(Notification notification, Object handback)
{
restoreTimers();
}
public void insertTimer(String timerId, TimedObjectId timedObjectId, Date firstEvent, long intervalDuration, Serializable info)
{
try
{
dbpPlugin.insertTimer(timerId, timedObjectId, firstEvent, intervalDuration, info);
}
catch (SQLException e)
{
RuntimeException ex = new IllegalStateException("Unable to persist timer");
ex.initCause(e);
throw ex;
}
}
public void deleteTimer(String timerId, TimedObjectId timedObjectId)
{
Transaction threadTx = suspendTransaction();
try
{
dbpPlugin.deleteTimer(timerId, timedObjectId);
}
catch (SQLException e)
{
log.warn("Unable to delete timer", e);
}
finally
{
resumeTransaction(threadTx);
}
}
public List listTimerHandles()
{
List list = new ArrayList();
try
{
list.addAll(dbpPlugin.selectTimers());
}
catch (SQLException e)
{
log.warn("Unable to get timer handles", e);
}
return list;
}
public void restoreTimers()
{
if (timersToRestore != null && timersToRestore.size() > 0)
{
log.debug("Restoring " + timersToRestore.size() + " timer(s)");
for (int i = 0; i < timersToRestore.size(); i++)
{
TimerHandleImpl handle = (TimerHandleImpl)timersToRestore.get(i);
try
{
TimedObjectId targetId = handle.getTimedObjectId();
ObjectName containerName = targetId.getContainerId();
ContainerMBean container = (ContainerMBean)MBeanProxy.get(ContainerMBean.class, containerName, server);
TimerService timerService = container.getTimerService(targetId.getInstancePk());
timerService.createTimer(handle.getFirstTime(), handle.getPeriode(), handle.getInfo());
}
catch (Exception e)
{
log.warn("Unable to restore timer record: " + handle);
}
}
timersToRestore.clear();
}
}
public void clearTimers()
{
try
{
dbpPlugin.clearTimers();
}
catch (SQLException e)
{
log.warn("Unable to clear timers", e);
}
}
public void resetAndRestoreTimers() throws SQLException
{
timersToRestore = dbpPlugin.selectTimers();
log.debug("Found " + timersToRestore.size() + " timer(s)");
if (timersToRestore.size() > 0)
{
clearTimers();
}
restoreTimers();
}
public ObjectName getDataSource()
{
return dataSource;
}
public void setDataSource(ObjectName dataSource)
{
this.dataSource = dataSource;
}
public String getDatabasePersistencePlugin()
{
return dbpPluginClassName;
}
public void setDatabasePersistencePlugin(String dbpPluginClass)
{
this.dbpPluginClassName = dbpPluginClass;
}
private Transaction suspendTransaction()
{
Transaction threadTx = null;
try
{
threadTx = tm.suspend();
}
catch (SystemException e)
{
log.warn("Cannot suspend Tx: " + e.toString());
}
return threadTx;
}
private void resumeTransaction(Transaction threadTx)
{
try
{
if (threadTx != null)
tm.resume(threadTx);
}
catch (Exception e)
{
log.warn("Cannot resume Tx: " + e.toString());
}
}
private void registerNotificationListener() throws InstanceNotFoundException
{
NotificationFilterSupport filter = new NotificationFilterSupport();
filter.enableType(Server.START_NOTIFICATION_TYPE);
server.addNotificationListener(ObjectNameFactory.create("jboss.system:type=Server"), this, filter, null);
}
}