package org.akaza.openclinica.control.extract; import static java.util.Arrays.asList; import static java.util.Collections.emptySet; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.akaza.openclinica.bean.admin.CRFBean; import org.akaza.openclinica.bean.core.AuditableEntityBean; import org.akaza.openclinica.bean.core.DiscrepancyNoteType; import org.akaza.openclinica.bean.core.ResolutionStatus; import org.akaza.openclinica.bean.extract.DownloadDiscrepancyNote; import org.akaza.openclinica.bean.managestudy.DiscrepancyNoteBean; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.managestudy.StudyEventBean; import org.akaza.openclinica.bean.managestudy.StudyEventDefinitionBean; import org.akaza.openclinica.bean.managestudy.StudySubjectBean; import org.akaza.openclinica.bean.submit.*; import org.akaza.openclinica.control.core.SecureController; import org.akaza.openclinica.control.form.FormProcessor; import org.akaza.openclinica.core.form.StringUtil; import org.akaza.openclinica.core.util.Pair; import org.akaza.openclinica.dao.admin.CRFDAO; import org.akaza.openclinica.dao.managestudy.DiscrepancyNoteDAO; import org.akaza.openclinica.dao.managestudy.ListNotesFilter; import org.akaza.openclinica.dao.managestudy.StudyDAO; import org.akaza.openclinica.dao.managestudy.StudyEventDAO; import org.akaza.openclinica.dao.managestudy.StudyEventDefinitionDAO; import org.akaza.openclinica.dao.managestudy.StudySubjectDAO; import org.akaza.openclinica.dao.submit.*; import org.akaza.openclinica.i18n.core.LocaleResolver; import org.akaza.openclinica.i18n.util.ResourceBundleProvider; import org.akaza.openclinica.service.DiscrepancyNoteThread; import org.akaza.openclinica.service.DiscrepancyNoteUtil; import org.akaza.openclinica.service.managestudy.ViewNotesFilterCriteria; import org.akaza.openclinica.service.managestudy.ViewNotesService; import org.akaza.openclinica.service.managestudy.ViewNotesSortCriteria; import org.akaza.openclinica.web.InsufficientPermissionException; import org.springframework.web.context.support.WebApplicationContextUtils; /** * A servlet that sends via HTTP a file containing Discrepancy-Note related data. * @author Bruce W. Perry * @see ChooseDownloadFormat * @see org.akaza.openclinica.bean.extract.DownloadDiscrepancyNote */ public class DiscrepancyNoteOutputServlet extends SecureController { // These are the headers that must appear in the HTTP response, when sending a // file back to the user public static String CONTENT_DISPOSITION_HEADER = "Content-Disposition"; public static String CONTENT_DISPOSITION_VALUE = "attachment; filename="; /* Handle the HTTP Get or Post request. */ @Override protected void processRequest() throws Exception { FormProcessor fp = new FormProcessor(request); // the fileName contains any subject id and study unique protocol id; // see: chooseDownloadFormat.jsp String fileName = request.getParameter("fileName"); // replace any spaces in the study's unique protocol id, so that // the filename is formulated correctly if (fileName != null) { fileName = fileName.replaceAll(" ", "_"); } fileName = fileName == null ? "" : fileName; // the format will be either csv (comma separated values) or pdf (portable document format) String format = request.getParameter("fmt"); String studyIdentifier = request.getParameter("studyIdentifier"); // Determine whether to limit the displayed DN's to a certain resolutionStatus // CHANGED TO LIST OF RESOLUTION STATUS IDS /*int resolutionStatus = 0; try { resolutionStatus = Integer.parseInt(request.getParameter("resolutionStatus")); } catch(NumberFormatException nfe){ //Show all DN's resolutionStatus=-1; }*/ // possibly for a later implementation: int definitionId = fp.getInt("defId"); //here subjectId actually is study_subject_id !!! int subjectId = fp.getInt("subjectId"); int discNoteType = fp.getInt("discNoteType"); DownloadDiscrepancyNote downLoader = new DownloadDiscrepancyNote(); if ("csv".equalsIgnoreCase(format)) { fileName = fileName + ".csv"; response.setContentType(DownloadDiscrepancyNote.CSV); } else { response.setContentType(DownloadDiscrepancyNote.PDF); fileName = fileName + ".pdf"; } response.addHeader(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE + fileName); // Are we downloading a List of discrepancy notes or just one? // Not needed now: boolean isList = ("y".equalsIgnoreCase(isAList)); StudyBean studyBean = (StudyBean) session.getAttribute("study"); // Set<Integer> resolutionStatusIds = (HashSet) session.getAttribute("resolutionStatus"); // It will also change any resolution status IDs among parents of children that have a different // id value (last boolean parameter; 'true' to perform the latter task) // In this case we want to include all the discrepancy notes, despite the res status or // type filtering, because we don't want to filter out parents, thus leaving out a child note // that might match the desired res status ListNotesFilter listNotesFilter = new ListNotesFilter(); ViewNotesService viewNotesService = (ViewNotesService) WebApplicationContextUtils.getWebApplicationContext( getServletContext()).getBean("viewNotesService"); ViewNotesFilterCriteria filter = ViewNotesFilterCriteria.buildFilterCriteria( getFilters(request), getDateFormat(), discrepancyNoteTypesDecoder, resolutionStatusDecoder); List<DiscrepancyNoteBean> notes = viewNotesService.listNotes( currentStudy, filter, ViewNotesSortCriteria.buildFilterCriteria(getSortOrder(request))); ArrayList<DiscrepancyNoteBean> allDiscNotes = notes instanceof ArrayList ? (ArrayList<DiscrepancyNoteBean>) notes : new ArrayList<DiscrepancyNoteBean>(notes); allDiscNotes = populateRowsWithAttachedData(allDiscNotes); // Now we have to package all the discrepancy notes in DiscrepancyNoteThread objects // Do the filtering for type or status here DiscrepancyNoteUtil discNoteUtil = new DiscrepancyNoteUtil(); Set<Integer> resolutionStatusIds = emptySet(); List<DiscrepancyNoteThread> discrepancyNoteThreads = discNoteUtil.createThreads(allDiscNotes, sm.getDataSource(), studyBean); if ("csv".equalsIgnoreCase(format)) { /*response.setContentLength( downLoader.getListContentLength(allDiscNotes,DownloadDiscrepancyNote.CSV));*/ //3014: this has been changed to only show the parent of the thread; then changed back again! int contentLen = downLoader.getThreadListContentLength(discrepancyNoteThreads); response.setContentLength(contentLen); /*downLoader.downLoadDiscBeans(allDiscNotes, DownloadDiscrepancyNote.CSV,response.getOutputStream(), null);*/ downLoader.downLoadThreadedDiscBeans(discrepancyNoteThreads, DownloadDiscrepancyNote.CSV, response, null); } else { response.setHeader("Pragma", "public"); /*downLoader.downLoadDiscBeans(allDiscNotes, DownloadDiscrepancyNote.PDF, response.getOutputStream(), studyIdentifier);*/ downLoader.downLoadThreadedDiscBeans(discrepancyNoteThreads, DownloadDiscrepancyNote.PDF, response, studyIdentifier); } } private Map<String,String> makeDiscrepancyNoteTypesDecoder() { Map<String,String> decoder = new HashMap<String,String>(); ResourceBundle reterm = ResourceBundleProvider.getTermsBundle(); for (DiscrepancyNoteType type : DiscrepancyNoteType.list) { decoder.put(type.getName(), Integer.toString(type.getId())); } decoder.put(reterm.getString("Query_and_Failed_Validation_Check"), "1,3"); return decoder; } private Map<String,String> discrepancyNoteTypesDecoder = makeDiscrepancyNoteTypesDecoder(); private Map<String,String> makeResolutionStatusDecoder() { Map<String,String> decoder = new HashMap<String,String>(); ResourceBundle reterm = ResourceBundleProvider.getTermsBundle(); for (ResolutionStatus status : ResolutionStatus.list) { decoder.put(status.getName(), Integer.toString(status.getId())); } decoder.put(reterm.getString("New_and_Updated"), "1,2"); return decoder; } private Map<String,String> resolutionStatusDecoder = makeResolutionStatusDecoder(); private String getDateFormat() { Locale locale = LocaleResolver.getLocale(request); ResourceBundle resformat = ResourceBundleProvider.getFormatBundle(locale); return resformat.getString("date_format_string"); } private Map<String,String> getFilters(HttpServletRequest request) { Map<String,String> filters = new HashMap<String,String>(); String ids[] = { "studySubject.label", "siteId", "studySubject.labelExact", "discrepancyNoteBean.createdDate", "discrepancyNoteBean.updatedDate", "discrepancyNoteBean.description", "discrepancyNoteBean.user", "discrepancyNoteBean.disType", "discrepancyNoteBean.entityType", "discrepancyNoteBean.resolutionStatus", "age", "days", "eventName", "crfName", "entityName", "entityValue", "discrepancyNoteBean.description", "discrepancyNoteBean.user" }; for (String s: ids) { String val = request.getParameter(s); if (val != null) { filters.put(s, val); } } return filters; } private List<Pair<String,String>> getSortOrder(HttpServletRequest request) { String ids[] = { "studySubject.label", "discrepancyNoteBean.createdDate", "days", "age" }; List<Pair<String,String>> sortOrders = new ArrayList<Pair<String,String>>(4); for (String s: ids) { /* * The HTTP parameters for sorting are prefixed with 'sort'. */ String orders[] = request.getParameterValues("sort." + s); if (orders != null) { for (String order: orders) { if ("ASC".equals(order) || "DESC".equals(order)) { sortOrders.add(new Pair<String,String>(s, order)); break; } } } } return sortOrders; } private ArrayList<DiscrepancyNoteBean> populateRowsWithAttachedData(ArrayList<DiscrepancyNoteBean> noteRows) { Locale l = LocaleResolver.getLocale(request); resword = ResourceBundleProvider.getWordsBundle(l); resformat = ResourceBundleProvider.getFormatBundle(l); SimpleDateFormat sdf = new SimpleDateFormat(resformat.getString("date_format_string"), ResourceBundleProvider.getLocale()); DiscrepancyNoteDAO dndao = new DiscrepancyNoteDAO(sm.getDataSource()); StudySubjectDAO studySubjectDAO = new StudySubjectDAO(sm.getDataSource()); StudyEventDAO sedao = new StudyEventDAO(sm.getDataSource()); CRFVersionDAO cvdao = new CRFVersionDAO(sm.getDataSource()); CRFDAO cdao = new CRFDAO(sm.getDataSource()); StudyEventDefinitionDAO seddao = new StudyEventDefinitionDAO(sm.getDataSource()); EventCRFDAO ecdao = new EventCRFDAO(sm.getDataSource()); ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource()); ItemDAO idao = new ItemDAO(sm.getDataSource()); StudyDAO studyDao = new StudyDAO(sm.getDataSource()); ItemGroupMetadataDAO<String, ArrayList> igmdao = new ItemGroupMetadataDAO<String, ArrayList>(sm.getDataSource()); ItemGroupDAO<String, ArrayList> igdao = new ItemGroupDAO<String, ArrayList>(sm.getDataSource()); ArrayList<DiscrepancyNoteBean> allNotes = new ArrayList<DiscrepancyNoteBean>(); for (int i = 0; i < noteRows.size(); i++) { DiscrepancyNoteBean dnb = noteRows.get(i); dnb.setCreatedDateString(dnb.getCreatedDate()==null?"":sdf.format(dnb.getCreatedDate())); if (dnb.getParentDnId() == 0) { ArrayList children = dndao.findAllByStudyAndParent(currentStudy, dnb.getId()); children = children == null? new ArrayList():children; dnb.setNumChildren(children.size()); dnb.setChildren(children); int lastDnId = dnb.getId(); int lastChild = 0; for (int j = 0; j < children.size(); j++) { DiscrepancyNoteBean child = (DiscrepancyNoteBean) children.get(j); child.setCreatedDateString(child.getCreatedDate()==null?"":sdf.format(child.getCreatedDate())); child.setUpdatedDateString(child.getCreatedDate()!=null?sdf.format(child.getCreatedDate()):""); if (child.getId() > lastDnId) { lastDnId = child.getId(); lastChild = j; } } if(children.size()>0) { DiscrepancyNoteBean lastdn = (DiscrepancyNoteBean) children.get(lastChild); //dnb.setResStatus(ResolutionStatus.get(lastdn.getResolutionStatusId())); /* * The update date is the date created of the latest child * note */ dnb.setUpdatedDate(lastdn.getCreatedDate()); dnb.setUpdatedDateString(dnb.getUpdatedDate()!=null?sdf.format(dnb.getUpdatedDate()):""); } } String entityType = dnb.getEntityType(); if (dnb.getEntityId() > 0 && !entityType.equals("")) { AuditableEntityBean aeb = dndao.findEntity(dnb); dnb.setEntityName(aeb.getName()); if (entityType.equalsIgnoreCase("subject")) { // allNotes.add(dnb); SubjectBean sb = (SubjectBean) aeb; StudySubjectBean ssb = studySubjectDAO.findBySubjectIdAndStudy(sb.getId(), currentStudy); dnb.setStudySub(ssb); dnb.setSubjectName(ssb.getLabel()); String column = dnb.getColumn().trim(); if (!StringUtil.isBlank(column)) { if ("gender".equalsIgnoreCase(column)) { dnb.setEntityValue(sb.getGender() + ""); dnb.setEntityName(resword.getString("gender")); } else if ("date_of_birth".equals(column)) { if (sb.getDateOfBirth() != null) { dnb.setEntityValue(sb.getDateOfBirth().toString()); } dnb.setEntityName(resword.getString("date_of_birth")); } else if ("unique_identifier".equalsIgnoreCase(column)) { dnb.setEntityName(resword.getString("unique_identifier")); dnb.setEntityValue(sb.getUniqueIdentifier()); } } } else if (entityType.equalsIgnoreCase("studySub")) { // allNotes.add(dnb); StudySubjectBean ssb = (StudySubjectBean) aeb; dnb.setStudySub(ssb); dnb.setSubjectName(ssb.getLabel()); String column = dnb.getColumn().trim(); if (!StringUtil.isBlank(column)) { if ("enrollment_date".equals(column)) { if (ssb.getEnrollmentDate() != null) { dnb.setEntityValue(ssb.getEnrollmentDate().toString()); } dnb.setEntityName(resword.getString("enrollment_date")); } } } else if (entityType.equalsIgnoreCase("eventCRF")) { StudyEventBean se = (StudyEventBean) sedao.findByPK(dnb.getEntityId()); StudyEventDefinitionBean sedb = (StudyEventDefinitionBean) seddao.findByPK(se.getStudyEventDefinitionId()); EventCRFBean ecb = (EventCRFBean) aeb; CRFVersionBean cvb = (CRFVersionBean) cvdao.findByPK(ecb.getCRFVersionId()); CRFBean cb = (CRFBean) cdao.findByPK(cvb.getCrfId()); dnb.setStageId(ecb.getStage().getId()); dnb.setEntityName(cb.getName() + " (" + cvb.getName() + ")"); StudySubjectBean ssub = (StudySubjectBean) studySubjectDAO.findByPK(ecb.getStudySubjectId()); dnb.setStudySub(ssub); dnb.setSubjectName(ssub.getLabel()); if (se != null) { dnb.setEventStart(se.getDateStarted()); dnb.setEventName(se.getName()); } dnb.setCrfName(cb.getName()); String crfStatus = resword.getString(ecb.getStage().getNameRaw()); if (crfStatus.equals("Invalid")) { crfStatus = ""; } else if (crfStatus.equals("Data Entry Complete")) { crfStatus = "Complete"; } dnb.setCrfStatus(crfStatus); String column = dnb.getColumn().trim(); if (!StringUtil.isBlank(column)) { if ("date_interviewed".equals(column)) { if (ecb.getDateInterviewed() != null) { dnb.setEntityValue(ecb.getDateInterviewed().toString()); } dnb.setEntityName(resword.getString("date_interviewed")); } else if ("interviewer_name".equals(column)) { dnb.setEntityValue(ecb.getInterviewerName()); dnb.setEntityName(resword.getString("interviewer_name")); } } dnb.setEvent(se); dnb.setStudyEventDefinitionBean(sedb); // } } else if (entityType.equalsIgnoreCase("studyEvent")) { // allNotes.add(dnb); StudyEventBean se = (StudyEventBean) sedao.findByPK(dnb.getEntityId()); StudyEventDefinitionBean sedb = (StudyEventDefinitionBean) seddao.findByPK(se.getStudyEventDefinitionId()); se.setName(sedb.getName()); dnb.setEntityName(sedb.getName()); StudySubjectBean ssub = (StudySubjectBean) studySubjectDAO.findByPK(se.getStudySubjectId()); dnb.setStudySub(ssub); dnb.setEventStart(se.getDateStarted()); dnb.setEventName(se.getName()); dnb.setSubjectName(ssub.getLabel()); String column = dnb.getColumn().trim(); if (!StringUtil.isBlank(column)) { if ("date_start".equals(column)) { if (se.getDateStarted() != null) { dnb.setEntityValue(se.getDateStarted().toString()); } dnb.setEntityName(resword.getString("start_date")); } else if ("date_end".equals(column)) { if (se.getDateEnded() != null) { dnb.setEntityValue(se.getDateEnded().toString()); } dnb.setEntityName(resword.getString("end_date")); } else if ("location".equals(column)) { dnb.setEntityValue(se.getLocation()); dnb.setEntityName(resword.getString("location")); } } dnb.setEvent(se); dnb.setStudyEventDefinitionBean(sedb); } else if (entityType.equalsIgnoreCase("itemData")) { ItemDataBean idb = (ItemDataBean) iddao.findByPK(dnb.getEntityId()); ItemBean ib = (ItemBean) idao.findByPK(idb.getItemId()); EventCRFBean ec = (EventCRFBean) ecdao.findByPK(idb.getEventCRFId()); CRFVersionBean cvb = (CRFVersionBean) cvdao.findByPK(ec.getCRFVersionId()); CRFBean cb = (CRFBean) cdao.findByPK(cvb.getCrfId()); ItemGroupMetadataBean itemGroupMetadataBean = (ItemGroupMetadataBean)igmdao.findByItemAndCrfVersion(ib.getId(), cvb.getId()); Boolean isRepeatForSure = itemGroupMetadataBean.isRepeatingGroup(); if (isRepeatForSure){ ItemGroupBean ig = (ItemGroupBean)igdao.findByPK(itemGroupMetadataBean.getItemGroupId()); dnb.setItemDataOrdinal(idb.getOrdinal()); dnb.setItemGroupName(ig.getName()); } // allNotes.add(dnb); dnb.setStageId(ec.getStage().getId()); dnb.setEntityName(ib.getName()); dnb.setEntityValue(idb.getValue()); StudyEventBean se = (StudyEventBean) sedao.findByPK(ec.getStudyEventId()); StudyEventDefinitionBean sedb = (StudyEventDefinitionBean) seddao.findByPK(se.getStudyEventDefinitionId()); se.setName(sedb.getName()); StudySubjectBean ssub = (StudySubjectBean) studySubjectDAO.findByPK(ec.getStudySubjectId()); dnb.setStudySub(ssub); dnb.setSubjectName(ssub.getLabel()); dnb.setEventStart(se.getDateStarted()); dnb.setEventName(se.getName()); dnb.setCrfName(cb.getName()); String crfStatus = resword.getString(ec.getStage().getNameRaw()); if (crfStatus.equals("Invalid")) { crfStatus = ""; } else if (crfStatus.equals("Data Entry Complete")) { crfStatus = "Complete"; } dnb.setCrfStatus(crfStatus); dnb.setEvent(se); dnb.setStudyEventDefinitionBean(sedb); } } dnb.setStudy((StudyBean)studyDao.findByPK(dnb.getStudyId())); if(dnb.getParentDnId()==0 && dnb.getChildren().size()>0) { ArrayList<DiscrepancyNoteBean> children = dnb.getChildren(); int childrenSize = children.size(); for (int j = 0; j < childrenSize; j++) { DiscrepancyNoteBean child = children.get(j); child.setSubjectName(dnb.getSubjectName()); child.setEventName(dnb.getEventName()); child.setCrfName(dnb.getCrfName()); child.setCrfStatus(dnb.getCrfStatus()); child.setEntityName(dnb.getEntityName()); child.setEntityValue(dnb.getEntityValue()); child.setStudySub(dnb.getStudySub()); child.setStudy(dnb.getStudy()); } } allNotes.add(dnb); } return allNotes; } @Override protected void mayProceed() throws InsufficientPermissionException { } }