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

Quick Search    Search Deep

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


1   /*
2    * Copyright (c) Carnegie Lake Rowing Association 2002. All rights reserved.
3    * Distributed under the GPL license. See doc/COPYING.
4    * $RCSfile: ParticipantBean.java,v $
5    * $Date: 2003/02/26 03:38:45 $
6    * $Revision: 1.5 $
7    */
8   
9   package com.clra.rowing.remote;
10  
11  import com.clra.member.MemberSnapshot;
12  import com.clra.rowing.Attendance;
13  import com.clra.rowing.Configuration;
14  import com.clra.rowing.IBoating;
15  import com.clra.rowing.IParticipant;
16  import com.clra.rowing.IRowingSession;
17  import com.clra.rowing.ParticipantSnapshot;
18  import com.clra.rowing.ParticipantStateException;
19  import com.clra.rowing.RowingDBRead;
20  import com.clra.rowing.RowingException;
21  import com.clra.rowing.RowingSessionStateException;
22  import com.clra.rowing.RowingSessionLevel;
23  import com.clra.rowing.RowingSessionState;
24  import com.clra.rowing.RowingSessionType;
25  import com.clra.rowing.RowingSessionSnapshot;
26  import com.clra.rowing.RowingUtils;
27  import com.clra.rowing.SeatPreference;
28  import com.clra.rowing.SeatSnapshot;
29  import com.clra.util.DBConfiguration;
30  import com.clra.util.ErrorUtils;
31  import java.rmi.RemoteException;
32  import java.sql.Connection;
33  import java.sql.PreparedStatement;
34  import java.sql.ResultSet;
35  import java.sql.SQLException;
36  import java.sql.Types;
37  import java.util.ArrayList;
38  import java.util.Collection;
39  import java.util.Date;
40  import javax.ejb.CreateException;
41  import javax.ejb.EJBException;
42  import javax.ejb.EntityBean;
43  import javax.ejb.EntityContext;
44  import javax.ejb.FinderException;
45  import javax.ejb.NoSuchEntityException;
46  import javax.ejb.ObjectNotFoundException;
47  import javax.ejb.RemoveException;
48  import org.apache.log4j.Category;
49  
50  /**
51   * @version $Revision: 1.5 $ $Date: 2003/02/26 03:38:45 $
52   * @author <a href="mailto:rphall@pluto.njcc.com">Rick Hall</a>
53   */
54  public class ParticipantBean implements EntityBean {
55  
56    private final static String base = ParticipantBean.class.getName();
57    private final static Category theLog = Category.getInstance( base );
58  
59    /*
60     * Indicates a NULL int when storing an int to the database.
61     * @see com.clra.rowing.RowingDBRead#NULL_INT
62     */
63    public final static int NULL_INT = RowingDBRead.NULL_INT;
64  
65    private transient boolean _isDirty = true;
66    private Integer _rowingId = null;
67    private Integer _memberId = null;
68    private Integer _participantId = null;
69    private SeatPreference _seatPreference = null;
70    private Integer _replacesId = null;
71    private Integer _initialSeatId = null;
72    private Integer _finalSeatId = null;
73    private Attendance _attendance = null;
74  
75    private EntityContext context;
76  
77    /** Returns a snapshot of a participant */
78    public ParticipantSnapshot getData() {
79      ParticipantSnapshot retVal = new ParticipantSnapshot( this._memberId,
80        this._rowingId, this._participantId, this._seatPreference,
81        this._replacesId, this._initialSeatId, this._finalSeatId,
82        this._attendance );
83      return retVal;
84    }
85  
86    /**
87     * Returns the primary key of a participant. The id is immutable
88     * after a participant is created.
89     */
90    public Integer getParticipantId() {
91      return this._participantId;
92    }
93  
94    /**
95     * Returns the primary key of the member that the participant represents.
96     * The id is immutable after a participant is created.
97     */
98    public Integer getMemberId() {
99      return this._memberId;
100   }
101 
102   /**
103    * Returns the primary key of the rowing session to which the participant
104    * belongs. The id is immutable after a participant is created.
105    */
106   public Integer getRowingId() {
107     return this._rowingId;
108   }
109 
110   /**
111    * Returns the seat preference of a participant. The seat preference
112    * is immutable after a participant is created. A signed-up participant
113    * is created with a seat preference; an extra participant is created
114    * without a seat preference; and a substitute participant is created
115    * without a seat preference (but seating algorithms should assign the
116    * substitute the same initial seat as the original participant).
117    * @return a non-null SeatPreference if the participant signed up
118    * in advance for the rowing session, or null if the participant
119    * joined the rowing session as an 'Extra' or as a substitute for
120    * another, signed-up participant.
121    */
122   public SeatPreference getSeatPreference() {
123     return this._seatPreference;
124   }
125 
126   /**
127    * Sets the seat preference of a participant.
128    * @param a non-null seat preference
129    * @exception ParticipantStateException if a participant has already
130    * been assigned an initial or final seating for a rowing session, or
131    * if attendance has already been marked for the participant.
132    * @exception RowingException if a participant is not a signed-up
133    * participant. (An 'extra' or a 'substitute' participant can not be
134    * converted into a signed-up participant by setting a seat preference.)
135    */
136   public void setSeatPreference( SeatPreference seatPreference )
137       throws ParticipantStateException, RowingException {
138 
139     // Preconditions
140     if ( seatPreference == null ) {
141       throw new IllegalArgumentException( "null seat preference" );
142     }
143     if ( this.getSeatPreference() == null ) {
144       String msg =
145         "preference not allowed for an 'extra' or 'substitute' participant";
146       throw new RowingException( msg );
147     }
148     // FIXME use getInitialSeat() for OO consistency
149     // FIXME use getFinalSeat() for OO consistency
150     if ( this._initialSeatId != null || this._finalSeatId != null ) {
151       String msg = "preference can not be set after seat assignment";
152       throw new ParticipantStateException( msg );
153     }
154     if ( this._attendance != null ) {
155       String msg = "preference can not be set after attendance";
156       throw new ParticipantStateException( msg );
157     }
158 
159     this._seatPreference = seatPreference;
160     this._isDirty = true;
161 
162     return;
163   } // setSeatPreference(SeatPreference)
164 
165   /**
166    * Returns the participant for whom this participant is substituting.
167    * The substitutee is immutable after a participant is created. For a
168    * signed-up or an extra participant, the substitutee is null. For a
169    * substitute participant, the substitutee is non-null.
170    * @return a non-null IParticipant if this participant is a substitute,
171    * or null if this participant signed up or joined as an 'Extra'.
172    */
173   public IParticipant getSubstitutedParticipant() {
174 
175     IParticipant retVal = null;
176     if ( this._replacesId != null ) {
177       // retVal = RowingUtils.findParticipantByPrimaryId( this._replacesId );
178       throw new RuntimeException( "not yet implemented" );
179     }
180 
181     return retVal;
182   } // getSubstitutedParticipant()
183 
184   /**
185    * Assigns a preliminary seating to a participant before a rowing session
186    * starts.
187    * @exception ParticipantStateException if the participant
188    * has not signed up for the rowing session.
189    * @exception RowingException if the assignment conflicts with the
190    * business rules for updating a boating; for example, if the
191    * rowing session to which the boating belongs is not locked.
192    */
193   public void setInitialSeat( SeatSnapshot seat, IBoating boating )
194       throws ParticipantStateException, RowingException {
195 
196     if ( this._seatPreference == null ) {
197       throw new ParticipantStateException( "not signed up" );
198     }
199 
200     this._isDirty = true;
201     // FIXME : SchedulingManager to make initial seating assignment
202     throw new RowingException( "business rules not yet implemented" );
203 
204   } // setInitialSeat(SeatSnapshot,IBoating)
205 
206   /**
207    * Returns the initial seat assignment of this participant, or null
208    * if an initial seating was not made.
209    */
210   public SeatSnapshot getInitialSeat() {
211     
212     // FIXME : RowingDBRead to look up initialSeatSnapshot
213     throw new RuntimeException( "not yet implemented" );
214 
215   } // getInitialSeat()
216 
217   /**
218    * Assigns a final seating to a participant at the start of a rowing
219    * session, after attendance has been taken.
220    *
221    * @param seat the final seating of a participant, or <tt>null</tt> if
222    * a participant is not boated for the session.
223    * @exception ParticipantStateException if the state of the participant
224    * conflicts with the seating assignment; for example, the participant
225    * is not present for the rowing session.
226    * @exception RowingException if the assignment conflicts with the
227    * business rules for updating a boating; for example, if the
228    * rowing session to which the boating belongs is not in the BOATING2 state.
229    */
230   public void setFinalSeat( SeatSnapshot seat, IBoating boating )
231       throws ParticipantStateException, RowingException {
232 
233     if ( !Attendance.PRESENT.equals( this._attendance ) ) {
234       throw new ParticipantStateException( "not signed up" );
235     }
236 
237     this._isDirty = true;
238     // FIXME : BoatingManager to make final seating assignment
239     throw new RowingException( "business rules not yet implemented" );
240 
241   } // setFinalSeat(SeatSnapshot,IBoating)
242 
243   /**
244    * Returns the final seat assignment of this participant, or null
245    * if a final seating was not made.
246    */
247   public SeatSnapshot getFinalSeat() {
248     
249     // FIXME : RowingDBRead to look up finalSeatSnapshot
250     throw new RuntimeException( "not yet implemented" );
251 
252   } // getFinalSeat()
253 
254   /**
255    * Marks the attendance of a participant at a rowing session.
256    * @exception ParticipantStateException if the instance data of the
257    * participant conflicts with marking attendance; for example, if the
258    * participant has already been assigned a final seating assignment, or
259    * if an "extra" participant is marked absent.
260    * @exception RowingException if marking attendance conflicts with the
261    * business rules for updating a rowing session; for example, if the
262    * rowing session is not in the BOATING1 state.
263    */
264   public void setAttendance( Attendance attend, IRowingSession session )
265       throws ParticipantStateException, RowingException {
266 
267     // Preconditions
268     if ( attend == null ) {
269       throw new IllegalArgumentException( "null attendance" );
270     }
271     if ( session == null ) {
272       throw new IllegalArgumentException( "null rowing session" );
273     }
274 
275     // Participant-specific business rules
276     if ( attend.equals( Attendance.ABSENT ) ) {
277       if ( this._seatPreference == null ) {
278         String msg = "extra or substitute can not be marked absent";
279         throw new ParticipantStateException( msg );
280       }
281       if ( this._initialSeatId == null ) {
282 
283         // A null initial seating assignment means participant was
284         // not expected to be present.
285         //
286         // FIXME move this business logic to AttendanceMgr
287         //
288         String msg = "participant was not expected at rowing session";
289         throw new ParticipantStateException( msg );
290       }
291       if ( this._finalSeatId != null ) {
292         String msg = "final seating assignment conflicts with absence";
293         throw new ParticipantStateException( msg );
294       }
295       String msg = "business rules not yet implemented";
296       throw new RowingException( msg );
297     }
298     else if ( attend.equals( Attendance.PRESENT ) ) {
299       String msg = "business rules not yet implemented";
300       throw new RowingException( msg );
301     }
302     else {
303       throw new Error( "design error" );
304     }
305 
306     //this._isDirty = true;
307     //throw new RuntimeException( "not yet implemented" );
308 
309   } // setAttendance(Attendance,IRowingSession)
310 
311   /**
312    * Returns the attendance of a participant at a rowing session, or null
313    * if attendance has not been marked.
314    */
315   public Attendance getAttendance() {
316     return this._attendance;
317   }
318 
319   /**
320    * @param member the member who is signing up.
321    * @param session the session for which the member is signing up.
322    * @param preferred the seating requested by the member for the
323    * rowing session.
324    * @exception CreateException if the rowing session is not OPEN.
325    */
326   public Integer ejbCreate( Integer memberId, Integer rowingId,
327       SeatPreference preferred ) throws CreateException {
328 
329     // Precondition
330     if ( memberId == null ) {
331       throw new CreateException( "null member" );
332     }
333     if ( rowingId == null ) {
334       throw new CreateException( "null rowing session" );
335     }
336     if ( preferred == null ) {
337       throw new CreateException( "null seat preference" );
338     }
339 
340     if ( theLog.isDebugEnabled() ) {
341       String msg = "Creating participant: mid == " + memberId
342         + ", rid == " + rowingId + ", sp == " + preferred.getName();
343       theLog.debug( msg );
344     }
345 
346     Integer retVal = createWithSessionConstraint( memberId, rowingId,
347       preferred, RowingSessionState.OPEN );
348 
349     return retVal;
350   } // ejbCreate(Integer,Integer,SeatPreference)
351 
352   public void ejbPostCreate(Integer mId,Integer rId, SeatPreference sp ) {
353   }
354 
355   /**
356    * Creates an "extra" participant; that is, a participant who is
357    * present at a rowing session without signing up and who isn't
358    * substituting for another member. The participant is constructed in
359    * the PRESENT state.
360    * @param member the member who is signing up.
361    * @param rowing the session for which the member is signing up.
362    * @exception CreateException if the rowing session is not in the
363    * BOATING1 state (during which attendance if marked).
364    */
365   public Integer ejbCreate(MemberSnapshot member, RowingSessionSnapshot rowing)
366       throws RemoteException, CreateException {
367 
368     // Preconditions
369     if ( member == null ) {
370       throw new CreateException( "null member" );
371     }
372     if ( rowing == null ) {
373       throw new CreateException( "null rowing session" );
374     }
375     if ( !RowingSessionState.BOATING1.equals( rowing.getState() ) ) {
376       String msg  = "invalid rowing state == " + rowing.getState().getName();
377       throw new CreateException( msg );
378     }
379     // FIXME check Regular/Full vs LTR/LTR
380 
381     Integer memberId = member.getId();
382     Integer rowingId = rowing.getId();
383 
384     Integer retVal = createWithSessionConstraint( memberId, rowingId,
385       null, RowingSessionState.BOATING1 );
386 
387     return retVal;
388   } // ejbCreate(Integer,Integer)
389 
390   public void ejbPostCreate(MemberSnapshot ms, RowingSessionSnapshot rss) {
391   }
392 
393   /**
394    * Creates a "substitute" participant; that is, a participant who is
395    * present at a rowing session as a substitute for another, signed-up
396    * participant. The substitute is constructed in the PRESENT state,
397    * and the signed-up participant transitions to the ABSENT state.
398    * @param member the member who is signing up.
399    * @param replaces the participant who is being replaced.
400    * @exception CreateException if the rowing session is not in the
401    * BOATING1 state (during which attendance if marked).
402    */
403   public Integer ejbCreate(MemberSnapshot member, ParticipantSnapshot replaces)
404       throws CreateException, RemoteException {
405 
406     // Preconditions
407     if ( member == null ) {
408       throw new CreateException( "null member" );
409     }
410     if ( replaces == null ) {
411       throw new CreateException( "null participant" );
412     }
413 
414     Integer memberId = member.getId();
415     Integer rowingId = replaces.getRowingId();
416     Integer retVal = null;
417 
418     // try {
419     //   Mark replaced participant as ABSENT
420     //   Create replacement
421     // }
422     // catch ( Something ) {
423     //   Main cause is rowing state != BOATING1 ??
424     //   If so, no transaction, no rollback required ??
425     // }
426     throw new CreateException( "not yet implemented" );
427 
428   } // ejbCreate(MemberSnapshot,ParticipantSnapshot)
429 
430   public void ejbPostCreate(MemberSnapshot ms, ParticipantSnapshot ps) {
431   }
432 
433   private Integer createWithSessionConstraint( Integer memberId,
434     Integer rowingId, SeatPreference sp, RowingSessionState st )
435       throws CreateException {
436 
437     Integer retVal = null;
438     try {
439 
440       this._memberId = memberId;
441       this._rowingId = rowingId;
442       this._participantId = nextId();
443       this._seatPreference = sp;
444 
445       // FIXME add constraint on RowingSessionLevel
446 
447       insertRowWithSessionConstraints( memberId, rowingId,
448         this._participantId, this._seatPreference, st );
449 
450       this._isDirty = false;
451 
452       retVal = this._participantId;
453 
454       if ( theLog.isInfoEnabled() ) {
455         theLog.debug( "ejbCreate: retVal == " + retVal );
456         String msg = "ejbCreate: "
457           + this._participantId + ", " + this._rowingId  + ", "
458           + this._memberId + ", '" + this._seatPreference.getName() + "', '"
459           + st.getName() + "'";
460         theLog.info( msg );
461       }
462 
463     }
464     catch (CreateException x) {
465       String msg = ErrorUtils.createDbgMsg( "ejbCreate", x );
466       throw x;
467     }
468     catch (Exception ex) {
469       String msg = ErrorUtils.createDbgMsg( "ejbCreate", ex );
470       theLog.error( msg, ex );
471       throw new EJBException( msg );
472     }
473 
474     return retVal;
475   } // createWithSessionConstraint(..)
476 
477   public Integer ejbFindByPrimaryKey( Integer primaryKey )
478       throws FinderException {
479 
480     // Precondition
481     if ( primaryKey == null ) {
482       throw new FinderException( "null primaryKey" );
483     }
484 
485     boolean hasRow = false;
486     try {
487       hasRow = selectByPrimaryKey(primaryKey);
488       if ( theLog.isDebugEnabled() ) {
489         String msg = "ejbFindByPrimaryKey: " + primaryKey + " " + hasRow;
490         theLog.debug( msg );
491       }
492     }
493     catch (Exception ex) {
494       String msg = ErrorUtils.createDbgMsg( "ejbFindByPrimaryKey", ex );
495       theLog.error( msg, ex );
496       throw new EJBException(msg);
497     }
498 
499     if (!hasRow) {
500       String msg = "Row for id " + primaryKey + " not found.";
501       throw new ObjectNotFoundException( msg );
502     }
503 
504     return primaryKey;
505   } // ejbFindByPrimaryKey(Integer)
506 
507   public Collection ejbFindByMemberIdRowingId(Integer memberId,Integer rowingId)
508       throws FinderException {
509 
510     // Preconditions
511     if ( memberId == null ) {
512       throw new FinderException( "null memberId" );
513     }
514     if ( rowingId == null ) {
515       throw new FinderException( "null rowingId" );
516     }
517 
518     Collection retVal = null;
519     try {
520       retVal = selectByMemberIdRowingId( memberId, rowingId );
521       if ( theLog.isDebugEnabled() ) {
522         String msg = "ejbFindInDateRange: size == " + retVal.size();
523         theLog.debug( msg );
524       }
525     }
526     catch (Exception ex) {
527       String msg = ErrorUtils.createDbgMsg( "ejbFindByMemberIdRowingId", ex );
528       theLog.error( msg, ex );
529       throw new EJBException(msg);
530     }
531 
532     return retVal;
533   } // ejbFindByMemberIdRowingId(Integer,Integer)
534 
535   public Collection ejbFindByRowingId(Integer rowingId) throws FinderException {
536 
537     // Preconditions
538     if ( rowingId == null ) {
539       throw new FinderException( "null rowingId" );
540     }
541 
542     Collection retVal = null;
543     try {
544       retVal = selectByRowingId( rowingId );
545       if ( theLog.isDebugEnabled() ) {
546         String msg = "ejbFindInDateRange: size == " + retVal.size();
547         theLog.debug( msg );
548       }
549     }
550     catch (Exception ex) {
551       String msg = ErrorUtils.createDbgMsg( "ejbFindByRowingId", ex );
552       theLog.error( msg, ex );
553       throw new EJBException(msg);
554     }
555 
556     return retVal;
557   } // ejbFindByMemberIdRowingId(Integer,Integer)
558 
559   /**
560    * Returns a collection of rowing sessions that fall within the
561    * inclusive date range.
562    */
563   public Collection ejbFindAll() throws FinderException {
564 
565     Collection retVal = null;
566     try {
567       retVal = selectAll();
568       if ( theLog.isDebugEnabled() ) {
569         String msg = "ejbFindAll: size == " + retVal.size();
570         theLog.debug( msg );
571       }
572     }
573     catch (Exception ex) {
574       String msg = ErrorUtils.createDbgMsg( "findAll", ex );
575       theLog.error( msg, ex );
576       throw new EJBException(msg);
577     }
578 
579     return retVal;
580   } // ejbFindAll()
581 
582   public void ejbRemove() {
583 
584     try {
585       Integer tmpId = this.getParticipantId();
586       deleteRow( tmpId );
587       if ( theLog.isInfoEnabled() ) {
588         theLog.info( "ejbRemove: row deleted, participantId == " + tmpId );
589       }
590     }
591     catch (Exception ex) {
592       String msg = ErrorUtils.createDbgMsg( "ejbRemove", ex );
593       theLog.error( msg, ex );
594       throw new EJBException(msg);
595     }
596 
597   } // ejbRemove()
598 
599   public void setEntityContext(EntityContext context) {
600 
601     this.context = context;
602     if ( theLog.isDebugEnabled() ) {
603       theLog.debug( "setEntityContext: context set" );
604     }
605 
606   } // setEntityContext(EntityContext)
607 
608   public void unsetEntityContext() {
609 
610     this.context = null;
611     if ( theLog.isDebugEnabled() ) {
612       theLog.debug( "unsetEntityContext: context nulled" );
613     }
614 
615   } // unsetEntityContext()
616 
617   public void ejbActivate() {
618     this._participantId = (Integer)context.getPrimaryKey();
619     if ( theLog.isDebugEnabled() ) {
620       theLog.debug( "ejbActivate: participantId == " + this._participantId );
621     }
622   }
623 
624   public void ejbPassivate() {
625     this._participantId = null;
626     if ( theLog.isDebugEnabled() ) {
627       theLog.debug( "ejbPassivate: participantId nulled" );
628     }
629   }
630 
631   public void ejbLoad() {
632 
633     try {
634       loadRow();
635       if ( theLog.isDebugEnabled() ) {
636         theLog.debug( "ejbLoad: row loaded for #"  + this._participantId );
637       }
638       _isDirty = false;
639     }
640     catch (Exception ex) {
641       String msg = ErrorUtils.createDbgMsg( "ejbLoad", ex );
642       theLog.error( msg, ex );
643       throw new EJBException(msg);
644     }
645 
646   } // ejbLoad()
647   
648   public void ejbStore() {
649 
650     try {
651       if ( _isDirty ) {
652         storeRow();
653         if ( theLog.isDebugEnabled() ) {
654           theLog.debug( "ejbStore: row stored for #"  + this._participantId );
655         }
656         _isDirty = false;
657       }
658       else {
659         if ( theLog.isDebugEnabled() ) {
660           theLog.debug( "ejbStore: row skipped" );
661         }
662       }
663     }
664     catch (Exception ex) {
665       String msg = ErrorUtils.createDbgMsg( "ejbStore", ex );
666       theLog.error( msg, ex );
667       throw new EJBException(msg);
668     }
669 
670   } // ejbStore()
671 
672   private boolean selectByPrimaryKey(Integer primaryKey) 
673     throws SQLException {
674 
675     Connection conn = null;
676     PreparedStatement stmt = null;
677     ResultSet rs = null;
678     boolean retVal = false;
679     try {
680       conn = DBConfiguration.getConnection();
681       stmt = conn.prepareStatement(
682           Configuration.SQL_PARTICIPANT_01,
683           ResultSet.TYPE_FORWARD_ONLY,
684           ResultSet.CONCUR_READ_ONLY);
685 
686       stmt.setInt( 1, primaryKey.intValue() );
687 
688       rs = stmt.executeQuery();
689       // FIXME cache instance data and set isDirty=false
690       retVal = rs.next();
691       if ( theLog.isDebugEnabled() ) {
692         theLog.debug( "selectByPrimaryKey: retVal == " + retVal );
693       }
694 
695     }
696     finally {
697       DBConfiguration.closeSQLResultSet( rs );
698       DBConfiguration.closeSQLStatement( stmt );
699       DBConfiguration.closeSQLConnection( conn );
700       rs = null;
701       stmt = null;
702       conn = null;
703     }
704 
705     return retVal;
706   } // selectByPrimaryKey(Integer)
707 
708   private Collection selectByMemberIdRowingId( Integer memberId,
709     Integer rowingId) throws SQLException {
710 
711     Connection conn = null;
712     PreparedStatement stmt = null;
713     ResultSet rs = null;
714     Collection retVal = new ArrayList();
715     try {
716       conn = DBConfiguration.getConnection();
717       stmt = conn.prepareStatement(
718           Configuration.SQL_PARTICIPANT_03,
719           ResultSet.TYPE_FORWARD_ONLY,
720           ResultSet.CONCUR_READ_ONLY);
721 
722       stmt.setInt( 1, memberId.intValue() );
723       stmt.setInt( 2, rowingId.intValue() );
724 
725       rs = stmt.executeQuery();
726 
727       int rowCount = 0;
728       while ( rs.next() ) {
729         Integer id = new Integer( rs.getInt("participant_id") );
730         retVal.add(id);
731         ++rowCount;
732       }
733 
734       if ( theLog.isDebugEnabled() ) {
735         String msg = "selectByMemberIdRowingId: rowCount == " + rowCount;
736         theLog.debug( msg );
737       }
738 
739     }
740     finally {
741       DBConfiguration.closeSQLResultSet( rs );
742       DBConfiguration.closeSQLStatement( stmt );
743       DBConfiguration.closeSQLConnection( conn );
744       rs = null;
745       stmt = null;
746       conn = null;
747     }
748 
749     return retVal;
750   } // selectByMemberIdRowingId(Integer,Integer)
751 
752   private Collection selectByRowingId( Integer rowingId ) throws SQLException {
753 
754     Connection conn = null;
755     PreparedStatement stmt = null;
756     ResultSet rs = null;
757     Collection retVal = new ArrayList();
758     try {
759       conn = DBConfiguration.getConnection();
760       stmt = conn.prepareStatement(
761           Configuration.SQL_PARTICIPANT_02,
762           ResultSet.TYPE_FORWARD_ONLY,
763           ResultSet.CONCUR_READ_ONLY);
764 
765       stmt.setInt( 1, rowingId.intValue() );
766 
767       rs = stmt.executeQuery();
768 
769       int rowCount = 0;
770       while ( rs.next() ) {
771         Integer id = new Integer( rs.getInt("participant_id") );
772         retVal.add(id);
773         ++rowCount;
774       }
775 
776       if ( theLog.isDebugEnabled() ) {
777         String msg = "selectByRowingId: rowCount == " + rowCount;
778         theLog.debug( msg );
779       }
780 
781     }
782     finally {
783       DBConfiguration.closeSQLResultSet( rs );
784       DBConfiguration.closeSQLStatement( stmt );
785       DBConfiguration.closeSQLConnection( conn );
786       rs = null;
787       stmt = null;
788       conn = null;
789     }
790 
791     return retVal;
792   } // selectByRowingId(Integer)
793 
794   private Collection selectAll() throws SQLException {
795 
796     Connection conn = null;
797     PreparedStatement stmt = null;
798     ResultSet rs = null;
799     Collection retVal = new ArrayList();
800     try {
801       conn = DBConfiguration.getConnection();
802       stmt = conn.prepareStatement(
803           Configuration.SQL_PARTICIPANT_04,
804           ResultSet.TYPE_FORWARD_ONLY,
805           ResultSet.CONCUR_READ_ONLY);
806 
807       rs = stmt.executeQuery();
808 
809       int rowCount = 0;
810       while ( rs.next() ) {
811         Integer id = new Integer( rs.getInt("participant_id") );
812         retVal.add(id);
813         ++rowCount;
814       }
815 
816       if ( theLog.isDebugEnabled() ) {
817         String msg = "selectAll: rowCount == " + rowCount;
818         theLog.debug( msg );
819       }
820 
821     }
822     finally {
823       DBConfiguration.closeSQLResultSet( rs );
824       DBConfiguration.closeSQLStatement( stmt );
825       DBConfiguration.closeSQLConnection( conn );
826       rs = null;
827       stmt = null;
828       conn = null;
829     }
830 
831     return retVal;
832   } // selectAll()
833 
834   private void insertRowWithSessionConstraints( Integer memberId,
835     Integer rowingId, Integer participantId, SeatPreference seatPreference,
836       RowingSessionState rsState ) throws CreateException, SQLException {
837 
838     // Precondition
839     try {
840       RowingSessionSnapshot rss = RowingDBRead.loadRowingSession( rowingId );
841       if ( !rsState.equals(rss.getState()) ) {
842         String msg = "invalid session state == " + rss.getState().getName()
843             + " != " + rsState.getName();
844         throw new CreateException( msg );
845       }
846     }
847     catch( RowingException x ) {
848       String msg = ErrorUtils.createDbgMsg( "insertRowWith...", x );
849       theLog.error( msg );
850       throw new CreateException( msg );
851     }
852 
853     Connection conn = null;
854     PreparedStatement stmt = null;
855     ResultSet rs = null;
856     int rowCount = 0;
857     try {
858 
859       conn = DBConfiguration.getConnection();
860       stmt = conn.prepareStatement(
861           Configuration.SQL_PARTICIPANT_05,
862           ResultSet.TYPE_FORWARD_ONLY,
863           ResultSet.CONCUR_READ_ONLY);
864 
865       stmt.setInt( 1, memberId.intValue()      );
866       stmt.setInt( 2, participantId.intValue() );
867 
868       if ( seatPreference != null ) {
869         stmt.setString(  3, seatPreference.getName() );
870       }
871       else {
872         stmt.setNull( 3, Types.CHAR );
873       }
874 
875       stmt.setInt(    4, rowingId.intValue() );
876       // stmt.setString( 5, rsState.getName()   );
877 
878       if ( theLog.isDebugEnabled() ) {
879         theLog.debug( "SQL == " + Configuration.SQL_PARTICIPANT_05 );
880         theLog.debug( "arg 1 == " + memberId.intValue() );
881         theLog.debug( "arg 2 == " + participantId.intValue() );
882         theLog.debug( "arg 3 == " + seatPreference );
883         theLog.debug( "arg 4 == " + rowingId.intValue() );
884         // theLog.debug( "arg 5 == " + rsState.getName() );
885       }
886 
887       rowCount = stmt.executeUpdate();
888 
889       if ( theLog.isDebugEnabled() ) {
890         theLog.debug( "insertRow: participantId " + participantId );
891         theLog.debug( "insertRow: rowCount " + rowCount );
892       }
893 
894     }
895     finally {
896       DBConfiguration.closeSQLResultSet( rs );
897       DBConfiguration.closeSQLStatement( stmt );
898       DBConfiguration.closeSQLConnection( conn );
899       rs = null;
900       stmt = null;
901       conn = null;
902     }
903 
904     /*
905      * Under rare conditions, when a participant is inserted at the same
906      * same time a rowing session is being promoted, the INSERT statement
907      * could fail quietly.
908     */
909 try {
910   theLog.debug( "trying to load new participant..." );
911   ParticipantSnapshot _ps = RowingDBRead.loadParticipant( participantId );
912   theLog.debug( "...loaded " + participantId );
913 } catch (Exception _x) {
914   String _msg = ErrorUtils.createDbgMsg( "...load failed", _x );
915   theLog.debug( _msg );
916 }
917     if ( rowCount != 1 ) {
918       String msg = "participant #" + participantId + " was not added";
919       throw new CreateException( msg );
920     }
921 
922     return;
923   } // insertRowWithSessionConstraints(..)
924 
925   private void deleteRow(Integer id) throws RemoveException, SQLException {
926 
927     Connection conn = null;
928     PreparedStatement stmt = null;
929     ResultSet rs = null;
930     int rowCount = 0;
931     try {
932       conn = DBConfiguration.getConnection();
933       stmt = conn.prepareStatement(
934           Configuration.SQL_PARTICIPANT_06,
935           ResultSet.TYPE_FORWARD_ONLY,
936           ResultSet.CONCUR_READ_ONLY);
937 
938       stmt.setInt( 1, id.intValue() );
939 
940       rowCount = stmt.executeUpdate();
941 
942       if ( theLog.isDebugEnabled() ) {
943         theLog.debug( "deleteRow: row " + id );
944       }
945 
946     }
947     finally {
948       DBConfiguration.closeSQLResultSet( rs );
949       DBConfiguration.closeSQLStatement( stmt );
950       DBConfiguration.closeSQLConnection( conn );
951       rs = null;
952       stmt = null;
953       conn = null;
954     }
955 
956     if ( rowCount != 1 ) {
957       String msg = "row #" + id + " was not deleted";
958       throw new RemoveException( msg );
959     }
960 
961     return;
962   } // deleteRow(Integer)
963 
964   private void loadRow()
965     throws SQLException, RowingException, NoSuchEntityException {
966 
967     /*
968      * Implementation note: the translation from DB row to snapshot
969      * to bean looks inefficient, but it is not the bottleneck in
970      * loading bean. The bottleneck is the EJB algorithm for finding
971      * an id, then loading a row, then storing the result back to
972      * the DB. That means at least two DB calls (assuming the storage
973      * step is skipped by checking an isDirty flag). The DB calls
974      * completely dominate performance.
975      *
976      * On the other hand, returning a row as a snapshot allows the
977      * RowingDBRead code to be reused directly elsewhere. Where
978      * speed is critical, and where it is unlikely that a ParticipantBean
979      * is already in memory, it is best to use the RowingDBRead code to
980      * directly load a (read-only) snapshot from the database.
981      */
982     ParticipantSnapshot snapshot =
983         RowingDBRead.loadParticipant( this._participantId );
984 
985     this._rowingId = snapshot.getRowingId();
986     this._memberId = snapshot.getMemberId();
987     this._participantId = snapshot.getParticipantId();
988     this._seatPreference = snapshot.getSeatPreference();
989     this._replacesId = snapshot.getReplacesId();
990     this._initialSeatId = snapshot.getInitialSeatId();
991     this._finalSeatId = snapshot.getFinalSeatId();
992     this._attendance = snapshot.getAttendance();
993 
994     return;
995   } // loadRow()
996 
997   private void storeRow() throws SQLException {
998 
999     Connection conn = null;
1000    PreparedStatement stmt = null;
1001    int rowCount = 0;
1002    try {
1003      conn = DBConfiguration.getConnection();
1004      stmt = conn.prepareStatement(
1005          Configuration.SQL_PARTICIPANT_07,
1006          ResultSet.TYPE_FORWARD_ONLY,
1007          ResultSet.CONCUR_READ_ONLY);
1008
1009      if ( this._seatPreference != null ) {
1010        stmt.setString( 1, this._seatPreference.getName() );
1011      }
1012      else {
1013        stmt.setNull( 1, Types.CHAR );
1014      }
1015
1016      if ( this._initialSeatId != null ) {
1017        stmt.setInt( 2, this._initialSeatId.intValue() );
1018      }
1019      else {
1020        stmt.setNull( 2, Types.INTEGER );
1021      }
1022
1023      if ( this._finalSeatId != null ) {
1024        stmt.setInt( 3, this._finalSeatId.intValue() );
1025      }
1026      else {
1027        stmt.setNull( 3, Types.INTEGER );
1028      }
1029
1030      if ( this._attendance != null ) {
1031        stmt.setString( 4, this._attendance.getName() );
1032      }
1033      else {
1034        stmt.setNull( 4, Types.CHAR );
1035      }
1036
1037      stmt.setInt( 5, this._participantId.intValue() );
1038
1039      rowCount = stmt.executeUpdate();
1040
1041      if ( theLog.isDebugEnabled() ) {
1042        theLog.debug( "storeRow: rowCount == " + rowCount );
1043        String msg = "storeRow: " + this._participantId
1044          + ", " + this._initialSeatId
1045          + ", " + this._finalSeatId + ", "
1046          + ( this._attendance == null ? null : this._attendance.getName() );
1047        theLog.debug( msg );
1048      }
1049
1050    }
1051    finally {
1052      DBConfiguration.closeSQLStatement( stmt );
1053      DBConfiguration.closeSQLConnection( conn );
1054      stmt = null;
1055      conn = null;
1056    }
1057
1058    if ( rowCount != 1 ) {
1059      String msg = "failed to store participant ==  " + this._participantId;
1060      theLog.error( msg );
1061      throw new EJBException( msg );
1062    }
1063
1064    return;
1065  } // storeRow()
1066
1067  /** A utility that gets (and reserves) the next id for a rowing session */
1068  public static Integer nextId() throws SQLException, CreateException {
1069
1070    Connection conn = null;
1071    PreparedStatement stmt = null;
1072    ResultSet rs = null;
1073    Integer retVal = null;
1074    try {
1075      conn = DBConfiguration.getConnection();
1076      stmt = conn.prepareStatement(
1077          Configuration.SQL_PARTICIPANT_08,
1078          ResultSet.TYPE_FORWARD_ONLY,
1079          ResultSet.CONCUR_READ_ONLY);
1080
1081      if ( theLog.isDebugEnabled() ) {
1082        String msg =
1083          "nextId update: SQL == " + Configuration.SQL_PARTICIPANT_08;
1084        theLog.debug( msg );
1085      }
1086
1087      if ( !DBConfiguration.isOracle() ) {
1088
1089        boolean moreResults = stmt.execute();
1090
1091        stmt = conn.prepareStatement(
1092            Configuration.SQL_PARTICIPANT_08A,
1093            ResultSet.TYPE_FORWARD_ONLY,
1094            ResultSet.CONCUR_READ_ONLY);
1095
1096        if ( theLog.isDebugEnabled() ) {
1097          String msg =
1098            "nextId select: SQL == " + Configuration.SQL_PARTICIPANT_08A;
1099          theLog.debug( msg );
1100        }
1101
1102      } // if !isOracle
1103
1104      rs = stmt.executeQuery();
1105
1106      int rowCount = 0;
1107      while ( rs.next() ) {
1108        retVal = new Integer( rs.getInt(1) );
1109        ++rowCount;
1110      }
1111      if ( rowCount != 1 ) {
1112        String msg =  "unable to get next id: rowCount == " + rowCount;
1113        throw new CreateException( msg );
1114      }
1115
1116      if ( theLog.isDebugEnabled() ) {
1117        String msg = "nextId: retVal == " + retVal.intValue();
1118        theLog.debug( msg );
1119      }
1120
1121    }
1122    finally {
1123      DBConfiguration.closeSQLResultSet( rs );
1124      DBConfiguration.closeSQLStatement( stmt );
1125      DBConfiguration.closeSQLConnection( conn );
1126      rs = null;
1127      stmt = null;
1128      conn = null;
1129    }
1130
1131    return retVal;
1132  } // nextId()
1133
1134} // ParticipantBean
1135
1136/*
1137 * $Log: ParticipantBean.java,v $
1138 * Revision 1.5  2003/02/26 03:38:45  rphall
1139 * Added copyright and GPL license
1140 *
1141 * Revision 1.4  2003/02/19 22:09:13  rphall
1142 * Removed gratuitous use of CLRA acronym
1143 *
1144 * Revision 1.3  2003/02/16 00:47:27  rphall
1145 * Removed dead code
1146 *
1147 */
1148