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();
      }
    }
  }
    @Override
    public String lookup(String theKey) {

      /*
       * TODO: this method could be made more efficient through some sort of lookup map
       */

      if ("operationType".equals(theKey)) {
        if (myRequestDetails.getRestOperationType() != null) {
          return myRequestDetails.getRestOperationType().getCode();
        }
        return "";
      } else if ("operationName".equals(theKey)) {
        if (myRequestDetails.getRestOperationType() != null) {
          switch (myRequestDetails.getRestOperationType()) {
            case EXTENDED_OPERATION_INSTANCE:
            case EXTENDED_OPERATION_SERVER:
            case EXTENDED_OPERATION_TYPE:
              return myRequestDetails.getOperation();
            default:
              return "";
          }
        } else {
          return "";
        }
      } else if ("id".equals(theKey)) {
        if (myRequestDetails.getId() != null) {
          return myRequestDetails.getId().getValue();
        }
        return "";
      } else if ("servletPath".equals(theKey)) {
        return StringUtils.defaultString(myRequest.getServletPath());
      } else if ("idOrResourceName".equals(theKey)) {
        if (myRequestDetails.getId() != null) {
          return myRequestDetails.getId().getValue();
        }
        if (myRequestDetails.getResourceName() != null) {
          return myRequestDetails.getResourceName();
        }
        return "";
      } else if (theKey.equals("requestParameters")) {
        StringBuilder b = new StringBuilder();
        for (Entry<String, String[]> next : myRequestDetails.getParameters().entrySet()) {
          for (String nextValue : next.getValue()) {
            if (b.length() == 0) {
              b.append('?');
            } else {
              b.append('&');
            }
            try {
              b.append(URLEncoder.encode(next.getKey(), "UTF-8"));
              b.append('=');
              b.append(URLEncoder.encode(nextValue, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
              throw new ca.uhn.fhir.context.ConfigurationException("UTF-8 not supported", e);
            }
          }
        }
        return b.toString();
      } else if (theKey.startsWith("requestHeader.")) {
        String val = myRequest.getHeader(theKey.substring("requestHeader.".length()));
        return StringUtils.defaultString(val);
      } else if (theKey.startsWith("remoteAddr")) {
        return StringUtils.defaultString(myRequest.getRemoteAddr());
      } else if (theKey.equals("responseEncodingNoDefault")) {
        EncodingEnum encoding =
            RestfulServerUtils.determineResponseEncodingNoDefault(
                myRequestDetails, myRequestDetails.getServer().getDefaultResponseEncoding());
        if (encoding != null) {
          return encoding.name();
        } else {
          return "";
        }
      } else if (theKey.equals("exceptionMessage")) {
        return myException != null ? myException.getMessage() : null;
      } else if (theKey.equals("requestUrl")) {
        return myRequest.getRequestURL().toString();
      } else if (theKey.equals("requestVerb")) {
        return myRequest.getMethod();
      } else if (theKey.equals("requestBodyFhir")) {
        String contentType = myRequest.getContentType();
        if (isNotBlank(contentType)) {
          int colonIndex = contentType.indexOf(';');
          if (colonIndex != -1) {
            contentType = contentType.substring(0, colonIndex);
          }
          contentType = contentType.trim();

          EncodingEnum encoding = EncodingEnum.forContentType(contentType);
          if (encoding != null) {
            byte[] requestContents = myRequestDetails.loadRequestContents();
            return new String(requestContents, Charsets.UTF_8);
          }
        }
        return "";
      }

      return "!VAL!";
    }
 /**
  * This method is called for nested bundles (e.g. if we received a transaction with an entry that
  * was a GET search, this method is called on the bundle for the search result, that will be
  * placed in the outer bundle). This method applies the _summary and _content parameters to the
  * output of that bundle.
  *
  * <p>TODO: This isn't the most efficient way of doing this.. hopefully we can come up with
  * something better in the future.
  */
 private IBaseResource filterNestedBundle(
     RequestDetails theRequestDetails, IBaseResource theResource) {
   IParser p = getContext().newJsonParser();
   RestfulServerUtils.configureResponseParser(theRequestDetails, p);
   return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
 }
  private Object returnResponse(
      IRestfulServer<?> theServer,
      RequestDetails theRequest,
      MethodOutcome response,
      IBaseResource originalOutcome,
      IBaseResource resource)
      throws IOException {
    boolean allowPrefer = false;
    int operationStatus = getOperationStatus(response);
    IBaseResource outcome = originalOutcome;

    if (ourOperationsWhichAllowPreferHeader.contains(getRestOperationType())) {
      allowPrefer = true;
    }

    if (resource != null && allowPrefer) {
      String prefer = theRequest.getHeader(Constants.HEADER_PREFER);
      PreferReturnEnum preferReturn = RestfulServerUtils.parsePreferHeader(prefer);
      if (preferReturn != null) {
        if (preferReturn == PreferReturnEnum.REPRESENTATION) {
          outcome = resource;
        }
      }
    }

    for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
      IServerInterceptor next = theServer.getInterceptors().get(i);
      boolean continueProcessing = next.outgoingResponse(theRequest, outcome);
      if (!continueProcessing) {
        return null;
      }
    }

    IRestfulResponse restfulResponse = theRequest.getResponse();

    if (response != null) {
      if (response.getResource() != null) {
        restfulResponse.setOperationResourceLastUpdated(
            RestfulServerUtils.extractLastUpdatedFromResource(response.getResource()));
      }

      IIdType responseId = response.getId();
      if (responseId != null && responseId.getResourceType() == null && responseId.hasIdPart()) {
        responseId = responseId.withResourceType(getResourceName());
      }

      if (responseId != null) {
        String serverBase = theRequest.getFhirServerBase();
        responseId =
            RestfulServerUtils.fullyQualifyResourceIdOrReturnNull(
                theServer, resource, serverBase, responseId);
        restfulResponse.setOperationResourceId(responseId);
      }
    }

    boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
    Set<SummaryEnum> summaryMode = Collections.emptySet();

    return restfulResponse.streamResponseAsResource(
        outcome, prettyPrint, summaryMode, operationStatus, null, theRequest.isRespondGzip(), true);
    //		return theRequest.getResponse().returnResponse(ParseAction.create(outcome), operationStatus,
    // allowPrefer, response, getResourceName());
  }
  @Override
  public void invokeServer(RestfulServer theServer, Request theRequest)
      throws BaseServerResponseException, IOException {

    // Pretty print
    boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);

    // Narrative mode
    NarrativeModeEnum narrativeMode = RestfulServerUtils.determineNarrativeMode(theRequest);

    // Determine response encoding
    EncodingEnum responseEncoding =
        RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());

    // Is this request coming from a browser
    String uaHeader = theRequest.getServletRequest().getHeader("user-agent");
    boolean requestIsBrowser = false;
    if (uaHeader != null && uaHeader.contains("Mozilla")) {
      requestIsBrowser = true;
    }

    Object requestObject = parseRequestObject(theRequest);

    // Method params
    Object[] params = new Object[getParameters().size()];
    for (int i = 0; i < getParameters().size(); i++) {
      IParameter param = getParameters().get(i);
      if (param != null) {
        params[i] = param.translateQueryParametersIntoServerArgument(theRequest, requestObject);
      }
    }

    Object resultObj = invokeServer(theRequest, params);

    Integer count = RestfulServerUtils.extractCountParameter(theRequest.getServletRequest());
    boolean respondGzip = theRequest.isRespondGzip();
    HttpServletResponse response = theRequest.getServletResponse();
    switch (getReturnType()) {
      case BUNDLE:
        {
          if (getMethodReturnType() == MethodReturnTypeEnum.BUNDLE_RESOURCE) {
            IResource resource;
            if (resultObj instanceof IBundleProvider) {
              IBundleProvider result = (IBundleProvider) resultObj;
              resource = result.getResources(0, 1).get(0);
            } else {
              resource = (IResource) resultObj;
            }

            /*
             * We assume that the bundle we got back from the handling method may not have everything populated
             * (e.g. self links, bundle type, etc) so we do that here.
             */
            IVersionSpecificBundleFactory bundleFactory =
                theServer.getFhirContext().newBundleFactory();
            bundleFactory.initializeWithBundleResource(resource);
            bundleFactory.addRootPropertiesToBundle(
                null,
                theRequest.getFhirServerBase(),
                theRequest.getCompleteUrl(),
                count,
                getResponseBundleType());

            for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
              IServerInterceptor next = theServer.getInterceptors().get(i);
              boolean continueProcessing =
                  next.outgoingResponse(
                      theRequest,
                      resource,
                      theRequest.getServletRequest(),
                      theRequest.getServletResponse());
              if (!continueProcessing) {
                ourLog.debug("Interceptor {} returned false, not continuing processing");
                return;
              }
            }
            RestfulServerUtils.streamResponseAsResource(
                theServer,
                response,
                resource,
                responseEncoding,
                prettyPrint,
                requestIsBrowser,
                narrativeMode,
                Constants.STATUS_HTTP_200_OK,
                respondGzip,
                theRequest.getFhirServerBase(),
                isAddContentLocationHeader());
            break;
          } else {
            Set<Include> includes = getRequestIncludesFromParams(params);

            IBundleProvider result = (IBundleProvider) resultObj;
            if (count == null) {
              count = result.preferredPageSize();
            }

            IVersionSpecificBundleFactory bundleFactory =
                theServer.getFhirContext().newBundleFactory();
            bundleFactory.initializeBundleFromBundleProvider(
                theServer,
                result,
                responseEncoding,
                theRequest.getFhirServerBase(),
                theRequest.getCompleteUrl(),
                prettyPrint,
                0,
                count,
                null,
                getResponseBundleType(),
                includes);
            Bundle bundle = bundleFactory.getDstu1Bundle();
            if (bundle != null) {
              for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
                IServerInterceptor next = theServer.getInterceptors().get(i);
                boolean continueProcessing =
                    next.outgoingResponse(
                        theRequest,
                        bundle,
                        theRequest.getServletRequest(),
                        theRequest.getServletResponse());
                if (!continueProcessing) {
                  ourLog.debug("Interceptor {} returned false, not continuing processing");
                  return;
                }
              }
              RestfulServerUtils.streamResponseAsBundle(
                  theServer,
                  response,
                  bundle,
                  responseEncoding,
                  theRequest.getFhirServerBase(),
                  prettyPrint,
                  narrativeMode,
                  respondGzip,
                  requestIsBrowser);
            } else {
              IBaseResource resBundle = bundleFactory.getResourceBundle();
              for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
                IServerInterceptor next = theServer.getInterceptors().get(i);
                boolean continueProcessing =
                    next.outgoingResponse(
                        theRequest,
                        resBundle,
                        theRequest.getServletRequest(),
                        theRequest.getServletResponse());
                if (!continueProcessing) {
                  ourLog.debug("Interceptor {} returned false, not continuing processing");
                  return;
                }
              }
              RestfulServerUtils.streamResponseAsResource(
                  theServer,
                  response,
                  (IResource) resBundle,
                  responseEncoding,
                  prettyPrint,
                  requestIsBrowser,
                  narrativeMode,
                  Constants.STATUS_HTTP_200_OK,
                  theRequest.isRespondGzip(),
                  theRequest.getFhirServerBase(),
                  isAddContentLocationHeader());
            }

            break;
          }
        }
      case RESOURCE:
        {
          IBundleProvider result = (IBundleProvider) resultObj;
          if (result.size() == 0) {
            throw new ResourceNotFoundException(theRequest.getId());
          } else if (result.size() > 1) {
            throw new InternalErrorException("Method returned multiple resources");
          }

          IResource resource = result.getResources(0, 1).get(0);

          for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
            IServerInterceptor next = theServer.getInterceptors().get(i);
            boolean continueProcessing =
                next.outgoingResponse(
                    theRequest,
                    resource,
                    theRequest.getServletRequest(),
                    theRequest.getServletResponse());
            if (!continueProcessing) {
              return;
            }
          }

          RestfulServerUtils.streamResponseAsResource(
              theServer,
              response,
              resource,
              responseEncoding,
              prettyPrint,
              requestIsBrowser,
              narrativeMode,
              Constants.STATUS_HTTP_200_OK,
              respondGzip,
              theRequest.getFhirServerBase(),
              isAddContentLocationHeader());
          break;
        }
    }
  }