Java tutorial
/******************************************************************************* * Copyright SemanticBits, Northwestern University and Akaza Research * * Distributed under the OSI-approved BSD 3-Clause License. * See http://ncip.github.com/caaers/LICENSE.txt for details. ******************************************************************************/ package gov.nih.nci.cabig.caaers.domain; import gov.nih.nci.cabig.caaers.domain.comparator.AdverseEventComprator; import gov.nih.nci.cabig.caaers.domain.report.Report; import gov.nih.nci.cabig.caaers.domain.workflow.ReportingPeriodReviewComment; import gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware; import gov.nih.nci.cabig.caaers.utils.DateUtils; import gov.nih.nci.cabig.caaers.utils.ObjectUtils; import gov.nih.nci.cabig.caaers.validation.CourseCycleGroup; import gov.nih.nci.cabig.caaers.validation.fields.validators.NotNullConstraint; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.hibernate.annotations.*; import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.Parameter; import javax.persistence.*; import javax.persistence.Entity; import javax.persistence.OrderBy; import javax.persistence.Table; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.*; /** * This class represents the Reporting Period associated to StudyParticipant Associations. * * @author Sameer Sawant * @author Biju Joseph */ @Entity @Table(name = "ae_reporting_periods") @GenericGenerator(name = "id-generator", strategy = "native", parameters = { @Parameter(name = "sequence", value = "seq_ae_reporting_periods_id") }) public class AdverseEventReportingPeriod extends AbstractMutableRetireableDomainObject implements WorkflowAware, Serializable { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -5343583772734352886L; /** The Constant BASELINE_REPORTING_TYPE. */ private static final String BASELINE_REPORTING_TYPE = "Baseline"; /** The description. */ private String description; /** The cycle number. */ private Integer cycleNumber; /** The workflow id. */ private Integer workflowId; /** The review status. */ private ReviewStatus reviewStatus; /** The treatment assignment. */ private TreatmentAssignment treatmentAssignment; /** The treatment assignment description. */ private String treatmentAssignmentDescription; /** The epoch. */ private Epoch epoch; /** The start date. */ private Date startDate; /** The end date. */ private Date endDate; /** The assignment. */ private StudyParticipantAssignment assignment; /** The adverse events. */ private List<AdverseEvent> adverseEvents; /** The ae reports. */ private List<ExpeditedAdverseEventReport> aeReports; /** The name. */ private String name; private String oldAeMapping; /** The baseline reporting type. */ private boolean baselineReportingType; // This holds the total number of reports within all the ExpeditedReport generated in this reporting period /** The number of reports. */ private int numberOfReports; // This gives the Data Entry Status for ths reporing Period /** The data entry status. */ private String dataEntryStatus; // This gives the Report Status for the reporting Period /** The report status. */ private String reportStatus; /** The review comments. */ private List<ReportingPeriodReviewComment> reviewComments; /** The active ae reports. */ private List<ExpeditedAdverseEventReport> activeAeReports; private String externalId; public String getExternalId() { return externalId; } public void setExternalId(String externalId) { this.externalId = externalId; } /** * Instantiates a new adverse event reporting period. */ public AdverseEventReportingPeriod() { } //LOGIC /** * Adds the adverse event. * * @param adverseEvent the adverse event */ public void addAdverseEvent(AdverseEvent adverseEvent) { getAdverseEvents().add(adverseEvent); adverseEvent.setReportingPeriod(this); } // BEAN PROPERTIES /** * Gets the participant. * * @return the participant */ @Transient public Participant getParticipant() { return getAssignment() == null ? null : getAssignment().getParticipant(); } /** * Gets the study. * * @return the study */ @Transient public Study getStudy() { StudySite ss = getStudySite(); return ss == null ? null : ss.getStudy(); } /** * Gets the StudySite. * * @return the study site */ @Transient public StudySite getStudySite() { StudySite ss = getAssignment() == null ? null : getAssignment().getStudySite(); return ss; } /** * Gets the summary. * * @return the summary */ @Transient public Map<String, String> getSummary() { Map<String, String> summary = new LinkedHashMap<String, String>(); summary.put("Participant", getParticipantSummaryLine()); summary.put("Study", getStudySummaryLine()); summary.put("Adverse event count", Integer.toString(getAdverseEvents().size())); return summary; } /** * Gets the participant summary line. * * @return the participant summary line */ @Transient public String getParticipantSummaryLine() { Participant participant = getParticipant(); if (participant == null) return null; StringBuilder sb = new StringBuilder(participant.getFullName()); appendPrimaryIdentifier(participant, sb); return sb.toString(); } /** * Gets the study summary line. * * @return the study summary line */ @Transient public String getStudySummaryLine() { Study study = getStudy(); if (study == null) return null; StringBuilder sb = new StringBuilder(study.getShortTitle()); appendPrimaryIdentifier(study, sb); return sb.toString(); } /** * Append primary identifier. * * @param ided the ided * @param sb the sb */ private void appendPrimaryIdentifier(IdentifiableByAssignedIdentifers ided, StringBuilder sb) { if (ided.getPrimaryIdentifier() != null) { sb.append(" (").append(ided.getPrimaryIdentifier().getValue()).append(')'); } } // This is annotated this way so that the IndexColumn will work with // the bidirectional mapping. See section 2.4.6.2.3 of the hibernate annotations docs. /** * Gets the adverse events. * * @return the adverse events */ @OneToMany(mappedBy = "reportingPeriod", orphanRemoval = true) @Cascade(value = { CascadeType.ALL }) @OrderBy @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT) public List<AdverseEvent> getAdverseEvents() { if (adverseEvents == null) adverseEvents = new ArrayList<AdverseEvent>(); return adverseEvents; } /** * Sets the adverse events. * * @param adverseEvents the new adverse events */ public void setAdverseEvents(final List<AdverseEvent> adverseEvents) { this.adverseEvents = adverseEvents; } /** * Gets the evaluated adverse events. * * @return the evaluated adverse events */ @Transient public List<AdverseEvent> getEvaluatedAdverseEvents() { List<AdverseEvent> evaluatedAdverseEvents = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : this.getAdverseEvents()) { if (ae.isRetired()) continue; if (ae.getGrade() != null && !(ae.getGrade().equals(Grade.NOT_EVALUATED))) evaluatedAdverseEvents.add(ae); } //sort the list Collections.sort(evaluatedAdverseEvents, AdverseEventComprator.DEFAULT_ADVERSE_EVENT_COMPARATOR); return evaluatedAdverseEvents; } /** * This method returnes all the adverse events whose attributes are populated with some values. The attributes of adverse events * that are checked for some values are the ones that take part in rules. These attributes are namely - grade, Hospitalization, * expected, participant at risk, attribution, outcome identifier. If the grade is null or normal or not evaluated then its considered * to be not populated. Also if hospitalization has value NONE then its considered to be not populated. * * @return the populated adverse events */ @Transient public List<AdverseEvent> getPopulatedAdverseEvents() { //Grade, Hospitalization (or prolonged hospitalization), expected, participant at increased risk, attribution, outcome identifier List<AdverseEvent> populatedAdverseEvents = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : getAdverseEvents()) { if (ae.isPopulated()) populatedAdverseEvents.add(ae); } Collections.sort(populatedAdverseEvents, AdverseEventComprator.DEFAULT_ADVERSE_EVENT_COMPARATOR); return populatedAdverseEvents; } /** * This method will return a a sorted list containing the evaluated adverse events + adverse events associated to data collection, that got modified. * * @return the reportable adverse events * @see AdverseEventComprator#compare(AdverseEvent, AdverseEvent) */ @Transient public List<AdverseEvent> getReportableAdverseEvents() { List<AdverseEvent> reportableAdverseEvents = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : getPopulatedAdverseEvents()) { if (ae.getAdverseEventTerm().getTerm() != null) reportableAdverseEvents.add(ae); } return reportableAdverseEvents; } /** * This method will return the adverse events that are graded, but not yet associated to any * expedited data collection. * * @return the non expedited adverse events */ @Transient public List<AdverseEvent> getNonExpeditedAdverseEvents() { List<AdverseEvent> unReportedAes = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : getPopulatedAdverseEvents()) { if (ae.getReport() == null /*&& ae.getAdverseEventTerm().getTerm() != null*/) unReportedAes.add(ae); } return unReportedAes; } /** * This method will return a list of adverse events in the reporting period that are not part of any data collection and who have same + * ctc term as the given AE * * @return list of duplicate adverse events */ public List<AdverseEvent> findDuplicateAesByAeCtcTerms(AdverseEvent ae) { List<AdverseEvent> dupAes = new ArrayList<AdverseEvent>(); if (ae.getAdverseEventCtcTerm() != null && ae.getAdverseEventCtcTerm().getCtcTerm() != null) { for (AdverseEvent advEvent : getAdverseEvents()) { // find out all adverse events which are not part of any data collection and which have same ctc term as the input adverse event if (advEvent.getReport() == null && advEvent.getAdverseEventCtcTerm() != null && advEvent.getAdverseEventCtcTerm().getCtcTerm() != null) { if (ae.getAdverseEventCtcTerm().getCtcTerm() .equals(advEvent.getAdverseEventCtcTerm().getCtcTerm()) && !ae.getId().equals(advEvent.getId())) { dupAes.add(advEvent); } } } } return dupAes; } /** * This method will return a a sorted list containing the newly added evaluated adverse events + adverse events associated to data collection, that got modified + * adverse events associated to data collection that are not reported. * * @return the modified reportable adverse events */ @Transient public List<AdverseEvent> getModifiedReportableAdverseEvents() { List<AdverseEvent> reportableAdverseEvents = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : getPopulatedAdverseEvents()) { if (ae.isModified() || BooleanUtils.isNotTrue(ae.getReported())) reportableAdverseEvents.add(ae); } return reportableAdverseEvents; } /** * This return the modified adverse events that are associated to an expedited data collection. * * @return the modified expedited adverse events */ @Transient public List<AdverseEvent> getModifiedExpeditedAdverseEvents() { List<AdverseEvent> modifiedAdverseEvents = new ArrayList<AdverseEvent>(); for (AdverseEvent ae : getPopulatedAdverseEvents()) { if (ae.getReport() != null && ae.isModified()) modifiedAdverseEvents.add(ae); } return modifiedAdverseEvents; } /** * Gets the assignment. * * @return the assignment */ @ManyToOne(fetch = FetchType.LAZY) @Cascade(value = { CascadeType.MERGE, CascadeType.LOCK }) public StudyParticipantAssignment getAssignment() { return assignment; } /** * Sets the assignment. * * @param assignment the new assignment */ public void setAssignment(StudyParticipantAssignment assignment) { this.assignment = assignment; } /** * Gets the end date. * * @return the end date */ @NotNullConstraint(groups = CourseCycleGroup.class, fieldPath = "reportingPeriod.endDate") public Date getEndDate() { return endDate; } /** * Sets the end date. * * @param endDate the new end date */ public void setEndDate(Date endDate) { this.endDate = endDate; } /** * Gets the start date. * * @return the start date */ @NotNullConstraint(groups = CourseCycleGroup.class, fieldPath = "reportingPeriod.startDate") public Date getStartDate() { return startDate; } /** * Sets the start date. * * @param startDate the new start date */ public void setStartDate(Date startDate) { this.startDate = startDate; } public String getOldAeMapping() { return oldAeMapping; } public void setOldAeMapping(String oldAeMapping) { this.oldAeMapping = oldAeMapping; } /** * Gets the treatment assignment. * * @return the treatment assignment */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "treatment_assignment_id") @Cascade({ CascadeType.LOCK }) public TreatmentAssignment getTreatmentAssignment() { return treatmentAssignment; } /** * Sets the treatment assignment. * * @param treatmentAssignment the new treatment assignment */ public void setTreatmentAssignment(TreatmentAssignment treatmentAssignment) { this.treatmentAssignment = treatmentAssignment; } /** * Gets the description. * * @return the description */ public String getDescription() { return description; } /** * Sets the description. * * @param description the new description */ public void setDescription(String description) { this.description = description; } /** * Gets the cycle number. * * @return the cycle number */ @NotNullConstraint(groups = CourseCycleGroup.class, fieldPath = "reportingPeriod.cycleNumber") public Integer getCycleNumber() { return cycleNumber; } /** * Sets the cycle number. * * @param cycleNumber the new cycle number */ public void setCycleNumber(Integer cycleNumber) { this.cycleNumber = cycleNumber; } /* (non-Javadoc) * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#getWorkflowId() */ public Integer getWorkflowId() { return workflowId; } /* (non-Javadoc) * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#setWorkflowId(java.lang.Integer) */ public void setWorkflowId(Integer workflowId) { this.workflowId = workflowId; } /* (non-Javadoc) * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#getReviewStatus() */ @Column(name = "review_status_code") @Type(type = "reviewStatus") public ReviewStatus getReviewStatus() { return reviewStatus; } /* (non-Javadoc) * @see gov.nih.nci.cabig.caaers.domain.workflow.WorkflowAware#setReviewStatus(gov.nih.nci.cabig.caaers.domain.ReviewStatus) */ public void setReviewStatus(ReviewStatus reviewStatus) { this.reviewStatus = reviewStatus; } /** * Gets the epoch. * * @return the epoch */ @NotNullConstraint(groups = CourseCycleGroup.class, fieldPath = "reportingPeriod.epoch") @ManyToOne(fetch = FetchType.LAZY) public Epoch getEpoch() { return epoch; } /** * Sets the epoch. * * @param epoch the new epoch */ public void setEpoch(Epoch epoch) { this.epoch = epoch; } /** * Gets the ae reports. * * @return the ae reports */ @OneToMany(mappedBy = "reportingPeriod", orphanRemoval = true) @Cascade(value = { CascadeType.DELETE }) @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT) public List<ExpeditedAdverseEventReport> getAeReports() { if (this.aeReports == null) this.aeReports = new ArrayList<ExpeditedAdverseEventReport>(); return aeReports; } /** * This method returns a list of expedited aeReports that are active. An Expedited AeReport * is active if it has atleast on report in non-withdrawn state. * * @return the active ae reports */ @Transient public List<ExpeditedAdverseEventReport> getActiveAeReports() { activeAeReports = new ArrayList<ExpeditedAdverseEventReport>(); if (aeReports != null) { for (ExpeditedAdverseEventReport aeReport : aeReports) { if (isAeReportActive(aeReport)) activeAeReports.add(aeReport); } } return activeAeReports; } /** * If any report associated to expedited AeReport is in non-withdrawn state, * the expedited aeReport is considered to be an active report. * * @param aeReport the ae report * @return the boolean */ private Boolean isAeReportActive(ExpeditedAdverseEventReport aeReport) { for (Report report : aeReport.getReports()) { if (!report.getStatus().equals(ReportStatus.WITHDRAWN) && !report.getStatus().equals(ReportStatus.REPLACED) && !report.getStatus().equals(ReportStatus.AMENDED)) return true; } return false; } /** * Sets the ae reports. * * @param aeReports the new ae reports */ public void setAeReports(List<ExpeditedAdverseEventReport> aeReports) { this.aeReports = aeReports; } // This is annotated this way so that the IndexColumn will work with // the bidirectional mapping. See section 2.4.6.2.3 of the hibernate annotations docs. /** * Gets the review comments internal. * * @return the review comments internal */ @OneToMany(orphanRemoval = true) @JoinColumn(name = "rp_id", nullable = true) @IndexColumn(name = "list_index", nullable = false) @Cascade(value = { CascadeType.ALL }) @Fetch(value = org.hibernate.annotations.FetchMode.SUBSELECT) public List<ReportingPeriodReviewComment> getReviewCommentsInternal() { if (reviewComments == null) reviewComments = new ArrayList<ReportingPeriodReviewComment>(); return reviewComments; } /** * Sets the review comments internal. * * @param reviewComments the new review comments internal */ public void setReviewCommentsInternal(List<ReportingPeriodReviewComment> reviewComments) { this.reviewComments = reviewComments; } //http://opensource.atlassian.com/projects/hibernate/browse/HHH-2802 /** * Gets the review comments. * * @return the review comments */ @Transient public List<ReportingPeriodReviewComment> getReviewComments() { ArrayList<ReportingPeriodReviewComment> comments = new ArrayList<ReportingPeriodReviewComment>( getReviewCommentsInternal()); Collections.reverse(comments); return comments; } /** * Sets the review comments. * * @param reviewComments the new review comments */ public void setReviewComments(List<ReportingPeriodReviewComment> reviewComments) { this.reviewComments = reviewComments; } /** * Adds the ae report. * * @param aeReport the ae report */ public void addAeReport(ExpeditedAdverseEventReport aeReport) { if (aeReport == null) return; aeReport.setReportingPeriod(this); getAeReports().add(aeReport); } /** * Gets the name. * * @return the name */ @Transient public String getName() { if (StringUtils.isEmpty(name)) { SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy"); StringBuffer sb = new StringBuffer(); sb.append((getCycleNumber() != null) ? "Cycle #: " + getCycleNumber() + "; " : "") .append((getTreatmentAssignment() != null) ? "TAC: " + getTreatmentAssignment().getCode() + "; " : "Other") .append((startDate != null) ? "Start Date: " + formatter.format(startDate) : ""); name = sb.toString(); } return name; } /** * Sets the name. * * @param name the new name */ public void setName(String name) { this.name = name; } /** * Checks if is baseline reporting type. * * @return true, if is baseline reporting type */ @Transient public boolean isBaselineReportingType() { if (this.getEpoch() != null) return getEpoch().getName().equals(BASELINE_REPORTING_TYPE); return false; } /** * Gets the number of reports. * * @return the number of reports */ @Transient public int getNumberOfReports() { int count = 0; for (ExpeditedAdverseEventReport report : this.getAeReports()) { for (Report r : report.getReports()) { if (!r.getStatus().equals(ReportStatus.REPLACED)) count++; } } return count; } /** * Gets the number of a es. * * @return the number of a es */ @Transient public int getNumberOfAEs() { int count = 0; for (ExpeditedAdverseEventReport aeReport : getAeReports()) count += aeReport.getNumberOfAes(); return count; } /** * Gets the data entry status. * * @return the data entry status */ @Transient public String getDataEntryStatus() { return "In-progress"; } /** * Will tell the combined submission status of individual expedited reports. * * @return {@link ReportStatus}.COMPLETED -When all reports are submitted sucessfully or (withdrawn), {@link ReportStatus}.PENDING when any of the report is pending,inprocess or failed. */ @Transient public String getReportStatus() { if (getAeReports().isEmpty()) return "No Reports"; // If for any reports associated to all the Data Collection has status other than COMPLETED // or WITHDRAWN then return a status "Report(s) Due" or else return a status "Report(s) Completed" for (ExpeditedAdverseEventReport aeReport : this.getAeReports()) { for (Report report : aeReport.getReports()) { if (report.isOverdue()) return "Reports Overdue"; ReportStatus status = report.getLastVersion().getReportStatus(); if (status == ReportStatus.PENDING || status == ReportStatus.INPROCESS) { return "Reports Due"; } else if (status == ReportStatus.FAILED) { return "Report Submission Failed"; } } } return "Reports Completed"; } /** * This returns the string that is used as a name in ProcessInstance and TaskInstance (workflow related tables). * * @return String */ @Transient public String getWorkflowIdentifier() { return "routineFlow-" + getId(); } /** * Checks whether a different AE with the same term is avilable in this reporting period. * * @param otherAE the other ae * @return true, if successful */ public boolean hasDiffrentAEWithSameTerm(AdverseEvent otherAE) { for (AdverseEvent ae : getAdverseEvents()) { if (ae.isRetired()) continue; if (ae.getId().equals(otherAE.getId())) continue; if (ae.getAdverseEventTerm() == null || otherAE.getAdverseEventTerm() == null) continue; if (ae.getAdverseEventTerm().equals(otherAE.getAdverseEventTerm())) return true; } return false; } /** * Gets the treatment assignment description. * * @return the treatment assignment description */ @Column(name = "treatment_assignment_desc") public String getTreatmentAssignmentDescription() { return treatmentAssignmentDescription; } /** * Sets the treatment assignment description. * * @param treatmentAssignmentDescription the new treatment assignment description */ public void setTreatmentAssignmentDescription(String treatmentAssignmentDescription) { this.treatmentAssignmentDescription = StringEscapeUtils.unescapeHtml(treatmentAssignmentDescription); } /** * This method will return the earliest graded date, of reportable adverse event. * * @return the earliest adverse event graded date */ @Transient public Date getEarliestAdverseEventGradedDate() { return AdverseEventReportingPeriod.findEarliestGradedDate(getReportableAdverseEvents()); } /** * This method will return the earliest post submission updated date of report-able adverse events. * * @return the earliest post submission updated date */ @Transient public Date getEarliestPostSubmissionUpdatedDate() { return AdverseEventReportingPeriod.findEarliestPostSubmissionUpdatedDate(getReportableAdverseEvents()); } /** * Find earliest post submission updated date. * * @param adverseEvents the adverse events * @return the date */ public static Date findEarliestPostSubmissionUpdatedDate(List<AdverseEvent> adverseEvents) { Date d = null; for (AdverseEvent ae : adverseEvents) { if (ae.getPostSubmissionUpdatedDate() == null) continue; if (d == null) { d = ae.getPostSubmissionUpdatedDate(); } else { d = (DateUtils.compateDateAndTime(ae.getPostSubmissionUpdatedDate(), d) < 0) ? ae.getPostSubmissionUpdatedDate() : d; } } return d; } /** * Find earliest graded date. * * @param adverseEvents the adverse events * @return the date */ public static Date findEarliestGradedDate(List<AdverseEvent> adverseEvents) { Date d = null; for (AdverseEvent ae : adverseEvents) { if (ae == null || ae.getGradedDate() == null) continue; if (d == null) { d = ae.getGradedDate(); } else { d = (DateUtils.compateDateAndTime(ae.getGradedDate(), d) < 0) ? ae.getGradedDate() : d; } } return d; } /** * Find earliest post submission updated date or graded date for unsubmited events. * * @param adverseEvents the adverse events * @return the date */ public static Date findEarliestBaseDate(List<AdverseEvent> adverseEvents) { Date d = null; for (AdverseEvent ae : adverseEvents) { if (ae.getPostSubmissionUpdatedDate() == null || ae.getAddedToReportAtLeastOnce() == null || !ae.getAddedToReportAtLeastOnce()) { //AE not updated. if (ae.getGradedDate() != null) { if (d == null) { d = ae.getGradedDate(); } else { d = (DateUtils.compateDateAndTime(ae.getGradedDate(), d) < 0) ? ae.getGradedDate() : d; } } } else { //AE updated/ if (d == null) { d = ae.getPostSubmissionUpdatedDate(); } else { d = (DateUtils.compateDateAndTime(ae.getPostSubmissionUpdatedDate(), d) < 0) ? ae.getPostSubmissionUpdatedDate() : d; } } } return d; } /** Create a Map with aeReportID as key, and ExpeditedAdverseEventReport as value * * @return aeReportIndexMap */ public Map<Integer, ExpeditedAdverseEventReport> populateAeReportIndexMap() { Map<Integer, ExpeditedAdverseEventReport> aeReportIndexMap = new HashMap<Integer, ExpeditedAdverseEventReport>(); for (ExpeditedAdverseEventReport aeReport : this.getAeReports()) { aeReportIndexMap.put(aeReport.getId(), aeReport); } return aeReportIndexMap; } /** * Will find the Adverse Event that has matching * - externalId * - term * - dates * @param thatAe * @return */ public AdverseEvent findAdverseEventByIdTermAndDates(AdverseEvent thatAe) { for (AdverseEvent thisAe : getAdverseEvents()) { //are Ids matching ? if (ObjectUtils.equals(thisAe.getId(), thatAe.getId())) return thisAe; //externalId matching ? if (ObjectUtils.equals(thisAe.getExternalId(), thatAe.getExternalId())) return thisAe; //are dates matching ? no then continue with next if (DateUtils.compareDate(thisAe.getStartDate(), thatAe.getStartDate()) != 0) continue; if (DateUtils.compareDate(thisAe.getEndDate(), thatAe.getEndDate()) != 0) continue; AbstractAdverseEventTerm thisTerm = thisAe.getAdverseEventTerm(); AbstractAdverseEventTerm thatTerm = thatAe.getAdverseEventTerm(); if (thisTerm == null && thatTerm == null) { //verbatim only study if (StringUtils.equals(thisAe.getDetailsForOther(), thatAe.getDetailsForOther())) return thisAe; } else if ((thatTerm != null && thatTerm instanceof AdverseEventCtcTerm) && (thisTerm != null && thisTerm instanceof AdverseEventCtcTerm)) { //ctc ? AdverseEventCtcTerm thisAeCtcTerm = (AdverseEventCtcTerm) thisTerm; AdverseEventCtcTerm thatAeCtcTerm = (AdverseEventCtcTerm) thatTerm; //is other specify - yes then check MedDRA code set in Adverse events if (thisAeCtcTerm.isOtherRequired() && thatAeCtcTerm.isOtherRequired()) { String thisMeddraCode = thisAe.getLowLevelTerm() != null ? thisAe.getLowLevelTerm().getMeddraCode() : null; String thatMeddraCode = thatAe.getLowLevelTerm() != null ? thatAe.getLowLevelTerm().getMeddraCode() : null; if (StringUtils.equals(thisMeddraCode, thatMeddraCode)) return thisAe; } else { //check the ctep code String thisCtcCode = thisAeCtcTerm.getCtcTerm() != null ? thisAeCtcTerm.getCtcTerm().getCtepCode() : null; String thatCtcCode = thatAeCtcTerm.getCtcTerm() != null ? thatAeCtcTerm.getCtcTerm().getCtepCode() : null; if (StringUtils.equals(thisCtcCode, thatCtcCode)) return thisAe; } } else if ((thatTerm != null && thatTerm instanceof AdverseEventMeddraLowLevelTerm) && (thisTerm != null && thisTerm instanceof AdverseEventMeddraLowLevelTerm)) { //MedDRA ? AdverseEventMeddraLowLevelTerm thisAeMeddraTerm = (AdverseEventMeddraLowLevelTerm) thisTerm; AdverseEventMeddraLowLevelTerm thatAeMeddraTerm = (AdverseEventMeddraLowLevelTerm) thatTerm; //check the meddra code String thisMeddraCode = thisAeMeddraTerm.getLowLevelTerm() != null ? thisAeMeddraTerm.getLowLevelTerm().getMeddraCode() : null; String thatMeddraCode = thatAeMeddraTerm.getLowLevelTerm() != null ? thatAeMeddraTerm.getLowLevelTerm().getMeddraCode() : null; if (StringUtils.equals(thisMeddraCode, thatMeddraCode)) return thisAe; } } return null; } /** * This method finds the adverse event, defined in this reporting period, identified by the ID. * * @param id the id * @return the adverse event */ public AdverseEvent findAdverseEventById(Integer id) { for (AdverseEvent ae : getAdverseEvents()) { if (ae.getId().equals(id)) return ae; } return null; } /** * Will return the {@link ExpeditedAdverseEventReport} associated to this course, identified by id. * * @param id the id * @return the expedited adverse event report */ public ExpeditedAdverseEventReport findExpeditedAdverseEventReport(Integer id) { for (ExpeditedAdverseEventReport aeReport : getAeReports()) { if (aeReport.getId().equals(id)) return aeReport; } return null; } /** * This method sets the retired indicator attribute of the reporting period. It overrides the superclass method so that we can * take cascading actions. Incase a reporting period (course) is retired (retired_indicator = true), then all the adverse events in the * course should also be retied. * * @param retiredIndicator the new retired indicator */ @Override public void setRetiredIndicator(Boolean retiredIndicator) { super.setRetiredIndicator(retiredIndicator); if (retiredIndicator) { for (AdverseEvent ae : getAdverseEvents()) { ae.setRetiredIndicator(retiredIndicator); } } } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof AdverseEventReportingPeriod)) return false; AdverseEventReportingPeriod that = (AdverseEventReportingPeriod) o; if (getId() != null && that.getId() != null && that.getId().equals(this.getId())) return true; if (externalId != null && that.externalId != null && StringUtils.equals(externalId, that.externalId)) return true; if (startDate != null && that.startDate != null && DateUtils.compareDate(this.startDate, that.startDate) != 0) return false; if (endDate != null && that.endDate != null && DateUtils.compareDate(this.endDate, that.endDate) != 0) return false; if (getEpoch() != null && that.getEpoch() != null && !this.getEpoch().equals(that.getEpoch())) return false; if (getTreatmentAssignment() != null && that.getTreatmentAssignment() != null && !this.getTreatmentAssignment().getCode().equals(that.getTreatmentAssignment().getCode())) return false; if (getTreatmentAssignmentDescription() != null && that.getTreatmentAssignmentDescription() != null && !this.getTreatmentAssignmentDescription().equals(that.getTreatmentAssignmentDescription())) return false; return true; } @Override public int hashCode() { int result = treatmentAssignment != null ? treatmentAssignment.hashCode() : 0; result = 31 * result + (getId() != null ? getId().hashCode() : 0); result = 31 * result + (epoch != null ? epoch.hashCode() : 0); result = 31 * result + (startDate != null ? startDate.hashCode() : 0); result = 31 * result + (endDate != null ? endDate.hashCode() : 0); result = 31 * result + (externalId != null ? externalId.hashCode() : 0); return result; } @Override public String toString() { return "AdverseEventReportingPeriod [cycleNumber=" + cycleNumber + ", reviewStatus=" + reviewStatus + ", externalId=" + externalId + "]"; } /** * verifies that other reporting period has no common TAC or otherTreatmentAssignmentDescription * related to CAAERS-7323 * * @param otherReportingPeriod, the other reporting period * @return true, if successful */ public Boolean hasNoCommonTacOrOtherTreatmentAssignmentDescription( AdverseEventReportingPeriod otherReportingPeriod) { if (getTreatmentAssignment() != null && getTreatmentAssignment().getCode() != null) { // verify that it has different TAC return (otherReportingPeriod.getTreatmentAssignment() == null || !StringUtils.equalsIgnoreCase(getTreatmentAssignment().getCode(), otherReportingPeriod.getTreatmentAssignment().getCode())); } // verify that it has different otherTreatmentAssignmentDescription return !StringUtils.equalsIgnoreCase(getTreatmentAssignmentDescription(), otherReportingPeriod.getTreatmentAssignmentDescription()); } /** * verifies whether the reporting period has same core attributes * related to CAAERS-7414 * * @param otherCycleNumber, reporting period cycle number * @param otherStartDate, reporting start date * @param treatmentAssignment, treatment assignment * @return true, if successful */ public boolean hasSameCoreAttributes(Integer otherCycleNumber, Date otherStartDate, String otherTAC) { // if thisTAC or otherTAC are null assign them the value 'OTHER' String thisTAC = this.getTreatmentAssignment() != null && this.getTreatmentAssignment().getCode() != null ? StringUtils.upperCase(this.getTreatmentAssignment().getCode()) : "OTHER"; String thatTAC = otherTAC != null ? StringUtils.upperCase(otherTAC) : "OTHER"; if (!ObjectUtils.equals(thisTAC, thatTAC)) { return false; } // if at least one of the start dates is not null, compare them if ((this.getStartDate() != null || otherStartDate != null) && (DateUtils.compareDate(this.startDate, otherStartDate) != 0)) return false; // if at least one of the cycle numbers is not null, compare them if ((this.getCycleNumber() != null || otherCycleNumber != null) && (!ObjectUtils.equals(this.getCycleNumber(), otherCycleNumber))) return false; return true; } }