View Javadoc

1   /*   Copyright (C) 2004 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   */
17  
18  package com.finalist.util.sequencegenerator;
19  
20  import com.finalist.util.sequencegenerator.tablecreator.TableCreator;
21  
22  import javax.ejb.CreateException;
23  import javax.ejb.EJBException;
24  import javax.ejb.SessionBean;
25  import javax.ejb.SessionContext;
26  import javax.naming.InitialContext;
27  import javax.naming.NamingException;
28  import javax.sql.DataSource;
29  import java.rmi.RemoteException;
30  import java.sql.Connection;
31  import java.sql.PreparedStatement;
32  import java.sql.ResultSet;
33  import java.sql.SQLException;
34  import java.util.HashMap;
35  import java.util.Properties;
36  
37  /*** Generates unique sequences.<p>
38   * This EJB can use any datasource and table. If the table and/or required<br>
39   * columns doesn't exist, the EJB will create them. By using a factory<br>
40   * it can manage several types of databases.<p>
41   * If the EJB is instantiated the datasource and table must be supplied.<br>
42   * It uses an internal HashMap for sequenceblock.<p>
43   * The EJB doesn't garantees a continous sequence! So the sequence can contain<br>
44   * so called gaps.<p>
45   * Since version 2.0 all settings are delivered by a Properties objects. This object<br>
46   * must be provided by the Facade in the application using this (shared) EJB.<br>
47   * In this Properties objects the keys are provided by the SequenceGeneratorConstants and<br>
48   * are mapped as follows:
49   * <ul><li>SequenceGeneratorConstants.DATASOURCENAME: Datasource name of the datasource holding the sequence table (mandatory, no default)</li>
50   * <li>SequenceGeneratorConstants.BLOCKSIZE: Default blocksize for new sequences stored as String (default: 10)</li>
51   * <li>SequenceGeneratorConstants.TABLENAME: Name of the sequence table (default: SEQUENCETABLE)</li>
52   * <li>SequenceGeneratorConstants.NAMECOLUMN: Name of the column where the sequence names are stored (default: SEQUENCE_NAME)</li>
53   * <li>SequenceGeneratorConstants.VALUECOLUMN: Name of the column where the sequence values are stored (default: SEQUENCE_VALUE)</li>
54   * <li>SequenceGeneratorConstants.BLOCKSIZECOLUMN: Name of the column where the sequence blocksizes are stored (default: SEQUENCE_BLOCKSIZE)</li>
55   * <li>SequenceGeneratorConstants.USEPUBLICSYNONYMS: Boolean value (stored as String) for indication to check for synonyms first (default: false)</li>
56   * <li>SequenceGeneratorConstants.CUSTOMTABLENAME: Name of a alternate table for the sequences. Has higher preference to TABLENAME (default: none)</li>
57   * </ul>
58   * Since this version the CustomSequenceGeneratorSettings object is no longer supported!<p>
59   *
60   * <i><b>NOTE:</b> The generator supports SYNONYMS in the TableCreator, however it <br>
61   * cannot alter the original table of the synonym. When using SYNONYMS make sure<br>
62   * the table is correct before using the generator!</i><p>
63   * Usage:<br>
64   * Create a FacadeBean that uses this Session EJB. This Facade knows about the <br>
65   * used datasource and table name. Another advantage is that it is loose coupled<br>
66   * So changing the SequenceGenerator is easy.<br>
67   * Another approach is creating an Object that holds all configuration information.<br>
68   * See SequenceGeneratorCustomizable interface on how to do this.
69   * @author Vincent van Wichen (based on code of Erik Jan de Wit)
70   * @version $Revision: 1.7 $, $Date: 2004/04/03 13:40:36 $
71   * @ejb:bean type="Stateless"
72   *           name="com.finalist.util.sequencegenerator.SequenceGenerator"
73   *           local-jndi-name="local/com/finalist/util/sequencegenerator/SequenceGenerator"
74   *           jndi-name="com/finalist/util/sequencegenerator/SequenceGenerator"
75   *           view-type="both"
76   * @ejb:transaction type="NotSupported"
77   * @ejb:transaction-type type="Container"
78   * @ejb:util generate="physical"
79   * @see SequenceGeneratorCustomizable
80   * @see SequenceGeneratorConstants
81   */
82  public class SequenceGeneratorEJB implements SessionBean {
83  
84     /*** Log handler */
85     private transient org.apache.log4j.Category log = org.apache.log4j.Category.getInstance(SequenceGeneratorEJB.class);
86  
87     /*** Start of every new sequence */
88     private static final long DEFAULT_START_OF_SEQUENCE = 1l;
89     /*** Stores all sequence blocks. Static so all EJB's will use the same instance. */
90     private static HashMap sequenceBlocks;
91  
92     /*** Default blocksize */
93     private static int blockSize;
94  
95     /*** Datasource to work with */
96     private String datasourceName;
97  
98     /*** Stores the last used datasource. Used for caching */
99     private String lastDatasourceNameUsed = "";
100 
101    /*** Reference to the datasource. */
102    private DataSource datasource = null;
103 
104    /*** Name of the sequence table in the database. */
105    private String sequenceTableName;
106 
107    private SessionContext ctx;
108 
109    /*** Selects the next value in the sequencetable. */
110    private String SELECTSEQUENCE;
111 
112    /*** Selects the next value in the sequencetable. */
113    private String SELECTSEQUENCE_NONLOCKING;
114 
115    /*** Updates the new value in the database. */
116    private String UPDATESEQUENCE;
117 
118    /*** Updates the blocksize in the database. */
119    private String UPDATEBLOCKSIZE;
120 
121    /*** Inserts a new sequence in the database. */
122    private String INSERTSEQUENCE;
123 
124    /*** Deletes a sequence from the database. */
125    private String DELETESEQUENCE;
126 
127    /*** Holder for default setting Object */
128    private static SequenceGeneratorDefaults defaults = null;
129    /*** Holder for user settings object (if any) */
130    //private SequenceGeneratorCustomizable settings = null;
131 
132    /*** Private holder for the column name for the sequence name */
133    private String sequenceNameCol = null;
134    /*** Private holder for the column name for the value of the sequence */
135    private String sequenceValueCol = null;
136    /*** Private holder for the column name for the block size */
137    private String sequenceBlocksizeCol = null;
138 
139    private boolean useLocking = true;
140 
141 
142    public void setSessionContext(SessionContext context) throws RemoteException, EJBException {
143       ctx = context;
144    }
145 
146 
147    public void ejbActivate() throws RemoteException, EJBException {
148    }
149 
150 
151    public void ejbPassivate() throws RemoteException, EJBException {
152    }
153 
154 
155    public void ejbRemove() throws RemoteException, EJBException {
156    }
157 
158 
159    /*** Instantiates the EJB
160     * @ejb:create-method
161     * @throws CreateException
162     */
163    public void ejbCreate() throws CreateException  {
164       if (sequenceBlocks == null) {
165          log.debug("Creating new SEQUENCEBLOCKS");
166          sequenceBlocks = new HashMap();
167       }
168    }
169 
170 
171    /*** Constructs a Property Object using the old settings method. Using a CustomSequenceGeneratorSettings Object
172     * @param datasourceName Name of the Datasource
173     * @param customSequenceTableName Name of a alternate tablename. <CODE>null</CODE> when using the table set in the settings.
174     * @return Properties Object reflecting the old settings
175     * @BUSINESSMETHOD
176     * @ejb:interface-mathod
177     */
178 
179    public Properties getPropertiesByOldMethod(String datasourceName, String customSequenceTableName) {
180       Properties props = new Properties();
181       SequenceGeneratorCustomizable settings = null;
182       try {
183          Class foundClass = Class.forName("com.finalist.util.sequencegenerator.CustomSequenceGeneratorSettings");
184          log.debug("Custom settings object found!");
185          settings = (com.finalist.util.sequencegenerator.SequenceGeneratorCustomizable) foundClass.newInstance();
186       }
187       catch (ClassNotFoundException cnfe) {
188          log.debug("Custom settings object *not* found! All defaults will be used");
189       }
190       catch (InstantiationException ie) {
191          log.error("Custom settings object could not be instantiated. ABORT");
192          throw new EJBException(ie);
193       }
194       catch (IllegalAccessException iae) {
195          log.error("Custom settings object could not be instantiated. ABORT");
196          throw new EJBException(iae);
197       }
198 
199 
200       if (settings != null) {
201          props.setProperty(SequenceGeneratorConstants.DATASOURCENAME, settings.getDataSourceName());
202       }
203 
204       if (customSequenceTableName == null) {
205          if (settings != null) {
206             props.setProperty(SequenceGeneratorConstants.TABLENAME, settings.getSequenceTableName());
207          }
208       }
209       else {
210          props.setProperty(SequenceGeneratorConstants.CUSTOMTABLENAME, customSequenceTableName);
211       }
212       if (settings != null) {
213          props.setProperty(SequenceGeneratorConstants.NAMECOLUMN, settings.getSequenceNameColumnName());
214          props.setProperty(SequenceGeneratorConstants.VALUECOLUMN, settings.getSequenceValueColumnName());
215          props.setProperty(SequenceGeneratorConstants.BLOCKSIZECOLUMN, settings.getSequenceBlockSizeColumnName());
216          props.setProperty(SequenceGeneratorConstants.BLOCKSIZE, "" + settings.getBlockSize());
217          props.setProperty(SequenceGeneratorConstants.USEPUBLICSYNONYMS, "" + settings.usePublicSynonyms());
218       }
219 
220       return props;
221    }
222 
223 
224    /*** Initializes the attributes for its action.<p>
225     * This method is must always be called when handling a business method.
226     * @param datasourceName The datasource name for this sequence.
227     * @param customSequenceTableName The table name for this sequence in mentioned datasource.
228     * @deprecated Only <CODE>init(Properties)</CODE> is used.
229     */
230    private void init(String datasourceName, String customSequenceTableName) {
231       Properties props = this.getPropertiesByOldMethod(datasourceName, customSequenceTableName);
232       this.init(props);
233    }
234 
235 
236    /*** Initializes the attributes for its action.<p>
237     * This method is must always be called when handling a business method.
238     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
239     * See the SequenceGeneratorConstants for the settings.
240     */
241    private void init(Properties props) {
242       if (defaults == null) {
243          defaults = new SequenceGeneratorDefaults();
244       }
245       // Getting Possible Settings
246       this.sequenceTableName = props.getProperty(SequenceGeneratorConstants.CUSTOMTABLENAME);
247       this.datasourceName = props.getProperty(SequenceGeneratorConstants.DATASOURCENAME);
248       this.blockSize = Integer.parseInt(props.getProperty(SequenceGeneratorConstants.BLOCKSIZE, "" + defaults.getBlockSize()));
249       this.sequenceNameCol = props.getProperty(SequenceGeneratorConstants.NAMECOLUMN, defaults.getSequenceNameColumnName());
250       this.sequenceValueCol = props.getProperty(SequenceGeneratorConstants.VALUECOLUMN, defaults.getSequenceValueColumnName());
251       this.sequenceBlocksizeCol = props.getProperty(SequenceGeneratorConstants.BLOCKSIZECOLUMN, defaults.getSequenceBlockSizeColumnName());
252 
253       if (this.datasourceName == null) {
254          throw new EJBException("Datasource not specified");
255       }
256       if (this.sequenceTableName == null) {
257          this.sequenceTableName = props.getProperty(SequenceGeneratorConstants.TABLENAME, defaults.getSequenceTableName());
258          if (this.sequenceTableName == null) {
259             throw new EJBException("Sequence table is not specified");
260          }
261       }
262       if (this.blockSize == -1 || this.sequenceNameCol == null || this.sequenceValueCol == null || this.sequenceBlocksizeCol == null) {
263          throw new EJBException("One or more of the required attributes is/are not specified");
264       }
265 
266       //Constructing SQL
267       this.SELECTSEQUENCE_NONLOCKING =
268          "SELECT " + this.sequenceNameCol + "," + this.sequenceValueCol + "," + this.sequenceBlocksizeCol +
269          " FROM " + sequenceTableName + " WHERE " + this.sequenceNameCol + " = ?";
270       this.SELECTSEQUENCE = SELECTSEQUENCE_NONLOCKING + " FOR UPDATE";
271 
272       this.UPDATESEQUENCE =
273          "UPDATE " + this.sequenceTableName + " SET " + this.sequenceValueCol + " = ?, " + this.sequenceBlocksizeCol + " = ? " +
274          "WHERE " + this.sequenceNameCol + " = ? AND " + this.sequenceValueCol + " <= ?";
275       this.UPDATEBLOCKSIZE =
276          "UPDATE " + this.sequenceTableName + " SET " + this.sequenceBlocksizeCol + " = ? " +
277          "WHERE " + this.sequenceNameCol + " = ?";
278       this.INSERTSEQUENCE =
279          "INSERT INTO " + this.sequenceTableName + " (" + this.sequenceNameCol + ", " +
280          this.sequenceValueCol + ", " + this.sequenceBlocksizeCol + ") VALUES (?,?,?)";
281       this.DELETESEQUENCE =
282          "DELETE FROM " + this.sequenceTableName + " WHERE " + this.sequenceNameCol + " = ?";
283    }
284 
285 
286    /*** Returns the next sequence number.<p>
287     * Uses the datasource and table specified in the configuration settings.<br>
288     * Same as <CODE>getNextNumberInSequence(name, null, null)</CODE>
289     * @BUSINESSMETHOD
290     * @ejb:interface-method
291     * @return Next sequence.
292     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
293     * @deprecated Use {@link getNextNumberInSequence(String, Properties)}
294     */
295    public long getNextNumberInSequence(String name)  {
296       return this.getNextNumberInSequence(name, null, null);
297    }
298 
299 
300    /*** Returns the next sequence number.<p>
301     * Uses the table specified in the configuration settings.<br>
302     * Same as <CODE>getNextNumberInSequence(name, datasourceName, null)</CODE>
303     * @BUSINESSMETHOD
304     * @ejb:interface-method
305     * @return Next sequence.
306     * @param datasourceName Datasource name for the database
307     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
308     * @deprecated Use {@link getNextNumberInSequence(String, Properties)}
309     */
310    public long getNextNumberInSequence(String name, String datasourceName) {
311       return this.getNextNumberInSequence(name, datasourceName, null);
312    }
313 
314 
315    /*** Returns the next sequence number.<p>
316     * @BUSINESSMETHOD
317     * @ejb:interface-method
318     * @return Next sequence.
319     * @param datasourceName Datasource name for the database
320     * @param sequenceTableName Table name for this sequence in mentioned datasource
321     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
322     * @deprecated Use {@link getNextNumberInSequence(String, Properties)}
323     */
324    public long getNextNumberInSequence(String name, String datasourceName, String sequenceTableName) {
325       return this.getNextNumberInSequence(name, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
326    }
327 
328 
329    /*** Returns the next sequence number.<p>
330     * @BUSINESSMETHOD
331     * @ejb:interface-method
332     * @return Next sequence.
333     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
334     * See the SequenceGeneratorConstants for the settings.
335     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
336     */
337    public long getNextNumberInSequence(String name, Properties props)  {
338       init(props);
339       SequenceBlock sequenceBlock = this.getSequenceBlock(name, props);
340 
341       synchronized (sequenceBlock) {
342          if (sequenceBlock.current == sequenceBlock.last) {
343             this.refreshBlockForSequence(name, props);
344          }
345          return sequenceBlock.current++;
346       }
347    }
348 
349 
350    /*** Returns the next sequence number as String.<p>
351     * @BUSINESSMETHOD
352     * @ejb:interface-method
353     * @return Next sequence.
354     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
355     * @deprecated use {@link getNextNumberInSequenceAsString(String, Properties)}
356     */
357    public String getNextNumberInSequenceAsString(String name)  {
358       return this.getNextNumberInSequenceAsString(name, null, null);
359    }
360 
361 
362    /*** Returns the next sequence number as String.<p>
363     * @BUSINESSMETHOD
364     * @ejb:interface-method
365     * @return Next sequence.
366     * @param datasourceName Datasource name for the database
367     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
368     * @deprecated use {@link getNextNumberInSequenceAsString(String, Properties)}
369     */
370    public String getNextNumberInSequenceAsString(String name, String datasourceName)  {
371       return this.getNextNumberInSequenceAsString(name, datasourceName, null);
372    }
373 
374 
375    /*** Returns the next sequence number as String.<p>
376     * @BUSINESSMETHOD
377     * @ejb:interface-method
378     * @return Next sequence.
379     * @param datasourceName Datasource name for the database
380     * @param sequenceTableName Table name for this sequence in mentioned datasource
381     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
382     * @deprecated use {@link getNextNumberInSequenceAsString(String, Properties)}
383     */
384    public String getNextNumberInSequenceAsString(String name, String datasourceName, String sequenceTableName)  {
385       return "" + this.getNextNumberInSequence(name, datasourceName, sequenceTableName);
386    }
387 
388 
389    /*** Returns the next sequence number as String.<p>
390     * @BUSINESSMETHOD
391     * @ejb:interface-method
392     * @return Next sequence.
393     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
394     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
395     * See the SequenceGeneratorConstants for the settings.
396     */
397    public String getNextNumberInSequenceAsString(String name, Properties props)  {
398       return "" + this.getNextNumberInSequence(name, props);
399    }
400 
401 
402    /*** Returns the next sequence number as fixed length zero-filled String.<p>
403     * @BUSINESSMETHOD
404     * @ejb:interface-method
405     * @return Next sequence.
406     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
407     * @param length of the desired String
408     * @deprecated Use {@link getNextNumberInSequenceAsString(String, int, Properties)}
409     */
410    public String getNextNumberInSequenceAsString(String name, int length)  {
411       return this.getNextNumberInSequenceAsString(name, null, null, length);
412    }
413 
414 
415    /*** Returns the next sequence number as fixed length zero-filled String.<p>
416     * @BUSINESSMETHOD
417     * @ejb:interface-method
418     * @return Next sequence.
419     * @param datasourceName Datasource name for the database
420     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
421     * @param length of the desired String
422     * @deprecated Use {@link getNextNumberInSequenceAsString(String, int, Properties)}
423     */
424    public String getNextNumberInSequenceAsString(String name, String datasourceName, int length)  {
425       return this.getNextNumberInSequenceAsString(name, datasourceName, null, length);
426    }
427 
428 
429    /*** Returns the next sequence number as fixed length zero-filled String.<p>
430     * @BUSINESSMETHOD
431     * @ejb:interface-method
432     * @return Next sequence.
433     * @param datasourceName Datasource name for the database
434     * @param sequenceTableName Table name for this sequence in mentioned datasource
435     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
436     * @param length of the desired String
437     * @deprecated Use {@link getNextNumberInSequenceAsString(String, int, Properties)}
438     */
439    public String getNextNumberInSequenceAsString(String name, String datasourceName, String sequenceTableName, int length)  {
440       return this.getNextNumberInSequenceAsString(name, length, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
441    }
442 
443 
444    /*** Returns the next sequence number as fixed length zero-filled String.<p>
445     * @BUSINESSMETHOD
446     * @ejb:interface-method
447     * @return Next sequence.
448     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
449     * See the SequenceGeneratorConstants for the settings.
450     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
451     * @param length of the desired String
452     */
453    public String getNextNumberInSequenceAsString(String name, int length, Properties props)  {
454       StringBuffer sb = new StringBuffer(this.getNextNumberInSequenceAsString(name, props));
455       while (sb.length() < length) {
456          sb.insert(0, '0');
457       }
458       return sb.toString();
459    }
460 
461 
462    /*** Sets the new number in the sequence.<p>
463     * The new number must greater than or equal to the current key<br>
464     * and if the falls outside the block, it must be greater than or equal to the current value in the<br>
465     * database. If not then it will throw an exception.
466     * Uses the datasource and table specified in the configuration settings.<br>
467     * Same as <CODE>setNumberInSequence(name, newNumber, null, null)</CODE>
468     * @BUSINESSMETHOD
469     * @ejb:interface-method
470     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
471     * @param newNumber New number in the sequence.
472     * @deprecated Use {@link setNumberInSequence(String, long, Properties)}
473     */
474    public void setNumberInSequence(String name, long newNumber) {
475       this.setNumberInSequence(name, newNumber, null, null);
476    }
477 
478 
479    /*** Sets the new number in the sequence.<p>
480     * The new number must greater than or equal to the current key<br>
481     * and if the falls outside the block, it must be greater than or equal to the current value in the<br>
482     * database. If not then it will throw an exception.
483     * Uses the table specified in the configuration settings.<br>
484     * Same as <CODE>setNumberInSequence(name, newNumber, datasourceName, null)</CODE>
485     * @BUSINESSMETHOD
486     * @ejb:interface-method
487     * @param datasourceName Datasource name for the database
488     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
489     * @param newNumber New number in the sequence.
490     * @deprecated Use {@link setNumberInSequence(String, long, Properties)}
491     */
492    public void setNumberInSequence(String name, long newNumber, String datasourceName)  {
493       this.setNumberInSequence(name, newNumber, datasourceName, null);
494    }
495 
496 
497    /*** Sets the new number in the sequence.<p>
498     * The new number must greater than or equal to the current key<br>
499     * and if the falls outside the block, it must be greater than or equal to the current value in the<br>
500     * database. If not then it will throw an exception.
501     * @BUSINESSMETHOD
502     * @ejb:interface-method
503     * @param datasourceName Datasource name for the database
504     * @param sequenceTableName Table name for this sequence in mentioned datasource
505     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
506     * @param newNumber New number in the sequence.
507     * @deprecated Use {@link setNumberInSequence(String, long, Properties)}
508     */
509    public void setNumberInSequence(String name, long newNumber, String datasourceName, String sequenceTableName)  {
510       this.setNumberInSequence(name, newNumber, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
511    }
512 
513 
514    /*** Sets the new number in the sequence.<p>
515     * The new number must greater than or equal to the current key<br>
516     * and if the falls outside the block, it must be greater than or equal to the current value in the<br>
517     * database. If not then it will throw an exception.
518     * @BUSINESSMETHOD
519     * @ejb:interface-method
520     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
521     * See the SequenceGeneratorConstants for the settings.
522     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
523     * @param newNumber New number in the sequence.
524     */
525    public void setNumberInSequence(String name, long newNumber, Properties props)  {
526       log.debug("+ setNumberInSequence for " + name + " with value " + newNumber);
527       init(props);
528       SequenceBlock sequenceBlock = this.getSequenceBlock(name, props);
529       synchronized (sequenceBlock) {
530          if (newNumber < sequenceBlock.current) {
531             throw new EJBException("New key must be greater than or equal to current key! Sequence not updated");
532          }
533          if (newNumber <= sequenceBlock.last) {
534             sequenceBlock.current = newNumber;
535             log.info("Updating current key succeeded in memory! Update done in Memory.");
536             return;
537          }
538          Connection connection = null;
539          PreparedStatement ps = null;
540          try {
541             connection = getDatabaseConnection();
542             ps = connection.prepareStatement(this.UPDATESEQUENCE);
543             ps.setLong(1, newNumber);
544             ps.setInt(2, sequenceBlock.blockSize);
545             ps.setString(3, name);
546             ps.setLong(4, newNumber);
547             if (ps.executeUpdate() > 0) {
548                sequenceBlock.last = sequenceBlock.current + sequenceBlock.blockSize;
549                log.info("Updating current key succeeded! Update done in database & memory.");
550             }
551             else {
552                log.warn("Current key not updated in database & memory! Check if new key is >= than old key!");
553                return;
554             }
555          }
556          catch (SQLException sqle) {
557             throw new EJBException(sqle);
558          }
559          finally {
560             try {
561                if (ps != null) {
562                   ps.close();
563                   ps = null;
564                }
565                if (connection != null) {
566                   connection.close();
567                   connection = null;
568                }
569             }
570             catch (SQLException slqe1) {
571                //
572             }
573          }
574       }
575    }
576 
577 
578    /*** Sets a new block size of a sequence.<p>
579     * This new blocksize will be used when the block will be refreshed.<br>
580     * @BUSINESSMETHOD
581     * @ejb:interface-method
582     * @param datasourceName Datasource name for the database
583     * @param sequenceTableName Table name for this sequence in mentioned datasource
584     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
585     * @param blockSize New block size. Must be greater than 0
586     * @deprecated Use {@link setBlockSizeForSequence(String, int, boolean, Properties)}
587     */
588    public void setBlockSizeForSequence(String name, int blockSize, String datasourceName, String sequenceTableName)  {
589       this.setBlockSizeForSequence(name, blockSize, false, datasourceName, sequenceTableName);
590    }
591 
592 
593    /*** Sets a new block size of a sequence.<p>
594     * This new blocksize will be used when the block will be refreshed. This can be<br>
595     * done by setting refreshBlock true as 3rd parameter.
596     * Uses the datasource and table specified in the configuration settings.<br>
597     * Same as <CODE>setBlockSizeForSequence(name, blockSize, refreshBlock, null, null)</CODE>
598     * @BUSINESSMETHOD
599     * @ejb:interface-method
600     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
601     * @param blockSize New block size. Must be greater than 0
602     * @param refreshBlock <CODE>True</CODE> if a refresh is forced.
603     * @deprecated Use {@link setBlockSizeForSequence(String, int, boolean, Properties)}
604     */
605    public void setBlockSizeForSequence(String name, int blockSize, boolean refreshBlock) {
606       this.setBlockSizeForSequence(name, blockSize, refreshBlock, null, null);
607    }
608 
609 
610    /*** Sets a new block size of a sequence.<p>
611     * This new blocksize will be used when the block will be refreshed. This can be<br>
612     * done by setting refreshBlock true as 3rd parameter.
613     * Uses the table specified in the configuration settings.<br>
614     * Same as <CODE>setBlockSizeForSequence(name, blockSize, refreshBlock, datasourceName, null)</CODE>
615     * @BUSINESSMETHOD
616     * @ejb:interface-method
617     * @param datasourceName Datasource name for the database
618     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
619     * @param blockSize New block size. Must be greater than 0
620     * @param refreshBlock True if a refresh is forced.
621     * @deprecated Use {@link setBlockSizeForSequence(String, int, boolean, Properties)}
622     */
623    public void setBlockSizeForSequence(String name, int blockSize, boolean refreshBlock, String datasourceName)  {
624       this.setBlockSizeForSequence(name, blockSize, refreshBlock, datasourceName, null);
625    }
626 
627 
628    /*** Sets a new block size of a sequence.<p>
629     * This new blocksize will be used when the block will be refreshed. This can be<br>
630     * done by setting refreshBlock true as 3rd parameter.
631     * @BUSINESSMETHOD
632     * @ejb:interface-method
633     * @param datasourceName Datasource name for the database
634     * @param sequenceTableName Table name for this sequence in mentioned datasource
635     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
636     * @param blockSize New block size. Must be greater than 0
637     * @param refreshBlock True if a refresh is forced.
638     * @deprecated Use {@link setBlockSizeForSequence(String, int, boolean, Properties)}
639     */
640    public void setBlockSizeForSequence(String name, int blockSize, boolean refreshBlock, String datasourceName, String sequenceTableName)  {
641       this.setBlockSizeForSequence(name, blockSize, refreshBlock, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
642    }
643 
644 
645    /*** Sets a new block size of a sequence.<p>
646     * This new blocksize will be used when the block will be refreshed. This can be<br>
647     * done by setting refreshBlock true as 3rd parameter.
648     * @BUSINESSMETHOD
649     * @ejb:interface-method
650     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
651     * See the SequenceGeneratorConstants for the settings.
652     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
653     * @param blockSize New block size. Must be greater than 0
654     * @param refreshBlock True if a refresh is forced.
655     */
656    public void setBlockSizeForSequence(String name, int blockSize, boolean refreshBlock, Properties props)  {
657       log.debug("+ setBlockSizeForSequence changing Blocksize for " + name + " with value " + blockSize + " (refresh forced " + refreshBlock + ")");
658       init(props);
659       SequenceBlock sequenceBlock = this.getSequenceBlock(name, props);
660       synchronized (sequenceBlock) {
661          Connection connection = null;
662          PreparedStatement ps = null;
663          try {
664             connection = this.getDatabaseConnection();
665             ps = connection.prepareStatement(this.UPDATEBLOCKSIZE);
666             ps.setInt(1, blockSize);
667             ps.setString(2, name);
668             if (ps.executeUpdate() > 0) {
669                log.info("Blocksize for " + name + " changed to " + blockSize);
670             }
671             else {
672                log.error("Blocksize change failed for " + name);
673                return;
674             }
675          }
676          catch (SQLException sqle) {
677             throw new EJBException(sqle);
678          }
679          finally {
680             try {
681                if (ps != null) {
682                   ps.close();
683                   ps = null;
684                }
685                if (connection != null) {
686                   connection.close();
687                   connection = null;
688                }
689             }
690             catch (SQLException sqle1) {
691                //
692             }
693          }
694          sequenceBlock.blockSize = blockSize;
695       }
696       if (refreshBlock) {
697          this.refreshBlockForSequence(name, props);
698       }
699    }
700 
701 
702    /*** Refreshes the sequence block with a new sequence out of the database and updates the database.<p>
703     * Uses the datasource and table specified in the configuration settings.<br>
704     * Same as <CODE>refreshBlockForSequence(name, null, null)</CODE>
705     * @BUSINESSMETHOD
706     * @ejb:interface-method
707     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
708     * @deprecated Use {@link refreshBlockForSequence(String, Properties)}
709     */
710    public void refreshBlockForSequence(String name) {
711       this.refreshBlockForSequence(name, null, null);
712    }
713 
714 
715    /*** Refreshes the sequence block with a new sequence out of the database and updates the database.<p>
716     * Uses the table specified in the configuration settings.<br>
717     * Same as <CODE>refreshBlockForSequence(name, datasourceName, null)</CODE>
718     * @BUSINESSMETHOD
719     * @ejb:interface-method
720     * @param datasourceName Datasource name for the database
721     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
722     * @deprecated Use {@link refreshBlockForSequence(String, Properties)}
723     */
724    public void refreshBlockForSequence(String name, String datasourceName)  {
725       this.refreshBlockForSequence(name, datasourceName, null);
726    }
727 
728 
729    /*** Refreshes the sequence block with a new sequence out of the database and updates the database.<p>
730     * @BUSINESSMETHOD
731     * @ejb:interface-method
732     * @param datasourceName Datasource name for the database
733     * @param sequenceTableName Table name for this sequence in mentioned datasource
734     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
735     * @deprecated Use {@link refreshBlockForSequence(String, Properties)}
736     */
737    public void refreshBlockForSequence(String name, String datasourceName, String sequenceTableName)  {
738       this.refreshBlockForSequence(name, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
739    }
740 
741 
742    /*** Refreshes the sequence block with a new sequence out of the database and updates the database.<p>
743     * @BUSINESSMETHOD
744     * @ejb:interface-method
745     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
746     * See the SequenceGeneratorConstants for the settings.
747     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
748     */
749    public void refreshBlockForSequence(String name, Properties props)  {
750       log.debug("+ refreshBlockForSequence for " + name);
751       init(props);
752       SequenceBlock sequenceBlock = this.getSequenceBlock(name, props);
753       synchronized (sequenceBlock) {
754          SequenceBlock newBlock = this.getNextKeyAfterIncrementingBy(name);
755          sequenceBlock.last = newBlock.last;
756          sequenceBlock.current = newBlock.current;
757          sequenceBlock.blockSize = newBlock.blockSize;
758          log.debug("Sequence Block updated: " + sequenceBlock.toString());
759       }
760    }
761 
762 
763    /*** Returns the low watermark in the sequence block.<p>
764     * This is the same value as getNextNumerInSequence, however it will not increase<br>
765     * the sequence.<br>
766     * Uses the datasource and table specified in the configuration settings.<br>
767     * Same as <CODE>getLowWaterMarkForSequence(name, null, null)</CODE>
768     * @BUSINESSMETHOD
769     * @ejb:interface-method
770     * @return The low watermark in the sequence.
771     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
772     * @deprecated Use {@link getLowWaterMarkForSequence(name, Properties)}
773     */
774    public long getLowWaterMarkForSequence(String name)  {
775       return this.getLowWaterMarkForSequence(name, null, null);
776    }
777 
778 
779    /*** Returns the low watermark in the sequence block.<p>
780     * This is the same value as getNextNumerInSequence, however it will not increase<br>
781     * the sequence.
782     * Uses the table specified in the configuration settings.<br>
783     * Same as <CODE>getLowWaterMarkForSequence(name, datasourceName, null)</CODE>
784     * @BUSINESSMETHOD
785     * @ejb:interface-method
786     * @return The low watermark in the sequence.
787     * @param datasourceName Datasource name for the database
788     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
789     * @deprecated Use {@link getLowWaterMarkForSequence(name, Properties)}
790     */
791    public long getLowWaterMarkForSequence(String name, String datasourceName)  {
792       return this.getLowWaterMarkForSequence(name, datasourceName, null);
793    }
794 
795 
796    /*** Returns the low watermark in the sequence block.<p>
797     * This is the same value as getNextNumerInSequence, however it will not increase<br>
798     * the sequence.
799     * @BUSINESSMETHOD
800     * @ejb:interface-method
801     * @return The low watermark in the sequence.
802     * @param datasourceName Datasource name for the database
803     * @param sequenceTableName Table name for this sequence in mentioned datasource
804     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
805     * @deprecated Use {@link getLowWaterMarkForSequence(name, Properties)}
806     */
807    public long getLowWaterMarkForSequence(String name, String datasourceName, String sequenceTableName)  {
808       return this.getLowWaterMarkForSequence(name, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
809    }
810 
811 
812    /*** Returns the low watermark in the sequence block.<p>
813     * This is the same value as getNextNumerInSequence, however it will not increase<br>
814     * the sequence.
815     * @BUSINESSMETHOD
816     * @ejb:interface-method
817     * @return The low watermark in the sequence.
818     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
819     * See the SequenceGeneratorConstants for the settings.
820     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
821     */
822    public long getLowWaterMarkForSequence(String name, Properties props)  {
823       init(props);
824       return getSequenceBlock(name, props).current;
825    }
826 
827 
828    /*** Gets the high watermark in the sequence.<p>
829     * This is the last number in the current sequence block of this sequence in memory. If the low watermark and<br>
830     * the high watermark is equal than a refresh is called.<br>
831     * Uses the datasource and table specified in the configuration settings.<br>
832     * Same as <CODE>getHighWaterMarkForSequence(name, null, null)</CODE>
833     * @BUSINESSMETHOD
834     * @ejb:interface-method
835     * @return The high watermark for this sequence.
836     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
837     * @deprecated Use {@link getHighWaterMarkForSequence(String, Properties)}
838     */
839    public long getHighWaterMarkForSequence(String name)  {
840       return this.getHighWaterMarkForSequence(name, null, null);
841    }
842 
843 
844    /*** Gets the high watermark in the sequence. <p>
845     * This is the last number in the<br>
846     * current sequence block of this sequence in memory. If the low watermark and<br>
847     * the high watermark is equal than a refresh is called.<br>
848     * Uses the table specified in the configuration settings.<br>
849     * Same as <CODE>getHighWaterMarkForSequence(name, datasourceName, null)</CODE>
850     * @BUSINESSMETHOD
851     * @ejb:interface-method
852     * @return The high watermark for this sequence.
853     * @param datasourceName Datasource name for the database
854     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
855     * @deprecated Use {@link getHighWaterMarkForSequence(String, Properties)}
856     */
857    public long getHighWaterMarkForSequence(String name, String datasourceName)  {
858       return this.getHighWaterMarkForSequence(name, datasourceName, null);
859    }
860 
861 
862    /*** Gets the high watermark in the sequence. <p>
863     * This is the last number in the<br>
864     * current sequence block of this sequence in memory. If the low watermark and<br>
865     * the high watermark is equal than a refresh is called.
866     * @BUSINESSMETHOD
867     * @ejb:interface-method
868     * @return The high watermark for this sequence.
869     * @param datasourceName Datasource name for the database
870     * @param sequenceTableName Table name for this sequence in mentioned datasource
871     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
872     * @deprecated Use {@link getHighWaterMarkForSequence(String, Properties)}
873     */
874    public long getHighWaterMarkForSequence(String name, String datasourceName, String sequenceTableName)  {
875       return this.getHighWaterMarkForSequence(name, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
876    }
877 
878 
879    /*** Gets the high watermark in the sequence. <p>
880     * This is the last number in the<br>
881     * current sequence block of this sequence in memory. If the low watermark and<br>
882     * the high watermark is equal than a refresh is called.
883     * @BUSINESSMETHOD
884     * @ejb:interface-method
885     * @return The high watermark for this sequence.
886     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
887     * See the SequenceGeneratorConstants for the settings.
888     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
889     */
890    public long getHighWaterMarkForSequence(String name, Properties props)  {
891       init(props);
892       return getSequenceBlock(name, props).last;
893    }
894 
895 
896    /*** Removes a sequence from the database.<p>
897     * If the sequence doesn't exist or several sequences matches the name<br>
898     * (nearly impossible) an exception is thrown.<br>
899     * Uses the datasource and table specified in the configuration settings.<br>
900     * Same as <CODE>removeSequence(name, null, null)</CODE>
901     * @BUSINESSMETHOD
902     * @ejb:interface-method
903     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
904     * @deprecated Use {@link removeSequence(String, Properties)}
905     */
906    public void removeSequence(String name)  {
907       this.removeSequence(name, null, null);
908    }
909 
910 
911    /*** Removes a sequence from the database.<p>
912     * If the sequence doesn't exist or several sequences matches the name<br>
913     * (nearly impossible) an exception is thrown.<br>
914     * Uses the table specified in the configuration settings.<br>
915     * Same as <CODE>removeSequence(name, datasourceName, null)</CODE>
916     * @BUSINESSMETHOD
917     * @ejb:interface-method
918     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
919     * @param datasourceName Datasource name for the database
920     * @deprecated Use {@link removeSequence(String, Properties)}
921     */
922    public void removeSequence(String name, String datasourceName)  {
923       this.removeSequence(name, datasourceName, null);
924    }
925 
926 
927    /*** Removes a sequence from the database.<p>
928     * If the sequence doesn't exist or several sequences matches the name<br>
929     * (nearly impossible) an exception is thrown.
930     * @BUSINESSMETHOD
931     * @ejb:interface-method
932     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
933     * @param datasourceName Datasource name for the database
934     * @param sequenceTableName Table name for this sequence in mentioned datasource
935     * @deprecated Use {@link removeSequence(String, Properties)}
936     */
937    public void removeSequence(String name, String datasourceName, String sequenceTableName)  {
938       this.removeSequence(name, this.getPropertiesByOldMethod(datasourceName, sequenceTableName));
939 
940    }
941 
942 
943    /*** Removes a sequence from the database.<p>
944     * If the sequence doesn't exist or several sequences matches the name<br>
945     * (nearly impossible) an exception is thrown.
946     * @BUSINESSMETHOD
947     * @ejb:interface-method
948     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
949     * See the SequenceGeneratorConstants for the settings.
950     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
951     */
952    public void removeSequence(String name, Properties props)  {
953       log.debug("+ removeSequence for " + name);
954       init(props);
955       Connection connection = null;
956       PreparedStatement ps = null;
957       try {
958          connection = this.getDatabaseConnection();
959          connection.setAutoCommit(false);
960          ps = connection.prepareStatement(this.DELETESEQUENCE);
961          ps.setString(1, name);
962          if (ps.executeUpdate() != 1) {
963             connection.rollback();
964             log.error("Removal of " + name + " failed. No or several items exist");
965          }
966          else {
967             connection.commit();
968             log.info("Removal of " + name + " succeeded");
969          }
970       }
971       catch (SQLException sqle) {
972          log.error("Removal of " + name + " failed. Exception occurred: " + sqle.toString());
973          throw new EJBException(sqle);
974       }
975       finally {
976          try {
977             if (ps != null) {
978                ps.close();
979                ps = null;
980             }
981             if (connection != null) {
982                connection.close();
983                connection = null;
984             }
985          }
986          catch (SQLException sqle) {
987             //
988          }
989       }
990       this.removeSequenceBlock(name);
991    }
992 
993    //
994    //
995    // PRIVATE HELPER METHODS
996    //
997    //
998 
999 
1000    /*** Gets the requested sequence stored in memory.<p> If not existing then a new one<br>
1001     * will be created. Before creation the database will be checked if it is valid.
1002     * @return A SequenceBlock
1003     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
1004     * See the SequenceGeneratorConstants for the settings.
1005     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
1006     */
1007    private synchronized SequenceBlock getSequenceBlock(String name, Properties props) {
1008       SequenceBlockId sequenceBlockId = new SequenceBlockId(this.datasourceName, this.sequenceTableName, name);
1009       SequenceBlock sequenceBlock = (SequenceBlock) sequenceBlocks.get(sequenceBlockId);
1010       if (sequenceBlock == null) {
1011 
1012          // If sequenceBlock is new in memory always check the database
1013          log.info("New sequence found! Checking database!");
1014          this.checkTable(props);
1015 
1016          sequenceBlock = this.getNextKeyAfterIncrementingBy(name);
1017          log.info("New sequenceBlock (" + name + ") created: " + sequenceBlock.toString());
1018          sequenceBlocks.put(sequenceBlockId, sequenceBlock);
1019       }
1020       log.debug("" + sequenceBlocks.size() + " SequenceBlocks in memory");
1021       if (sequenceBlock == null) {
1022          throw new EJBException("SequenceBlock not found and created!");
1023       }
1024       return sequenceBlock;
1025    }
1026 
1027 
1028    /*** Gets the requested sequence stored in memory.<p> If not existing then a new one<br>
1029     * will be created. Before creation the database will be checked if it is valid.
1030     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
1031     */
1032    private synchronized void removeSequenceBlock(String name) {
1033       SequenceBlockId sequenceBlockId = new SequenceBlockId(this.datasourceName, this.sequenceTableName, name);
1034       sequenceBlocks.remove(sequenceBlockId);
1035    }
1036 
1037 
1038    /*** Checks if the database is valid and if it contains a valid table.<p>
1039     * If the table is not present one will be created. If the table exists<br>
1040     * it is checked and changed accordingly.<p>
1041     * It uses the TableCreator for this task.
1042     * @param props Properties Object with key/value as settings for the SequenceGenerator.<br>
1043     * See the SequenceGeneratorConstants for the settings.
1044     */
1045    private synchronized void checkTable(Properties props) {
1046       log.debug("+ checkTable");
1047       try {
1048          Connection con = this.getDatabaseConnection();
1049          try {
1050             TableCreator tableCreator = TableCreator.getInstance(con, props);
1051             if (tableCreator.checkDatabase()) {
1052                log.info("Table checked");
1053             }
1054             else {
1055                log.warn("Table check returned false!");
1056             }
1057          }
1058          finally {
1059             con.close();
1060          }
1061       }
1062       catch (SQLException sqle) {
1063          log.error(sqle);
1064          throw new EJBException(sqle);
1065       }
1066    }
1067 
1068 
1069    /*** Gets a database connection out of the datasource.<p>
1070     * @throws SQLException Thrown if something goes wrong in JDBC
1071     * @return A jdbc Connection
1072     */
1073    private Connection getDatabaseConnection() throws SQLException {
1074 
1075       if (this.datasource == null || !this.datasourceName.equals(this.lastDatasourceNameUsed)) {
1076          this.lastDatasourceNameUsed = this.datasourceName;
1077          String tryDatasourceName = null;
1078          int maxTypes = 3;
1079          int retryType = 0;
1080          boolean found = false;
1081          while (!found) {
1082             try {
1083                tryDatasourceName = this.getDatabaseLookupName(retryType);
1084                log.debug("Going to try datasource: " + tryDatasourceName);
1085                if (tryDatasourceName != null) { // Null means no combination
1086                   if (tryDatasourceName.equals("ABORT")) { //No type
1087                      log.fatal("No suitable datasource found for SequenceGenerator! ABORT!!");
1088                      throw new EJBException("No suitable datasource name found! Abort");
1089                   }
1090                   else {
1091                      this.datasource = (DataSource) (new InitialContext().lookup(tryDatasourceName));
1092                      found = true;
1093                      log.info("Found a suitable name and datasource!");
1094                   }
1095                }
1096             }
1097             catch (NamingException ne) {
1098                String errorMessage = "JDBC Datasource " + tryDatasourceName + " not found. Next try!";
1099                log.warn(errorMessage);
1100             }
1101             retryType++; //Next option
1102          }
1103       }
1104       return datasource.getConnection();
1105    }
1106 
1107 
1108    /*** Strips the given datasource name.<p>
1109     * Strips the given datasource name to overcome the differences between<br>
1110     * several application server handling the JNDI lookups and the datasources.<p>
1111     * @param type Type of the fixed name:
1112     * <ul><li>0 - The original name</li>
1113     * <li>1 - The original name without comp/env/ (if any)</li>
1114     * <li>2 - The original name without java: (if any)</li>
1115     * <li>3 - 1 and 2 combined</li></UL><ul>
1116     * <li>Any - return <CODE>"ABORT"</CODE></li>
1117     * </ul>
1118     * @return The stripped name will be returned or...<br>
1119     * If a type doesn't result in a valid name it will return <CODE>null</CODE>.<br>
1120     * If a invalid type is given <CODE>"ABORT"</CODE> will be returned.
1121     */
1122    private String getDatabaseLookupName(int type) {
1123 
1124       String compenv = "comp/env/";
1125       String javaColon = "java:";
1126       switch (type) {
1127          case 0:
1128             { // Given datasource
1129                return this.datasourceName;
1130             }
1131          case 1:
1132             { // Without comp/env
1133                if (this.datasourceName.indexOf(compenv) > -1) {
1134                   return this.datasourceName.substring(0, this.datasourceName.indexOf(compenv)) + this.datasourceName.substring(this.datasourceName.indexOf(compenv) + compenv.length());
1135                }
1136                else {
1137                   return null;
1138                }
1139             }
1140          case 2:
1141             { // Without java:
1142                if (this.datasourceName.indexOf(javaColon) > -1) {
1143                   return this.datasourceName.substring(javaColon.length());
1144                }
1145                else {
1146                   return null;
1147                }
1148             }
1149          case 3:
1150             { // Without comp/env and java:
1151                String case3 = this.getDatabaseLookupName(1);
1152                if (case3 != null && case3.indexOf(javaColon) > -1) {
1153                   return this.getDatabaseLookupName(1).substring(javaColon.length());
1154                }
1155                else {
1156                   return null;
1157                }
1158             }
1159          default:
1160             {
1161                return "ABORT";
1162             }
1163       }
1164    }
1165 
1166 
1167    /*** Gets a new SequenceBlock out of the database.<p> Same as refresh and get new value.
1168     * @param name Name of the sequence. In combination with the datasource and table it can identify itself
1169     * @return A new sequenceBlock
1170     */
1171    private SequenceBlock getNextKeyAfterIncrementingBy(String name) {
1172       log.debug("+ GetNextKeyAfterIncrementingBy");
1173       Connection con = null;
1174       PreparedStatement psSelect = null;
1175       PreparedStatement psUpdate = null;
1176       boolean retry = false;
1177       int retryCounter = 0;
1178       int maxRetry = 2;
1179       SequenceBlock result = new SequenceBlock();
1180       result.current = -1;
1181 
1182       try {
1183          con = this.getDatabaseConnection();
1184          con.setAutoCommit(false);
1185 
1186          psSelect = useLocking ?
1187             con.prepareStatement(SELECTSEQUENCE) : con.prepareStatement(SELECTSEQUENCE_NONLOCKING);
1188          psUpdate = con.prepareStatement(UPDATESEQUENCE);
1189 
1190          do {
1191             ResultSet rs = null;
1192 
1193             try {
1194                retry = false;
1195                psSelect.setString(1, name);
1196                try {
1197                   rs = psSelect.executeQuery();
1198                }
1199                catch (SQLException se) {
1200                   psSelect = con.prepareStatement(SELECTSEQUENCE_NONLOCKING);
1201                   psSelect.setString(1, name);
1202                   rs = psSelect.executeQuery();
1203                   log.warn("=========== SEQUENCE GENERATOR: !!WARNING!! ===========");
1204                   log.warn("Your database appears to not support locking:  SequenceGenerator will " +
1205                      "continue without locking, but CAN NOT GUARANTEE that the generated primary " +
1206                      "keys will be unique.");
1207                   useLocking = false;
1208                }
1209 
1210                if (!rs.next()) {
1211                   retry = true;
1212                   PreparedStatement psInsert = null;
1213                   try {
1214                      psInsert = con.prepareStatement(INSERTSEQUENCE);
1215                      psInsert.setString(1, name);
1216                      psInsert.setLong(2, DEFAULT_START_OF_SEQUENCE);
1217                      psInsert.setInt(3, this.blockSize);
1218                      if (psInsert.executeUpdate() != 1) {
1219                         con.rollback();
1220                         throw new EJBException("CANNOT CREATE SEQUENCE");
1221                      }
1222                      con.commit();
1223                   }
1224                   catch (SQLException sqle) {
1225                      con.rollback();
1226                      this.ctx.setRollbackOnly();
1227                      throw new EJBException(sqle);
1228                   }
1229                   finally {
1230                      try {
1231                         if (psInsert != null) {
1232                            psInsert.close();
1233                            psInsert = null;
1234                         }
1235                         if (rs != null) {
1236                            rs.close();
1237                            rs = null;
1238                         }
1239                      }
1240                      catch (SQLException eee) {
1241                         log.error("Exception while closing connections for insert", eee);
1242                      }
1243                   }
1244                }
1245                else {
1246                   int blockSize = rs.getInt(this.sequenceBlocksizeCol);
1247                   if (blockSize == 0) {
1248                      blockSize = this.blockSize;
1249                   }
1250                   long oldValue = rs.getLong(this.sequenceValueCol);
1251                   long newValue = oldValue + blockSize;
1252                   psUpdate.setLong(1, newValue);
1253                   psUpdate.setInt(2, blockSize);
1254                   psUpdate.setString(3, name);
1255                   psUpdate.setLong(4, newValue);
1256                   if (psUpdate.executeUpdate() != 1) {
1257                      con.rollback();
1258                      this.ctx.setRollbackOnly();
1259                      throw new EJBException("CANNOT UPDATE SEQUENCE");
1260                   }
1261                   else {
1262                      con.commit();
1263                      result.current = oldValue;
1264                      result.last = newValue;
1265                      result.blockSize = blockSize;
1266                   }
1267                }
1268             }
1269             catch (SQLException ee) {
1270                log.error("Exception while doing update: " + ee.toString());
1271                ee.printStackTrace();
1272                retry = retryCounter++ < maxRetry;
1273             }
1274             finally {
1275                try {
1276                   if (rs != null) {
1277                      rs.close();
1278                      rs = null;
1279                   }
1280                }
1281                catch (SQLException eee) {
1282                   log.error("Error while closing a resultSet: ", eee);
1283                }
1284             }
1285          } while (retry);
1286       }
1287       catch (SQLException e) {
1288          throw new EJBException(e);
1289       }
1290       finally {
1291          try {
1292             if (psUpdate != null) {
1293                psUpdate.close();
1294                psUpdate = null;
1295             }
1296             if (psSelect != null) {
1297                psSelect.close();
1298                psSelect = null;
1299             }
1300             if (con != null) {
1301                con.close();
1302                con = null;
1303             }
1304          }
1305          catch (SQLException se) {
1306             log.error("Exception while closing: ", se);
1307          }
1308       }
1309       log.debug("- GetNextKeyAfterIncrementBy");
1310       if (result.current != -1) {
1311          return result;
1312       }
1313       else {
1314          throw new EJBException("UNKNOWN SEQUENCE ERROR OCCURED");
1315       }
1316    }
1317 }
1318 
1319 /*
1320  * $Log: SequenceGeneratorEJB.java,v $
1321  * Revision 1.7  2004/04/03 13:40:36  ekkelenkamp
1322  * Update javadoc
1323  *
1324  * Revision 1.6  2004/04/03 13:37:12  ekkelenkamp
1325  * Remove Remote Exceptions
1326  *
1327  * Revision 1.5  2004/04/03 12:47:15  ekkelenkamp
1328  * Update JNDI Name
1329  *
1330  * Revision 1.4  2004/03/24 19:39:22  ekkelenkamp
1331  * updated xdoclet tags
1332  *
1333  * Revision 1.3  2004/03/05 13:31:35  ekkelenkamp
1334  * refactored private classes
1335  *
1336  * Revision 1.2  2004/03/05 12:47:17  ekkelenkamp
1337  * refactored private classes
1338  *
1339  * Revision 1.1  2004/03/01 19:41:41  ekkelenkamp
1340  * initial version
1341  *
1342  * Revision 1.15  2003/12/09 14:24:17  m.oconnor
1343  * added warning about locking
1344  *
1345  * Revision 1.14  2003/12/09 13:12:12  m.oconnor
1346  * generic DB support
1347  *
1348  * Revision 1.13  2003/09/25 12:45:14  vincent
1349  * Connections problem JBoss 3.0.7+ solved
1350  *
1351  * Revision 1.12  2003/08/27 11:14:09  edwin
1352  * *** empty log message ***
1353  *
1354  * Revision 1.11  2003/01/22 10:19:58  vincent
1355  * Version 2.0
1356  *
1357  * Revision 1.10  2003/01/06 15:57:05  vincent
1358  * Version 1.5. Zie README
1359  *
1360  * Revision 1.9  2002/12/18 11:55:15  vincent
1361  * Version 1.4.4
1362  *
1363  * Revision 1.8  2002/11/21 16:16:49  vincent
1364  * Version 1.4.3
1365  * Log4j is used now for logging. Make sure Log4J is included in the project
1366  *
1367  * Revision 1.7  2002/10/22 08:22:18  vincent
1368  * Supports several naming 'conventions' for the JNDI name of the datasource:
1369  * java:/comp/env/jdbc/name (ex. Bluestone)
1370  * java:jdbc/name           (ex. JBoss)
1371  * comp/env/jdbc/name
1372  * jdbc/name
1373  *
1374  * Use first option to be almost 100% compatible
1375  *
1376  * Revision 1.6  2002/10/21 09:46:35  vincent
1377  * Default field length for sequence value adjusted to 38
1378  * Sequences are now returned in longs.
1379  *
1380  * Revision 1.5  2002/10/18 11:31:38  vincent
1381  * Use of synonyms
1382  * Version 1.4
1383  *
1384  * Revision 1.4  2002/10/15 14:27:43  vincent
1385  * Versie 1.3
1386  * Introduction of the CustomSequenceGeneratorSettings method using the SequenceGeneratorCustomizable
1387  * Check built on blocksize
1388  *
1389  * Revision 1.3  2002/10/14 12:08:37  vincent
1390  * removeSequence added
1391  *
1392  * Revision 1.2  2002/10/14 11:36:27  vincent
1393  * Updated Javadocs
1394  *
1395  * Revision 1.1  2002/10/06 15:41:08  vincent
1396  * Initial Checkin
1397  *
1398  */