1 /*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a 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.txtimer;
23
24 // $Id: DatabasePersistencePolicy.java 62320 2007-04-13 10:56:45Z dimitris@jboss.org $
25
26 import java.io.Serializable;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31
32 import javax.ejb.TimerService;
33 import javax.management.ObjectName;
34
35 import org.jboss.ejb.ContainerMBean;
36 import org.jboss.logging.Logger;
37 import org.jboss.mx.util.MBeanProxyExt;
38 import org.jboss.system.ServiceMBeanSupport;
39
40 /**
41 * This service implements a PersistencePolicy that persistes the timer to a
42 * database.
43 *
44 * @author Thomas.Diesler@jboss.org
45 * @author Scott.Stark@jboss.org
46 * @author Dimitris.Andreadis@jboss.org
47 * @version $Revision: 62320 $
48 * @since 09-Sep-2004
49 */
50 public class DatabasePersistencePolicy extends ServiceMBeanSupport
51 implements DatabasePersistencePolicyMBean
52 {
53 /** logging support */
54 private static Logger log = Logger.getLogger(DatabasePersistencePolicy.class);
55
56 /** The persistence plugin */
57 private DatabasePersistencePlugin dbpPlugin;
58
59 /** The datasource */
60 private ObjectName dataSource;
61 /** The persistence plugin */
62 private String dbpPluginClassName;
63 /** The timers table */
64 private String timersTable = "TIMERS";
65
66 /** The persisted timers seen on startup */
67 private List timersToRestore;
68
69 /**
70 * Initializes this service.
71 */
72 public void startService() throws Exception
73 {
74 // Get the persistence plugin
75 if (dbpPluginClassName != null)
76 {
77 Class dbpPolicyClass = Thread.currentThread().getContextClassLoader().loadClass(dbpPluginClassName);
78 dbpPlugin = (DatabasePersistencePlugin)dbpPolicyClass.newInstance();
79 }
80 else
81 {
82 dbpPlugin = new GeneralPurposeDatabasePersistencePlugin();
83 }
84
85 // init the plugin
86 if (dbpPlugin instanceof DatabasePersistencePluginExt)
87 {
88 // if using the extended plugin interface, initialize the timers table name
89 ((DatabasePersistencePluginExt)dbpPlugin).init(server, dataSource, timersTable);
90 }
91 else
92 {
93 dbpPlugin.init(server, dataSource);
94 }
95
96 // warn if timers table cannot be set
97 if (dbpPlugin.getTableName().equals(timersTable) == false)
98 {
99 log.warn("Database persistence plugin '" + dbpPluginClassName +
100 "' uses hardcoded timers table name: '" + dbpPlugin.getTableName());
101 }
102
103 // create the table if needed
104 dbpPlugin.createTableIfNotExists();
105 }
106
107 /**
108 * Creates the timer in persistent storage.
109 *
110 * @param timerId The timer id
111 * @param timedObjectId The timed object id
112 * @param firstEvent The point in time at which the first txtimer expiration must occur.
113 * @param intervalDuration The number of milliseconds that must elapse between txtimer expiration notifications.
114 * @param info A serializable handback object.
115 */
116 public void insertTimer(String timerId, TimedObjectId timedObjectId, Date firstEvent, long intervalDuration, Serializable info)
117 {
118 try
119 {
120 dbpPlugin.insertTimer(timerId, timedObjectId, firstEvent, intervalDuration, info);
121 }
122 catch (SQLException e)
123 {
124 RuntimeException ex = new IllegalStateException("Unable to persist timer");
125 ex.initCause(e);
126 throw ex;
127 }
128 }
129
130 /**
131 * Removes the timer from persistent storage.
132 *
133 * @param timerId The timer id
134 */
135 public void deleteTimer(String timerId, TimedObjectId timedObjectId)
136 {
137 try
138 {
139 dbpPlugin.deleteTimer(timerId, timedObjectId);
140 }
141 catch (SQLException e)
142 {
143 log.warn("Unable to delete timer", e);
144 }
145 }
146
147 /**
148 * List the persisted timer handles for a particular container
149 *
150 * @param containerId The Container ObjectName
151 * @param loader The ClassLoader to use for loading the handles
152 * @return a list of TimerHandleImpl objects
153 */
154 public List listTimerHandles(ObjectName containerId, ClassLoader loader)
155 {
156 List list = new ArrayList();
157
158 ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
159 try
160 {
161 if (loader != null)
162 {
163 Thread.currentThread().setContextClassLoader(loader);
164 }
165 list.addAll(dbpPlugin.selectTimers(containerId));
166 }
167 catch (SQLException e)
168 {
169 log.warn("Unable to get timer handles for containerId: " + containerId, e);
170 }
171 finally
172 {
173 // restore class loader
174 Thread.currentThread().setContextClassLoader(oldCl);
175 }
176 return list;
177 }
178
179 /**
180 * Return a List of TimerHandle objects.
181 */
182 public List listTimerHandles()
183 {
184 List list = new ArrayList();
185 try
186 {
187 list.addAll(dbpPlugin.selectTimers(null));
188 }
189 catch (SQLException e)
190 {
191 log.warn("Unable to get timer handles", e);
192 }
193 return list;
194 }
195
196 /**
197 * Restore the persistent timers seen during service startup
198 */
199 public void restoreTimers()
200 {
201 if (timersToRestore != null && timersToRestore.size() > 0)
202 {
203 log.debug("Restoring " + timersToRestore.size() + " timer(s)");
204
205 // recreate the timers
206 for (int i = 0; i < timersToRestore.size(); i++)
207 {
208 TimerHandleImpl handle = (TimerHandleImpl)timersToRestore.get(i);
209
210 try
211 {
212 TimedObjectId targetId = handle.getTimedObjectId();
213 ObjectName containerName = targetId.getContainerId();
214 ContainerMBean container = (ContainerMBean)MBeanProxyExt.create(ContainerMBean.class, containerName, server);
215 TimerService timerService = container.getTimerService(targetId.getInstancePk());
216 timerService.createTimer(handle.getFirstTime(), handle.getPeriode(), handle.getInfo());
217 }
218 catch (Exception e)
219 {
220 log.warn("Unable to restore timer record: " + handle);
221 }
222 }
223 timersToRestore.clear();
224 }
225 }
226
227 /**
228 * Delete all persisted timers
229 */
230 public void clearTimers()
231 {
232 try
233 {
234 dbpPlugin.clearTimers();
235 }
236 catch (SQLException e)
237 {
238 log.warn("Unable to clear timers", e);
239 }
240 }
241
242 /** Re-read the current persistent timers list, clear the db of timers,
243 * and restore the timers.
244 *
245 * @jmx.managed-operation
246 */
247 public void resetAndRestoreTimers() throws SQLException
248 {
249 timersToRestore = dbpPlugin.selectTimers(null);
250 log.debug("Found " + timersToRestore.size() + " timer(s)");
251 if (timersToRestore.size() > 0)
252 {
253 // delete all timers
254 clearTimers();
255 }
256 restoreTimers();
257 }
258
259 // MBean attributes *************************************************************************************************\
260
261 /**
262 * @jmx.managed-attribute
263 */
264 public ObjectName getDataSource()
265 {
266 return dataSource;
267 }
268
269 /**
270 * @jmx.managed-attribute
271 */
272 public void setDataSource(ObjectName dataSource)
273 {
274 this.dataSource = dataSource;
275 }
276
277 /**
278 * @jmx.managed-attribute
279 */
280 public String getDatabasePersistencePlugin()
281 {
282 return dbpPluginClassName;
283 }
284
285 /**
286 * @jmx.managed-attribute
287 */
288 public void setDatabasePersistencePlugin(String dbpPluginClass)
289 {
290 this.dbpPluginClassName = dbpPluginClass;
291 }
292
293 /**
294 * @jmx.managed-attribute
295 */
296 public String getTimersTable()
297 {
298 return timersTable;
299 }
300
301 /**
302 * @jmx.managed-attribute
303 */
304 public void setTimersTable(String timersTable)
305 {
306 this.timersTable = timersTable;
307 }
308 }