gov.nih.nci.cabig.caaers.web.ae.AdverseEventReconciliationCommand.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.cabig.caaers.web.ae.AdverseEventReconciliationCommand.java

Source

/*******************************************************************************
 * 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.web.ae;

import gov.nih.nci.cabig.caaers.dao.CtcTermDao;
import gov.nih.nci.cabig.caaers.dao.ExternalAdverseEventDao;
import gov.nih.nci.cabig.caaers.dao.ReconciliationReportDao;
import gov.nih.nci.cabig.caaers.dao.meddra.LowLevelTermDao;
import gov.nih.nci.cabig.caaers.dao.query.ExternalAdverseEventQuery;
import gov.nih.nci.cabig.caaers.domain.*;
import gov.nih.nci.cabig.caaers.domain.dto.AdverseEventDTO;
import gov.nih.nci.cabig.caaers.domain.dto.AeMappingsDTO;
import gov.nih.nci.cabig.caaers.domain.dto.AeMergeDTO;
import gov.nih.nci.cabig.caaers.domain.meddra.LowLevelTerm;
import gov.nih.nci.cabig.caaers.security.SecurityUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.util.*;

/**
 * @author: Biju Joseph
 */
public class AdverseEventReconciliationCommand {

    private ReconciliationReportDao reconciliationReportDao;
    private ExternalAdverseEventDao externalAdverseEventDao;
    private CtcTermDao ctcTermDao;
    private LowLevelTermDao lowLevelTermDao;

    private String rejectedInternalAeStr;
    private String rejectedExternalAeStr;
    private String unmappedExternalAeStr;
    private String unmappedInternalAeStr;
    private String matchedAeMappingStr;

    private AdverseEventReportingPeriod reportingPeriod;

    private List<AdverseEventDTO> unMappedExternalAeList;
    private List<AdverseEventDTO> unMappedInternalAeList;
    private List<AdverseEventDTO> rejectedExternalAeList;
    private List<AdverseEventDTO> rejectedInternalAeList;

    private List<AdverseEventDTO> externalAeList;
    private List<AdverseEventDTO> internalAeList;
    private Map<Integer, AdverseEventDTO> externalAeMap;
    private Map<String, AdverseEventDTO> externalAeExternalIdMap;
    private Map<Integer, AdverseEventDTO> internalAeMap;

    private Map<AdverseEventDTO, AdverseEventDTO> matchedAeMapping;
    private Map<Integer, Integer> matchedAeIdMapping;

    private Map<String, AdverseEventDTO> mergeMap;

    private List<AdverseEventDTO> errorAeList;

    private boolean noExternalAes;

    static AdverseEventDTO find(AdverseEventDTO value, Map<AdverseEventDTO, AdverseEventDTO> map) {
        for (Map.Entry<AdverseEventDTO, AdverseEventDTO> e : map.entrySet()) {
            if (e.getValue().equals(value))
                return e.getKey();
        }
        return null;
    }

    static AdverseEventDTO find(AdverseEventDTO ae, List<AdverseEventDTO> list) {
        AdverseEventDTO firstMatch = null;
        for (AdverseEventDTO dto : list) {
            if (ae.isSamePerMatchPercentage(dto)) {
                if (firstMatch == null) {
                    firstMatch = dto;
                    continue;
                }
                // related to https://tracker.nci.nih.gov/browse/CAAERS-5931
                return null;
            }
        }
        return firstMatch;
    }

    static AdverseEventDTO find(int id, List<AdverseEventDTO> list) {
        AdverseEventDTO found = null;
        for (AdverseEventDTO dto : list) {
            if (dto.getId() == id) {
                found = dto;
                break;
            }
        }

        return found;
    }

    public AdverseEventReconciliationCommand(ReconciliationReportDao reconciliationReportDao,
            ExternalAdverseEventDao externalAdverseEventDao, CtcTermDao ctcTermDao,
            LowLevelTermDao lowLevelTermDao) {
        this.reconciliationReportDao = reconciliationReportDao;
        this.externalAdverseEventDao = externalAdverseEventDao;
        this.ctcTermDao = ctcTermDao;
        this.lowLevelTermDao = lowLevelTermDao;

        this.errorAeList = new ArrayList<AdverseEventDTO>();
        externalAeList = new ArrayList<AdverseEventDTO>();
        internalAeList = new ArrayList<AdverseEventDTO>();

        externalAeMap = new LinkedHashMap<Integer, AdverseEventDTO>();
        externalAeExternalIdMap = new LinkedHashMap<String, AdverseEventDTO>();
        internalAeMap = new LinkedHashMap<Integer, AdverseEventDTO>();
        mergeMap = new HashMap<String, AdverseEventDTO>();

        unMappedInternalAeList = new ArrayList<AdverseEventDTO>();
        unMappedExternalAeList = new ArrayList<AdverseEventDTO>();
        rejectedInternalAeList = new ArrayList<AdverseEventDTO>();
        rejectedExternalAeList = new ArrayList<AdverseEventDTO>();

        matchedAeMapping = new HashMap<AdverseEventDTO, AdverseEventDTO>();
        matchedAeIdMapping = new HashMap<Integer, Integer>();

    }

    private boolean isValidGrade(Grade g, List<? extends CodedGrade> grades) {
        if (g == null)
            return false;
        if (grades == null || grades.isEmpty())
            return false;
        for (CodedGrade cg : grades) {
            if (cg.getCode() == g.getCode())
                return true;
        }
        return false;
    }

    public void loadExternalAdverseEvents() {
        ExternalAdverseEventQuery query = new ExternalAdverseEventQuery();

        query.filterByStatus(ExternalAEReviewStatus.PENDING);
        query.filterByReportingPeriod(reportingPeriod.getId());
        List<ExternalAdverseEvent> eaeList = (List<ExternalAdverseEvent>) externalAdverseEventDao.search(query);
        AeTerminology terminology = reportingPeriod.getStudy().getAeTerminology();
        StringBuilder errorBuilder = new StringBuilder();
        noExternalAes = eaeList.isEmpty();
        for (ExternalAdverseEvent eae : eaeList) {
            AdverseEventDTO dto = AdverseEventDTO.create(eae);
            errorBuilder.setLength(0);
            if (terminology.getTerm() == Term.CTC) {
                CtcTerm term = ctcTermDao.getByCtepCodeandVersion(eae.getAdverseEventTermCode(),
                        terminology.getCtcVersion());
                if (term == null) {
                    errorBuilder.append(
                            String.format("Invalid CTC term. Unable to find ('%s') with in Ctc version '%s'.",
                                    eae.getAdverseEventTermCode(), terminology.getCtcVersion().getName()));
                } else {
                    dto.getTerm().setId(term.getId());
                    dto.getTerm().setName(term.getFullName());
                    dto.getTerm().setCode(term.getCtepCode());
                    if (StringUtils.isNotEmpty(eae.getAdverseEventTermOtherValue())) {
                        //load the other Other Meddra.
                        MeddraVersion meddraVersion = reportingPeriod.getStudy().getOtherMeddra();
                        if (meddraVersion != null) {
                            List<LowLevelTerm> lowLevelTerms = lowLevelTermDao.getByMeddraCodeandVersion(
                                    eae.getAdverseEventTermCode(), terminology.getMeddraVersion().getId());
                            LowLevelTerm otherTerm = (lowLevelTerms == null || lowLevelTerms.isEmpty()) ? null
                                    : lowLevelTerms.get(0);
                            if (otherTerm != null) {
                                dto.getTerm().setOtherSpecify(otherTerm.getFullName());
                            }
                        }
                    }
                    if (!isValidGrade(eae.getGrade(), term.getGrades())) {
                        String gradeString = "";
                        for (CodedGrade g : term.getGrades()) {
                            if (gradeString.length() > 0)
                                gradeString += ", ";
                            gradeString += g.getCode() + ":" + Grade.getByCode(g.getCode()).getShortName();
                        }
                        errorBuilder.append(String.format(
                                "Grade '%s' is not valid for the term '%s:%s'. Valid options are '%s'",
                                eae.getGrade().getCode() + ":" + eae.getGrade().getShortName(),
                                eae.getAdverseEventTermCode(), term.getFullName(), gradeString));
                    }
                }

            } else if (terminology.getTerm() == Term.MEDDRA) {
                List<LowLevelTerm> lowLevelTerms = lowLevelTermDao.getByMeddraCodeandVersion(
                        eae.getAdverseEventTermCode(), terminology.getMeddraVersion().getId());
                LowLevelTerm term = (lowLevelTerms == null || lowLevelTerms.isEmpty()) ? null
                        : lowLevelTerms.get(0);
                if (term == null) {
                    errorBuilder.append(String.format(
                            "Invalid MedDRA term. Unable to find ('%s:%s') with in MedDRA version '%s'.",
                            eae.getAdverseEventTermCode(), eae.getAdverseEventTerm(),
                            terminology.getMeddraVersion().getName()));
                } else {
                    dto.getTerm().setId(term.getId());
                    dto.getTerm().setCode(term.getMeddraCode());
                    dto.getTerm().setName(term.getFullName());
                }
            }

            if (!dto.isDateValid()) {
                errorBuilder.append("Invalid start date or end date.");
            }

            if (errorBuilder.length() > 0) {
                dto.setError(errorBuilder.toString());
                errorAeList.add(dto);
            } else {
                externalAeList.add(dto);
                externalAeMap.put(dto.getId(), dto);
                externalAeExternalIdMap.put(dto.getExternalID(), dto);
                unMappedExternalAeList.add(dto);
            }
        }

    }

    public void loadInternalAdverseEvents() {
        for (AdverseEvent ae : reportingPeriod.getAdverseEvents()) {
            if (ae.isRetired())
                continue;
            if (StringUtils.isEmpty(ae.getExternalId())
                    || externalAeExternalIdMap.containsKey(ae.getExternalId())) {
                AdverseEventDTO dto = AdverseEventDTO.create(ae);
                internalAeList.add(dto);
                internalAeMap.put(dto.getId(), dto);
                unMappedInternalAeList.add(dto);
            }
        }
    }

    public void doAutoMapping() {
        AeMappingsDTO oldMapping = StringUtils.isNotEmpty(reportingPeriod.getOldAeMapping())
                ? AeMappingsDTO.deseralize(reportingPeriod.getOldAeMapping())
                : null;
        if (oldMapping != null) {
            //handle rejections
            if (oldMapping.getRejectedExternalAeIds() != null) {
                for (Integer id : oldMapping.getRejectedExternalAeIds()) {
                    AdverseEventDTO rejected = externalAeMap.get(id);
                    if (rejected != null) {
                        unMappedExternalAeList.remove(rejected);
                        rejectedExternalAeList.add(rejected);
                    }
                }
            }
            if (oldMapping.getRejectedInternalAeIds() != null) {
                for (Integer id : oldMapping.getRejectedInternalAeIds()) {
                    AdverseEventDTO rejected = internalAeMap.get(id);
                    if (rejected != null) {
                        unMappedInternalAeList.remove(rejected);
                        rejectedInternalAeList.add(rejected);
                    }
                }
            }

            //handle mappings
            if (oldMapping.getRelations() != null) {
                for (AeMergeDTO relation : oldMapping.getRelations()) {
                    AdverseEventDTO iae = internalAeMap.get(relation.getInteralAeId());
                    AdverseEventDTO eae = externalAeMap.get(relation.getExternalAeId());
                    if (iae == null || eae == null)
                        continue;
                    matchedAeMapping.put(iae, eae);
                    matchedAeIdMapping.put(iae.getId(), eae.getId());
                    unMappedExternalAeList.remove(eae);
                    unMappedInternalAeList.remove(iae);
                    AdverseEventDTO merged = addToMergeMap(iae, eae);
                    relation.mergeChanges(iae, eae, merged);
                }
            }

        }

        List<AdverseEventDTO> unmapped = new ArrayList<AdverseEventDTO>(unMappedInternalAeList);
        for (AdverseEventDTO ae : unmapped) {
            AdverseEventDTO found = find(ae, unMappedExternalAeList);
            if (found != null) {
                matchedAeMapping.put(ae, found);
                matchedAeIdMapping.put(ae.getId(), found.getId());
                unMappedExternalAeList.remove(found);
                unMappedInternalAeList.remove(ae);
                addToMergeMap(ae, found);
            }
        }

    }

    public void seralizeMapping() {
        AeMappingsDTO mappings = new AeMappingsDTO();
        List<Integer> rejectedExternal = new ArrayList<Integer>();
        for (AdverseEventDTO ae : getRejectedExternalAeList())
            rejectedExternal.add(ae.getId());
        mappings.setRejectedExternalAeIds(ArrayUtils.toPrimitive(rejectedExternal.toArray(new Integer[] {})));

        List<Integer> rejectedInternal = new ArrayList<Integer>();
        for (AdverseEventDTO ae : getRejectedInternalAeList())
            rejectedInternal.add(ae.getId());
        mappings.setRejectedInternalAeIds(ArrayUtils.toPrimitive(rejectedInternal.toArray(new Integer[] {})));
        List<AeMergeDTO> relations = new ArrayList<AeMergeDTO>();
        for (Map.Entry<AdverseEventDTO, AdverseEventDTO> entry : matchedAeMapping.entrySet()) {
            String key = entry.getKey().getId() + "_" + entry.getValue().getId();
            AeMergeDTO merge = new AeMergeDTO();
            merge.setInteralAeId(entry.getKey().getId());
            merge.setExternalAeId(entry.getValue().getId());
            relations.add(merge);
            AdverseEventDTO ae = mergeMap.get(key);
            if (ae != null)
                merge.copyChanges(entry.getKey(), entry.getValue(), ae);
        }
        mappings.setRelations(relations.toArray(new AeMergeDTO[] {}));

        reportingPeriod.setOldAeMapping(AeMappingsDTO.seralize(mappings));
    }

    public Study getStudy() {
        return reportingPeriod.getStudy();
    }

    public Participant getParticipant() {
        return reportingPeriod.getParticipant();
    }

    public AdverseEventReportingPeriod getReportingPeriod() {
        return reportingPeriod;
    }

    public void setReportingPeriod(AdverseEventReportingPeriod reportingPeriod) {
        this.reportingPeriod = reportingPeriod;
    }

    public StudyParticipantAssignment getAssignment() {
        return reportingPeriod.getAssignment();
    }

    public List<AdverseEventDTO> getUnMappedExternalAeList() {
        return unMappedExternalAeList;
    }

    public void setUnMappedExternalAeList(List<AdverseEventDTO> unMappedExternalAeList) {
        this.unMappedExternalAeList = unMappedExternalAeList;
    }

    public List<AdverseEventDTO> getUnMappedInternalAeList() {
        return unMappedInternalAeList;
    }

    public void setUnMappedInternalAeList(List<AdverseEventDTO> unMappedInternalAeList) {
        this.unMappedInternalAeList = unMappedInternalAeList;
    }

    public List<AdverseEventDTO> getRejectedExternalAeList() {
        return rejectedExternalAeList;
    }

    public void setRejectedExternalAeList(List<AdverseEventDTO> rejectedExternalAeList) {
        this.rejectedExternalAeList = rejectedExternalAeList;
    }

    public List<AdverseEventDTO> getRejectedInternalAeList() {
        return rejectedInternalAeList;
    }

    public void setRejectedInternalAeList(List<AdverseEventDTO> rejectedInternalAeList) {
        this.rejectedInternalAeList = rejectedInternalAeList;
    }

    public List<AdverseEventDTO> getExternalAeList() {
        return externalAeList;
    }

    public void setExternalAeList(List<AdverseEventDTO> externalAeList) {
        this.externalAeList = externalAeList;
    }

    public List<AdverseEventDTO> getInternalAeList() {
        return internalAeList;
    }

    public void setInternalAeList(List<AdverseEventDTO> internalAeList) {
        this.internalAeList = internalAeList;
    }

    public Map<AdverseEventDTO, AdverseEventDTO> getMatchedAeMapping() {
        return matchedAeMapping;
    }

    public void setMatchedAeMapping(Map<AdverseEventDTO, AdverseEventDTO> matchedAeMapping) {
        this.matchedAeMapping = matchedAeMapping;
    }

    public String getRejectedExternalAeStr() {
        return rejectedExternalAeStr;
    }

    public void setRejectedExternalAeStr(String rejectedExternalAeStr) {
        this.rejectedExternalAeStr = rejectedExternalAeStr;
    }

    public String getUnmappedExternalAeStr() {
        return unmappedExternalAeStr;
    }

    public void setUnmappedExternalAeStr(String unmappedExternalAeStr) {
        this.unmappedExternalAeStr = unmappedExternalAeStr;
    }

    public String getUnmappedInternalAeStr() {
        return unmappedInternalAeStr;
    }

    public void setUnmappedInternalAeStr(String unmappedInternalAeStr) {
        this.unmappedInternalAeStr = unmappedInternalAeStr;
    }

    public String getMatchedAeMappingStr() {
        return matchedAeMappingStr;
    }

    public void setMatchedAeMappingStr(String matchedAeMappingStr) {
        this.matchedAeMappingStr = matchedAeMappingStr;
    }

    public Map<Integer, AdverseEventDTO> getExternalAeMap() {
        return externalAeMap;
    }

    public void setExternalAeMap(Map<Integer, AdverseEventDTO> externalAeMap) {
        this.externalAeMap = externalAeMap;
    }

    public Map<Integer, AdverseEventDTO> getInternalAeMap() {
        return internalAeMap;
    }

    public void setInternalAeMap(Map<Integer, AdverseEventDTO> internalAeMap) {
        this.internalAeMap = internalAeMap;
    }

    public Map<String, AdverseEventDTO> getMergeMap() {
        return mergeMap;
    }

    public void setMergeMap(Map<String, AdverseEventDTO> mergeMap) {
        this.mergeMap = mergeMap;
    }

    public Map<Integer, Integer> getMatchedAeIdMapping() {
        return matchedAeIdMapping;
    }

    public void setMatchedAeIdMapping(Map<Integer, Integer> matchedAeIdMapping) {
        this.matchedAeIdMapping = matchedAeIdMapping;
    }

    public String getRejectedInternalAeStr() {
        return rejectedInternalAeStr;
    }

    public void setRejectedInternalAeStr(String rejectedInternalAeStr) {
        this.rejectedInternalAeStr = rejectedInternalAeStr;
    }

    public List<AdverseEventDTO> getErrorAeList() {
        return errorAeList;
    }

    public void setErrorAeList(List<AdverseEventDTO> errorAeList) {
        this.errorAeList = errorAeList;
    }

    public boolean isNoExternalAes() {
        return noExternalAes;
    }

    public void setNoExternalAes(boolean noExternalAes) {
        this.noExternalAes = noExternalAes;
    }

    public List<String> getAllReviewedExternalAeExternalIds() {
        List<String> ids = new ArrayList<String>();
        List<String> rejected = getRejectedExternalAeExternalIds();
        List<String> incorrect = getIncorrectExternalAeExternalIds();
        boolean hasRejected = rejected.isEmpty();
        boolean hasIncorrect = incorrect.isEmpty();
        for (AdverseEventDTO ae : externalAeList) {
            if (hasRejected && rejected.contains(ae.getExternalID()))
                continue;
            if (hasIncorrect && incorrect.contains(ae.getExternalID()))
                continue;
            ids.add(ae.getExternalID());
        }
        return ids;
    }

    public List<String> getRejectedExternalAeExternalIds() {
        List<String> ids = new ArrayList<String>();
        for (AdverseEventDTO ae : rejectedExternalAeList) {
            ids.add(ae.getExternalID());
        }
        return ids;
    }

    public List<String> getIncorrectExternalAeExternalIds() {
        List<String> ids = new ArrayList<String>();
        for (AdverseEventDTO ae : errorAeList) {
            ids.add(ae.getExternalID());
        }
        return ids;
    }

    public void processExternalAeRejections() {
        rejectedExternalAeList.clear();
        if (StringUtils.isEmpty(rejectedExternalAeStr))
            return;

        String arr[] = StringUtils.split(rejectedExternalAeStr, '_');
        Set<Integer> set = new HashSet<Integer>();
        if (arr != null) {
            for (String s : arr) {
                if (StringUtils.isEmpty(s))
                    continue;
                Integer i = Integer.parseInt(s);
                if (set.add(i)) {
                    AdverseEventDTO ae = externalAeMap.get(i);
                    unMappedExternalAeList.remove(ae);
                    rejectedExternalAeList.add(ae);
                }

            }
        }
    }

    public void processInternalAeRejections() {
        rejectedInternalAeList.clear();
        if (StringUtils.isEmpty(rejectedInternalAeStr))
            return;
        String arr[] = StringUtils.split(rejectedInternalAeStr, '_');

        Set<Integer> set = new HashSet<Integer>();
        if (arr != null) {
            for (String s : arr) {
                if (StringUtils.isEmpty(s))
                    continue;
                Integer i = Integer.parseInt(s);
                if (set.add(i)) {
                    AdverseEventDTO ae = internalAeMap.get(i);
                    unMappedInternalAeList.remove(ae);
                    rejectedInternalAeList.add(ae);
                }
            }
        }
    }

    public void processUnmappedExternalAes() {
        unMappedExternalAeList.clear();
        if (StringUtils.isEmpty(unmappedExternalAeStr))
            return;
        String arr[] = StringUtils.split(unmappedExternalAeStr, '_');

        if (arr != null) {
            for (String s : arr) {
                AdverseEventDTO ae = externalAeMap.get(Integer.parseInt(s));
                unMappedExternalAeList.add(ae);
            }
        }
    }

    public void processUnmappedInternalAes() {
        unMappedInternalAeList.clear();
        String arr[] = StringUtils.split(unmappedInternalAeStr, '_');
        if (StringUtils.isEmpty(unmappedInternalAeStr))
            return;

        if (arr != null) {
            for (String s : arr) {
                AdverseEventDTO ae = internalAeMap.get(Integer.parseInt(s));
                unMappedInternalAeList.add(ae);
            }
        }
    }

    public void processAeMapping() {
        matchedAeMapping.clear();
        matchedAeIdMapping.clear();
        if (StringUtils.isEmpty(matchedAeMappingStr))
            return;
        String arr[] = StringUtils.split(matchedAeMappingStr, '&');
        if (arr != null) {
            for (String s : arr) {
                String ids[] = StringUtils.split(s, '=');
                if (ids != null) {
                    AdverseEventDTO iae = internalAeMap.get(Integer.parseInt(ids[0]));
                    AdverseEventDTO eae = externalAeMap.get(Integer.parseInt(ids[1]));
                    matchedAeMapping.put(iae, eae);
                    matchedAeIdMapping.put(iae.getId(), eae.getId());
                    addToMergeMap(iae, eae);
                }
            }
        }
    }

    public AdverseEventDTO addToMergeMap(AdverseEventDTO iae, AdverseEventDTO eae) {
        String key = iae.getId() + "_" + eae.getId();
        if (!mergeMap.containsKey(key)) {
            AdverseEventDTO ae = iae.clone();
            List<String> diff = iae.diff(eae);
            ae.clearFields(diff.toArray(new String[] {}));
            mergeMap.put(key, ae);
            return ae;
        }
        return mergeMap.get(key);
    }

    public ReconciliationReport generateReconcilationReport() {
        ReconciliationReport report = new ReconciliationReport();
        report.setReviewedBy(SecurityUtils.getUserLoginName());
        report.setCreatedDate(new Date());
        for (AdverseEventDTO ae : rejectedExternalAeList) {
            report.addReconciledAdverseEvent(ae.getReconciledAdverseEvent(ReconciliationAction.DELETE));
        }
        for (AdverseEventDTO ae : rejectedInternalAeList) {
            report.addReconciledAdverseEvent(ae.getReconciledAdverseEvent(ReconciliationAction.DELETE));
        }
        for (AdverseEventDTO ae : unMappedExternalAeList) {
            report.addReconciledAdverseEvent(ae.getReconciledAdverseEvent(ReconciliationAction.ADD));
        }
        for (AdverseEventDTO ae : unMappedInternalAeList) {
            report.addReconciledAdverseEvent(ae.getReconciledAdverseEvent(ReconciliationAction.ADD));
        }
        for (AdverseEventDTO ae : errorAeList) {
            report.addReconciledAdverseEvent(ae.getReconciledAdverseEvent(ReconciliationAction.ERROR));
        }

        for (Map.Entry<AdverseEventDTO, AdverseEventDTO> e : matchedAeMapping.entrySet()) {
            AdverseEventDTO iae = e.getKey();
            AdverseEventDTO eae = e.getValue();
            String key = iae.getId() + "_" + eae.getId();

            AdverseEventDTO merged = mergeMap.get(key);
            if (merged == null)
                continue;

            boolean linked = true;

            if (!iae.diff(merged).isEmpty()) {
                ReconciledAdverseEvent rae = merged.getReconciledAdverseEvent(ReconciliationAction.UPDATE);
                rae.setSystem(ReconciliationSystem.CAAERS);
                rae.setExternalId(eae.getExternalID());
                rae.setItemId(iae.getId());
                report.addReconciledAdverseEvent(rae);
                linked = false;
            }

            if (!eae.diff(merged).isEmpty()) {
                ReconciledAdverseEvent rae = merged.getReconciledAdverseEvent(ReconciliationAction.UPDATE);
                rae.setSystem(ReconciliationSystem.FORCE);
                rae.setItemId(eae.getId());
                report.addReconciledAdverseEvent(rae);
                linked = false;
            }

            if (linked) {
                ReconciledAdverseEvent rae = merged.getReconciledAdverseEvent(ReconciliationAction.LINKED);
                rae.setSystem(ReconciliationSystem.CAAERS);
                rae.setExternalId(eae.getExternalID());
            }

        }

        return report;
    }
}