ourLog.trace("Servlet Path: {}", servletPath);
        ourLog.trace("Request Url: {}", requestUrl);
        ourLog.trace("Context Path: {}", servletContextPath);
      }
      IdDt id = null;
      IdDt versionId = null;
      String operation = null;
      String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length());
      if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
        requestPath = requestPath.substring(1);
      }
      String fhirServerBase;
      fhirServerBase = myServerAddressStrategy.determineServerBase(theRequest);
      if (fhirServerBase.endsWith("/")) {
        fhirServerBase = fhirServerBase.substring(0, fhirServerBase.length() - 1);
      }
      String completeUrl = StringUtils.isNotBlank(theRequest.getQueryString()) ? requestUrl + "?" + theRequest.getQueryString() : requestUrl.toString();
      Map<String, String[]> params = new HashMap<String, String[]>(theRequest.getParameterMap());
      StringTokenizer tok = new StringTokenizer(requestPath, "/");
      if (tok.hasMoreTokens()) {
        resourceName = tok.nextToken();
        if (resourceName.startsWith("_")) {
          operation = resourceName;
          resourceName = null;
        }
      }
      ResourceBinding resourceBinding = null;
      BaseMethodBinding<?> resourceMethod = null;
      if ("metadata".equals(resourceName)) {
        resourceMethod = myServerConformanceMethod;
      } else if (resourceName == null) {
        resourceBinding = myNullResourceBinding;
      } else {
        resourceBinding = myResourceNameToProvider.get(resourceName);
        if (resourceBinding == null) {
          throw new InvalidRequestException("Unknown resource type '" + resourceName + "' - Server knows how to handle: " + myResourceNameToProvider.keySet());
        }
      }
      if (tok.hasMoreTokens()) {
        String nextString = tok.nextToken();
        if (nextString.startsWith("_")) {
          operation = nextString;
        } else {
          id = new IdDt(resourceName, nextString);
        }
      }
      if (tok.hasMoreTokens()) {
        String nextString = tok.nextToken();
        if (nextString.equals(Constants.PARAM_HISTORY)) {
          if (tok.hasMoreTokens()) {
            String versionString = tok.nextToken();
            if (id == null) {
              throw new InvalidRequestException("Don't know how to handle request path: " + requestPath);
            }
            id = new IdDt(resourceName + "/" + id.getIdPart() + "/_history/" + versionString);
            versionId = id;
          } else {
            operation = Constants.PARAM_HISTORY;
          }
        } else if (nextString.startsWith("_")) {
          if (operation != null) {
            throw new InvalidRequestException("URL Path contains two operations (part beginning with _): " + requestPath);
          }
          operation = nextString;
        }
      }
      // Secondary is for things like ..../_tags/_delete
      String secondaryOperation = null;
      while (tok.hasMoreTokens()) {
        String nextString = tok.nextToken();
        if (operation == null) {
          operation = nextString;
        } else if (secondaryOperation == null) {
          secondaryOperation = nextString;
        } else {
          throw new InvalidRequestException("URL path has unexpected token '" + nextString + "' at the end: " + requestPath);
        }
      }
      if (theRequestType == RequestType.PUT && versionId == null) {
        String contentLocation = theRequest.getHeader("Content-Location");
        if (contentLocation != null) {
          versionId = new IdDt(contentLocation);
        }
      }
      // TODO: look for more tokens for version, compartments, etc...