protected void streamOperationOutcome(
      BaseServerResponseException theE,
      RestfulServer theServer,
      EncodingEnum theEncodingNotNull,
      HttpServletResponse theResponse,
      RequestDetails theRequest)
      throws IOException {
    theResponse.setStatus(theE.getStatusCode());

    theServer.addHeadersToResponse(theResponse);

    if (theE.getOperationOutcome() != null) {
      theResponse.setContentType(theEncodingNotNull.getResourceContentType());
      IParser parser = theEncodingNotNull.newParser(theServer.getFhirContext());
      parser.setPrettyPrint(RestfulServerUtils.prettyPrintResponse(theServer, theRequest));
      Writer writer = theResponse.getWriter();
      try {
        parser.encodeResourceToWriter(theE.getOperationOutcome(), writer);
      } finally {
        writer.close();
      }
    } else {
      theResponse.setContentType(Constants.CT_TEXT);
      Writer writer = theResponse.getWriter();
      try {
        writer.append(theE.getMessage());
      } finally {
        writer.close();
      }
    }
  }
  public void process(Bundle bundle) {
    Bundle response = null;
    RecordMatchResultsBuilder respBuilder;

    if (BundleType.MESSAGE.equals(bundle.getType())) {
      // Create a CSV data source for FRIL
      final File jobDir = newRunDir(workDir);

      final List<BundleEntryComponent> bundleEntries = bundle.getEntry();
      try {
        // The first entry is supposed to be the MessageHeader
        // This will force an exception if not true.
        final MessageHeader msgHdr = (MessageHeader) bundleEntries.get(0).getResource();
        // This log statement keeps above from getting optimized out
        LOG.trace("msg hdr id {}", msgHdr.getId());

        Parameters masterQryParams = null;
        Parameters queryQryParams = null;
        String masterSearchUrl = null;
        String querySearchUrl = null;
        String masterServerBase = null;
        String queryServerBase = null;
        String resourceType = "Patient";
        boolean isDeduplication = true;

        // Find the Parameters resources that contain the search parameters
        // and use those to construct search Urls
        for (BundleEntryComponent entry : bundleEntries) {
          Resource r = entry.getResource();
          LOG.debug("Found Resource type: " + r.getResourceType().toString());
          if (ResourceType.Parameters.equals(r.getResourceType())) {
            Parameters params = (Parameters) r;
            List<ParametersParameterComponent> paramList = params.getParameter();
            // Now look for the parameter with name, resourceType.
            ParametersParameterComponent p = ParametersUtil.findByName(paramList, RESOURCE_TYPE);
            if (p != null) {
              resourceType = p.getValue().toString();
            }
            // Find parameter that distinguishes between master and query sets
            p = ParametersUtil.findByName(paramList, "type");
            if (p != null) {
              String val = p.getValue().toString();
              if (val.equalsIgnoreCase(MASTER)) {
                masterQryParams = params;
                masterSearchUrl = buildSearchUrl(params);
                masterServerBase = getServerBase(resourceType, masterQryParams);
              } else if (val.equalsIgnoreCase(QUERY)) {
                queryQryParams = params;
                querySearchUrl = buildSearchUrl(params);
                queryServerBase = getServerBase(resourceType, queryQryParams);
              }
            }
          }
        }

        if (masterSearchUrl == null) {
          final String errMsg =
              "Required Parameter for master record set is missing, bundle: " + bundle.getId();
          LOG.warn(errMsg);
          // Construct and return an error result
          respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
          respBuilder.outcomeIssueDiagnostics(errMsg);
          response = respBuilder.build();
          getProducer().sendBody(getProducerEndpointUri(), response);
          return;
        }

        LoggingInterceptor loggingInterceptor = null;
        if (LOG.isDebugEnabled()) {
          loggingInterceptor = new LoggingInterceptor(true);
          fhirRestClient.registerInterceptor(loggingInterceptor);
        }

        int numMasterRecs = 0;
        try {
          // Retrieve the data associated with the search urls
          numMasterRecs = retrieveAndStoreData(masterSearchUrl, masterServerBase, jobDir, "master");

          if (querySearchUrl != null) {
            isDeduplication = false;
            retrieveAndStoreData(querySearchUrl, queryServerBase, jobDir, "query");
          }

        } catch (BaseServerResponseException e) {
          final String errMsg =
              String.format(
                  "Error response from server.  code: %d, %s", e.getStatusCode(), e.getMessage());
          LOG.warn(errMsg);
          // Construct and return an error result
          respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
          respBuilder.outcomeIssueDiagnostics(errMsg);
          response = respBuilder.build();
          getProducer().sendBody(getProducerEndpointUri(), response);
          return;
        } catch (Exception e) {
          final String errMsg = String.format("Unable to retrieve messages: %s", e.getMessage());
          LOG.warn(errMsg, e);
          // Construct and return an error result
          respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
          respBuilder.outcomeIssueDiagnostics(errMsg);
          response = respBuilder.build();
          getProducer().sendBody(getProducerEndpointUri(), response);
          return;
        } finally {
          if (loggingInterceptor != null) {
            fhirRestClient.unregisterInterceptor(loggingInterceptor);
          }
        }

        // if no records were returned for the master record set query
        if (numMasterRecs == 0) {
          respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.OK);
          respBuilder.outcomeDetailText("No Records Found in Master Record Set");
          response = respBuilder.build();
        } else {
          final File configFile = prepareMatchingRuleConfiguration(isDeduplication, jobDir);

          // Perform the Match Operation
          LOG.debug("About to Start FRIL w/ config {}", configFile.getAbsolutePath());
          final int numMatches = findMatches(isDeduplication, configFile);
          LOG.info("FRIL Number of Matches: {}", numMatches);

          if (numMatches == 0) {
            respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.OK);
            respBuilder.outcomeDetailText("No Matches Found");
            response = respBuilder.build();

          } else if (numMatches > 0) {
            // Find the name of the file containing duplicates from the config
            // file
            final File dupsFile = getDuplicatesFile(configFile);
            // Ensure the duplicates file exists
            if (!dupsFile.exists()) {
              final String errMsg = "Unable to find duplicates file";
              LOG.error(errMsg + " at " + dupsFile.getAbsolutePath());
              throw new FileNotFoundException(errMsg);
            }

            // Construct results
            respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.OK);
            respBuilder.outcomeDetailText("Deduplication Complete");
            respBuilder.duplicates(dupsFile);
            response = respBuilder.build();

          } else {
            final String errMsg = "Unknown Processing Error";
            LOG.error("{} bundleId: {}", errMsg, bundle.getId());

            // Construct an error result
            respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
            respBuilder.outcomeIssueDiagnostics(errMsg);
            response = respBuilder.build();
          }
        }

      } catch (Exception e) {
        final String errMsg = "Unexpected Error";
        LOG.error("Processing bundle: {}", bundle.getId(), e);

        // Construct an error result
        respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
        respBuilder.outcomeIssueDiagnostics(errMsg);
        try {
          response = respBuilder.build();
        } catch (IOException ioe) {
          // only so many times we can attempt to send a response; log error
          LOG.error("Unable to Send Error Response. request bundle: {}", bundle.getId(), ioe);
        }
      }

      if (deleteJobResults) {
        // Delete the Job Results folder and content
        deleteFolder(jobDir);
      }
    } else {
      final String errMsg = "Unsupported Bundle type: " + bundle.getType().toString();
      LOG.info("{} msgId: {}", errMsg, bundle.getId());

      // Construct an error result
      respBuilder = new RecordMatchResultsBuilder(bundle, ResponseType.FATALERROR);
      respBuilder.outcomeIssueDiagnostics(errMsg);
      try {
        response = respBuilder.build();
      } catch (IOException e) {
        // only so many times we can attempt to send a response; log error
        LOG.error("Unable to Send Error Response. request bundle: {}", bundle.getId());
      }
    }

    // Send the response back to the requester
    if (response != null) {
      getProducer().sendBody(getProducerEndpointUri(), response);
    } else {
      LOG.error("Null Response for request! bundleId: {}", bundle.getId());
    }
  }
Пример #3
0
  private Bundle batch(final RequestDetails theRequestDetails, Bundle theRequest) {
    ourLog.info("Beginning batch with {} resources", theRequest.getEntry().size());
    long start = System.currentTimeMillis();

    TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
    txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

    Bundle resp = new Bundle();
    resp.setType(BundleType.BATCHRESPONSE);
    OperationOutcome ooResp = new OperationOutcome();
    resp.addEntry().setResource(ooResp);

    /*
     * For batch, we handle each entry as a mini-transaction in its own database transaction so that if one fails, it doesn't prevent others
     */

    for (final BundleEntryComponent nextRequestEntry : theRequest.getEntry()) {

      TransactionCallback<Bundle> callback =
          new TransactionCallback<Bundle>() {
            @Override
            public Bundle doInTransaction(TransactionStatus theStatus) {
              Bundle subRequestBundle = new Bundle();
              subRequestBundle.setType(BundleType.TRANSACTION);
              subRequestBundle.addEntry(nextRequestEntry);

              Bundle subResponseBundle =
                  transaction(
                      (ServletRequestDetails) theRequestDetails,
                      subRequestBundle,
                      "Batch sub-request");
              return subResponseBundle;
            }
          };

      BaseServerResponseException caughtEx;
      try {
        Bundle nextResponseBundle = txTemplate.execute(callback);
        caughtEx = null;

        BundleEntryComponent subResponseEntry = nextResponseBundle.getEntry().get(0);
        resp.addEntry(subResponseEntry);
        /*
         * If the individual entry didn't have a resource in its response, bring the sub-transaction's OperationOutcome across so the client can see it
         */
        if (subResponseEntry.getResource() == null) {
          subResponseEntry.setResource(nextResponseBundle.getEntry().get(0).getResource());
        }

      } catch (BaseServerResponseException e) {
        caughtEx = e;
      } catch (Throwable t) {
        ourLog.error("Failure during BATCH sub transaction processing", t);
        caughtEx = new InternalErrorException(t);
      }

      if (caughtEx != null) {
        BundleEntryComponent nextEntry = resp.addEntry();

        OperationOutcome oo = new OperationOutcome();
        oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
        nextEntry.setResource(oo);

        BundleEntryResponseComponent nextEntryResp = nextEntry.getResponse();
        nextEntryResp.setStatus(toStatusString(caughtEx.getStatusCode()));
      }
    }

    long delay = System.currentTimeMillis() - start;
    ourLog.info("Batch completed in {}ms", new Object[] {delay});
    ooResp
        .addIssue()
        .setSeverity(IssueSeverity.INFORMATION)
        .setDiagnostics("Batch completed in " + delay + "ms");

    return resp;
  }