Java tutorial
/******************************************************************************* * Copyright (c) 2009 David Harrison. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl-3.0.html * * Contributors: * David Harrison - initial API and implementation ******************************************************************************/ package com.sfs.whichdoctor.dao; import com.sfs.DataFilter; import com.sfs.Formatter; import com.sfs.beans.BuilderBean; import com.sfs.beans.ObjectTypeBean; import com.sfs.beans.PrivilegesBean; import com.sfs.beans.UserBean; import com.sfs.dao.SFSDaoException; import com.sfs.whichdoctor.beans.AccreditationBean; import com.sfs.whichdoctor.beans.AssessmentBean; import com.sfs.whichdoctor.beans.GroupBean; import com.sfs.whichdoctor.beans.ItemBean; import com.sfs.whichdoctor.beans.PersonBean; import com.sfs.whichdoctor.beans.OrganisationBean; import com.sfs.whichdoctor.beans.ReportBean; import com.sfs.whichdoctor.beans.RotationBean; import com.sfs.whichdoctor.beans.SearchBean; import com.sfs.whichdoctor.beans.SearchResultsBean; import com.sfs.whichdoctor.beans.SupervisorBean; import com.sfs.whichdoctor.formatter.OutputFormatter; import com.sfs.whichdoctor.search.WhichDoctorSearchDaoException; import java.sql.Date; import java.sql.ResultSet; import java.sql.Timestamp; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.TreeMap; import javax.annotation.Resource; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; /** * The Class RotationDAOImpl. */ public class RotationDAOImpl extends WhichDoctorCoreObjectDAOImpl implements RotationDAO { /** The data logger. */ private static Logger dataLogger = Logger.getLogger(RotationDAOImpl.class); /** The committee name. */ private String committeeName; /** The accreditation dao. */ @Resource private AccreditationDAO accreditationDAO; /** The assessment dao. */ @Resource private AssessmentDAO assessmentDAO; /** The person dao. */ @Resource private PersonDAO personDAO; /** The membership dao. */ @Resource private MembershipDAO membershipDAO; /** The supervisor dao. */ @Resource private SupervisorDAO supervisorDAO; /** The report dao. */ @Resource private ReportDAO reportDAO; /** The relationship dao. */ @Resource private RelationshipDAO relationshipDAO; /** The online tools dao. */ @Resource private OnlineToolDAO onlineToolDAO; /** The Constant DEFAULT_ROTATION. */ private static final int DEFAULT_ROTATION = 0; /** The Constant CONTINUING_ROTATION. */ private static final int CONTINUING_ROTATION = 1; /** The Constant INTERRUPTED_ROTATION. */ private static final int INTERRUPTED_ROTATION = 2; /** * The generic committee name for a rotation. e.g. Specialist Training Committee * * @param committeeNameVal the committee name */ public final void setCommitteeName(final String committeeNameVal) { this.committeeName = committeeNameVal; } /** * Gets the committee name. * * @return the committee name */ public final String getCommitteeName() { return this.committeeName; } /** * Load a RotationBean for a specified rotationId. * * @param rotationId the rotation id * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean load(final int rotationId) throws WhichDoctorDaoException { return load(rotationId, new BuilderBean(), false); } /** * Load a RotationBean for a specified rotationId and supplied load details. * * @param rotationId the rotation id * @param loadDetails the load details * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean load(final int rotationId, final BuilderBean loadDetails) throws WhichDoctorDaoException { return load(rotationId, loadDetails, false); } /** * Load a RotationBean for a specified rotationId and supplied load details. * A boolean parameter identifies whether to use the default reader * connection or optional writer connection datasource. * * @param rotationId the rotation id * @param loadDetails the load details * @param useWriterConn the use writer conn * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ @SuppressWarnings("unchecked") private RotationBean load(final int rotationId, final BuilderBean loadDetails, final boolean useWriterConn) throws WhichDoctorDaoException { RotationBean rotation = null; final String loadRotationId = getSQL().getValue("rotation/load") + " AND rotation.RotationId = ?"; JdbcTemplate jdbcTemplate = this.getJdbcTemplateReader(); if (useWriterConn) { jdbcTemplate = this.getJdbcTemplateWriter(); } try { rotation = (RotationBean) jdbcTemplate.queryForObject(loadRotationId, new Object[] { rotationId }, new RowMapper() { public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException { return loadRotation(rs, loadDetails); } }); } catch (IncorrectResultSizeDataAccessException ie) { dataLogger.debug("No results found for the search: " + ie.getMessage()); } return rotation; } /** * Load a RotationBean for a specified name. * * @param strRotation the str rotation * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean load(final String strRotation) throws WhichDoctorDaoException { return load(strRotation, new BuilderBean()); } /** * Load a RotationBean for a specified name and supplied load details. * * @param strRotation the str rotation * @param loadDetails the load details * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean load(final String strRotation, final BuilderBean loadDetails) throws WhichDoctorDaoException { dataLogger.info("Rotation Name: " + strRotation + " requested"); int rotationGUID = 0; final String loadSQL = getSQL().getValue("rotation/loadName"); try { rotationGUID = this.getJdbcTemplateReader().queryForInt(loadSQL, new Object[] { strRotation }); } catch (DataAccessException de) { dataLogger.error("Error getting guid for supplied rotation: " + de.getMessage()); } if (rotationGUID > 0) { return loadGUID(rotationGUID, loadDetails); } else { throw new WhichDoctorDaoException("Sorry no rotation matching " + "those details could be identified"); } } /** * Load a RotationBean for a specified GUID. * * @param guid the guid * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean loadGUID(final int guid) throws WhichDoctorDaoException { return loadGUID(guid, new BuilderBean()); } /** * Load a RotationBean for a specified GUID and supplied load details. * * @param guid the guid * @param loadDetails the load details * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ @SuppressWarnings("unchecked") public final RotationBean loadGUID(final int guid, final BuilderBean loadDetails) throws WhichDoctorDaoException { final String loadGUID = getSQL().getValue("rotation/load") + " AND rotation.Active = true AND people.Active = true " + "AND rotation.GUID = ?"; RotationBean rotation = null; try { rotation = (RotationBean) this.getJdbcTemplateReader().queryForObject(loadGUID, new Object[] { guid }, new RowMapper() { public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException { return loadRotation(rs, loadDetails); } }); } catch (IncorrectResultSizeDataAccessException ie) { dataLogger.debug("No results found for search: " + ie.getMessage()); } return rotation; } /** * Load the current rotations for the supplied person GUID. * * @param personGUID the person guid * @return the collection * @throws WhichDoctorDaoException the which doctor dao exception */ public final Collection<RotationBean> loadCurrentForPerson(final int personGUID) throws WhichDoctorDaoException { return loadCurrentForPerson(personGUID, new BuilderBean()); } /** * Load all active rotations. * * @return the collection< rotation bean> * * @throws WhichDoctorDaoException the which doctor dao exception */ public final Collection<RotationBean> loadActiveRotations() throws WhichDoctorDaoException { Collection<RotationBean> rotations = new ArrayList<RotationBean>(); SearchBean search = this.getSearchDAO().initiate("rotation", null); search.setLimit(0); Collection<Object> results = null; try { results = this.getSearchDAO().search(search).getSearchResults(); } catch (WhichDoctorSearchDaoException wse) { dataLogger.error("Error searching for active rotations: " + wse.getMessage()); throw new WhichDoctorDaoException("Error searching for active people: " + wse.getMessage()); } if (results != null) { for (Object objRotation : results) { if (objRotation != null) { rotations.add((RotationBean) objRotation); } } } return rotations; } /** * Load the current rotations for the supplied person GUID. * * @param personGUID the person guid * @param loadDetails the load details * @return the collection * @throws WhichDoctorDaoException the which doctor dao exception */ @SuppressWarnings("unchecked") public final Collection<RotationBean> loadCurrentForPerson(final int personGUID, final BuilderBean loadDetails) throws WhichDoctorDaoException { Collection<RotationBean> rotations = new ArrayList<RotationBean>(); Date currentTime = new Date(Calendar.getInstance().getTimeInMillis()); final String loadCurrent = getSQL().getValue("rotation/load") + " AND rotation.Active = true AND people.Active = true " + " AND people.GUID = ? AND rotation.StartDate < ? AND rotation.EndDate > ?"; try { rotations = this.getJdbcTemplateReader().query(loadCurrent, new Object[] { personGUID, currentTime, currentTime }, new RowMapper() { public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException { return loadRotation(rs, loadDetails); } }); } catch (IncorrectResultSizeDataAccessException ie) { dataLogger.debug("No results found for search: " + ie.getMessage()); } return rotations; } /** * Calculates and updates the accreditation based on a Rotation's GUID value. * * @param rotationGUID the rotation guid * * @throws WhichDoctorDaoException the which doctor dao exception */ public final void recalculateAccreditationForRotation(final int rotationGUID) throws WhichDoctorDaoException { if (rotationGUID > 0) { try { RotationBean rotation = loadGUID(rotationGUID); if (rotation != null) { recalculateAccreditationForPerson(rotation.getPersonId()); } } catch (WhichDoctorDaoException wde) { throw new WhichDoctorDaoException(wde.getMessage()); } } } /** * Calculates and updates the accreditation for a person based on their GUID value. * * @param personGUID the person guid * * @throws WhichDoctorDaoException the which doctor dao exception */ public final void recalculateAccreditationForPerson(final int personGUID) throws WhichDoctorDaoException { if (personGUID == 0) { throw new WhichDoctorDaoException( "Cannot update accreditation " + "summary for person with GUID of zero"); } int total = 0; Collection<Integer> changeToDefault = new ArrayList<Integer>(); Collection<Integer> changeToExcess = new ArrayList<Integer>(); int defaultTrainingTypeId = 0; int excessTrainingTypeId = 0; try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type", "", "Standard training"); defaultTrainingTypeId = object.getObjectTypeId(); } catch (SFSDaoException sfe) { dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage()); } try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type", "", "Continuing training"); excessTrainingTypeId = object.getObjectTypeId(); } catch (SFSDaoException sfe) { dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage()); } Collection<String> accreditationTypes = this.membershipDAO.getTrainingTypes(); for (String type : accreditationTypes) { /* Delete the existing search index entry */ try { this.getSearchIndexDAO().delete(personGUID, type); } catch (Exception e) { dataLogger.error("Error removing search index (" + type + "): " + e.getMessage()); } int runningTotal = 0; boolean excessSet = false; int accreditationLimit = this.membershipDAO.getTrainingLimit(type); // Build a map to hold the accreditation summary Collection<HashMap<String, Integer>> accreditationSummary = buildAccreditationSummary(personGUID, type); // Holds the accreditation type count HashMap<Integer, Integer> accreditationTypeMap = new HashMap<Integer, Integer>(); // Holds specialty accreditation count HashMap<Integer, Integer> specialtyMap = new HashMap<Integer, Integer>(); // Holds the count of the accreditation and specialty. HashMap<String, Integer> accredSpecialtyMap = new HashMap<String, Integer>(); for (HashMap<String, Integer> summary : accreditationSummary) { final int trainingId = summary.get("TrainingId"); if (!excessSet) { final int value = summary.get("Accreditation"); final int accreditationTypeId = summary.get("AccreditationTypeId"); final int specialtyId = summary.get("SpecialtyId"); // Check if the value has changed for a valid accreditation/specialty if (value > 0 && accreditationTypeId > 0 && specialtyId > 0) { // Add accreditation value to running total runningTotal += value; // This is a continuing rotation, but it needs to be a default if (trainingId == CONTINUING_ROTATION) { changeToDefault.add(summary.get("GUID")); } if (accreditationTypeMap.containsKey(accreditationTypeId)) { Integer existingValue = accreditationTypeMap.get(accreditationTypeId); accreditationTypeMap.put(accreditationTypeId, existingValue + value); } else { accreditationTypeMap.put(accreditationTypeId, value); } if (specialtyMap.containsKey(specialtyId)) { Integer existingValue = specialtyMap.get(specialtyId); specialtyMap.put(specialtyId, existingValue + value); } else { specialtyMap.put(specialtyId, value); } final String key = String.valueOf(accreditationTypeId) + "_" + String.valueOf(specialtyId); if (accredSpecialtyMap.containsKey(specialtyId)) { Integer existingValue = accredSpecialtyMap.get(key); accredSpecialtyMap.put(key, existingValue + value); } else { accredSpecialtyMap.put(key, value); } if (accreditationLimit != 0 && runningTotal >= accreditationLimit) { excessSet = true; } } } else { // Accreditation is beyond limit, add rotation guid if a default if (trainingId == DEFAULT_ROTATION) { changeToExcess.add(summary.get("GUID")); } } } // Add running total to total accreditation total += runningTotal; // Enter running total into index try { this.getSearchIndexDAO().update(personGUID, type, 0, 0, runningTotal); } catch (Exception e) { dataLogger.error("Error updating " + type + " index: " + e.getMessage()); } // Cycle through each divisionId, submitting totals to index for (Integer accreditationTypeId : accreditationTypeMap.keySet()) { try { final Integer value = accreditationTypeMap.get(accreditationTypeId); this.getSearchIndexDAO().update(personGUID, type, accreditationTypeId, 0, value); } catch (Exception e) { dataLogger.error("Error updating " + type + " search index: " + e.getMessage()); } } // Cycle through each specialtyId, submitting totals to index for (Integer specialtyId : specialtyMap.keySet()) { try { final Integer value = specialtyMap.get(specialtyId); this.getSearchIndexDAO().update(personGUID, type, 0, specialtyId, value); } catch (Exception e) { dataLogger.error("Error updating " + type + " search index: " + e.getMessage()); } } // Cycle through each divisionId/specialtyId, submitting totals to index for (String key : accredSpecialtyMap.keySet()) { // Break up the accreditation/specialty id pair final String strAccreditationId = key.substring(0, key.indexOf("_")); final String strSpecialtyId = key.substring(key.indexOf("_") + 1); try { final Integer value = accredSpecialtyMap.get(key); this.getSearchIndexDAO().update(personGUID, type, Integer.valueOf(strAccreditationId), Integer.valueOf(strSpecialtyId), value); } catch (Exception e) { dataLogger.error("Error updating " + type + " search index: " + e.getMessage()); } } } for (Integer guid : changeToExcess) { updateExcessLevel(guid, excessTrainingTypeId); } for (Integer guid : changeToDefault) { updateExcessLevel(guid, defaultTrainingTypeId); } try { this.getSearchIndexDAO().update(personGUID, "Total Training", 0, 0, total); } catch (Exception e) { dataLogger.error("Error updating total training index: " + e.getMessage()); } } /** * Recalculate all of the rotation years. * * @throws WhichDoctorDaoException the which doctor dao exception */ public final void recalculateAllRotationYears() throws WhichDoctorDaoException { // Load all of the rotations Collection<RotationBean> rotations = new ArrayList<RotationBean>(); try { rotations = this.loadActiveRotations(); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error loading all rotations: " + wde.getMessage()); } if (rotations != null) { for (RotationBean rotation : rotations) { try { this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/updateYear"), new Object[] { getRotationYear(rotation.getStartDate(), rotation.getEndDate()), rotation.getGUID() }); } catch (DataAccessException de) { dataLogger.error("Error updating the year for the rotation guid: " + rotation.getGUID() + ", " + de.getMessage()); } } } } /** * Creates the RotationBean. * * @param rotation the rotation * @param checkUser the check user * @param privileges the privileges * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean create(final RotationBean rotation, final UserBean checkUser, final PrivilegesBean privileges) throws WhichDoctorDaoException { rotation.setActive(true); int rotationId = save(rotation, checkUser, privileges, "create"); RotationBean newRotation = null; if (rotationId > 0) { BuilderBean loadDetails = new BuilderBean(); loadDetails.setParameter("SUPERVISORS", true); newRotation = load(rotationId, loadDetails, true); if (newRotation != null) { // Create any reports Collection<ReportBean> autoReports = this.reportDAO .getReportsToCreate(newRotation.getRotationType()); for (ReportBean auto : autoReports) { ReportBean newReport = new ReportBean(); newReport.setReferenceGUID(newRotation.getGUID()); newReport.setReportType(auto.getReportType()); newReport.setReportStatus(auto.getReportStatus()); if (StringUtils.equals(auto.getReportGrouping(), "Supervisors")) { // Set the supervisors as the author if (newRotation.getSupervisors() != null) { for (SupervisorBean spvr : newRotation.getSupervisors()) { if (spvr.getPerson() != null) { newReport.addAuthor(spvr.getPerson()); } } } } else { // Set the trainee as the author newReport.addAuthor(newRotation.getPerson()); } try { this.reportDAO.create(newReport, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error creating report: " + wde.getMessage()); } } } } return newRotation; } /** * Modify the RotationBean. * * @param rotation the rotation * @param checkUser the check user * @param privileges the privileges * * @return the rotation bean * * @throws WhichDoctorDaoException the which doctor dao exception */ public final RotationBean modify(final RotationBean rotation, final UserBean checkUser, final PrivilegesBean privileges) throws WhichDoctorDaoException { rotation.setActive(true); int rotationId = save(rotation, checkUser, privileges, "modify"); return load(rotationId, new BuilderBean(), true); } /** * Delete the RotationBean. * * @param rotation the rotation * @param checkUser the check user * @param privileges the privileges * * @return true, if successful * * @throws WhichDoctorDaoException the which doctor dao exception */ public final boolean delete(final RotationBean rotation, final UserBean checkUser, final PrivilegesBean privileges) throws WhichDoctorDaoException { boolean success = false; if (privileges.getPrivilege(checkUser, "rotations", "delete")) { // Before deleting the rotation remove its child objects final BuilderBean loadDetails = new BuilderBean(); loadDetails.setParameter("LOAD_ALL", true); try { final RotationBean deleteObj = this.loadGUID(rotation.getGUID(), loadDetails); deleteAssociatedObjects(deleteObj, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error deleting children: " + wde.getMessage(), wde); throw new WhichDoctorDaoException("Error deleting children objects: " + wde.getMessage()); } } rotation.setActive(false); int rotationId = save(rotation, checkUser, privileges, "delete"); if (rotationId > 0) { success = true; } return success; } /** * Rebuild the workplace index for all rotations. * * @param user the user * @param privileges the privileges */ public final void rebuildWorkplaceReferences(final UserBean user, final PrivilegesBean privileges) { // Delete the existing linked workplace details as this process will recreate them try { // Delete the corresponding GUID entries for these workplace entries this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/deleteWorkplaceGUIDEntries"), new Object[] {}); // Delete item entries with a ReferenceGUID > 0 this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/deleteWorkplaceEntries"), new Object[] {}); } catch (DataAccessException dae) { dataLogger.error("Error removing existing rotation linked workplaces: " + dae.getMessage()); } SearchBean search = this.getSearchDAO().initiate("rotation", new UserBean()); search.setLimit(0); SearchResultsBean results = null; try { final BuilderBean loadDetails = new BuilderBean(); loadDetails.setParameter("SUPERVISORS", true); results = this.getSearchDAO().search(search, loadDetails); } catch (WhichDoctorSearchDaoException wse) { dataLogger.error("Error performing rotation search: " + wse.getMessage()); } if (results != null) { for (Object objRotation : results.getSearchResults()) { RotationBean rotation = (RotationBean) objRotation; try { this.updateWorkplace(rotation, new ArrayList<Integer>(), "modify", user, privileges); dataLogger.error("Refreshed workplace for rotation: " + rotation.getGUID()); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error refreshing workplace for rotation:" + rotation.getGUID() + ": " + wde.getMessage()); } } } } /** * Gets the rotation year. * * @param date the start date * @return the rotation year */ public final int getRotationYear(final java.util.Date date) { return this.getRotationYear(date, null); } /** * Gets the rotation year. * * @param startDate the start date * @param endDate the end date * @return the rotation year */ public final int getRotationYear(final java.util.Date startDate, final java.util.Date endDate) { int year = 0; if (startDate != null && endDate == null) { Calendar time = Calendar.getInstance(); time.setTime(startDate); year = time.get(Calendar.YEAR); } if (startDate == null && endDate != null) { Calendar time = Calendar.getInstance(); time.setTime(endDate); year = time.get(Calendar.YEAR); } if (startDate != null && endDate != null) { Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); start.setTime(startDate); end.setTime(endDate); year = start.get(Calendar.YEAR); String yearEndString = "31/12/" + String.valueOf(year); Calendar yearEnd = Calendar.getInstance(); yearEnd.setTime(DataFilter.parseDate(yearEndString, true)); double timeBefore = yearEnd.getTimeInMillis() - start.getTimeInMillis(); double duration = end.getTimeInMillis() - start.getTimeInMillis(); if ((timeBefore / duration) <= 0.33 && start.get(Calendar.MONTH) > 9) { // If more than 33% of the rotation occurred in the following year // and the start month is after September, add one to the year. year++; } } return year; } /** * Save the RotationBean. * * @param rotation the rotation * @param checkUser the check user * @param privileges the privileges * @param action the action * * @return the int * * @throws WhichDoctorDaoException the which doctor dao exception */ private int save(final RotationBean rotation, final UserBean checkUser, final PrivilegesBean privileges, final String action) throws WhichDoctorDaoException { /* Create rotation requires all the essential rotation information */ if (StringUtils.isBlank(rotation.getDescription())) { throw new NullPointerException("Rotation description field cannot be an empty string"); } if (StringUtils.isBlank(rotation.getRotationType())) { throw new WhichDoctorDaoException("Rotation type field cannot be an empty string"); } if (rotation.getStartDate() == null) { throw new WhichDoctorDaoException("Rotation requires a start date"); } if (rotation.getEndDate() == null) { throw new WhichDoctorDaoException("Rotation requires an end date"); } if (rotation.getPersonId() == 0) { throw new WhichDoctorDaoException("Rotation requires a valid person GUID"); } if (!privileges.getPrivilege(checkUser, "rotations", action)) { throw new WhichDoctorDaoException("Insufficient user credentials to " + action + " rotation"); } int rotationTypeId = 0; int trainingTypeId = 0; int organisation1TypeId = 0; int organisation2TypeId = 0; if (StringUtils.isNotBlank(rotation.getOrganisation1Type())) { try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Site Type", "", rotation.getOrganisation1Type()); organisation1TypeId = object.getObjectTypeId(); } catch (SFSDaoException sfe) { dataLogger.error("Error loading objecttype for the rotation site type: " + sfe.getMessage()); } } if (StringUtils.isNotBlank(rotation.getTrainingClass())) { try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type", rotation.getTrainingType(), rotation.getTrainingClass()); trainingTypeId = object.getObjectTypeId(); } catch (SFSDaoException sfe) { dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage()); } } try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Type", "", rotation.getRotationType()); rotationTypeId = object.getObjectTypeId(); } catch (Exception e) { dataLogger.error("Error loading objecttype for rotation type: " + e.getMessage()); throw new WhichDoctorDaoException("Rotation requires a valid type"); } if (StringUtils.isNotBlank(rotation.getOrganisation2Type())) { try { ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Site Type", "", rotation.getOrganisation2Type()); organisation2TypeId = object.getObjectTypeId(); } catch (SFSDaoException sfe) { dataLogger.error("Error loading objecttype for the rotation site type: " + sfe.getMessage()); } } /* Load the current rotation to get the existing organisations */ Collection<Integer> existingOrganisations = new ArrayList<Integer>(); if (rotation.getGUID() > 0) { try { RotationBean existing = this.loadGUID(rotation.getGUID()); if (existing.getOrganisation1Id() > 0) { existingOrganisations.add(existing.getOrganisation1Id()); } if (existing.getOrganisation2Id() > 0) { existingOrganisations.add(existing.getOrganisation2Id()); } } catch (WhichDoctorDaoException wde) { dataLogger.error("Error loading existing rotation: " + wde.getMessage()); } } int rotationId = 0; Timestamp sqlTimeStamp = new Timestamp(Calendar.getInstance().getTimeInMillis()); Date startDate = new Date(Calendar.getInstance().getTimeInMillis()); if (rotation.getStartDate() != null) { startDate = new Date(rotation.getStartDate().getTime()); } Date endDate = new Date(Calendar.getInstance().getTimeInMillis()); if (rotation.getEndDate() != null) { endDate = new Date(rotation.getEndDate().getTime()); } String organisation1Name = ""; String organisation2Name = ""; if (rotation.getOrganisation1() == null) { organisation1Name = rotation.getOrganisation1Name(); } if (rotation.getOrganisation2() == null) { organisation2Name = rotation.getOrganisation2Name(); } ArrayList<Object> parameters = new ArrayList<Object>(); parameters.add(rotation.getDescription()); parameters.add(rotationTypeId); parameters.add(trainingTypeId); parameters.add(startDate); parameters.add(endDate); parameters.add(getRotationYear(rotation.getStartDate(), rotation.getEndDate())); parameters.add(rotation.getOrganisation1Id()); parameters.add(rotation.getOrganisation2Id()); parameters.add(organisation1TypeId); parameters.add(organisation2TypeId); parameters.add(organisation1Name); parameters.add(organisation2Name); parameters.add(rotation.getPersonId()); parameters.add(rotation.getLeaveDays()); parameters.add(rotation.getTrainingTime()); parameters.add(rotation.getCommitteeName()); parameters.add(rotation.getActive()); parameters.add(sqlTimeStamp); parameters.add(checkUser.getDN()); parameters.add(rotation.getLogMessage(action)); try { Integer[] result = this.performUpdate("rotation", rotation.getGUID(), parameters, "Rotation", checkUser, action); /* Set the returned guid and id values */ rotation.setGUID(result[0]); rotationId = result[1]; } catch (Exception e) { dataLogger.error("Error processing rotation record: " + e.getMessage()); throw new WhichDoctorDaoException("Error processing rotation record: " + e.getMessage()); } if (rotationId > 0) { dataLogger.info(checkUser.getDN() + " created rotationId: " + String.valueOf(rotationId)); postProcessRotationChange(action, checkUser, privileges, rotation, existingOrganisations); } return rotationId; } /** * Delete the objects associated with the supplied RotationBean. * * @param deleteObjects the delete objects * @param checkUser the check user * @param privileges the privileges */ private void deleteAssociatedObjects(final RotationBean deleteObjects, final UserBean checkUser, final PrivilegesBean privileges) { if (deleteObjects.getAccreditation() != null) { for (AccreditationBean accreditation : deleteObjects.getAccreditation()) { try { accreditation.setLogMessage(accreditation.getLogMessage("delete")); this.accreditationDAO.delete(accreditation, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error deleting accreditation: " + wde.getMessage()); } } } if (deleteObjects.getSupervisors() != null) { for (SupervisorBean supervisor : deleteObjects.getSupervisors()) { try { supervisor.setLogMessage(supervisor.getLogMessage("delete")); this.supervisorDAO.delete(supervisor, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error deleting supervisor: " + wde.getMessage()); } } } if (deleteObjects.getReports() != null) { for (ReportBean report : deleteObjects.getReports()) { try { report.setLogMessage(report.getLogMessage("delete")); this.reportDAO.delete(report, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error deleting report: " + wde.getMessage()); } } } if (deleteObjects.getAssessment() != null) { for (AssessmentBean assessment : deleteObjects.getAssessment()) { try { assessment.setLogMessage(assessment.getLogMessage("delete")); this.assessmentDAO.delete(assessment, checkUser, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error deleting assessment: " + wde.getMessage()); } } } deleteMemos(deleteObjects, checkUser, privileges); deleteGroups(deleteObjects, checkUser, privileges); } /** * Update the workplace. * * @param rotation the rotation * @param existingOrganisationGUIDs the existing organisation gui ds * @param parentAction the parent action * @param checkUser the check user * @param privileges the privileges * * @throws WhichDoctorDaoException the which doctor dao exception */ private void updateWorkplace(final RotationBean rotation, final Collection<Integer> existingOrganisationGUIDs, final String parentAction, final UserBean checkUser, final PrivilegesBean privileges) throws WhichDoctorDaoException { ItemBean workplace = null; final int defaultWeighting = 10; Collection<Integer> newOrganisationGUIDs = new ArrayList<Integer>(); if (rotation.getOrganisation1Id() > 0) { newOrganisationGUIDs.add(rotation.getOrganisation1Id()); } if (rotation.getOrganisation2Id() > 0) { newOrganisationGUIDs.add(rotation.getOrganisation2Id()); } /* Determine what workplaces need creating/modifying/deleting */ HashMap<Integer, String> organisations = new HashMap<Integer, String>(); for (Integer organisationGUID : existingOrganisationGUIDs) { organisations.put(organisationGUID, "delete"); } if (!StringUtils.equals(parentAction, "delete")) { // If the rotation is not being deleted add the new workplaces for (Integer organisationGUID : newOrganisationGUIDs) { if (organisations.containsKey(organisationGUID)) { organisations.put(organisationGUID, "modify"); } else { organisations.put(organisationGUID, "create"); } } } for (Integer organisationGUID : organisations.keySet()) { final String action = organisations.get(organisationGUID); if (!StringUtils.equals(action, "create")) { // Load the workplace object workplace = this.getItemDAO().loadReference(rotation.getGUID(), organisationGUID, "Employer"); } if (workplace == null && !StringUtils.equals(action, "delete")) { workplace = new ItemBean(); } if (workplace != null) { workplace.setTitle(rotation.getDescription()); workplace.setObject1GUID(organisationGUID); workplace.setObject2GUID(rotation.getPersonId()); workplace.setReferenceGUID(rotation.getGUID()); workplace.setStartDate(rotation.getStartDate()); workplace.setEndDate(rotation.getEndDate()); workplace.setWeighting(defaultWeighting); StringBuffer info = new StringBuffer(); if (rotation.getSupervisors() != null && rotation.getSupervisors().size() > 0) { int i = 1; for (SupervisorBean supervisor : rotation.getSupervisors()) { if (supervisor != null && supervisor.getPerson() != null) { if (info.length() > 0) { if (i == rotation.getSupervisors().size()) { info.append(" and "); } else { info.append(", "); } } info.append(OutputFormatter.toCasualName(supervisor.getPerson())); i++; } } if (info.length() > 0) { info.insert(0, "Supervised by "); info.append("\n"); } } info.append(rotation.getTotalDays()); info.append(" approximate days training ("); info.append(Formatter.toPercent(rotation.getTrainingTime(), 0, "%")); info.append(" time"); if (rotation.getLeaveDays() > 0) { info.append(", "); info.append(rotation.getLeaveDays()); info.append(" days on leave"); } info.append(")"); workplace.setComment(info.toString()); workplace.setItemType("Employer"); updateWorkplace(workplace, action, checkUser, privileges); } } } /** * Update workplace. * * @param workplace the workplace * @param action the action * @param checkUser the check user * @param privileges the privileges * * @throws WhichDoctorDaoException the which doctor dao exception */ private void updateWorkplace(final ItemBean workplace, final String action, final UserBean checkUser, final PrivilegesBean privileges) throws WhichDoctorDaoException { if (StringUtils.equals(action, "delete")) { // Deleting the rotation so remove the workplace entry workplace.setLogMessage("Workplace linked to rotation " + "automatically deleted"); this.getItemDAO().delete(workplace, checkUser, privileges, null); } else { if (workplace.getGUID() > 0) { // The workplace has a GUID, modify workplace.setLogMessage("Workplace linked to rotation " + "automatically modified"); this.getItemDAO().modify(workplace, checkUser, privileges, null); } else { // The workplace lacks a GUID so create an entry workplace.setLogMessage("Workplace linked to rotation " + "automatically created"); this.getItemDAO().create(workplace, checkUser, privileges, null); } } } /** * Update excess level. * * @param guid the guid * @param trainingTypeId the training type id */ private void updateExcessLevel(final int guid, final int trainingTypeId) { try { this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/updateRotationExcess"), new Object[] { trainingTypeId, guid }); } catch (DataAccessException de) { dataLogger.error("Error updating excess flag of rotation guid: " + guid + ", " + de.getMessage()); } } /** * Post process rotation change. * * @param action the action * @param checkUser the check user * @param privileges the privileges * @param rotation the rotation * @param existingOrganisations the existing organisations * * @throws WhichDoctorDaoException the which doctor dao exception */ private void postProcessRotationChange(final String action, final UserBean checkUser, final PrivilegesBean privileges, final RotationBean rotation, final Collection<Integer> existingOrganisations) throws WhichDoctorDaoException { UserBean user = this.getSystemUser("Rotation", "Change"); // Clone the user and give them super privileges to perform any changes. try { user = (UserBean) BeanUtils.cloneBean(checkUser); user.setOverridePrivileges(true); } catch (Exception e) { dataLogger.error("Cannot clone user: " + e.getMessage()); } /* update the supervisor details */ try { this.supervisorDAO.update(rotation.getGUID(), action, rotation.getSupervisors(), rotation.getPersonId(), user, privileges); } catch (Exception e) { dataLogger.error("Error updating supervisor details: " + e.getMessage()); } /* Update the accreditation excess levels */ try { this.recalculateAccreditationForPerson(rotation.getPersonId()); } catch (Exception e) { dataLogger.error("Error updating excess accreditation levels " + "for person GUID " + rotation.getPersonId() + ": " + e.getMessage()); } /* Update the work place details */ try { updateWorkplace(rotation, existingOrganisations, action, user, privileges); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error updating rotation workplace: " + wde.getMessage()); } /* Update the relationships for the supplied person GUID */ try { this.relationshipDAO.rebuildRelationships(rotation.getPersonId(), "Person"); } catch (Exception e) { dataLogger.error("Error rebuilding relationships: " + e.getMessage()); } /* Check whether the online tools relationships need to be updated */ this.onlineToolDAO.rebuildRotationRelationships(rotation.getPersonId(), user, privileges); /* Check whether the training status needs to be updated */ this.membershipDAO.updateTrainingStatus(rotation.getPersonId(), user, privileges); } /** * Load the RotationBean data. * * @param rs the result set * @param loadDetails the load details * * @return the rotation bean * * @throws SQLException the SQL exception */ private RotationBean loadRotation(final ResultSet rs, final BuilderBean loadDetails) throws SQLException { RotationBean rotation = new RotationBean(); rotation.setId(rs.getInt("RotationId")); rotation.setGUID(rs.getInt("GUID")); rotation.setDescription(rs.getString("Description")); rotation.setRotationType(rs.getString("Type")); rotation.setRotationTypeAbbreviation(rs.getString("TypeAbbreviation")); rotation.setTrainingClass(rs.getString("TrainingClass")); rotation.setTrainingType(rs.getString("TrainingType")); rotation.setTrainingMapping(rs.getString("TrainingMapping")); rotation.setOrganisation1Name(rs.getString("OtherOrganisation1Name")); rotation.setOrganisation2Name(rs.getString("OtherOrganisation2Name")); rotation.setOrganisation1Type(rs.getString("Organisation1Type")); rotation.setOrganisation1TypeMapping(rs.getString("Organisation1TypeMapping")); rotation.setOrganisation2Type(rs.getString("Organisation2Type")); rotation.setOrganisation2TypeMapping(rs.getString("Organisation2TypeMapping")); rotation.setYear(rs.getInt("RotationYear")); try { rotation.setStartDate(rs.getDate("StartDate")); } catch (SQLException sqe) { dataLogger.debug("Error loading StartDate: " + sqe.getMessage()); } try { rotation.setEndDate(rs.getDate("EndDate")); } catch (SQLException sqe) { dataLogger.debug("Error loading StartDate: " + sqe.getMessage()); } rotation.setLeaveDays(rs.getInt("LeaveDays")); rotation.setTrainingTime(rs.getDouble("TrainingTime")); rotation.setCommitteeName(rs.getString("CommitteeName")); // Load the supervisors for this rotation try { rotation.setSupervisors(loadSupervisors(rotation.getGUID(), loadDetails)); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error loading supervisors: " + wde.getMessage()); } rotation.setPersonId(rs.getInt("PersonId")); if (rotation.getPersonId() > 0) { rotation.setPerson(loadPerson(rotation.getPersonId(), loadDetails, rs)); } rotation.setOrganisation1Id(rs.getInt("Organisation1Id")); if (rotation.getOrganisation1Id() > 0) { OrganisationBean organisation = new OrganisationBean(); organisation.setId(rotation.getOrganisation1Id()); organisation.setName(rs.getString("Organisation1Name")); organisation.setGUID(rs.getInt("Organisation1GUID")); rotation.setOrganisation1(organisation); } rotation.setOrganisation2Id(rs.getInt("Organisation2Id")); if (rotation.getOrganisation2Id() > 0) { OrganisationBean organisation = new OrganisationBean(); organisation.setId(rotation.getOrganisation2Id()); organisation.setName(rs.getString("Organisation2Name")); organisation.setGUID(rs.getInt("Organisation2GUID")); rotation.setOrganisation2(organisation); } try { rotation.setReports(reportDAO.load(rotation.getGUID(), loadDetails.getBoolean("REPORTS_FULL"))); } catch (WhichDoctorDaoException wde) { dataLogger.error("Error loading reports: " + wde.getMessage()); } if (loadDetails.getBoolean("ASSESSMENTS")) { try { rotation.setAssessment(this.assessmentDAO.load(rotation.getGUID())); } catch (Exception e) { dataLogger.error("Error loading assessment (" + rotation.getGUID() + "): " + e.getMessage()); } } rotation.setActive(rs.getBoolean("Active")); if (loadDetails.getBoolean("HISTORY")) { try { rotation.setCreatedDate(rs.getTimestamp("CreatedDate")); } catch (SQLException sqe) { dataLogger.debug("Error reading CreatedDate: " + sqe.getMessage()); } rotation.setCreatedBy(rs.getString("CreatedBy")); try { rotation.setModifiedDate(rs.getTimestamp("ModifiedDate")); } catch (SQLException sqe) { dataLogger.debug("Error reading ModifiedDate: " + sqe.getMessage()); } rotation.setModifiedBy(rs.getString("ModifiedBy")); try { rotation.setExportedDate(rs.getTimestamp("ExportedDate")); } catch (SQLException sqe) { dataLogger.debug("Error reading ExportedDate: " + sqe.getMessage()); } rotation.setExportedBy(rs.getString("ExportedBy")); } if (loadDetails.getBoolean("ACCREDITATIONS")) { try { rotation.setAccreditation(this.accreditationDAO.load(rotation.getGUID(), loadDetails.getBoolean("ACCREDITATION_FULL"))); } catch (Exception e) { dataLogger.error( "Error loading accreditation details (" + rotation.getGUID() + "): " + e.getMessage()); } } if (loadDetails.getBoolean("ONLINETOOLS")) { try { rotation.setOnlineTools(this.onlineToolDAO.loadRotation(rotation.getGUID())); } catch (Exception e) { dataLogger.error("Error loading online tools for rotation: " + e.getMessage()); } } if (loadDetails.getBoolean("TAGS")) { try { rotation.setTags(this.getTagDAO().load(rotation.getGUID(), loadDetails.getString("USERDN"), true)); } catch (Exception e) { dataLogger.error("Error loading tags for rotation: " + e.getMessage()); } } if (loadDetails.getBoolean("MEMO")) { try { rotation.setMemo(this.getMemoDAO().load(rotation.getGUID(), loadDetails.getBoolean("MEMO_FULL"))); } catch (Exception e) { dataLogger.error("Error loading memos for rotation: " + e.getMessage()); } } if (loadDetails.getBoolean("GROUPS")) { rotation.setGroups(loadGroups(rotation.getGUID())); } if (loadDetails.getBoolean("CREATED")) { UserBean user = new UserBean(); user.setDN(rs.getString("CreatedBy")); user.setPreferredName(rs.getString("CreatedFirstName")); user.setLastName(rs.getString("CreatedLastName")); rotation.setCreatedUser(user); } if (loadDetails.getBoolean("MODIFIED")) { UserBean user = new UserBean(); user.setDN(rs.getString("ModifiedBy")); user.setPreferredName(rs.getString("ModifiedFirstName")); user.setLastName(rs.getString("ModifiedLastName")); rotation.setModifiedUser(user); } if (loadDetails.getBoolean("EXPORTED")) { UserBean user = new UserBean(); user.setDN(rs.getString("ExportedBy")); user.setPreferredName(rs.getString("ExportedFirstName")); user.setLastName(rs.getString("ExportedLastName")); rotation.setExportedUser(user); } return rotation; } /** * Gets the person. * * @param personGUID the person guid * @param loadDetails the load details * @param rs the rs * * @return the person * * @throws SQLException the SQL exception */ private PersonBean loadPerson(final int personGUID, final BuilderBean loadDetails, final ResultSet rs) throws SQLException { PersonBean person = null; if (loadDetails.getBoolean("LOAD_MEMBER")) { try { BuilderBean personDetails = new BuilderBean(); personDetails.setParameter("MEMBERSHIP", true); personDetails.setParameter("MEMBERSHIP_FULL", true); personDetails.setParameter("EMAIL", true); personDetails.setParameter("ADDRESS", true); personDetails.setParameter("ADDRESS_CLASS", loadDetails.getString("ADDRESS_CLASS")); personDetails.setParameter("ADDRESS_TYPE", loadDetails.getString("ADDRESS_TYPE")); personDetails.setParameter("SPECIALTY", true); personDetails.setParameter("TRAINING_ADVANCED", true); personDetails.setParameter("TRAINING_POSTFRACP", true); personDetails.setParameter("TRAINING_BASIC", true); person = this.personDAO.loadGUID(personGUID, personDetails); } catch (Exception e) { dataLogger.error("ERROR loading rotation person: " + e.getMessage()); } } else { person = new PersonBean(); person.setId(rs.getInt("pPersonId")); person.setPersonIdentifier(rs.getInt("PersonIdentifier")); person.setPreferredName(rs.getString("PreferredName")); person.setFirstName(rs.getString("FirstName")); person.setLastName(rs.getString("LastName")); person.setGUID(rs.getInt("PersonGUID")); person.setTitle(rs.getString("Title")); person.setGender(rs.getString("Gender")); if (loadDetails.getBoolean("ADDRESS")) { try { person.setAddress(this.getAddressDAO().load(person.getGUID(), false, loadDetails.getString("ADDRESS_CLASS"), loadDetails.getString("ADDRESS_TYPE"))); } catch (Exception e) { dataLogger.error("Error loading address for credit: " + e.getMessage()); } } } return person; } /** * Load supervisors. * * @param rotationGUID the rotation guid * @param loadDetails the load details * * @return the collection< supervisor bean> * * @throws WhichDoctorDaoException the which doctor dao exception */ private Collection<SupervisorBean> loadSupervisors(final int rotationGUID, final BuilderBean loadDetails) throws WhichDoctorDaoException { BuilderBean supervisorDetails = new BuilderBean(); supervisorDetails.setParameter("SUPERVISOR_PERSONOBJ", loadDetails.getBoolean("SUPERVISORS")); supervisorDetails.setParameter("EMAIL", loadDetails.getBoolean("SUPERVISORS_EMAIL")); Collection<SupervisorBean> supervisors = this.supervisorDAO.load(rotationGUID, supervisorDetails); return supervisors; } /** * Load groups. * * @param guid the guid * * @return the collection< group bean> */ private Collection<GroupBean> loadGroups(final int guid) { /* Create new SearchBean of type Rotation and default values */ SearchResultsBean results = new SearchResultsBean(); SearchBean groupSearch = this.getSearchDAO().initiate("group", null); groupSearch.setLimit(0); GroupBean searchCriteria = (GroupBean) groupSearch.getSearchCriteria(); searchCriteria.setObjectType("Rotations"); ItemBean item = new ItemBean(); item.setObject2GUID(guid); TreeMap<String, ItemBean> items = new TreeMap<String, ItemBean>(); items.put("Rotation", item); searchCriteria.setItems(items); groupSearch.setSearchCriteria(searchCriteria); try { BuilderBean loadGroup = new BuilderBean(); loadGroup.setParameter("ITEMS", true); loadGroup.setParameter("REFERENCEID", String.valueOf(guid)); results = this.getSearchDAO().search(groupSearch, loadGroup); } catch (Exception e) { dataLogger.error("Error loading groups for rotation: " + e.getMessage()); } ArrayList<GroupBean> groups = new ArrayList<GroupBean>(); for (Object group : results.getSearchResults()) { groups.add((GroupBean) group); } return groups; } /** * Builds the accreditation summary. * * @param personGUID the person guid * @param type the type * @return the collection */ @SuppressWarnings("unchecked") private Collection<HashMap<String, Integer>> buildAccreditationSummary(final int personGUID, final String type) { // Build a map to hold the accreditation summary Collection<HashMap<String, Integer>> accreditationSummary = new ArrayList<HashMap<String, Integer>>(); try { accreditationSummary = this.getJdbcTemplateWriter().query( this.getSQL().getValue("rotation/accreditationSummary"), new Object[] { personGUID, type }, new RowMapper() { public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException { HashMap<String, Integer> summary = new HashMap<String, Integer>(); summary.put("Accreditation", rs.getInt("Accreditation")); summary.put("GUID", rs.getInt("GUID")); summary.put("AccreditationTypeId", rs.getInt("AccreditationTypeId")); summary.put("SpecialtyId", rs.getInt("SpecialtyId")); int trainingId = DEFAULT_ROTATION; String type = rs.getString("TrainingClass"); if (StringUtils.contains(type, "ontinuing")) { trainingId = CONTINUING_ROTATION; } if (StringUtils.contains(type, "nterrupt")) { trainingId = INTERRUPTED_ROTATION; } summary.put("TrainingId", trainingId); return summary; } }); } catch (IncorrectResultSizeDataAccessException ie) { dataLogger.debug("No results found for this search: " + ie.getMessage()); } return accreditationSummary; } }