Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/clra/rowing/remote/RowingSessionBean.java


1   /*
2    * Copyright (c) Carnegie Lake Rowing Association 2002. All rights reserved.
3    * Distributed under the GPL license. See doc/COPYING.
4    * $RCSfile: RowingSessionBean.java,v $
5    * $Date: 2003/02/26 03:38:45 $
6    * $Revision: 1.8 $
7    */
8   
9   package com.clra.rowing.remote;
10  
11  import com.clra.rowing.Configuration;
12  import com.clra.rowing.DefaultRowingSessionComparator;
13  import com.clra.rowing.RowingDBRead;
14  import com.clra.rowing.RowingException;
15  import com.clra.rowing.RowingSessionStateException;
16  import com.clra.rowing.RowingSessionLevel;
17  import com.clra.rowing.RowingSessionState;
18  import com.clra.rowing.RowingSessionType;
19  import com.clra.rowing.RowingSessionSnapshot;
20  import com.clra.util.DBConfiguration;
21  import com.clra.util.ISerializableComparator;
22  import java.rmi.RemoteException;
23  import java.sql.Connection;
24  import java.sql.PreparedStatement;
25  import java.sql.ResultSet;
26  import java.sql.SQLException;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Date;
30  import javax.ejb.CreateException;
31  import javax.ejb.EJBException;
32  import javax.ejb.EntityBean;
33  import javax.ejb.EntityContext;
34  import javax.ejb.FinderException;
35  import javax.ejb.NoSuchEntityException;
36  import javax.ejb.ObjectNotFoundException;
37  import javax.ejb.RemoveException;
38  import org.apache.log4j.Category;
39  
40  /**
41   * @version $Revision: 1.8 $ $Date: 2003/02/26 03:38:45 $
42   * @author <a href="mailto:rphall@pluto.njcc.com">Rick Hall</a>
43   */
44  public class RowingSessionBean implements EntityBean {
45  
46    private final static String base = RowingSessionBean.class.getName();
47    private final static Category theLog = Category.getInstance( base );
48  
49    private transient boolean isDirty = true;
50    private Integer id = null;
51    private RowingSessionState state = null;
52    private Date date = null;
53    private RowingSessionLevel level = null;
54    private RowingSessionType type = null;
55  
56    private EntityContext context;
57  
58    /**
59     * Returns the natural Comparator for rowing sessions, in which rowing
60     * sessions are compared by date, state, type, level, and id, with that
61     * respective weighting.
62     */
63    public ISerializableComparator getNaturalComparator() {
64      return new DefaultRowingSessionComparator();
65    }
66  
67    /** Returns a snapshot of a rowing session */
68    public RowingSessionSnapshot getData() throws RemoteException {
69      RowingSessionSnapshot retVal = new RowingSessionSnapshot( this.id,
70        this.state, this.date, this.level, this.type );
71      return retVal;
72    }
73  
74    /**
75     * Sets the date, level and type of a rowing session if the rowing
76     * session is TENATIVE. The id and state properties are not set.
77     */
78    public void setData(RowingSessionSnapshot data)
79      throws RowingSessionStateException {
80      if ( this.state != RowingSessionState.TENATIVE ) {
81        String msg = "Can not edit data when state == '"
82            + this.state.getName() + "'";
83        throw new RowingSessionStateException( msg );
84      }
85      if ( !this.date.equals( data.getDate() ) ) {
86        this.isDirty = true;
87        this.date = data.getDate();
88      }
89      if ( !this.level.equals( data.getLevel() ) ) {
90        this.isDirty = true;
91        this.level = data.getLevel();
92      }
93      if ( !this.type.equals( data.getType() ) ) {
94        this.isDirty = true;
95        this.type = data.getType();
96      }
97    }
98  
99    /**
100    * Returns the primary key of a rowing session. The id is immutable
101    * after a rowing session is created.
102    */
103   public Integer getId() {
104     return this.id;
105   }
106 
107   /**
108    * Returns the state of a rowing session. The state of a rowing
109    * session can not be set directly. It is changed as a side-effect
110    * of other operations on a rowing session.
111    */
112   public RowingSessionState getState() {
113     return this.state;
114   }
115 
116   /**
117    * Publishes a rowing session. Only TENATIVE sessions may be published.
118    * The state of a published rowing session becomes OPEN.
119    * @exception RowingSessionStateException if a non-tenative rowing session is
120    * published.
121    */
122   public void publish() throws RowingSessionStateException {
123     if ( getState() != RowingSessionState.TENATIVE ) {
124       throw new RowingSessionStateException( "state is " +  getState() );
125     }
126     if ( !this.state.equals( RowingSessionState.OPEN ) ) {
127       // This block is here in case preconditions change
128       this.isDirty = true;
129       this.state = RowingSessionState.OPEN;
130     }
131   } // publish()
132 
133   /**
134    * Locks a rowing session. Only OPEN sessions may be locked.
135    * The state of a locked rowing session becomes LOCKED.
136    * @exception RowingSessionStateException if a non-open rowing session is
137    * locked.
138    */
139   public void lock() throws RowingSessionStateException {
140     if ( getState() != RowingSessionState.OPEN ) {
141       throw new RowingSessionStateException( "state is " +  getState() );
142     }
143     if ( !this.state.equals( RowingSessionState.LOCKED ) ) {
144       // This block is here in case preconditions change
145       this.isDirty = true;
146       this.state = RowingSessionState.LOCKED;
147     }
148   } // lock()
149 
150   /**
151    * Cancels a rowing session. The state of a cancelled state becomes
152    * CANCELLED.<p>
153    *
154    * A TENTATIVE session may not be cancelled (but it may be deleted).
155    * A COMPLETE, INVOICING or CLOSED session may not be cancelled.
156    *
157    * @exception RowingSessionStateException if a tenative, complete, invoicing
158    * or closed session is cancelled.
159    */
160   public void cancel() throws RowingSessionStateException {
161     if ( getState() == RowingSessionState.TENATIVE
162         || getState() == RowingSessionState.COMPLETE
163         || getState() == RowingSessionState.INVOICING
164         || getState() == RowingSessionState.CLOSED ) {
165       throw new RowingSessionStateException( "state is " +  getState() );
166     }
167     if ( !this.state.equals( RowingSessionState.CANCELLED ) ) {
168       this.isDirty = true;
169       this.state = RowingSessionState.CANCELLED;
170     }
171   } // cancel()
172 
173   /**
174    * Deletes a rowing session. Only a TENATIVE session may be deleted.
175    * A deleted session is removed from the database.<p>
176    *
177    * This is a safe version of the standard EJBObject.remove()
178    * operation. It checks that the session is tenative before removing it.
179    * <strong>Application code should always delete, rather than remove, rowing
180    * sessions.</strong> The remove operation, however, is required for testing
181    * purposes.<p>
182    *
183    * @exception RowingSessionStateException if a non-tenative rowing session is
184    * deleted.
185    * @see com.clra.rowing.IRowingSession.remove()
186    */
187   public void delete()
188     throws RemoteException, RemoveException, RowingSessionStateException {
189     if ( getState() != RowingSessionState.TENATIVE ) {
190       throw new RowingSessionStateException( "state is " +  getState() );
191     }
192     context.getEJBObject().remove();
193   } // delete();
194 
195   /** Returns the date (and time) of a rowing session */
196   public Date getDate() {
197     return this.date;
198   }
199 
200   /**
201    * Edits the date (and time) of a rowing session. Editing is allowed only
202    * for TENATIVE sessions.
203    * @exception RowingSessionStateException if the edited session is not
204    * in the TENATIVE state.
205    * @see RowingSessionState
206    */
207   public void setDate( Date date ) throws RowingSessionStateException {
208     // Precondition
209     if ( date == null ) {
210       throw new IllegalArgumentException( "null date" );
211     }
212     if ( this.state != RowingSessionState.TENATIVE ) {
213       String msg = "Can not edit date when state == '"
214           + this.state.getName() + "'";
215       throw new RowingSessionStateException( msg );
216     }
217     if ( !this.date.equals( date ) ) {
218       this.isDirty = true;
219       this.date = date;
220     }
221   }
222 
223   /** Returns the level of a rowing session */
224   public RowingSessionLevel getLevel() throws RemoteException {
225     return this.level;
226   }
227 
228   /**
229    * Edits the level of a rowing session. Editing is allowed only for
230    * TENATIVE sessions.
231    */
232   public void setLevel( RowingSessionLevel level )
233     throws RowingSessionStateException {
234     // Precondition
235     if ( level == null ) {
236       throw new IllegalArgumentException( "null level" );
237     }
238     if ( this.state != RowingSessionState.TENATIVE ) {
239       String msg = "Can not edit level when state == '"
240           + this.state.getName() + "'";
241       throw new RowingSessionStateException( msg );
242     }
243     if ( !this.level.equals( level ) ) {
244       this.isDirty = true;
245       this.level = level;
246     }
247   }
248 
249   /** Returns the type of a rowing session */
250   public RowingSessionType getType() throws RemoteException {
251     return this.type;
252   }
253 
254   /**
255    * Edits the type of a rowing session. Editing is allowed only for
256    * TENATIVE sessions.
257    */
258   public void setType( RowingSessionType type )
259     throws RowingSessionStateException {
260     // Precondition
261     if ( type == null ) {
262       throw new IllegalArgumentException( "null type" );
263     }
264     if ( this.state != RowingSessionState.TENATIVE ) {
265       String msg = "Can not edit type when state == '"
266           + this.state.getName() + "'";
267       throw new RowingSessionStateException( msg );
268     }
269     if ( !this.type.equals( type ) ) {
270       this.isDirty = true;
271       this.type = type;
272     }
273   }
274 
275   public Integer ejbCreate( Date date, RowingSessionLevel level,
276     RowingSessionType type ) throws CreateException {
277 
278     // Preconditions
279     if ( date == null ) {
280       throw new CreateException( "null date" );
281     }
282     if ( level == null ) {
283       throw new CreateException( "null level" );
284     }
285     if ( type == null ) {
286       throw new CreateException( "null type" );
287     }
288 
289     try {
290 
291       this.id = nextId();
292       this.state = RowingSessionState.TENATIVE;
293       this.date = date;
294       this.level = level;
295       this.type = type;
296 
297       insertRow( this.id, this.state, this.date, this.level, this.type );
298 
299       // FIXME shouldn't isDirty be set false here?
300       //this.isDirty = false;
301       // ENDFIXME
302 
303       if ( theLog.isDebugEnabled() ) {
304         String msg = "ejbCreate: " + id + ", '"
305           + RowingDBRead.dateFormat.format( date ) + "', " + level.getName()
306           + ", " + type.getName() + ", " + state.getName();
307         theLog.debug( msg );
308       }
309 
310     }
311     catch (Exception ex) {
312       throw new EJBException( "ejbCreate: " + ex.getMessage() );
313     }
314 
315     return this.id;
316   } // ejbCreate(Date,RowingSessionLevel,RowingSessionType)
317 
318   public Integer ejbFindByPrimaryKey(Integer primaryKey) 
319     throws FinderException {
320 
321     // Precondition
322     if ( primaryKey == null ) {
323       throw new FinderException( "null primaryKey" );
324     }
325 
326     boolean hasRow = false;
327     try {
328       hasRow = selectByPrimaryKey(primaryKey);
329       if ( theLog.isDebugEnabled() ) {
330         String msg = "ejbFindByPrimaryKey: " + id + " " + hasRow;
331         theLog.debug( msg );
332       }
333 
334     }
335     catch (Exception ex) {
336       throw new EJBException("ejbFindByPrimaryKey: " + ex.getMessage());
337     }
338 
339     if (!hasRow) {
340       String msg = "Row for id " + primaryKey + " not found.";
341       throw new ObjectNotFoundException( msg );
342     }
343 
344     return primaryKey;
345   } // ejbFindByPrimaryKey(Integer)
346 
347   /**
348    * Returns a collection of rowing sessions that fall within the
349    * inclusive date range.
350    */
351   public Collection ejbFindInDateRange( Date start, Date finish )
352     throws FinderException {
353 
354     // Preconditions
355     if ( start == null || finish == null ) {
356       throw new FinderException( "null date" );
357     }
358     if ( start.compareTo(finish) > 0 ) {
359       throw new FinderException( "start > finish" );
360     }
361 
362     Collection result = null;
363     try {
364       result = selectInDateRange( start, finish );
365       if ( theLog.isDebugEnabled() ) {
366         String msg = "ejbFindInDateRange: size == " + result.size();
367         theLog.debug( msg );
368       }
369     }
370     catch (Exception ex) {
371       throw new EJBException("ejbFindInDateRange: " + ex.getMessage());
372     }
373 
374     return result;
375   } // ejbFindInDateRange(Date,Date)
376 
377   /**
378    * Returns a collection of rowing sessions that fall within the
379    * inclusive date range.
380    */
381   public Collection ejbFindAll()
382     throws FinderException {
383 
384     Collection result = null;
385     try {
386       result = selectAll();
387       if ( theLog.isDebugEnabled() ) {
388         String msg = "ejbFindAll: size == " + result.size();
389         theLog.debug( msg );
390       }
391     }
392     catch (Exception ex) {
393       throw new EJBException("ejbFindAll: " + ex.getMessage());
394     }
395 
396     return result;
397   } // ejbFindAll()
398 
399   /** @see delete() */
400   public void ejbRemove() {
401 
402     try {
403       Integer tmpId = this.getId();
404       deleteRow(id);
405       if ( !RowingSessionState.TENATIVE.equals(this.getState()) ) {
406         theLog.warn( "ejbRemove: row deleted, id == " + tmpId );
407       }
408       else if ( theLog.isDebugEnabled() ) {
409         theLog.debug( "ejbRemove: row deleted, id == " + tmpId );
410       }
411     }
412     catch (Exception ex) {
413       throw new EJBException("ejbRemove: " + ex.getMessage());
414     }
415 
416   } // ejbRemove()
417 
418   public void setEntityContext(EntityContext context) {
419 
420     this.context = context;
421     if ( theLog.isDebugEnabled() ) {
422       theLog.debug( "setEntityContext: context set" );
423       theLog.debug( "setEntityContext: id == " + this.id );
424     }
425 
426     return;
427   } // setEntityContext(EntityContext)
428 
429   public void unsetEntityContext() {
430 
431     this.context = null;
432     if ( theLog.isDebugEnabled() ) {
433       theLog.debug( "unsetEntityContext: id nulled" );
434       theLog.debug( "unsetEntityContext: context nulled" );
435     }
436 
437     return;
438   } // unsetEntityContext()
439 
440   public void ejbActivate() {
441     this.id = (Integer)context.getPrimaryKey();
442     if ( theLog.isDebugEnabled() ) {
443       theLog.debug( "ejbActivate: id == " + this.id );
444     }
445   }
446 
447   public void ejbPassivate() {
448     this.id = null;
449     if ( theLog.isDebugEnabled() ) {
450       theLog.debug( "ejbPassivate: id == " + this.id );
451     }
452   }
453 
454   public void ejbLoad() {
455 
456     try {
457       loadRow();
458       if ( theLog.isDebugEnabled() ) {
459         theLog.debug( "ejbLoad: row loaded" );
460       }
461       isDirty = false;
462     }
463     catch (Exception ex) {
464       throw new EJBException("ejbLoad: " + ex.getMessage());
465     }
466 
467   } // ejbLoad()
468   
469   public void ejbStore() {
470 
471     try {
472       if ( isDirty ) {
473         storeRow();
474         if ( theLog.isDebugEnabled() ) {
475           theLog.debug( "ejbStore: row stored" );
476         }
477         isDirty = false;
478       }
479       else {
480         if ( theLog.isDebugEnabled() ) {
481           theLog.debug( "ejbStore: row skipped" );
482         }
483       }
484     }
485     catch (Exception ex) {
486       throw new EJBException("ejbStore: " + ex.getMessage());
487     }
488 
489   } // ejbStore()
490 
491   public void ejbPostCreate( Date date, RowingSessionLevel level,
492     RowingSessionType type ) {}
493 
494   private boolean selectByPrimaryKey(Integer primaryKey) 
495     throws SQLException {
496 
497     Connection conn = null;
498     PreparedStatement stmt = null;
499     ResultSet rs = null;
500     boolean retVal = false;
501     try {
502       conn = DBConfiguration.getConnection();
503       stmt = conn.prepareStatement(
504           Configuration.SQL_SESSION_02,
505           ResultSet.TYPE_FORWARD_ONLY,
506           ResultSet.CONCUR_READ_ONLY);
507 
508       stmt.setInt( 1, primaryKey.intValue() );
509 
510       rs = stmt.executeQuery();
511       retVal = rs.next();
512       if ( theLog.isDebugEnabled() ) {
513         theLog.debug( "selectByPrimaryKey: retVal == " + retVal );
514       }
515 
516     }
517     finally {
518       DBConfiguration.closeSQLResultSet( rs );
519       DBConfiguration.closeSQLStatement( stmt );
520       DBConfiguration.closeSQLConnection( conn );
521       rs = null;
522       stmt = null;
523       conn = null;
524     }
525 
526     return retVal;
527   } // selectByPrimaryKey(String)
528 
529   private Collection selectAll() 
530     throws SQLException {
531 
532     Connection conn = null;
533     PreparedStatement stmt = null;
534     ResultSet rs = null;
535     Collection retVal = new ArrayList();
536     try {
537       conn = DBConfiguration.getConnection();
538       stmt = conn.prepareStatement(
539           Configuration.SQL_SESSION_01,
540           ResultSet.TYPE_FORWARD_ONLY,
541           ResultSet.CONCUR_READ_ONLY);
542 
543       rs = stmt.executeQuery();
544 
545       int rowCount = 0;
546       while ( rs.next() ) {
547         Integer id = new Integer( rs.getInt(1) );
548         retVal.add(id);
549         ++rowCount;
550       }
551 
552       if ( theLog.isDebugEnabled() ) {
553         String msg = "selectAll: rowCount == " + rowCount;
554         theLog.debug( msg );
555       }
556 
557     }
558     finally {
559       DBConfiguration.closeSQLResultSet( rs );
560       DBConfiguration.closeSQLStatement( stmt );
561       DBConfiguration.closeSQLConnection( conn );
562       rs = null;
563       stmt = null;
564       conn = null;
565     }
566 
567     return retVal;
568   } // selectAll()
569 
570   private Collection selectInDateRange(Date start, Date finish) 
571       throws SQLException {
572 
573     Connection conn = null;
574     PreparedStatement stmt = null;
575     ResultSet rs = null;
576     Collection retVal = new ArrayList();
577     try {
578       conn = DBConfiguration.getConnection();
579       stmt = conn.prepareStatement(
580           Configuration.SQL_SESSION_03,
581           ResultSet.TYPE_FORWARD_ONLY,
582           ResultSet.CONCUR_READ_ONLY);
583 
584       String strStart  = RowingDBRead.dateFormat.format( start );
585       String strFinish = RowingDBRead.dateFormat.format( finish );
586 
587       stmt.setString( 1, strStart  );
588       stmt.setString( 2, strFinish );
589 
590       rs = stmt.executeQuery();
591 
592       int rowCount = 0;
593       while ( rs.next() ) {
594         Integer id = new Integer( rs.getInt(1) );
595         retVal.add(id);
596         ++rowCount;
597       }
598 
599       if ( theLog.isDebugEnabled() ) {
600         String msg = "selectInDateRange:  rowCount == " + rowCount;
601         theLog.debug( msg );
602       }
603 
604     }
605     finally {
606       DBConfiguration.closeSQLResultSet( rs );
607       DBConfiguration.closeSQLStatement( stmt );
608       DBConfiguration.closeSQLConnection( conn );
609       rs = null;
610       stmt = null;
611       conn = null;
612     }
613 
614     return retVal;
615   } // selectInDateRange(Date,Date)
616 
617   private void insertRow( Integer id, RowingSessionState state, Date date,
618     RowingSessionLevel level, RowingSessionType type ) throws SQLException {
619 
620     Connection conn = null;
621     PreparedStatement stmt = null;
622     ResultSet rs = null;
623     try {
624       conn = DBConfiguration.getConnection();
625       stmt = conn.prepareStatement(
626           Configuration.SQL_SESSION_04,
627           ResultSet.TYPE_FORWARD_ONLY,
628           ResultSet.CONCUR_READ_ONLY);
629 
630       String strDate = RowingDBRead.dateFormat.format( date );
631 
632       stmt.setInt(     1, id.intValue()   );
633       stmt.setString(  2, strDate         );
634       stmt.setString(  3, level.getName() );
635       stmt.setString(  4, type.getName()  );
636       stmt.setString(  5, state.getName() );
637 
638       rs = stmt.executeQuery();
639 
640       if ( theLog.isDebugEnabled() ) {
641         theLog.debug( "insertRow: row " + id );
642       }
643 
644     }
645     finally {
646       DBConfiguration.closeSQLResultSet( rs );
647       DBConfiguration.closeSQLStatement( stmt );
648       DBConfiguration.closeSQLConnection( conn );
649       rs = null;
650       stmt = null;
651       conn = null;
652     }
653 
654     return;
655   } // insertRow(..)
656 
657   private void deleteRow(Integer id) throws SQLException {
658 
659     Connection conn = null;
660     PreparedStatement stmt = null;
661     ResultSet rs = null;
662     try {
663       conn = DBConfiguration.getConnection();
664       stmt = conn.prepareStatement(
665           Configuration.SQL_SESSION_05,
666           ResultSet.TYPE_FORWARD_ONLY,
667           ResultSet.CONCUR_READ_ONLY);
668 
669       stmt.setInt( 1, id.intValue()   );
670 
671       rs = stmt.executeQuery();
672 
673       if ( theLog.isDebugEnabled() ) {
674         theLog.debug( "deleteRow: row " + id );
675       }
676 
677     }
678     finally {
679       DBConfiguration.closeSQLResultSet( rs );
680       DBConfiguration.closeSQLStatement( stmt );
681       DBConfiguration.closeSQLConnection( conn );
682       rs = null;
683       stmt = null;
684       conn = null;
685     }
686 
687     return;
688   } // deleteRow(Integer)
689 
690   private void loadRow()
691     throws SQLException, RowingException, NoSuchEntityException {
692 
693     /*
694      * Implementation note: the translation from DB row to snapshot
695      * to bean looks inefficient, but it is not the bottleneck in
696      * loading bean. The bottleneck is the EJB algorithm for finding
697      * an id, then loading a row, then storing the result back to
698      * the DB. That means at least two DB calls (assuming the storage
699      * step is skipped by checking an isDirty flag). The DB calls
700      * completely dominate performance.
701      *
702      * On the other hand, returning a row as a snapshot allows the
703      * RowingDBRead code to be reused directly elsewhere. Where
704      * speed is critical, and where it is unlikely that a RowingSessionBean
705      * is already in memory, it is best to use the RowingDBRead code to
706      * directly load a (read-only) snapshot from the database.
707      */
708     RowingSessionSnapshot snapshot = RowingDBRead.loadRowingSession( this.id );
709     this.id    = snapshot.getId();
710     this.state = snapshot.getState();
711     this.date  = snapshot.getDate();
712     this.level = snapshot.getLevel();
713     this.type  = snapshot.getType();
714 
715   } // loadRow()
716 
717   private void storeRow() throws SQLException {
718 
719     Connection conn = null;
720     PreparedStatement stmt = null;
721     int rowCount = 0;
722     try {
723       conn = DBConfiguration.getConnection();
724       stmt = conn.prepareStatement(
725           Configuration.SQL_SESSION_07,
726           ResultSet.TYPE_FORWARD_ONLY,
727           ResultSet.CONCUR_READ_ONLY);
728 
729       String strDate = RowingDBRead.dateFormat.format( this.date );
730 
731       stmt.setString(  1, strDate              );
732       stmt.setString(  2, this.level.getName() );
733       stmt.setString(  3, this.type.getName()  );
734       stmt.setString(  4, this.state.getName() );
735       stmt.setInt(     5, this.id.intValue()   );
736 
737       rowCount = stmt.executeUpdate();
738 
739       if ( theLog.isDebugEnabled() ) {
740         theLog.debug( "storeRow: rowCount == " + rowCount );
741         String msg = "storeRow: " + id.intValue() + ", '" + strDate + "', "
742           + level.getName() + ", " + type.getName() + ", " + state.getName();
743         theLog.debug( msg );
744       }
745 
746     }
747     finally {
748       DBConfiguration.closeSQLStatement( stmt );
749       DBConfiguration.closeSQLConnection( conn );
750       stmt = null;
751       conn = null;
752     }
753 
754     if ( rowCount != 1 ) {
755       throw new EJBException( "failed to store row ==  " + this.id );
756     }
757 
758     return;
759   } // storeRow()
760 
761   /** A utility that gets (and reserves) the next id for a rowing session */
762   public static Integer nextId() throws SQLException, CreateException {
763 
764     Connection conn = null;
765     PreparedStatement stmt = null;
766     ResultSet rs = null;
767     Integer retVal = null;
768     try {
769       conn = DBConfiguration.getConnection();
770       stmt = conn.prepareStatement(
771           Configuration.SQL_SESSION_08,
772           ResultSet.TYPE_FORWARD_ONLY,
773           ResultSet.CONCUR_READ_ONLY);
774 
775       if ( theLog.isDebugEnabled() ) {
776         String msg =
777           "nextId update: SQL == " + Configuration.SQL_SESSION_08;
778         theLog.debug( msg );
779       }
780 
781       if ( !DBConfiguration.isOracle() ) {
782 
783         /*
784          * There is a problem in this block of code because it is not
785          * locked in a transaction. If two different threads execute
786          * this block simultaneously, the MySQL sequence value will
787          * have been incremented twice, and both threads will use the
788          * same value in the code section that follows this block.
789          *
790          * As a practical matter, during normal operation, rowing
791          * sessions are created infrequently, and this block of code
792          * is executed by one thread at a time. This code works because
793          * this is a low-load application.
794          */
795 
796         boolean moreResults = stmt.execute();
797 
798         stmt = conn.prepareStatement(
799             Configuration.SQL_SESSION_08A,
800             ResultSet.TYPE_FORWARD_ONLY,
801             ResultSet.CONCUR_READ_ONLY);
802 
803         if ( theLog.isDebugEnabled() ) {
804           String msg =
805             "nextId select: SQL == " + Configuration.SQL_SESSION_08A;
806           theLog.debug( msg );
807         }
808 
809       } // if !isOracle
810 
811       rs = stmt.executeQuery();
812 
813       int rowCount = 0;
814       while ( rs.next() ) {
815         retVal = new Integer( rs.getInt(1) );
816         ++rowCount;
817       }
818       if ( rowCount != 1 ) {
819         String msg =  "unable to get next id: rowCount == " + rowCount;
820         throw new CreateException( msg );
821       }
822 
823       if ( theLog.isDebugEnabled() ) {
824         String msg = "nextId: retVal == " + retVal.intValue();
825         theLog.debug( msg );
826       }
827 
828     }
829     finally {
830       DBConfiguration.closeSQLResultSet( rs );
831       DBConfiguration.closeSQLStatement( stmt );
832       DBConfiguration.closeSQLConnection( conn );
833       rs = null;
834       stmt = null;
835       conn = null;
836     }
837 
838     return retVal;
839   } // nextId()
840 
841 } // RowingSessionBean
842 
843 /*
844  * $Log: RowingSessionBean.java,v $
845  * Revision 1.8  2003/02/26 03:38:45  rphall
846  * Added copyright and GPL license
847  *
848  * Revision 1.7  2003/02/19 22:09:14  rphall
849  * Removed gratuitous use of CLRA acronym
850  *
851  * Revision 1.6  2003/02/16 00:48:53  rphall
852  * Rolled back 'fix' for where primary key is set
853  *
854  * Revision 1.5  2003/02/15 04:31:42  rphall
855  * Changes connected to major revision of MemberBean
856  *
857  * Revision 1.4  2003/02/11 01:33:03  rphall
858  * Added comment about code block that is not thread safe
859  *
860  */
861