@@ -203,6 +203,18 @@ public class InformixPhasePersistence implements PhasePersistence {
203
203
+ "JOIN project_phase ON dependent_phase_id = project_phase_id "
204
204
+ "WHERE project_id IN " ;
205
205
206
+ /**
207
+ * Selects phase data.
208
+ */
209
+ private static final String SELECT_PHASE_FOR_PROJECT = "SELECT project_phase_id, project_id, fixed_start_time, "
210
+ + "scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, duration, "
211
+ + "project_phase.modify_date, "
212
+ + "phase_type_lu.phase_type_id, phase_type_lu.name phase_type_name, "
213
+ + "phase_status_lu.phase_status_id, phase_status_lu.name phase_status_name "
214
+ + "FROM project_phase JOIN phase_type_lu ON phase_type_lu.phase_type_id = project_phase.phase_type_id "
215
+ + "JOIN phase_status_lu ON phase_status_lu.phase_status_id = "
216
+ + "project_phase.phase_status_id WHERE project_id = ?" ;
217
+
206
218
/**
207
219
* Selects phase data.
208
220
*/
@@ -241,11 +253,6 @@ public class InformixPhasePersistence implements PhasePersistence {
241
253
*/
242
254
private static final String SELECT_PHASE_TYPES = "SELECT phase_type_id, name phase_type_name FROM phase_type_lu" ;
243
255
244
- /**
245
- * Selects all projects - checks if all exists in database.
246
- */
247
- private static final String SELECT_PROJECT_IDS = "SELECT project_id FROM project WHERE project_id IN " ;
248
-
249
256
/**
250
257
* <p>
251
258
* Represents the audit creation type.
@@ -469,7 +476,14 @@ public InformixPhasePersistence(DBConnectionFactory connectionFactory, String co
469
476
* @throws PhasePersistenceException if any database error happen.
470
477
*/
471
478
public Project getProjectPhases (long projectId ) throws PhasePersistenceException {
472
- return getProjectPhases (new long [] {projectId })[0 ];
479
+ Connection conn = createConnection (false );
480
+ try {
481
+ return getProjectPhasesImpl (conn , projectId );
482
+ } catch (SQLException ex ) {
483
+ throw new PhasePersistenceException ("Error occurs while retrieving the projects." , ex );
484
+ } finally {
485
+ close (conn );
486
+ }
473
487
}
474
488
475
489
/**
@@ -507,6 +521,65 @@ public Project[] getProjectPhases(long[] projectIds) throws PhasePersistenceExce
507
521
}
508
522
}
509
523
524
+ /**
525
+ * This the current implementation of the {@link #getProjectPhases(long)} method. It will first check which
526
+ * project for the given ids exists and which have no phases. The it selects all the phases for the project,
527
+ * create them and return.
528
+ *
529
+ * @param conn the database connection to use.
530
+ * @param projectIds the ids of the projects to retrieve.
531
+ * @return the array of projects with one to one mapping between project and it id.
532
+ *
533
+ * @throws SQLException if any database error occurs.
534
+ * @throws PhasePersistenceException if other error happen.
535
+ */
536
+ private Project getProjectPhasesImpl (Connection conn , long projectId ) throws SQLException ,
537
+ PhasePersistenceException {
538
+
539
+ PreparedStatement pstmt = null ;
540
+ ResultSet rs = null ;
541
+
542
+ // create workdays to be used to create the project
543
+ Workdays workdays = new DefaultWorkdaysFactory ().createWorkdaysInstance ();
544
+ Project project = new Project (new Date (Long .MAX_VALUE ), workdays );
545
+ project .setId (projectId );
546
+ try {
547
+ Map phasesMap = new HashMap ();
548
+ // prepare the query to retrieve the phases .
549
+ pstmt = conn .prepareStatement (SELECT_PHASE_FOR_PROJECT );
550
+ pstmt .setLong (1 , projectId );
551
+
552
+ rs = pstmt .executeQuery ();
553
+
554
+ // for each phase in the response create the Phase object and add it to the internal list
555
+ while (rs .next ()) {
556
+ Phase phase = populatePhase (rs , project );
557
+ phasesMap .put (new Long (phase .getId ()), phase );
558
+ }
559
+
560
+ // fill the phases depedencies and criteria for them
561
+ if (phasesMap .size () > 0 ) {
562
+ fillDependencies (conn , phasesMap , new long [] {projectId });
563
+ fillCriteria (conn , phasesMap , new long [] {projectId });
564
+ }
565
+
566
+ // this comparator is used to get the lowest start date
567
+ Comparator phasesComparator = new PhaseStartDateComparator ();
568
+ // set the correct date for project
569
+ Phase [] phases = project .getAllPhases (phasesComparator );
570
+ // if project has any phases - get the first one
571
+ if (phases .length > 0 ) {
572
+ project .setStartDate (phases [0 ].getScheduledStartDate ());
573
+ }
574
+
575
+ // create the result array
576
+ return project ;
577
+ } finally {
578
+ close (rs );
579
+ close (pstmt );
580
+ }
581
+ }
582
+
510
583
/**
511
584
* This the current implementation of the {@link #getProjectPhases(long[])} method. It will first check which
512
585
* project for the given ids exists and which have no phases. The it selects all the phases for the projects,
@@ -625,6 +698,142 @@ private Project[] getProjectPhasesImpl(Connection conn, long[] projectIds) throw
625
698
}
626
699
}
627
700
701
+ /**
702
+ * This method set the phase criteria into the phases from the given map.
703
+ *
704
+ * @param conn the database connection to be used.
705
+ * @param phases the Phases to which criteria will ba add. Key should be Long phase id, value - Phase object.
706
+ * @param projectIds all the project ids.
707
+ *
708
+ * @throws SQLException if any database error occurs.
709
+ */
710
+ private void fillCriteria (Connection conn , Map phases , long [] projectIds ) throws SQLException {
711
+ PreparedStatement pstmt = null ;
712
+ ResultSet rs = null ;
713
+
714
+ try {
715
+ // create the statement
716
+ pstmt = conn .prepareStatement (SELECT_PHASE_CRITERIA_FOR_PROJECTS + createQuestionMarks (projectIds .length ));
717
+
718
+ // set the id to the statement
719
+ for (int i = 0 ; i < projectIds .length ; ++i ) {
720
+ pstmt .setLong (i + 1 , projectIds [i ]);
721
+ }
722
+
723
+ // execute query
724
+ rs = pstmt .executeQuery ();
725
+
726
+ // create the phase criteria
727
+ while (rs .next ()) {
728
+ // get the phase id
729
+ Long id = new Long (rs .getLong ("project_phase_id" ));
730
+ // get criteria name and parameter
731
+ String name = rs .getString ("name" );
732
+ String parameter = rs .getString ("parameter" );
733
+
734
+ // get the phase and add criteria
735
+ Phase phase = (Phase ) phases .get (id );
736
+ phase .setAttribute (name , parameter );
737
+ }
738
+ } finally {
739
+ close (rs );
740
+ close (pstmt );
741
+ }
742
+ }
743
+
744
+ /**
745
+ * This method selects all the depedencies for phases.
746
+ *
747
+ * @param conn the database connection.
748
+ * @param phases the map of already retrieved phases.
749
+ * @param projectIds all the project ids.
750
+ *
751
+ * @throws SQLException if database error occures.
752
+ * @throws PhasePersistenceException if the phase depedencies cannot be filled.
753
+ */
754
+ private void fillDependencies (Connection conn , Map phases , long [] projectIds ) throws SQLException ,
755
+ PhasePersistenceException {
756
+ // get the phase
757
+ PreparedStatement pstmt = null ;
758
+ ResultSet rs = null ;
759
+
760
+ try {
761
+ // create the statement
762
+ pstmt = conn .prepareStatement (SELECT_DEPENDENCY_FOR_PROJECTS + createQuestionMarks (projectIds .length ));
763
+
764
+ // set the id to the statement
765
+ for (int i = 0 ; i < projectIds .length ; ++i ) {
766
+ pstmt .setLong (i + 1 , projectIds [i ]);
767
+ }
768
+
769
+ // execte the query
770
+ rs = pstmt .executeQuery ();
771
+
772
+ while (rs .next ()) {
773
+ // get the depedency
774
+ Long dependentId = new Long (rs .getLong ("dependent_phase_id" ));
775
+ Long dependencyId = new Long (rs .getLong ("dependency_phase_id" ));
776
+ // if the phase exists - create dependecy
777
+ if (phases .containsKey (dependentId ) && phases .containsKey (dependencyId )) {
778
+ Phase phase = (Phase ) phases .get (dependentId );
779
+ Dependency dependency = createDependency (rs , phases , phase );
780
+ phase .addDependency (dependency );
781
+ } else {
782
+ // because we have retrieved all the phases for project before, this should never happen
783
+ throw new PhasePersistenceException ("Missing dependecy: " + dependencyId
784
+ + " for phase: " + dependentId );
785
+ }
786
+ }
787
+
788
+ } finally {
789
+ close (rs );
790
+ close (pstmt );
791
+ }
792
+ }
793
+
794
+ /**
795
+ * Create the Dependency instance from given result set.
796
+ *
797
+ * @param rs the source result set.
798
+ * @param phases the retrieved phases.
799
+ * @param dependantPhase the dependant phase.
800
+ * @return the Dependency instance.
801
+ *
802
+ * @throws SQLException if database error occures.
803
+ */
804
+ private static Dependency createDependency (ResultSet rs , Map phases , Phase dependantPhase ) throws SQLException {
805
+ Phase dependencyPhase = (Phase ) phases .get (new Long (rs .getLong ("dependency_phase_id" )));
806
+ long lagTime = rs .getLong ("lag_time" );
807
+
808
+ return new Dependency (dependencyPhase , dependantPhase , rs .getBoolean ("dependency_start" ), rs
809
+ .getBoolean ("dependent_start" ), lagTime );
810
+ }
811
+
812
+ /**
813
+ * Creates the Phase instance from the given ResultSet.
814
+ *
815
+ * @param rs the source result set.
816
+ * @param project the project for phase.
817
+ * @return the Phase instance.
818
+ * @throws SQLException if database error occurs.
819
+ */
820
+ private static Phase populatePhase (ResultSet rs , Project project ) throws SQLException {
821
+ long duration = rs .getLong ("duration" );
822
+ Phase phase = new Phase (project , duration );
823
+ phase .setActualEndDate (rs .getTimestamp ("actual_end_time" ));
824
+ phase .setActualStartDate (rs .getTimestamp ("actual_start_time" ));
825
+ phase .setFixedStartDate (rs .getTimestamp ("fixed_start_time" ));
826
+ phase .setId (rs .getLong ("project_phase_id" ));
827
+
828
+ phase .setPhaseStatus (populatePhaseStatus (rs ));
829
+ phase .setPhaseType (populatePhaseType (rs ));
830
+ phase .setScheduledEndDate (rs .getTimestamp ("scheduled_end_time" ));
831
+ phase .setScheduledStartDate (rs .getTimestamp ("scheduled_start_time" ));
832
+ phase .setModifyDate (rs .getTimestamp ("modify_date" ));
833
+
834
+ return phase ;
835
+ }
836
+
628
837
/**
629
838
* <p>
630
839
* Returns all the PhaseTypes from the datastore. The returned array might be empty if no types exists, but it
0 commit comments