void doPost(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);
      rejectIfNoneMatch(req);
      rejectIfMatch(req);

      final Map<String, String[]> parameters = req.getParameterMap();
      final String action = asSingleValue(PARAM_ACTION, getParameter(req, PARAM_ACTION));
      if (action.equalsIgnoreCase(ACTION_ID_CREATE)) {
        final JsonValue content = getJsonContent(req);
        final CreateRequest request = Requests.newCreateRequest(getResourceName(req), content);
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (name.equalsIgnoreCase(PARAM_ACTION)) {
            // Ignore - already handled.
          } else if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      } else {
        // Action request.
        final JsonValue content = getJsonActionContent(req);
        final ActionRequest request =
            Requests.newActionRequest(getResourceName(req), action).setContent(content);
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (name.equalsIgnoreCase(PARAM_ACTION)) {
            // Ignore - already handled.
          } else if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  /**
   * Persist the supplied {@link JsonValue} {@code value} as the new state of this singleton
   * relationship on {@code resourceId}.
   *
   * <p><em>This is currently the only means of creating an instance of this singleton</em>
   *
   * @param context The context of this request
   * @param resourceId Id of the resource relation fields in value are to be memebers of
   * @param value A {@link JsonValue} map of relationship fields and their values
   * @return The persisted instance of {@code value}
   */
  @Override
  public Promise<JsonValue, ResourceException> setRelationshipValueForResource(
      Context context, String resourceId, JsonValue value) {
    if (value.isNotNull()) {
      try {
        final JsonValue id = value.get(FIELD_ID);

        // Update if we got an id, otherwise replace
        if (id != null && id.isNotNull()) {
          final UpdateRequest updateRequest = Requests.newUpdateRequest("", value);
          updateRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return updateInstance(context, value.get(FIELD_ID).asString(), updateRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        } else { // no id, replace current instance
          clear(context, resourceId);

          final CreateRequest createRequest = Requests.newCreateRequest("", value);
          createRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return createInstance(context, createRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        }
      } catch (ResourceException e) {
        return e.asPromise();
      }

    } else {
      clear(context, resourceId);
      return newResultPromise(json(null));
    }
  }
  void doPut(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);

      if (req.getHeader(HEADER_IF_MATCH) != null && req.getHeader(HEADER_IF_NONE_MATCH) != null) {
        // FIXME: i18n
        throw new PreconditionFailedException(
            "Simultaneous use of If-Match and If-None-Match not " + "supported for PUT requests");
      }

      final Map<String, String[]> parameters = req.getParameterMap();
      final JsonValue content = getJsonContent(req);

      final String rev = getIfNoneMatch(req);
      if (ETAG_ANY.equals(rev)) {
        // This is a create with a user provided resource ID: split the
        // path into the parent resource name and resource ID.
        final String resourceName = getResourceName(req);
        final int i = resourceName.lastIndexOf('/');
        final CreateRequest request;
        if (resourceName.isEmpty()) {
          // FIXME: i18n.
          throw new BadRequestException("No new resource ID in HTTP PUT request");
        } else if (i < 0) {
          // We have a pathInfo of the form "{id}"
          request = Requests.newCreateRequest(EMPTY_STRING, content);
          request.setNewResourceId(resourceName);
        } else {
          // We have a pathInfo of the form "{container}/{id}"
          request = Requests.newCreateRequest(resourceName.substring(0, i), content);
          request.setNewResourceId(resourceName.substring(i + 1));
        }
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      } else {
        final UpdateRequest request =
            Requests.newUpdateRequest(getResourceName(req), content).setRevision(getIfMatch(req));
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }