// Look through the http-import directory and process all // the files there, oldest first. Note that these are actual // files, not queue elements. private void processHttpImportFiles() { File importDirFile = new File(TrialConfig.basepath + TrialConfig.httpImportDir); if (!importDirFile.exists()) return; File[] files = importDirFile.listFiles(); for (int k = 0; k < files.length; k++) { File next = files[k]; if (next.canRead() && next.canWrite()) { FileObject fileObject = FileObject.getObject(next); if (preprocess(fileObject)) { process(fileObject); if (!queueForDatabase(fileObject)) Log.message(Quarantine.file(next, processorServiceName)); else Log.message(processorServiceName + ": Processing complete: " + next.getName()); } // If the file still exists, then there must be a bug // somewhere; log it and quarantine the file so we don't // fall into an infinite loop. if (next.exists()) { logger.warn( "File still in queue after processing:\n" + next + "The file will be quarantined."); Log.message(Quarantine.file(next, processorServiceName)); } Thread.currentThread().yield(); } } }
/** * The DicomEventListener implementation. Listen for an event from the SCP, log the file, and move * it to the dicom-import directory for anonymization and export. * * @param event the event identifying the file that was received. */ public void dicomEventOccurred(DicomEvent event) { if ((event.getStatus() == 0) && event.serviceAsString(event.getService()).equals("C_STORE_RQ")) { File inFile = new File(event.getFilename()); Log.message(dicomImportServiceName + ": Image received: " + inFile.getName()); // Make the output directory in case it doesn't exist. File outDir = new File(TrialConfig.basepath + TrialConfig.dicomImportDir); outDir.mkdirs(); // Put the new file in it, using the overwrite attribute of the trial to determine // whether duplicate SOPInstanceUIDs are to be renamed so as not to lose them. FileObject fileObject = new FileObject(inFile); fileObject.moveToDirectory(outDir, TrialConfig.allowOverwrite()); } else if (event.getStatus() != 0xff00) Log.message(dicomImportServiceName + ": unexpected status: " + event.toStringNoPath()); }
// Create a Log4J log file with a monthly rolling appender and populate // it with information from the dataset in a csv format so the log file // can be opened and processed with a spreadsheet. private void makeTrialLogEntry(String service, DicomObject dicomObject) { if (!TrialConfig.log()) return; if (processorLog == null) { try { processorLog = Logger.getLogger("trial"); processorLog.setAdditivity(false); PatternLayout layout = new PatternLayout("%d{yyyy-MM-dd},%d{HH:mm:ss},%m%n"); File logs = new File(TrialConfig.basepath + TrialConfig.logDirectory); logs.mkdirs(); DailyRollingFileAppender appender = new DailyRollingFileAppender( layout, TrialConfig.basepath + TrialConfig.logDirectory + File.separator + TrialConfig.serviceName + ".csv", "'.'yyyy-MM"); processorLog.addAppender(appender); processorLog.setLevel((Level) Level.ALL); } catch (Exception e) { logger.warn("Unable to instantiate a trial logger"); processorLog = null; return; } } processorLog.info( service + "," + dicomObject.getPatientName() + "," + dicomObject.getPatientID() + "," + dicomObject.getModality() + "," + dicomObject.getSeriesNumber() + "," + dicomObject.getAcquisitionNumber() + "," + dicomObject.getInstanceNumber()); }
// Look through the dicom-import directory and process // all the files there. Note that these are actual files, // not queue elements. private void processDicomImportFiles() { File importDirFile = new File(TrialConfig.basepath + TrialConfig.dicomImportDir); if (!importDirFile.exists()) return; File[] files = importDirFile.listFiles(); for (int k = 0; k < files.length; k++) { File next = files[k]; if (files[k].canRead() && files[k].canWrite()) { try { boolean forceQuarantine = false; httpExportDirectories = TrialConfig.getHttpExportDirectories(); httpExportDirectoryFiles = TrialConfig.getHttpExportDirectoryFiles(); // If enabled, anonymize. // Note: in normal clinical trials, the anonymizer is enabled and de-identified // images are transmitted by the HttpExportProcessor. // For normal research applications, images are not anonymized and the document // creates directories of identified and de-identified images. In this situation, // the anonymizer is disabled and the document takes care of de-identifying the // images. // Note: in research applications, the document takes its elements from the // identified (e.g., containing PHI) image, so such documents contain PHI. if (TrialConfig.dicomImportAnonymizerEnabled()) { String exceptions = DicomAnonymizer.anonymize( next, next, dicomAnonymizerProperties, lookupTableProperties, new LocalRemapper(), false, false); if (!exceptions.equals("")) { if (exceptions.indexOf("!quarantine!") != -1) { Log.message( "<font color=\"red\">DicomAnonymizer quarantine call:<br>" + next.getName() + "</font>"); forceQuarantine = true; } else if (exceptions.indexOf("!error!") != -1) { Log.message( "<font color=\"red\">DicomAnonymizer error call: " + exceptions + "<br>" + next.getName() + "</font>"); forceQuarantine = true; } else { // Note: the anonymizer logs the exception list to Log4J, // so we just have to log it to the displayed log. Log.message("Anonymization exceptions: " + exceptions + "<br>" + next.getName()); } } else { Log.message( "<font color=\"blue\">Anonymization complete" + "<br>" + next.getName() + "</font>"); } } if (!forceQuarantine) { // get the document for this study or create it if necessary DicomObject nextObject = new DicomObject(next); MircDocument td = new MircDocument(nextObject); // put in the object and store the updated document td.insert( nextObject, TrialConfig.allowOverwrite(), TrialConfig.dicomImportAnonymizerEnabled(), dicomAnonymizerProperties, lookupTableProperties); // export the object if (httpExportDirectoryFiles != null) { for (int i = 0; i < httpExportDirectoryFiles.length; i++) { try { ExportQueueElement eqe = ExportQueueElement.createEQE(nextObject); eqe.queue(httpExportDirectoryFiles[i]); } catch (Exception e) { Log.message( processorServiceName + ": " + httpExportDirectories[i] + " export failed:" + next.getName()); logger.warn(httpExportDirectories[i] + " export failed:" + next.getName()); } } } if (!queueForDatabase(nextObject)) Log.message(Quarantine.file(next, processorServiceName)); else Log.message(processorServiceName + ": Processing complete: " + next.getName()); // log the event if logging is enabled makeTrialLogEntry("dicom-import", nextObject); } // if the file still exists, then either the object was // set for quarantining or there is a bug somewhere; // log it and quarantine the file so we don't // fall into an infinite loop. if (next.exists()) { logger.warn("Forced quarantine: " + next); Log.message(Quarantine.file(next, processorServiceName)); } } catch (Exception e) { Log.message( processorServiceName + ": Error during processing: " + next.getName() + " - " + e.getMessage()); logger.warn("Error during processing: object quarantined: " + next.getName(), e); Log.message(Quarantine.file(next, processorServiceName)); } yield(); } } }