KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > txtimer > GeneralPurposeDatabasePersistencePlugin


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.txtimer;
23
24 // $Id: GeneralPurposeDatabasePersistencePlugin.java 38205 2005-11-17 22:16:37Z dimitris $
25

26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.ByteArrayOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.ObjectInputStream JavaDoc;
31 import java.io.ObjectOutputStream JavaDoc;
32 import java.io.Serializable JavaDoc;
33 import java.sql.Connection JavaDoc;
34 import java.sql.PreparedStatement JavaDoc;
35 import java.sql.ResultSet JavaDoc;
36 import java.sql.SQLException JavaDoc;
37 import java.sql.Statement JavaDoc;
38 import java.sql.Timestamp JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.Date JavaDoc;
41 import java.util.List JavaDoc;
42
43 import javax.management.MBeanServer JavaDoc;
44 import javax.management.ObjectName JavaDoc;
45 import javax.naming.InitialContext JavaDoc;
46 import javax.sql.DataSource JavaDoc;
47
48 import org.jboss.ejb.plugins.cmp.jdbc.JDBCUtil;
49 import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil;
50 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData;
51 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData;
52 import org.jboss.invocation.MarshalledValueInputStream;
53 import org.jboss.logging.Logger;
54 import org.jboss.mx.util.ObjectNameFactory;
55
56 /**
57  * This DatabasePersistencePlugin uses getBytes/setBytes to persist the
58  * serializable objects associated with the timer.
59  *
60  * @author Thomas.Diesler@jboss.org
61  * @author Dimitris.Andreadis@jboss.org
62  * @version $Revision: 38205 $
63  * @since 23-Sep-2004
64  */

65 public class GeneralPurposeDatabasePersistencePlugin implements DatabasePersistencePlugin
66 {
67    // logging support
68
private static Logger log = Logger.getLogger(GeneralPurposeDatabasePersistencePlugin.class);
69
70    // The service attributes
71
protected ObjectName JavaDoc dataSourceName;
72
73    // The mbean server
74
protected MBeanServer JavaDoc server;
75    // The data source the timers will be persisted to
76
protected DataSource JavaDoc ds;
77    // datasource meta data
78
protected ObjectName JavaDoc metaDataName;
79
80    /** Initialize the plugin */
81    public void init(MBeanServer JavaDoc server, ObjectName JavaDoc dataSourceName) throws SQLException JavaDoc
82    {
83       this.server = server;
84       this.dataSourceName = dataSourceName;
85
86       // Get the DataSource from JNDI
87
try
88       {
89          String JavaDoc dsJndiTx = (String JavaDoc)server.getAttribute(dataSourceName, "BindName");
90          ds = (DataSource JavaDoc)new InitialContext JavaDoc().lookup(dsJndiTx);
91       }
92       catch (Exception JavaDoc e)
93       {
94          throw new SQLException JavaDoc("Failed to lookup data source: " + dataSourceName);
95       }
96
97       // Get the DataSource meta data
98
String JavaDoc dsName = dataSourceName.getKeyProperty("name");
99       metaDataName = ObjectNameFactory.create("jboss.jdbc:datasource=" + dsName + ",service=metadata");
100       if (this.server.isRegistered(metaDataName) == false)
101          throw new IllegalStateException JavaDoc("Cannot find datasource meta data: " + metaDataName);
102    }
103
104    /** Create the timer table if it does not exist already */
105    public void createTableIfNotExists()
106            throws SQLException JavaDoc
107    {
108       Connection JavaDoc con = null;
109       Statement JavaDoc st = null;
110       try
111       {
112          if (!SQLUtil.tableExists(getTableName(), ds))
113          {
114             con = ds.getConnection();
115             JDBCTypeMappingMetaData typeMapping = (JDBCTypeMappingMetaData)server.getAttribute(metaDataName, "TypeMappingMetaData");
116             if (typeMapping == null)
117                throw new IllegalStateException JavaDoc("Cannot obtain type mapping from: " + metaDataName);
118
119             String JavaDoc dateType = typeMapping.getTypeMappingMetaData(Timestamp JavaDoc.class).getSqlType();
120             String JavaDoc objectType = typeMapping.getTypeMappingMetaData(Object JavaDoc.class).getSqlType();
121             String JavaDoc longType = typeMapping.getTypeMappingMetaData(Long JavaDoc.class).getSqlType();
122
123             // The create table DDL
124
StringBuffer JavaDoc createTableDDL = new StringBuffer JavaDoc("create table " + getTableName() + " (" +
125                     " " + getColumnTimerID() + " varchar(80) not null," +
126                     " " + getColumnTargetID() + " varchar(250) not null," +
127                     " " + getColumnInitialDate() + " " + dateType + " not null," +
128                     " " + getColumnTimerInterval() + " " + longType + "," +
129                     " " + getColumnInstancePK() + " " + objectType + "," +
130                     " " + getColumnInfo() + " " + objectType + ", ");
131
132             // Add the primary key constraint using the pk-constraint-template
133
JDBCFunctionMappingMetaData pkConstraint = typeMapping.getPkConstraintTemplate();
134             String JavaDoc[] templateParams = new String JavaDoc[] {
135                   getTableName() + "_PK",
136                   getColumnTimerID() + ", " + getColumnTargetID()
137                   };
138             pkConstraint.getFunctionSql(templateParams, createTableDDL);
139             
140             // Complete the statement
141
createTableDDL.append(" )");
142
143             log.debug("Executing DDL: " + createTableDDL);
144
145             st = con.createStatement();
146             st.executeUpdate(createTableDDL.toString());
147          }
148       }
149       catch (SQLException JavaDoc e)
150       {
151          throw e;
152       }
153       catch (Exception JavaDoc e)
154       {
155          log.error("Cannot create timer table", e);
156       }
157       finally
158       {
159          JDBCUtil.safeClose(st);
160          JDBCUtil.safeClose(con);
161       }
162    }
163
164    /** Insert a timer object */
165    public void insertTimer(String JavaDoc timerId, TimedObjectId timedObjectId, Date JavaDoc initialExpiration, long intervalDuration, Serializable JavaDoc info)
166            throws SQLException JavaDoc
167    {
168       Connection JavaDoc con = null;
169       PreparedStatement JavaDoc st = null;
170       try
171       {
172          con = ds.getConnection();
173
174          String JavaDoc sql = "insert into " + getTableName() + " " +
175                  "(" + getColumnTimerID() + "," + getColumnTargetID() + "," + getColumnInitialDate() + "," + getColumnTimerInterval() + "," + getColumnInstancePK() + "," + getColumnInfo() + ") " +
176                  "values (?,?,?,?,?,?)";
177          st = con.prepareStatement(sql);
178
179          st.setString(1, timerId);
180          st.setString(2, timedObjectId.toString());
181          st.setTimestamp(3, new Timestamp JavaDoc(initialExpiration.getTime()));
182          st.setLong(4, intervalDuration);
183          st.setBytes(5, serialize(timedObjectId.getInstancePk()));
184          st.setBytes(6, serialize(info));
185
186          int rows = st.executeUpdate();
187          if (rows != 1)
188             log.error("Unable to insert timer for: " + timedObjectId);
189       }
190       finally
191       {
192          JDBCUtil.safeClose(st);
193          JDBCUtil.safeClose(con);
194       }
195    }
196
197    /** Select a list of currently persisted timer handles
198     * @return List<TimerHandleImpl>
199     */

200    public List JavaDoc selectTimers(ObjectName JavaDoc containerId) throws SQLException JavaDoc
201    {
202       Connection JavaDoc con = null;
203       Statement JavaDoc st = null;
204       ResultSet JavaDoc rs = null;
205       try
206       {
207          con = ds.getConnection();
208
209          List JavaDoc list = new ArrayList JavaDoc();
210
211          st = con.createStatement();
212          rs = st.executeQuery("select * from " + getTableName());
213          while (rs.next())
214          {
215             String JavaDoc timerId = rs.getString(getColumnTimerID());
216             TimedObjectId targetId = TimedObjectId.parse(rs.getString(getColumnTargetID()));
217             
218             // add this handle to the returned list, if a null containerId was used
219
// or the containerId filter matches
220
if (containerId == null || containerId.equals(targetId.getContainerId()))
221             {
222                Date JavaDoc initialDate = rs.getTimestamp(getColumnInitialDate());
223                long interval = rs.getLong(getColumnTimerInterval());
224                Serializable JavaDoc pKey = (Serializable JavaDoc)deserialize(rs.getBytes(getColumnInstancePK()));
225                Serializable JavaDoc info = null;
226                try
227                {
228                   info = (Serializable JavaDoc)deserialize(rs.getBytes(getColumnInfo()));
229                }
230                catch (Exception JavaDoc e)
231                {
232                   // may happen if listing all handles (containerId is null)
233
// with a stored custom info object coming from a scoped
234
// deployment.
235
log.warn("Cannot deserialize custom info object", e);
236                }
237                // is this really needed? targetId encapsulates pKey as well!
238
targetId = new TimedObjectId(targetId.getContainerId(), pKey);
239                TimerHandleImpl handle = new TimerHandleImpl(timerId, targetId, initialDate, interval, info);
240                list.add(handle);
241             }
242          }
243
244          return list;
245       }
246       finally
247       {
248          JDBCUtil.safeClose(rs);
249          JDBCUtil.safeClose(st);
250          JDBCUtil.safeClose(con);
251       }
252    }
253
254    /** Delete a timer. */
255    public void deleteTimer(String JavaDoc timerId, TimedObjectId timedObjectId)
256            throws SQLException JavaDoc
257    {
258       Connection JavaDoc con = null;
259       PreparedStatement JavaDoc st = null;
260       ResultSet JavaDoc rs = null;
261
262       try
263       {
264          con = ds.getConnection();
265
266          String JavaDoc sql = "delete from " + getTableName() + " where " + getColumnTimerID() + "=? and " + getColumnTargetID() + "=?";
267          st = con.prepareStatement(sql);
268
269          st.setString(1, timerId);
270          st.setString(2, timedObjectId.toString());
271
272          int rows = st.executeUpdate();
273          
274          // This appears when a timer is created & persisted inside a tx,
275
// but then the tx is rolled back, at which point we go back
276
// to remove the entry, but no entry is found.
277
// Is this because we are "enlisting" the datasource in the tx, too?
278
if (rows != 1)
279          {
280             log.debug("Unable to remove timer for: " + timerId);
281          }
282       }
283       finally
284       {
285          JDBCUtil.safeClose(rs);
286          JDBCUtil.safeClose(st);
287          JDBCUtil.safeClose(con);
288       }
289    }
290
291    /** Clear all persisted timers */
292    public void clearTimers()
293            throws SQLException JavaDoc
294    {
295       Connection JavaDoc con = null;
296       PreparedStatement JavaDoc st = null;
297       ResultSet JavaDoc rs = null;
298       try
299       {
300          con = ds.getConnection();
301          st = con.prepareStatement("delete from " + getTableName());
302          st.executeUpdate();
303       }
304       finally
305       {
306          JDBCUtil.safeClose(rs);
307          JDBCUtil.safeClose(st);
308          JDBCUtil.safeClose(con);
309       }
310    }
311
312    /** Get the timer table name */
313    public String JavaDoc getTableName()
314    {
315       return "TIMERS";
316    }
317
318    /** Get the timer ID column name */
319    public String JavaDoc getColumnTimerID()
320    {
321       return "TIMERID";
322    }
323
324    /** Get the target ID column name */
325    public String JavaDoc getColumnTargetID()
326    {
327       return "TARGETID";
328    }
329
330    /** Get the initial date column name */
331    public String JavaDoc getColumnInitialDate()
332    {
333       return "INITIALDATE";
334    }
335
336    /** Get the timer interval column name */
337    public String JavaDoc getColumnTimerInterval()
338    {
339       // Note 'INTERVAL' is a reserved word in MySQL
340
return "TIMERINTERVAL";
341    }
342
343    /** Get the instance PK column name */
344    public String JavaDoc getColumnInstancePK()
345    {
346       return "INSTANCEPK";
347    }
348
349    /** Get the info column name */
350    public String JavaDoc getColumnInfo()
351    {
352       return "INFO";
353    }
354
355    /** Serialize an object */
356    protected byte[] serialize(Object JavaDoc obj)
357    {
358       if (obj == null)
359          return null;
360
361       ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(1024);
362       try
363       {
364          ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(baos);
365          oos.writeObject(obj);
366          oos.close();
367       }
368       catch (IOException JavaDoc e)
369       {
370          log.error("Cannot serialize: " + obj, e);
371       }
372       return baos.toByteArray();
373    }
374
375    /** Deserialize an object */
376    protected Object JavaDoc deserialize(byte[] bytes)
377    {
378       if (bytes == null)
379          return null;
380
381       ByteArrayInputStream JavaDoc bais = new ByteArrayInputStream JavaDoc(bytes);
382       try
383       {
384          // Use an ObjectInputStream that instantiates objects
385
// using the Thread Context ClassLoader (TCL)
386
ObjectInputStream JavaDoc oos = new MarshalledValueInputStream(bais);
387          return oos.readObject();
388       }
389       catch (Exception JavaDoc e)
390       {
391          log.error("Cannot deserialize", e);
392          return null;
393       }
394    }
395
396    /** Deserialize an object */
397    protected Object JavaDoc deserialize(InputStream JavaDoc input)
398    {
399
400       if (input == null)
401          return null;
402
403       byte[] barr = new byte[1024];
404       ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(1024);
405       try
406       {
407          for (int b = 0; (b = input.read(barr)) > 0;)
408          {
409             baos.write(barr, 0, b);
410          }
411          return deserialize(baos.toByteArray());
412       }
413       catch (Exception JavaDoc e)
414       {
415          log.error("Cannot deserialize", e);
416          return null;
417       }
418    }
419 }
420
421
Popular Tags