@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!";
    }
  @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;
        }
    }
  }