Example #1
0
 // Process a DICOM file.
 private void process(DicomObject dicomObject) {
   try {
     dicomObject.setExtension(".dcm");
     // get the document for this study or create it if necessary
     MircDocument td = new MircDocument(dicomObject);
     // Put in the object and store the updated document.
     // Note that since all http imports should have been
     // anonymized before transmission over the internet,
     // we assume that is the case. There is no way to tell.
     td.insert(dicomObject, TrialConfig.allowOverwrite(), true, null, null);
     // export the image via DICOM if in auto mode
     dicomExportDirectories = TrialConfig.getDicomExportDirectories();
     dicomExportDirectoryFiles = TrialConfig.getDicomExportDirectoryFiles();
     if (TrialConfig.getDicomExportMode().equals("auto") && (dicomExportDirectoryFiles != null)) {
       for (int i = 0; i < dicomExportDirectoryFiles.length; i++) {
         try {
           ExportQueueElement eqe = ExportQueueElement.createEQE(dicomObject);
           eqe.queue(dicomExportDirectoryFiles[i]);
         } catch (Exception e) {
           String name = dicomObject.getFile().getName();
           Log.message(
               processorServiceName
                   + ": "
                   + dicomExportDirectories[i]
                   + " DICOM export failed:"
                   + name);
           logger.warn(dicomExportDirectories[i] + " DICOM export failed:" + name);
         }
       }
     }
     // log the object if logging is enabled
     makeTrialLogEntry("http-import", dicomObject);
   } catch (Exception notDicom) {
   }
 }
Example #2
0
  // Initialize and start the SCP
  private static void startSCP(ObjectProcessor op) {
    if (scp != null) {
      // There is already a storage SCP; stop it.
      // This throws an exception, but ignore it.
      try {
        scp.stop();
      } catch (Exception ignore) {
      }
      scp = null;
    }

    // Now get a new SCP with the new params.
    scp = getDicomStore();

    // Start listening.
    scp.addDicomEventListener(op);

    // And start the scp.
    try {
      scp.start();
      Log.message(
          dicomImportServiceName
              + ": "
              + TrialConfig.getDicomStoreAETitle()
              + " Storage SCP started on port "
              + TrialConfig.getDicomStorePort());
    } catch (Exception e) {
      Log.message(dicomImportServiceName + ": SCP failed to start<br>" + e.getMessage());
    }
  }
Example #3
0
 // Get and initialize the DICOM Storage SCP
 private static DicomStorageScp getDicomStore() {
   String aetitle, port;
   Properties p = new Properties();
   aetitle = TrialConfig.getDicomStoreAETitle();
   port = TrialConfig.getDicomStorePort();
   p.setProperty("storage-scp-aet", aetitle);
   p.setProperty("port", port);
   p.setProperty("dest", TrialConfig.basepath + TrialConfig.dicomStoreDir);
   Dicom.initialize(p);
   return Dicom.getStorageScp();
 }
Example #4
0
 // Queue a file for the DatabaseExportService.
 private boolean queueForDatabase(FileObject fileObject) {
   if (TrialConfig.getDatabaseExportMode().equals("auto")) {
     File databaseExportDirectoryFile = TrialConfig.getDatabaseExportDirectoryFile();
     try {
       ExportQueueElement eqe = ExportQueueElement.createEQE(fileObject);
       eqe.queue(databaseExportDirectoryFile);
     } catch (Exception e) {
       Log.message(
           processorServiceName
               + ": Unable to queue "
               + fileObject.getFile().getName()
               + " for database export");
       logger.warn("Unable to queue " + fileObject.getFile().getName() + " for database export");
     }
   }
   return true;
 }
Example #5
0
 // Preprocess a FileObject.
 private boolean preprocess(FileObject fileObject) {
   if (TrialConfig.getPreprocessorEnabled().equals("yes")) {
     // Load the preprocessor class specified in the TrialConfig.
     // Reload each time in case the class changes behind our back.
     PreprocessorAdapter ppa = null;
     String className = TrialConfig.getPreprocessorClassName();
     try {
       Class theClass = Class.forName(className);
       ppa = (PreprocessorAdapter) theClass.newInstance();
       if (fileObject instanceof DicomObject) return ppa.process((DicomObject) fileObject);
       if (fileObject instanceof XmlObject) return ppa.process((XmlObject) fileObject);
       if (fileObject instanceof ZipObject) return ppa.process((ZipObject) fileObject);
       return ppa.process(fileObject);
     } catch (Exception ex) {
       Log.message("Exception while loading or running the preprocessor: " + className);
       logger.warn("Exception while loading or running the preprocessor: " + className);
       return false;
     }
   }
   return true;
 }
Example #6
0
 /**
  * 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());
 }
Example #7
0
 // Load the anonymizer.properties file.
 // This function is called whenever the Clinical Trial Service is restarted,
 // allowing new anonymization scripts to be loaded.
 private void initialize() {
   reinitialize = false;
   try {
     File propFile = new File(TrialConfig.basepath + TrialConfig.dicomAnonymizerFilename);
     dicomAnonymizerProperties = new Properties();
     dicomAnonymizerProperties.load(new FileInputStream(propFile));
     File lkupFile = new File(TrialConfig.basepath + TrialConfig.lookupTableFilename);
     lookupTableProperties = new Properties();
     try {
       lookupTableProperties.load(new FileInputStream(lkupFile));
     } catch (Exception ex) {
       lookupTableProperties = null;
     }
     if (TrialConfig.dicomImportAnonymizerEnabled())
       Log.message(processorServiceName + ": DicomAnonymizer initialized");
     else Log.message(processorServiceName + ": DicomAnonymizer not enabled");
   } catch (Exception e) {
     Log.message(processorServiceName + ": Unable to configure the DicomAnonymizer");
   }
 }
Example #8
0
 // 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());
 }
Example #9
0
  // 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();
      }
    }
  }