Skip to content

fix getting phases #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 17, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,18 @@ public class InformixPhasePersistence implements PhasePersistence {
+ "JOIN project_phase ON dependent_phase_id = project_phase_id "
+ "WHERE project_id IN ";

/**
* Selects phase data.
*/
private static final String SELECT_PHASE_FOR_PROJECT = "SELECT project_phase_id, project_id, fixed_start_time, "
+ "scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, duration, "
+ "project_phase.modify_date, "
+ "phase_type_lu.phase_type_id, phase_type_lu.name phase_type_name, "
+ "phase_status_lu.phase_status_id, phase_status_lu.name phase_status_name "
+ "FROM project_phase JOIN phase_type_lu ON phase_type_lu.phase_type_id = project_phase.phase_type_id "
+ "JOIN phase_status_lu ON phase_status_lu.phase_status_id = "
+ "project_phase.phase_status_id WHERE project_id = ?";

/**
* Selects phase data.
*/
Expand Down Expand Up @@ -241,11 +253,6 @@ public class InformixPhasePersistence implements PhasePersistence {
*/
private static final String SELECT_PHASE_TYPES = "SELECT phase_type_id, name phase_type_name FROM phase_type_lu";

/**
* Selects all projects - checks if all exists in database.
*/
private static final String SELECT_PROJECT_IDS = "SELECT project_id FROM project WHERE project_id IN ";

/**
* <p>
* Represents the audit creation type.
Expand Down Expand Up @@ -469,7 +476,14 @@ public InformixPhasePersistence(DBConnectionFactory connectionFactory, String co
* @throws PhasePersistenceException if any database error happen.
*/
public Project getProjectPhases(long projectId) throws PhasePersistenceException {
return getProjectPhases(new long[] {projectId})[0];
Connection conn = createConnection(false);
try {
return getProjectPhasesImpl(conn, projectId);
} catch (SQLException ex) {
throw new PhasePersistenceException("Error occurs while retrieving the projects.", ex);
} finally {
close(conn);
}
}

/**
Expand Down Expand Up @@ -507,6 +521,65 @@ public Project[] getProjectPhases(long[] projectIds) throws PhasePersistenceExce
}
}

/**
* This the current implementation of the {@link #getProjectPhases(long)} method. It will first check which
* project for the given ids exists and which have no phases. The it selects all the phases for the project,
* create them and return.
*
* @param conn the database connection to use.
* @param projectIds the ids of the projects to retrieve.
* @return the array of projects with one to one mapping between project and it id.
*
* @throws SQLException if any database error occurs.
* @throws PhasePersistenceException if other error happen.
*/
private Project getProjectPhasesImpl(Connection conn, long projectId) throws SQLException,
PhasePersistenceException {

PreparedStatement pstmt = null;
ResultSet rs = null;

// create workdays to be used to create the project
Workdays workdays = new DefaultWorkdaysFactory().createWorkdaysInstance();
Project project = new Project(new Date(Long.MAX_VALUE), workdays);
project.setId(projectId);
try {
Map phasesMap = new HashMap();
// prepare the query to retrieve the phases .
pstmt = conn.prepareStatement(SELECT_PHASE_FOR_PROJECT);
pstmt.setLong(1, projectId);

rs = pstmt.executeQuery();

// for each phase in the response create the Phase object and add it to the internal list
while (rs.next()) {
Phase phase = populatePhase(rs, project);
phasesMap.put(new Long(phase.getId()), phase);
}

// fill the phases depedencies and criteria for them
if (phasesMap.size() > 0) {
fillDependencies(conn, phasesMap, new long[] {projectId});
fillCriteria(conn, phasesMap, new long[] {projectId});
}

// this comparator is used to get the lowest start date
Comparator phasesComparator = new PhaseStartDateComparator();
// set the correct date for project
Phase[] phases = project.getAllPhases(phasesComparator);
// if project has any phases - get the first one
if (phases.length > 0) {
project.setStartDate(phases[0].getScheduledStartDate());
}

// create the result array
return project;
} finally {
close(rs);
close(pstmt);
}
}

/**
* This the current implementation of the {@link #getProjectPhases(long[])} method. It will first check which
* project for the given ids exists and which have no phases. The it selects all the phases for the projects,
Expand Down Expand Up @@ -625,6 +698,142 @@ private Project[] getProjectPhasesImpl(Connection conn, long[] projectIds) throw
}
}

/**
* This method set the phase criteria into the phases from the given map.
*
* @param conn the database connection to be used.
* @param phases the Phases to which criteria will ba add. Key should be Long phase id, value - Phase object.
* @param projectIds all the project ids.
*
* @throws SQLException if any database error occurs.
*/
private void fillCriteria(Connection conn, Map phases, long[] projectIds) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;

try {
// create the statement
pstmt = conn.prepareStatement(SELECT_PHASE_CRITERIA_FOR_PROJECTS + createQuestionMarks(projectIds.length));

// set the id to the statement
for (int i = 0; i < projectIds.length; ++i) {
pstmt.setLong(i + 1, projectIds[i]);
}

// execute query
rs = pstmt.executeQuery();

// create the phase criteria
while (rs.next()) {
// get the phase id
Long id = new Long(rs.getLong("project_phase_id"));
// get criteria name and parameter
String name = rs.getString("name");
String parameter = rs.getString("parameter");

// get the phase and add criteria
Phase phase = (Phase) phases.get(id);
phase.setAttribute(name, parameter);
}
} finally {
close(rs);
close(pstmt);
}
}

/**
* This method selects all the depedencies for phases.
*
* @param conn the database connection.
* @param phases the map of already retrieved phases.
* @param projectIds all the project ids.
*
* @throws SQLException if database error occures.
* @throws PhasePersistenceException if the phase depedencies cannot be filled.
*/
private void fillDependencies(Connection conn, Map phases, long[] projectIds) throws SQLException,
PhasePersistenceException {
// get the phase
PreparedStatement pstmt = null;
ResultSet rs = null;

try {
// create the statement
pstmt = conn.prepareStatement(SELECT_DEPENDENCY_FOR_PROJECTS + createQuestionMarks(projectIds.length));

// set the id to the statement
for (int i = 0; i < projectIds.length; ++i) {
pstmt.setLong(i + 1, projectIds[i]);
}

// execte the query
rs = pstmt.executeQuery();

while (rs.next()) {
// get the depedency
Long dependentId = new Long(rs.getLong("dependent_phase_id"));
Long dependencyId = new Long(rs.getLong("dependency_phase_id"));
// if the phase exists - create dependecy
if (phases.containsKey(dependentId) && phases.containsKey(dependencyId)) {
Phase phase = (Phase) phases.get(dependentId);
Dependency dependency = createDependency(rs, phases, phase);
phase.addDependency(dependency);
} else {
// because we have retrieved all the phases for project before, this should never happen
throw new PhasePersistenceException("Missing dependecy: " + dependencyId
+ " for phase: " + dependentId);
}
}

} finally {
close(rs);
close(pstmt);
}
}

/**
* Create the Dependency instance from given result set.
*
* @param rs the source result set.
* @param phases the retrieved phases.
* @param dependantPhase the dependant phase.
* @return the Dependency instance.
*
* @throws SQLException if database error occures.
*/
private static Dependency createDependency(ResultSet rs, Map phases, Phase dependantPhase) throws SQLException {
Phase dependencyPhase = (Phase) phases.get(new Long(rs.getLong("dependency_phase_id")));
long lagTime = rs.getLong("lag_time");

return new Dependency(dependencyPhase, dependantPhase, rs.getBoolean("dependency_start"), rs
.getBoolean("dependent_start"), lagTime);
}

/**
* Creates the Phase instance from the given ResultSet.
*
* @param rs the source result set.
* @param project the project for phase.
* @return the Phase instance.
* @throws SQLException if database error occurs.
*/
private static Phase populatePhase(ResultSet rs, Project project) throws SQLException {
long duration = rs.getLong("duration");
Phase phase = new Phase(project, duration);
phase.setActualEndDate(rs.getTimestamp("actual_end_time"));
phase.setActualStartDate(rs.getTimestamp("actual_start_time"));
phase.setFixedStartDate(rs.getTimestamp("fixed_start_time"));
phase.setId(rs.getLong("project_phase_id"));

phase.setPhaseStatus(populatePhaseStatus(rs));
phase.setPhaseType(populatePhaseType(rs));
phase.setScheduledEndDate(rs.getTimestamp("scheduled_end_time"));
phase.setScheduledStartDate(rs.getTimestamp("scheduled_start_time"));
phase.setModifyDate(rs.getTimestamp("modify_date"));

return phase;
}

/**
* <p>
* Returns all the PhaseTypes from the datastore. The returned array might be empty if no types exists, but it
Expand Down