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()); } }
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; }
<T> T invokeClient( FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint, boolean theLogRequestAndResponse) { if (!myDontValidateConformance) { myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this); } // TODO: handle non 2xx status codes by throwing the correct exception, // and ensure it's passed upwards HttpRequestBase httpRequest; HttpResponse response; try { Map<String, List<String>> params = createExtraParams(); if (theEncoding == EncodingEnum.XML) { params.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); } else if (theEncoding == EncodingEnum.JSON) { params.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); } if (thePrettyPrint == Boolean.TRUE) { params.put( Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE)); } EncodingEnum encoding = getEncoding(); if (theEncoding != null) { encoding = theEncoding; } httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding, thePrettyPrint); if (theLogRequestAndResponse) { ourLog.info("Client invoking: {}", httpRequest); if (httpRequest instanceof HttpEntityEnclosingRequest) { HttpEntity entity = ((HttpEntityEnclosingRequest) httpRequest).getEntity(); if (entity.isRepeatable()) { String content = IOUtils.toString(entity.getContent()); ourLog.info("Client request body: {}", content); } } } for (IClientInterceptor nextInterceptor : myInterceptors) { nextInterceptor.interceptRequest(httpRequest); } response = myClient.execute(httpRequest); for (IClientInterceptor nextInterceptor : myInterceptors) { nextInterceptor.interceptResponse(response); } } catch (DataFormatException e) { throw new FhirClientConnectionException(e); } catch (IOException e) { throw new FhirClientConnectionException(e); } try { String mimeType; if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatusLine().getStatusCode()) { mimeType = null; } else { ContentType ct = ContentType.get(response.getEntity()); mimeType = ct != null ? ct.getMimeType() : null; } Map<String, List<String>> headers = new HashMap<String, List<String>>(); if (response.getAllHeaders() != null) { for (Header next : response.getAllHeaders()) { String name = next.getName().toLowerCase(); List<String> list = headers.get(name); if (list == null) { list = new ArrayList<String>(); headers.put(name, list); } list.add(next.getValue()); } } if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() > 299) { String body = null; Reader reader = null; try { reader = createReaderFromResponse(response); body = IOUtils.toString(reader); } catch (Exception e) { ourLog.debug("Failed to read input stream", e); } finally { IOUtils.closeQuietly(reader); } String message = "HTTP " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); BaseOperationOutcome oo = null; if (Constants.CT_TEXT.equals(mimeType)) { message = message + ": " + body; } else { EncodingEnum enc = EncodingEnum.forContentType(mimeType); if (enc != null) { IParser p = enc.newParser(theContext); try { // TODO: handle if something other than OO comes back oo = (BaseOperationOutcome) p.parseResource(body); if (oo.getIssueFirstRep().getDetailsElement().isEmpty() == false) { message = message + ": " + oo.getIssueFirstRep().getDetailsElement().getValue(); } } catch (Exception e) { ourLog.debug("Failed to process OperationOutcome response"); } } } keepResponseAndLogIt(theLogRequestAndResponse, response, body); BaseServerResponseException exception = BaseServerResponseException.newInstance( response.getStatusLine().getStatusCode(), message); exception.setOperationOutcome(oo); if (body != null) { exception.setResponseBody(body); } throw exception; } if (binding instanceof IClientResponseHandlerHandlesBinary) { IClientResponseHandlerHandlesBinary<T> handlesBinary = (IClientResponseHandlerHandlesBinary<T>) binding; if (handlesBinary.isBinary()) { InputStream reader = response.getEntity().getContent(); try { if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) { byte[] responseBytes = IOUtils.toByteArray(reader); if (myKeepResponses) { myLastResponse = response; myLastResponseBody = null; } String message = "HTTP " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); if (theLogRequestAndResponse) { ourLog.info("Client response: {} - {} bytes", message, responseBytes.length); } else { ourLog.trace("Client response: {} - {} bytes", message, responseBytes.length); } reader = new ByteArrayInputStream(responseBytes); } return handlesBinary.invokeClient( mimeType, reader, response.getStatusLine().getStatusCode(), headers); } finally { IOUtils.closeQuietly(reader); } } } Reader reader = createReaderFromResponse(response); if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) { String responseString = IOUtils.toString(reader); keepResponseAndLogIt(theLogRequestAndResponse, response, responseString); reader = new StringReader(responseString); } try { return binding.invokeClient( mimeType, reader, response.getStatusLine().getStatusCode(), headers); } finally { IOUtils.closeQuietly(reader); } } catch (IllegalStateException e) { throw new FhirClientConnectionException(e); } catch (IOException e) { throw new FhirClientConnectionException(e); } finally { if (response instanceof CloseableHttpResponse) { try { ((CloseableHttpResponse) response).close(); } catch (IOException e) { ourLog.debug("Failed to close response", e); } } } }