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