KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb3 > entity > JTATableIdGenerator


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.ejb3.entity;
23
24 import java.io.Serializable JavaDoc;
25 import java.sql.Connection JavaDoc;
26 import java.sql.PreparedStatement JavaDoc;
27 import java.sql.ResultSet JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.sql.Types JavaDoc;
30 import java.util.Properties JavaDoc;
31 import javax.transaction.SystemException JavaDoc;
32 import javax.transaction.Transaction JavaDoc;
33 import javax.transaction.TransactionManager JavaDoc;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.hibernate.HibernateException;
37 import org.hibernate.LockMode;
38 import org.hibernate.dialect.Dialect;
39 import org.hibernate.engine.SessionImplementor;
40 import org.hibernate.exception.JDBCExceptionHelper;
41 import org.hibernate.id.Configurable;
42 import org.hibernate.id.IdentifierGenerationException;
43 import org.hibernate.id.IdentifierGeneratorFactory;
44 import org.hibernate.id.PersistentIdentifierGenerator;
45 import org.hibernate.transaction.JBossTransactionManagerLookup;
46 import org.hibernate.transaction.TransactionManagerLookup;
47 import org.hibernate.type.Type;
48 import org.hibernate.util.PropertiesHelper;
49
50 /**
51  * A hilo <tt>IdentifierGenerator</tt> that uses a database
52  * table to store the last generated value.
53  * <p/>
54  * <p/>
55  * This implementation is solely for use inside JBoss using JTA for transactions.
56  * </p>
57  * <p/>
58  * TODO implement sequence allocation
59  *
60  * @author <a HREF="mailto:kr@hbt.de">Klaus Richarz</a>.
61  * @version <tt>$Revision: 39332 $</tt>
62  * @see org.hibernate.id.TableGenerator
63  * @see javax.persistence.TableGenerator
64  */

65 public class JTATableIdGenerator implements PersistentIdentifierGenerator, Configurable
66 {
67    /* COLUMN and TABLE should be renamed but it would break the public API */
68    /**
69     * The column parameter
70     */

71    public static final String JavaDoc COLUMN = "column";
72
73    /**
74     * Default column name
75     */

76    public static final String JavaDoc DEFAULT_COLUMN_NAME = "next_hi";
77
78    /**
79     * The table parameter
80     */

81    public static final String JavaDoc TABLE = "table";
82
83    /**
84     * Default table name
85     */

86    public static final String JavaDoc DEFAULT_TABLE_NAME = "next_hi";
87
88    /**
89     * The allocation-size parameter
90     */

91    public static final String JavaDoc ALLOCATION_SIZE = "allocationSize";
92
93    /**
94     * Default allocation-size
95     */

96    public static final int DEFAULT_ALLOCATION_SIZE = 20;
97
98    /**
99     * logger for JTATableGenerator
100     */

101    private static final Log log = LogFactory.getLog(JTATableIdGenerator.class);
102
103    /**
104     * Holds the name where this generator gets its sequence from
105     */

106    private String JavaDoc tableName;
107
108    /**
109     * Holds the name ofthe column where the next sequence value is stored
110     */

111    private String JavaDoc columnName;
112
113    /**
114     * Holds the sql query to retrieve the next high value
115     */

116    private String JavaDoc query;
117
118    /**
119     * Holds the sql query to increment the sequence
120     */

121    private String JavaDoc update;
122
123    /**
124     * Holds the transaction manager lookup object
125     */

126    private TransactionManagerLookup transactionManagerLookup;
127
128    /**
129     * Holds the class type for the sequence value returned by generate()
130     */

131    private Class JavaDoc returnClass;
132
133    /**
134     * Holds the size for the sequence increment. The allocated sequences are managed in memory
135     * and may be lost if the system stops.
136     */

137    private int allocationSize;
138
139    public void configure(Type type, Properties JavaDoc params, Dialect dialect)
140    {
141       this.tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
142       this.columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
143       this.allocationSize = PropertiesHelper.getInt(ALLOCATION_SIZE, params, DEFAULT_ALLOCATION_SIZE);
144       String JavaDoc schemaName = params.getProperty(SCHEMA);
145       String JavaDoc catalogName = params.getProperty(CATALOG);
146
147       if (true) throw new RuntimeException JavaDoc("DOES ANYBODY USE THIS? It IS CURRENTLY BROKEN");
148
149       /*
150       getSchemaSeparator does not exist in hibernate anymore since 3.1 release
151
152       // prepare table name
153       if (tableName.indexOf(dialect.getSchemaSeparator()) < 0)
154       {
155          tableName = Table.qualify(catalogName, schemaName, tableName, dialect.getSchemaSeparator());
156       }
157       */

158
159       // prepare SQL statements
160
query = "select " +
161               columnName +
162               " from " +
163               dialect.appendLockHint(LockMode.UPGRADE, tableName) +
164               dialect.getForUpdateString();
165       update = "update " +
166                tableName +
167                " set " +
168                columnName +
169                " = ? where " +
170                columnName +
171                " = ?";
172
173       // set up transaction manager lookup
174
// only JBoss transaction manager is supported
175
transactionManagerLookup = new JBossTransactionManagerLookup();
176
177       // set the sequence type that should be returned
178
returnClass = type.getReturnedClass();
179
180       // debug chosen configuration
181
if (log.isDebugEnabled())
182       {
183          log.debug("configuring id generator: " + this.getClass().getName());
184          log.debug("tableName=" + tableName);
185          log.debug("columnName=" + columnName);
186          log.debug("allocationSize=" + allocationSize);
187          log.debug("query=" + query);
188          log.debug("update=" + update);
189          log.debug("returnClass=" + returnClass);
190       }
191    }
192
193    public synchronized Serializable JavaDoc generate(SessionImplementor session, Object JavaDoc object)
194            throws HibernateException
195    {
196       // get TransactionManager from JNDI
197
// no JNDI properties provided -> we are in the container
198
TransactionManager JavaDoc tm = transactionManagerLookup.getTransactionManager(new Properties JavaDoc());
199       Transaction JavaDoc surroundingTransaction = null; // for resuming in finally block
200
Connection JavaDoc conn = null; // for ressource cleanup
201
String JavaDoc sql = null; // for exception
202
try
203       {
204          long result; // holds the resulting sequence value
205

206          // prepare a new transaction context for the generator
207
surroundingTransaction = tm.suspend();
208          if (log.isDebugEnabled())
209          {
210             log.debug("surrounding tx suspended");
211          }
212          tm.begin();
213
214          // get connection from managed environment
215
conn = session.getBatcher().openConnection();
216
217          // execute fetching of current sequence value
218
sql = query;
219          PreparedStatement JavaDoc qps = conn.prepareStatement(query);
220          try
221          {
222             ResultSet JavaDoc rs = qps.executeQuery();
223             if (!rs.next())
224             {
225                String JavaDoc err = "could not read sequence value - you need to populate the table: " + tableName;
226                log.error(err);
227                throw new IdentifierGenerationException(err);
228             }
229             result = rs.getLong(1);
230             rs.close();
231          }
232          catch (SQLException JavaDoc sqle)
233          {
234             log.error("could not read a sequence value", sqle);
235             throw sqle;
236          }
237          finally
238          {
239             qps.close();
240          }
241
242          // increment sequence value
243
sql = update;
244          long sequence = result + 1;
245          PreparedStatement JavaDoc ups = conn.prepareStatement(update);
246          try
247          {
248             ups.setLong(1, sequence);
249             ups.setLong(2, result);
250             ups.executeUpdate();
251          }
252          catch (SQLException JavaDoc sqle)
253          {
254             log.error("could not update sequence value in: " + tableName, sqle);
255             throw sqle;
256          }
257          finally
258          {
259             ups.close();
260          }
261
262          // commit transaction to ensure updated sequence is not rolled back
263
tm.commit();
264
265          // transform sequence to the desired type and return the value
266
Number JavaDoc typedSequence = IdentifierGeneratorFactory.createNumber(sequence, returnClass);
267          if (log.isDebugEnabled())
268          {
269             log.debug("generate() returned: " + typedSequence);
270          }
271          return typedSequence;
272       }
273       catch (SQLException JavaDoc sqle)
274       {
275          throw JDBCExceptionHelper.convert(session.getFactory().getSQLExceptionConverter(),
276                                            sqle,
277                                            "could not get or update next value",
278                                            sql);
279       }
280       catch (Exception JavaDoc e)
281       {
282          try
283          {
284             tm.rollback();
285             throw new HibernateException(e);
286          }
287          catch (SystemException JavaDoc e1)
288          {
289             throw new HibernateException(e1);
290          }
291       }
292       finally
293       {
294          if (conn != null)
295             try
296             {
297                conn.close();
298             }
299             catch (SQLException JavaDoc e)
300             {
301                // ignore exception
302
}
303          // switch back to surrounding transaction context
304
if (surroundingTransaction != null)
305          {
306             try
307             {
308                tm.resume(surroundingTransaction);
309                if (log.isDebugEnabled())
310                {
311                   log.debug("surrounding tx resumed");
312                }
313             }
314             catch (Exception JavaDoc e)
315             {
316                throw new HibernateException(e);
317             }
318          }
319       }
320    }
321
322
323    public String JavaDoc[] sqlCreateStrings(Dialect dialect) throws HibernateException
324    {
325       return new String JavaDoc[]{
326          "create table " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.BIGINT) + " )",
327          "insert into " + tableName + " values ( 0 )"
328       };
329    }
330
331    public String JavaDoc[] sqlDropStrings(Dialect dialect)
332    {
333       //return "drop table " + tableName + dialect.getCascadeConstraintsString();
334
StringBuffer JavaDoc sqlDropString = new StringBuffer JavaDoc()
335               .append("drop table ");
336       if (dialect.supportsIfExistsBeforeTableName())
337       {
338          sqlDropString.append("if exists ");
339       }
340       sqlDropString.append(tableName)
341               .append(dialect.getCascadeConstraintsString());
342       if (dialect.supportsIfExistsAfterTableName())
343       {
344          sqlDropString.append(" if exists");
345       }
346       return new String JavaDoc[]{sqlDropString.toString()};
347    }
348
349    public Object JavaDoc generatorKey()
350    {
351       return tableName;
352    }
353 }
354
Popular Tags