KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jresearch > gossip > dao > drivers > keygen > KeyKeeper


1 /*
2  * $Id: KeyKeeper.java,v 1.3 2005/06/07 12:32:31 bel70 Exp $
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * The contents of this file are subject to the Mozilla Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License
8  * at http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific language governing rights and
13  * limitations under the License.
14  *
15  * The Original Code is JGossip forum code.
16  *
17  * The Initial Developer of the Original Code is the JResearch, Org.
18  * Portions created by the Initial Developer are Copyright (C) 2004
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  * Alexey Pavlov <alexnet@users.sourceforge.net>
23  *
24  * ***** END LICENSE BLOCK ***** */

25 package org.jresearch.gossip.dao.drivers.keygen;
26
27 import java.math.BigDecimal JavaDoc;
28 import java.sql.Connection JavaDoc;
29 import java.sql.PreparedStatement JavaDoc;
30 import java.sql.ResultSet JavaDoc;
31 import java.sql.SQLException JavaDoc;
32 import java.text.MessageFormat JavaDoc;
33
34 import org.apache.log.Logger;
35 import org.jresearch.gossip.exception.ConfiguratorException;
36 import org.jresearch.gossip.exception.SystemException;
37 import org.jresearch.gossip.log.avalon.JGossipLog;
38
39 /**
40  * This class provides generated keys.
41  *
42  * With this method, there's a multi-row table which has two columns, one for
43  * the identifier for the table name, and another for the next key value for
44  * that table. In this variation, a grab size is specified to get a block of
45  * keys to reduce database accesses.
46  *
47  * @author <a HREF="alexnet@sourceforge.net">A. Pavlov</a>
48  * @version $version$ $Date: 2005/06/07 12:32:31 $
49  */

50 public class KeyKeeper {
51
52     /**
53      * Logger instance.
54      */

55     private Logger log;
56
57     private static final String JavaDoc DATA_TYPE = "DATA_TYPE";
58
59     private static int increment = -1;
60
61     private int columnType = -1;
62
63     /**
64      * The high value is combined with the low value to produce the key.
65      */

66     Object JavaDoc high;
67
68     int low;
69
70     String JavaDoc[] primaryKey;
71
72     /**
73      * The key is generated for this table.
74      */

75     String JavaDoc tableName;
76
77     KeyKeeper(String JavaDoc tableName, String JavaDoc[] primaryKey) {
78         this.tableName = tableName;
79         this.primaryKey = primaryKey;
80         try {
81             log = JGossipLog.getInstance().getAppLogger();
82         } catch (SystemException e) { /* Ignore Exception! */
83         }
84     }
85
86     /**
87      * Obtains a block of available keys from the key-values table.
88      *
89      * @return the value beyond the block of available keys,
90      * @exception PersistenceException
91      * if an error occurs
92      */

93     Object JavaDoc fetchHigh(Connection JavaDoc connection) throws SQLException JavaDoc {
94         Object JavaDoc identity = null;
95
96         String JavaDoc tableColumn;
97         String JavaDoc table;
98         String JavaDoc keyColumn;
99         try {
100             // Get the name of the table used to store two columns.
101
table = KeyGeneratorFactory.conf
102                     .get(IKeyGenConst.KEY_KEEPER_TABLE_NAME);
103             // column name for identifier for table name
104
tableColumn = KeyGeneratorFactory.conf
105                     .get(IKeyGenConst.KEY_KEEPER_TABLE_COLUMN);
106             // column name for the next key for that table
107
keyColumn = KeyGeneratorFactory.conf
108                     .get(IKeyGenConst.KEY_KEEPER_KEY_COLUMN);
109         } catch (ConfiguratorException ce) {
110             if (log.isErrorEnabled()) {
111                 log.error(
112                         "Configurator error. Check your config files. Cause: ",
113                         ce);
114             }
115             // Nothing we can do - configuration info corrupted or incomplete.
116
// set default values here:
117
table = "JRF_KEY_KEEPER";
118             tableColumn = "table_name";
119             keyColumn = "next_key";
120         }
121         StringBuffer JavaDoc condition = new StringBuffer JavaDoc();
122         condition.append(tableColumn + " = ?");
123
124         ResultSet JavaDoc rs = null;
125         PreparedStatement JavaDoc pstmt = null;
126         PreparedStatement JavaDoc pstmt2 = null;
127         try {
128             // TODO: start db transaction here, if it is available
129

130             // First get column type of key.
131
if (columnType == -1) {
132                 columnType = getColumnType(connection, table, keyColumn);
133             }
134
135             if (columnType != java.sql.Types.INTEGER
136                     && columnType != java.sql.Types.NUMERIC
137                     && columnType != java.sql.Types.DECIMAL) {
138                 throw new SQLException JavaDoc(MessageFormat.format(
139                         "Key keeper has a SQL type[{0}] of key column[{1}]",
140                         new Object JavaDoc[] { new Integer JavaDoc(columnType), keyColumn }));
141
142             }
143
144             String JavaDoc sql = getStatement(keyColumn, table, condition.toString());
145             pstmt = connection.prepareStatement(sql);
146             pstmt.setString(1, tableName);
147
148             rs = pstmt.executeQuery();
149
150             // Count of records updated by SQL database
151
int count = 0;
152             if (rs.next()) {
153                 Object JavaDoc lastIdentity = rs.getObject(1);
154                 rs.close();
155
156                 if (columnType == java.sql.Types.INTEGER) {
157                     identity = new Integer JavaDoc(((Number JavaDoc) lastIdentity).intValue()
158                             + getGrabSize());
159                 } else {
160                     identity = new BigDecimal JavaDoc(((Number JavaDoc) lastIdentity)
161                             .doubleValue()
162                             + getGrabSize());
163                 }
164
165                 condition.append(" and " + keyColumn + "=?");
166
167                 // Update value
168
sql = getUpdateStatement(keyColumn, table, condition.toString());
169                 pstmt2 = connection.prepareStatement(sql);
170                 pstmt2.setObject(1, identity);
171                 pstmt2.setString(2, tableName);
172                 pstmt2.setObject(3, lastIdentity);
173                 count = pstmt2.executeUpdate();
174             }
175
176             if (count < 1)
177                 throw new SQLException JavaDoc("persist.highlowFailed");
178             if (connection.getAutoCommit() == false) {
179                 connection.commit();
180             }
181         } catch (SQLException JavaDoc sqle) {
182             log.error("persist.highlowFailed", sqle);
183         } finally {
184             try {
185                 if (rs != null)
186                     rs.close();
187
188                 if (pstmt != null) {
189                     pstmt.close();
190                 }
191                 pstmt = null;
192
193                 if (pstmt2 != null) {
194                     pstmt2.close();
195                 }
196                 pstmt2 = null;
197
198             } catch (SQLException JavaDoc excep) {
199                 // We can safely ignore all SQLException here, since we are not
200
// in the position
201
// to do much about it anyway.
202
}
203         }
204
205         return identity;
206     }
207
208     private final int getColumnType(Connection JavaDoc conn, String JavaDoc table, String JavaDoc column)
209             throws SQLException JavaDoc {
210         return java.sql.Types.INTEGER;
211         /*
212          * ResultSet rs = null; try { // Using meta data because many DBMS can
213          * not // pre-compile statements. DatabaseMetaData dmd =
214          * conn.getMetaData(); //TODO: //provide concrete references to
215          * tablespace. // jgossip% rs = dmd.getColumns(null, null,
216          * primaryKey[0].toUpperCase(), primaryKey[1].toUpperCase());
217          * synchronized (this) { if (rs.next()) { return rs.getInt(DATA_TYPE); }
218          * throw new SQLException( "mapping.checkKeyGen", getClass().getName()); } }
219          * finally { if (rs != null) { rs.close(); rs = null; } }
220          */

221     }
222
223     private final String JavaDoc getStatement(String JavaDoc column, String JavaDoc table,
224             String JavaDoc condition) {
225         // todo: make it tunable.
226
final String JavaDoc sql = "SELECT {0} FROM {1} WHERE {2} "; // FOR UPDATE?
227
return MessageFormat.format(sql, new Object JavaDoc[] { column, table,
228                 condition });
229     }
230
231     private final String JavaDoc getUpdateStatement(String JavaDoc column, String JavaDoc table,
232             String JavaDoc condition) {
233         // todo: make it tunable.
234
final String JavaDoc sql = "UPDATE {1} SET {0}=? WHERE {2}";
235         return MessageFormat.format(sql, new Object JavaDoc[] { column, table,
236                 condition });
237     }
238
239     /**
240      * Returns the next generated key.
241      *
242      * @param db
243      * the source of database connections for the key-values table
244      * @return the generated key
245      * @exception PersistenceException
246      * if an error occurs
247      */

248     synchronized Object JavaDoc nextKey(Connection JavaDoc con) throws SQLException JavaDoc {
249         if (high == null || low >= getGrabSize()) {
250             high = fetchHigh(con);
251             low = 0;
252         }
253
254         Class JavaDoc highClass = high.getClass();
255         if (highClass.equals(Integer JavaDoc.class)) {
256             return new Integer JavaDoc(((Integer JavaDoc) high).intValue() - getGrabSize()
257                     + low++);
258         } else if (highClass.equals(BigDecimal JavaDoc.class)) {
259             return new BigDecimal JavaDoc(((BigDecimal JavaDoc) high).intValue()
260                     - getGrabSize() + low++);
261
262         }
263         throw new SQLException JavaDoc(MessageFormat.format(
264                 "KeyKeeper[{0}] can't handle primary key of type[{1}]",
265                 new Object JavaDoc[] { getClass().getName(), highClass }));
266     }
267
268     private static int getGrabSize()
269
270     {
271         if (-1 == increment) {
272             synchronized (KeyKeeper.class) {
273                 if (-1 == increment) {
274                     try {
275                         final String JavaDoc value = KeyGeneratorFactory.conf
276                                 .get(IKeyGenConst.KEY_KEEPER_INCREMENT);
277                         increment = Integer.parseInt(value);
278                     } catch (Exception JavaDoc e) {
279                         increment = 10;
280                         try {
281                             if (JGossipLog.getInstance().getAppLogger()
282                                     .isErrorEnabled()) {
283                                 JGossipLog
284                                         .getInstance()
285                                         .getAppLogger()
286                                         .error(
287                                                 "Can't retreive increment value from configuration",
288                                                 e);
289                             }
290                         } catch (SystemException e1) { /* Ignore Exception! */
291                         }
292                     }
293                 }
294             }
295         }
296         return increment;
297     }
298 }
299
Popular Tags