package edu.ualberta.med.biobank.common.wrappers; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import edu.ualberta.med.biobank.common.exception.BiobankCheckException; import edu.ualberta.med.biobank.common.exception.BiobankException; import edu.ualberta.med.biobank.common.exception.BiobankQueryResultSizeException; import edu.ualberta.med.biobank.common.peer.CenterPeer; import edu.ualberta.med.biobank.common.peer.CollectionEventPeer; import edu.ualberta.med.biobank.common.peer.PatientPeer; import edu.ualberta.med.biobank.common.peer.ProcessingEventPeer; import edu.ualberta.med.biobank.common.peer.SpecimenPeer; import edu.ualberta.med.biobank.common.wrappers.WrapperTransaction.TaskList; import edu.ualberta.med.biobank.common.wrappers.base.PatientBaseWrapper; import edu.ualberta.med.biobank.common.wrappers.checks.CollectionIsEmptyCheck; import edu.ualberta.med.biobank.common.wrappers.checks.NotUsedCheck; import edu.ualberta.med.biobank.common.wrappers.loggers.PatientLogProvider; import edu.ualberta.med.biobank.model.CollectionEvent; import edu.ualberta.med.biobank.model.Patient; import edu.ualberta.med.biobank.model.ProcessingEvent; import edu.ualberta.med.biobank.model.Specimen; import edu.ualberta.med.biobank.server.applicationservice.BiobankApplicationService; import gov.nih.nci.system.applicationservice.ApplicationException; import gov.nih.nci.system.applicationservice.WritableApplicationService; import gov.nih.nci.system.query.hibernate.HQLCriteria; public class PatientWrapper extends PatientBaseWrapper { private static final PatientLogProvider LOG_PROVIDER = new PatientLogProvider(); private static final String HAS_SPECIMENS_MSG = Messages .getString("PatientWrapper.has.specimens.msg"); //$NON-NLS-1$ private static final String HAS_COLLECTION_EVENTS_MSG = Messages .getString("PatientWrapper.has.collection.event.msg"); //$NON-NLS-1$ public PatientWrapper(WritableApplicationService appService, Patient patient) { super(appService, patient); } public PatientWrapper(WritableApplicationService appService) { super(appService); } @Override protected Patient getNewObject() throws Exception { Patient newObject = super.getNewObject(); Calendar createdAt = Calendar.getInstance(); createdAt.setTime(new Date()); createdAt.set(Calendar.SECOND, 0); newObject.setCreatedAt(createdAt.getTime()); return newObject; } private static final String PATIENT_QRY = "from " + Patient.class.getName() //$NON-NLS-1$ + " where " + PatientPeer.PNUMBER.getName() + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ /** * Search a patient in the site with the given number */ public static PatientWrapper getPatient( WritableApplicationService appService, String patientNumber) throws ApplicationException { HQLCriteria criteria = new HQLCriteria(PATIENT_QRY, Arrays.asList(new Object[] { patientNumber })); List<Patient> patients = appService.query(criteria); if (patients.size() == 1) { return new PatientWrapper(appService, patients.get(0)); } return null; } /** * Search a patient in the site with the given number. Will return the * patient only if the current user has read access on a site that works * with this patient study * * @throws Exception */ public static PatientWrapper getPatient( WritableApplicationService appService, String patientNumber, UserWrapper user) throws Exception { PatientWrapper patient = getPatient(appService, patientNumber); if (patient != null) { StudyWrapper study = patient.getStudy(); List<CenterWrapper<?>> centers = new ArrayList<CenterWrapper<?>>( study.getSiteCollection(false)); centers.addAll(study.getClinicCollection()); if (Collections.disjoint(centers, user.getWorkingCenters())) { throw new ApplicationException(MessageFormat.format( Messages.getString("PatientWrapper.patient.access.msg"), //$NON-NLS-1$ patientNumber)); } } return patient; } private static final String SOURCE_SPECIMEN_COUNT_QRY = "select count(spcs) from " //$NON-NLS-1$ + CollectionEvent.class.getName() + " as cevent join cevent." //$NON-NLS-1$ + CollectionEventPeer.ORIGINAL_SPECIMENS.getName() + " as spcs where cevent." //$NON-NLS-1$ + Property.concatNames(CollectionEventPeer.PATIENT, PatientPeer.ID) + "=?"; //$NON-NLS-1$ public long getSourceSpecimenCount(boolean fast) throws ApplicationException, BiobankException { if (fast) { HQLCriteria criteria = new HQLCriteria(SOURCE_SPECIMEN_COUNT_QRY, Arrays.asList(new Object[] { getId() })); return getCountResult(appService, criteria); } long total = 0; for (CollectionEventWrapper cevent : getCollectionEventCollection(false)) total += cevent.getSourceSpecimensCount(false); return total; } private static final String ALIQUOTED_SPECIMEN_COUNT_QRY = "select count(spcs) from " //$NON-NLS-1$ + CollectionEvent.class.getName() + " as cevent join cevent." //$NON-NLS-1$ + CollectionEventPeer.ALL_SPECIMENS.getName() + " as spcs where cevent." //$NON-NLS-1$ + Property.concatNames(CollectionEventPeer.PATIENT, PatientPeer.ID) + "=? and spcs." //$NON-NLS-1$ + SpecimenPeer.PARENT_SPECIMEN.getName() + " is not null"; //$NON-NLS-1$ public long getAliquotedSpecimenCount(boolean fast) throws ApplicationException, BiobankException { if (fast) { HQLCriteria criteria = new HQLCriteria( ALIQUOTED_SPECIMEN_COUNT_QRY, Arrays.asList(new Object[] { getId() })); return getCountResult(appService, criteria); } long total = 0; for (CollectionEventWrapper cevent : getCollectionEventCollection(false)) total += cevent.getAliquotedSpecimensCount(false); return total; } @Override public int compareTo(ModelWrapper<Patient> wrapper) { if (wrapper instanceof PatientWrapper) { String number1 = getPnumber(); String number2 = wrapper.wrappedObject.getPnumber(); return number1.compareTo(number2); } return 0; } @Override public String toString() { return getPnumber(); } private static final String LAST_7_DAYS_PROCESSING_EVENTS_FOR_CENTER_QRY = "select distinct(pEvent) from " //$NON-NLS-1$ + Patient.class.getName() + " as patient join patient." //$NON-NLS-1$ + PatientPeer.COLLECTION_EVENTS.getName() + " as ces join ces." //$NON-NLS-1$ + CollectionEventPeer.ALL_SPECIMENS.getName() + " as specimens join specimens." //$NON-NLS-1$ + SpecimenPeer.PROCESSING_EVENT.getName() + " as pEvent where patient." //$NON-NLS-1$ + PatientPeer.ID.getName() + "=? and pEvent." //$NON-NLS-1$ + Property.concatNames(ProcessingEventPeer.CENTER, CenterPeer.ID) + "=? and pEvent." //$NON-NLS-1$ + ProcessingEventPeer.CREATED_AT.getName() + ">? and pEvent." + ProcessingEventPeer.CREATED_AT.getName() + "<?"; //$NON-NLS-1$ //$NON-NLS-2$ // used in scan link and cabinet link public List<ProcessingEventWrapper> getLast7DaysProcessingEvents( CenterWrapper<?> center) throws ApplicationException { Calendar cal = Calendar.getInstance(); // today at midnight cal.add(Calendar.DATE, 1); cal.set(Calendar.AM_PM, Calendar.AM); cal.set(Calendar.HOUR, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); Date endDate = cal.getTime(); // 7 days ago, at midnight cal.add(Calendar.DATE, -8); Date startDate = cal.getTime(); HQLCriteria criteria = new HQLCriteria( LAST_7_DAYS_PROCESSING_EVENTS_FOR_CENTER_QRY, Arrays.asList(new Object[] { getId(), center.getId(), startDate, endDate })); List<ProcessingEvent> res = appService.query(criteria); return ModelWrapper.wrapModelCollection(appService, res, ProcessingEventWrapper.class); } @Override public PatientLogProvider getLogProvider() { return LOG_PROVIDER; } /** * merge patient2 into this patient */ @Deprecated public void merge(PatientWrapper patient2) throws Exception { reload(); patient2.reload(); if (getStudy().equals(patient2.getStudy())) { List<CollectionEventWrapper> cevents = patient2 .getCollectionEventCollection(false); if (!cevents.isEmpty()) { Set<CollectionEventWrapper> toAdd = new HashSet<CollectionEventWrapper>(); boolean merged = false; for (CollectionEventWrapper p2event : cevents) { for (CollectionEventWrapper p1event : getCollectionEventCollection(false)) if (p1event.getVisitNumber().equals( p2event.getVisitNumber())) { // merge collection event p1event.merge(p2event); merged = true; } if (!merged) toAdd.add(p2event); merged = false; } for (CollectionEventWrapper addMe : toAdd) { addMe.setPatient(this); addMe.persist(); } persist(); patient2.delete(); ((BiobankApplicationService) appService).logActivity("merge", //$NON-NLS-1$ null, patient2.getPnumber(), null, null, patient2.getPnumber() + " --> " + getPnumber(), "Patient"); //$NON-NLS-1$ //$NON-NLS-2$ ((BiobankApplicationService) appService).logActivity("merge", //$NON-NLS-1$ null, getPnumber(), null, null, getPnumber() + " <-- " //$NON-NLS-1$ + patient2.getPnumber(), "Patient"); //$NON-NLS-1$ } } else { throw new BiobankCheckException( Messages.getString("PatientWrapper.merge.patient.error.msg")); //$NON-NLS-1$ } } public List<CollectionEventWrapper> getCollectionEventCollection( boolean sort, final boolean ascending) { List<CollectionEventWrapper> cEvents = getCollectionEventCollection(false); if (sort) { Collections.sort(cEvents, new Comparator<CollectionEventWrapper>() { @Override public int compare(CollectionEventWrapper ce1, CollectionEventWrapper ce2) { if (ascending) { return ce1.compareTo(ce2); } return ce2.compareTo(ce1); } }); } return cEvents; } public List<ProcessingEventWrapper> getProcessingEventCollection( CenterWrapper<?> workingCenter, boolean originalOnly) { List<CollectionEventWrapper> ces = getCollectionEventCollection(false); Set<ProcessingEventWrapper> pes = new HashSet<ProcessingEventWrapper>(); for (CollectionEventWrapper ce : ces) if (originalOnly) addProcessingEvents(pes, ce.getOriginalSpecimenCollection(false), workingCenter); else addProcessingEvents(pes, ce.getAllSpecimenCollection(false), workingCenter); return new ArrayList<ProcessingEventWrapper>(pes); } private void addProcessingEvents(Set<ProcessingEventWrapper> pes, List<SpecimenWrapper> specimens, CenterWrapper<?> workingCenter) { for (SpecimenWrapper spec : specimens) { if (spec.getProcessingEvent() != null && spec.getProcessingEvent().getCenter().equals(workingCenter)) pes.add(spec.getProcessingEvent()); } } public Long getCollectionEventCount(boolean fast) throws BiobankQueryResultSizeException, ApplicationException { return getPropertyCount(PatientPeer.COLLECTION_EVENTS, fast); } @Deprecated @Override protected void addPersistTasks(TaskList tasks) { tasks.add(check().notNull(PatientPeer.PNUMBER)); tasks.add(check().unique(PatientPeer.PNUMBER)); super.addPersistTasks(tasks); } @Deprecated @Override protected void addDeleteTasks(TaskList tasks) { String hasCollectionEventsMsg = HAS_COLLECTION_EVENTS_MSG; tasks.add(new CollectionIsEmptyCheck<Patient>(this, PatientPeer.COLLECTION_EVENTS, hasCollectionEventsMsg)); String hasSpecimensMsg = MessageFormat.format(HAS_SPECIMENS_MSG, getPnumber()); tasks.add(new NotUsedCheck<Patient>(this, SpecimenPeer.COLLECTION_EVENT .to(CollectionEventPeer.PATIENT), Specimen.class, hasSpecimensMsg)); super.addDeleteTasks(tasks); } public static Integer getNextVisitNumber( WritableApplicationService appService, PatientWrapper patient) throws Exception { HQLCriteria c = new HQLCriteria("select max(ce.visitNumber) from " //$NON-NLS-1$ + CollectionEvent.class.getName() + " ce where ce.patient.id=?", //$NON-NLS-1$ Arrays.asList(patient.getId())); List<Object> result = appService.query(c); if (result == null || result.size() == 0 || result.get(0) == null) return 1; return (Integer) result.get(0) + 1; } /** * return true if the user can delete this object */ @Override public boolean canDelete(UserWrapper user, CenterWrapper<?> center, StudyWrapper study) { return super.canDelete(user, center, study) && (getStudy() == null || user.getCurrentWorkingCenter() == null || user .getCurrentWorkingCenter().getStudyCollection() .contains(getStudy())); } /** * return true if the user can edit this object */ @Override public boolean canUpdate(UserWrapper user, CenterWrapper<?> center, StudyWrapper study) { return super.canUpdate(user, center, study) && (getStudy() == null || user.getCurrentWorkingCenter() == null || user .getCurrentWorkingCenter().getStudyCollection() .contains(getStudy())); } }