/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.ejb.txtimer; // $Id: DatabasePersistencePolicy.java 62320 2007-04-13 10:56:45Z dimitris@jboss.org $ import java.io.Serializable; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.ejb.TimerService; import javax.management.ObjectName; import org.jboss.ejb.ContainerMBean; import org.jboss.logging.Logger; import org.jboss.mx.util.MBeanProxyExt; import org.jboss.system.ServiceMBeanSupport; /** * This service implements a PersistencePolicy that persistes the timer to a * database. * * @author Thomas.Diesler@jboss.org * @author Scott.Stark@jboss.org * @author Dimitris.Andreadis@jboss.org * @version $Revision: 62320 $ * @since 09-Sep-2004 */ public class DatabasePersistencePolicy extends ServiceMBeanSupport implements DatabasePersistencePolicyMBean { /** logging support */ private static Logger log = Logger.getLogger(DatabasePersistencePolicy.class); /** The persistence plugin */ private DatabasePersistencePlugin dbpPlugin; /** The datasource */ private ObjectName dataSource; /** The persistence plugin */ private String dbpPluginClassName; /** The timers table */ private String timersTable = "TIMERS"; /** The persisted timers seen on startup */ private List timersToRestore; /** * Initializes this service. */ public void startService() throws Exception { // Get the persistence plugin if (dbpPluginClassName != null) { Class dbpPolicyClass = Thread.currentThread().getContextClassLoader().loadClass(dbpPluginClassName); dbpPlugin = (DatabasePersistencePlugin)dbpPolicyClass.newInstance(); } else { dbpPlugin = new GeneralPurposeDatabasePersistencePlugin(); } // init the plugin if (dbpPlugin instanceof DatabasePersistencePluginExt) { // if using the extended plugin interface, initialize the timers table name ((DatabasePersistencePluginExt)dbpPlugin).init(server, dataSource, timersTable); } else { dbpPlugin.init(server, dataSource); } // warn if timers table cannot be set if (dbpPlugin.getTableName().equals(timersTable) == false) { log.warn("Database persistence plugin '" + dbpPluginClassName + "' uses hardcoded timers table name: '" + dbpPlugin.getTableName()); } // create the table if needed dbpPlugin.createTableIfNotExists(); } /** * Creates the timer in persistent storage. * * @param timerId The timer id * @param timedObjectId The timed object id * @param firstEvent The point in time at which the first txtimer expiration must occur. * @param intervalDuration The number of milliseconds that must elapse between txtimer expiration notifications. * @param info A serializable handback object. */ 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; } } /** * Removes the timer from persistent storage. * * @param timerId The timer id */ public void deleteTimer(String timerId, TimedObjectId timedObjectId) { try { dbpPlugin.deleteTimer(timerId, timedObjectId); } catch (SQLException e) { log.warn("Unable to delete timer", e); } } /** * List the persisted timer handles for a particular container * * @param containerId The Container ObjectName * @param loader The ClassLoader to use for loading the handles * @return a list of TimerHandleImpl objects */ public List listTimerHandles(ObjectName containerId, ClassLoader loader) { List list = new ArrayList(); ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); try { if (loader != null) { Thread.currentThread().setContextClassLoader(loader); } list.addAll(dbpPlugin.selectTimers(containerId)); } catch (SQLException e) { log.warn("Unable to get timer handles for containerId: " + containerId, e); } finally { // restore class loader Thread.currentThread().setContextClassLoader(oldCl); } return list; } /** * Return a List of TimerHandle objects. */ public List listTimerHandles() { List list = new ArrayList(); try { list.addAll(dbpPlugin.selectTimers(null)); } catch (SQLException e) { log.warn("Unable to get timer handles", e); } return list; } /** * Restore the persistent timers seen during service startup */ public void restoreTimers() { if (timersToRestore != null && timersToRestore.size() > 0) { log.debug("Restoring " + timersToRestore.size() + " timer(s)"); // recreate the timers 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)MBeanProxyExt.create(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(); } } /** * Delete all persisted timers */ public void clearTimers() { try { dbpPlugin.clearTimers(); } catch (SQLException e) { log.warn("Unable to clear timers", e); } } /** Re-read the current persistent timers list, clear the db of timers, * and restore the timers. * * @jmx.managed-operation */ public void resetAndRestoreTimers() throws SQLException { timersToRestore = dbpPlugin.selectTimers(null); log.debug("Found " + timersToRestore.size() + " timer(s)"); if (timersToRestore.size() > 0) { // delete all timers clearTimers(); } restoreTimers(); } // MBean attributes *************************************************************************************************\ /** * @jmx.managed-attribute */ public ObjectName getDataSource() { return dataSource; } /** * @jmx.managed-attribute */ public void setDataSource(ObjectName dataSource) { this.dataSource = dataSource; } /** * @jmx.managed-attribute */ public String getDatabasePersistencePlugin() { return dbpPluginClassName; } /** * @jmx.managed-attribute */ public void setDatabasePersistencePlugin(String dbpPluginClass) { this.dbpPluginClassName = dbpPluginClass; } /** * @jmx.managed-attribute */ public String getTimersTable() { return timersTable; } /** * @jmx.managed-attribute */ public void setTimersTable(String timersTable) { this.timersTable = timersTable; } }