/**
   * Internally create a cse base based on the restconf call which is designed to be called from a
   * provisioning server or management app.
   *
   * @param onem2mResponse response
   */
  public void provisionCse(ResponsePrimitive onem2mResponse) {

    this.crudMonitor.enter();
    try {
      String cseId = this.getPrimitive("CSE_ID");
      if (cseId == null) {
        onem2mResponse.setRSC(Onem2m.ResponseStatusCode.BAD_REQUEST, "CSE_ID not specified!");
        return;
      }
      String cseType = this.getPrimitive("CSE_TYPE");
      if (cseType == null) {
        cseType = "IN-CSE";
      } else if (!cseType.contentEquals(
          "IN-CSE")) { // TODO: what is the difference between CSE types
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.BAD_REQUEST, "IN-CSE is the only one supported :-(");
        return;
      }

      this.setPrimitive(RequestPrimitive.RESOURCE_TYPE, Onem2m.ResourceType.CSE_BASE);
      this.setPrimitive(RequestPrimitive.NAME, cseId);
      this.setResourceName(cseId);

      if (Onem2mDb.getInstance().findCseByName(cseId)) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.ALREADY_EXISTS, "CSE name already exists: " + cseId);
        return;
      }

      this.setPrimitive(RequestPrimitive.CONTENT_FORMAT, Onem2m.ContentFormat.JSON);
      JSONObject jCse = new JSONObject();
      jCse.put(ResourceCse.CSE_ID, cseId);
      jCse.put(ResourceCse.CSE_TYPE, cseType);
      JSONObject j = new JSONObject();
      j.put(Onem2m.ResourceTypeString.CSE_BASE, jCse);
      this.setPrimitive(RequestPrimitive.CONTENT, j.toString());

      // process the resource specific attributes
      ResourceContentProcessor.handleCreate(this, onem2mResponse);
      if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
        return;
      }

      // TODO: see TS0004 6.8
      // if the create was successful, ie no error has already happened, set CREATED for status code
      // here
      if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) == null) {
        onem2mResponse.setPrimitive(
            ResponsePrimitive.RESPONSE_STATUS_CODE,
            "Provisioned cseBase: " + cseId + " type: " + cseType);
      }

      // TODO: add default ACP here?
      //            RequestPrimitive defaultACPrequest = new RequestPrimitive();
      //            defaultACPrequest.setPrimitive("protocol","Http");
      //            defaultACPrequest.setPrimitive("contentFormat","json");
      //            defaultACPrequest.setPrimitive("to","/"+ cseId);
      //            defaultACPrequest.setPrimitive("fr","//localhost:10000");
      //            defaultACPrequest.setPrimitive("rqi","12345");
      //            defaultACPrequest.setPrimitive("ot","NOW");
      //            defaultACPrequest.setPrimitive("ty","1");
      //            defaultACPrequest.setPrimitive("rcn","1");
      //            defaultACPrequest.setPrimitive("op","1");
      //            defaultACPrequest.setPrimitive("pc","{\n" +
      //                    "\n" +
      //                    "    \"m2m:acp\":{\n" +
      //                    "      \"pv\":\n" +
      //                    "        {\"acr\":[{\n" +
      //                    "              \n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":35\n" +
      //                    "              \n" +
      //                    "        },\n" +
      //                    "         {\n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \n" +
      //                    "          \"acop\":35\n" +
      //                    "         }\n" +
      //                    "        \n" +
      //                    "        ]},\n" +
      //                    "        \n" +
      //                    "      \"pvs\":\n" +
      //                    "        {\"acr\":[{\n" +
      //                    "              \n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":7\n" +
      //                    "              \n" +
      //                    "        },\n" +
      //                    "         {\n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":9\n" +
      //                    "         }\n" +
      //                    "        \n" +
      //                    "        ]}\n" +
      //                    "       \n" +
      //                    "    }\n" +
      //                    "  \n" +
      //                    "}");
      //            ResourceContentProcessor.handleCreate(defaultACPrequest, onem2mResponse);

      //            this.setPrimitive("to","/"+ cseId);
      //            this.setPrimitive("ty","1");
      //            this.setPrimitive("pc","{\n" +
      //                    "\n" +
      //                    "    \"m2m:acp\":{\n" +
      //                    "      \"pv\":\n" +
      //                    "        {\"acr\":[{\n" +
      //                    "              \n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":35\n" +
      //                    "              \n" +
      //                    "        },\n" +
      //                    "         {\n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \n" +
      //                    "          \"acop\":35\n" +
      //                    "         }\n" +
      //                    "        \n" +
      //                    "        ]},\n" +
      //                    "        \n" +
      //                    "      \"pvs\":\n" +
      //                    "        {\"acr\":[{\n" +
      //                    "              \n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":7\n" +
      //                    "              \n" +
      //                    "        },\n" +
      //                    "         {\n" +
      //                    "          \"acor\" : [\"111\",\"222\"],\n" +
      //                    "          \"acop\":9\n" +
      //                    "         }\n" +
      //                    "        \n" +
      //                    "        ]}\n" +
      //                    "       \n" +
      //                    "    }\n" +
      //                    "  \n" +
      //                    "}");
      //            ResourceContentProcessor.handleCreate(this, onem2mResponse);
    } finally {
      this.crudMonitor.leave();
    }
  }
  /**
   * Handle update
   *
   * @param onem2mResponse response
   */
  public void handleOperationUpdate(ResponsePrimitive onem2mResponse) {

    // Use table TS0004: 7.1.1.1-1 to validate UPDATE specific parameters that were not handled in
    // the calling routine

    // ensure the update has content ...
    String cf = getPrimitive(RequestPrimitive.CONTENT_FORMAT);
    if (cf == null) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.INSUFFICIENT_ARGUMENTS,
          "CONTENT_FORMAT(" + RequestPrimitive.CONTENT_FORMAT + ") not specified");
      return;
    } else if (!cf.contentEquals(Onem2m.ContentFormat.JSON)
        && !cf.contentEquals(Onem2m.ContentFormat.XML)) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
          "CONTENT_FORMAT(" + RequestPrimitive.CONTENT_FORMAT + ") not accepted (" + cf + ")");
      return;
    }
    String cn = getPrimitive(RequestPrimitive.CONTENT);
    if (cn == null) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.INSUFFICIENT_ARGUMENTS,
          "CONTENT(" + RequestPrimitive.CONTENT_FORMAT + ") not specified");
      return;
    }

    // validate result content options for Update
    String rc = getPrimitive(RequestPrimitive.RESULT_CONTENT);
    if (rc != null) {
      if (!(rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES)
          || rc.contentEquals(Onem2m.ResultContent.NOTHING)
          || rc.contentEquals(Onem2m.ResultContent.CHILD_RESOURCE_REFS)
          || rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES_CHILD_RESOURCE_REFS))) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
            "RESULT_CONTENT(" + RequestPrimitive.RESULT_CONTENT + ") not accepted (" + rc + ")");
        return;
      }
    }

    // now find the resource from the database
    String to = this.getPrimitive(RequestPrimitive.TO);
    if (Onem2mDb.getInstance().findResourceUsingURI(to, this, onem2mResponse) == false) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.NOT_FOUND, "Resource target URI not found: " + to);
      return;
    }

    // cannot update contentInstance resources so check resource type
    String rt = this.getOnem2mResource().getResourceType();
    if (rt != null && rt.contentEquals(Onem2m.ResourceType.CONTENT_INSTANCE)) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.OPERATION_NOT_ALLOWED,
          "Not permitted to update content instance: " + this.getPrimitive(RequestPrimitive.TO));
      return;
    }

    ResourceContentProcessor.handleUpdate(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }

    ResultContentProcessor.handleUpdate(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }

    NotificationProcessor.handleUpdate(this);

    // TODO: see TS0004 6.8
    // if FOUND, and all went well, send back CHANGED
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) == null) {
      onem2mResponse.setPrimitive(
          ResponsePrimitive.RESPONSE_STATUS_CODE, Onem2m.ResponseStatusCode.CHANGED);
    }
  }
  /**
   * Handle the request primitive retrieve ... TODO: Strategy for error handling ... TS0004 7.1.1.2
   *
   * @param onem2mResponse response
   */
  public void handleOperationRetrieve(ResponsePrimitive onem2mResponse) {

    // Use table TS0004: 7.1.1.1-1 to validate RETRIEVE specific parameters that were not handled in
    // the calling routine

    // if the content format is provided then it must be supported
    String cf = getPrimitive(RequestPrimitive.CONTENT_FORMAT);
    if (cf != null) {
      if (!cf.contentEquals(Onem2m.ContentFormat.JSON)
          && !cf.contentEquals(Onem2m.ContentFormat.XML)) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
            "CONTENT_FORMAT(" + RequestPrimitive.CONTENT_FORMAT + ") not accepted (" + cf + ")");
        return;
      }
    }

    // validate result content options for retrieve
    String rc = getPrimitive(RequestPrimitive.RESULT_CONTENT);
    if (rc != null) {
      if (!(rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES)
          || rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES_CHILD_RESOURCES)
          || rc.contentEquals(Onem2m.ResultContent.CHILD_RESOURCE_REFS)
          || rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES_CHILD_RESOURCE_REFS))) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
            "RESULT_CONTENT(" + RequestPrimitive.RESULT_CONTENT + ") not accepted (" + rc + ")");
        return;
      }
    }

    // return hierarchical address by default if not specified
    String drt = getPrimitive(RequestPrimitive.DISCOVERY_RESULT_TYPE);
    if (drt == null) {
      setPrimitive(RequestPrimitive.DISCOVERY_RESULT_TYPE, Onem2m.DiscoveryResultType.HIERARCHICAL);
    }

    // find the resource using the TO URI ...
    String to = this.getPrimitive(RequestPrimitive.TO);
    if (!Onem2mDb.getInstance().findResourceUsingURI(to, this, onem2mResponse)) {

      // check to see if an resource/attribute was specified
      if (!Onem2mDb.getInstance().findResourceUsingURIAndAttribute(to, this, onem2mResponse)) {

        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.NOT_FOUND, "Resource target URI not found: " + to);
        return;
      }
      return;
    }

    // process the resource specific attributes
    ResourceContentProcessor.handleRetrieve(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }

    // return the data according to result content and filter criteria
    ResultContentProcessor.handleRetrieve(this, onem2mResponse);

    // TODO: see TS0004 6.8
    // if FOUND, and all went well, send back OK
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) == null) {
      onem2mResponse.setPrimitive(
          ResponsePrimitive.RESPONSE_STATUS_CODE, Onem2m.ResponseStatusCode.OK);
    }
  }
  /**
   * Handle the request primitive delete ... TODO: Strategy for error handling ... TS0004 7.1.1.2
   *
   * @param onem2mResponse response
   */
  public void handleOperationDelete(ResponsePrimitive onem2mResponse) {

    // Use table TS0004: 7.1.1.1-1 to validate DELETE specific parameters that were not handled in
    // the calling routine

    String cf = getPrimitive(RequestPrimitive.CONTENT);
    if (cf != null) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.INVALID_ARGUMENTS,
          "CONTENT(" + RequestPrimitive.CONTENT + ") not permitted");
      return;
    }

    // validate result content options for delete
    String rc = getPrimitive(RequestPrimitive.RESULT_CONTENT);
    if (rc != null) {
      if (!(rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES)
          || rc.contentEquals(Onem2m.ResultContent.NOTHING)
          || rc.contentEquals(Onem2m.ResultContent.CHILD_RESOURCE_REFS)
          || rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES_CHILD_RESOURCE_REFS))) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
            "RESULT_CONTENT(" + RequestPrimitive.RESULT_CONTENT + ") not accepted (" + rc + ")");
        return;
      }
    }

    /** Find the resource, fill in the response based on result content */
    String to = this.getPrimitive(RequestPrimitive.TO);
    if (Onem2mDb.getInstance().findResourceUsingURI(to, this, onem2mResponse) == false) {
      // TODO: is it idempotent or not ... fail or succeed???
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.NOT_FOUND, "Resource target URI not found: " + to);
      return;
    }

    String protocol = getPrimitive(RequestPrimitive.PROTOCOL);
    String rt = this.getOnem2mResource().getResourceType();
    if (rt != null
        && rt.contentEquals(Onem2m.ResourceType.CSE_BASE)
        && !protocol.contentEquals(Onem2m.Protocol.NATIVEAPP)) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.OPERATION_NOT_ALLOWED,
          "Not permitted to delete this resource: " + this.getPrimitive(RequestPrimitive.TO));
      return;
    }

    ResourceContentProcessor.handleDelete(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }

    ResultContentProcessor.handleDelete(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }

    NotificationProcessor.handleDelete(this);

    // now delete the resource from the database
    // TODO: idempotent so who cares if cannot find the resource ... is this true?
    if (Onem2mDb.getInstance().deleteResourceUsingURI(this, onem2mResponse) == false) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.INTERNAL_SERVER_ERROR,
          "Resource target URI data store delete error: " + this.getPrimitive(RequestPrimitive.TO));
      return;
    }

    // TODO: see TS0004 6.8
    // if FOUND, and all went well, send back OK
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) == null) {
      onem2mResponse.setPrimitive(
          ResponsePrimitive.RESPONSE_STATUS_CODE, Onem2m.ResponseStatusCode.DELETED);
    }
  }
  /**
   * Handle the request primitive create ... TODO: Strategy for error handling ... TS0004 7.1.1.2
   *
   * @param onem2mResponse response
   */
  public void handleOperationCreate(ResponsePrimitive onem2mResponse) {

    // Use table TS0004: 7.1.1.1-1 to validate CREATE specific parameters that were not handled in
    // the
    // handleOperation

    // ensure the create has content ...
    String cf = getPrimitive(RequestPrimitive.CONTENT_FORMAT);
    if (cf == null) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.BAD_REQUEST,
          "CONTENT_FORMAT(" + RequestPrimitive.CONTENT_FORMAT + ") not specified");
      return;
    } else if (!cf.contentEquals(Onem2m.ContentFormat.JSON)
        && !cf.contentEquals(Onem2m.ContentFormat.XML)) {
      onem2mResponse.setRSC(
          Onem2m.ResponseStatusCode.BAD_REQUEST,
          "CONTENT_FORMAT(" + RequestPrimitive.CONTENT_FORMAT + ") not accepted (" + cf + ")");
      return;
    }

    String cn = getPrimitive(RequestPrimitive.CONTENT);
    if (cn == null) {
      if (cf.contentEquals(Onem2m.ContentFormat.JSON)) {
        this.setPrimitive(RequestPrimitive.CONTENT, "{}");
      } else {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.BAD_REQUEST,
            "CONTENT(" + RequestPrimitive.CONTENT_FORMAT + ") not specified");
        return;
      }
    }

    // validate result content options for create
    String rc = getPrimitive(RequestPrimitive.RESULT_CONTENT);
    if (rc != null) {
      if (!(rc.contentEquals(Onem2m.ResultContent.ATTRIBUTES)
          || rc.contentEquals(Onem2m.ResultContent.NOTHING)
          || rc.contentEquals(Onem2m.ResultContent.HIERARCHICAL_ADDRESS)
          || rc.contentEquals(Onem2m.ResultContent.HIERARCHICAL_ADDRESS_ATTRIBUTES))) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONTENTS_UNACCEPTABLE,
            "RESULT_CONTENT(" + RequestPrimitive.RESULT_CONTENT + ") not accepted (" + rc + ")");
        return;
      }
    }

    // lookup the resource ... this will be the parent where the new resource will be created
    String resourceType = getPrimitive(RequestPrimitive.RESOURCE_TYPE);
    if (!resourceType.contentEquals(Onem2m.ResourceType.CSE_BASE)) {
      String to = getPrimitive(RequestPrimitive.TO);
      if (!Onem2mDb.getInstance().findResourceUsingURI(to, this, onem2mResponse)) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.NOT_FOUND, "Resource target URI not found: " + to);
        return;
      }

      // the Onem2mResource is now stored in the onem2mRequest ... as it has been read in from the
      // data store

      // special case for AE resources ... where resource name is derived from FROM parameter
      String resourceName = this.getPrimitive((RequestPrimitive.NAME));
      //            if (resourceName == null && resourceType.contentEquals(Onem2m.ResourceType.AE))
      // {
      //                String from = this.getPrimitive(RequestPrimitive.FROM);
      //                if (from != null) {
      //                    resourceName = from;
      //                }
      //            }

      // if the a name is provided, ensure it is valid and unique at this hierarchical level
      if (resourceName != null) {
        // using the parent, see if this new resource name already exists under this parent resource
        if (Onem2mDb.getInstance()
            .findResourceUsingIdAndName(this.getOnem2mResource().getResourceId(), resourceName)) {
          // TS0004: 7.2.3.2
          onem2mResponse.setRSC(
              Onem2m.ResponseStatusCode.CONFLICT,
              "Resource already exists: "
                  + this.getPrimitive(RequestPrimitive.TO)
                  + "/"
                  + resourceName);
          return;
        }
        this.setResourceName(resourceName);
      }
    } else {
      String resourceName = this.getPrimitive((RequestPrimitive.NAME));
      if (resourceName == null) {
        onem2mResponse.setRSC(Onem2m.ResponseStatusCode.BAD_REQUEST, "CSE name not specified");
        return;
      }
      if (Onem2mDb.getInstance().findCseByName(resourceName)) {
        onem2mResponse.setRSC(
            Onem2m.ResponseStatusCode.CONFLICT, "CSE name already exists: " + resourceName);
        return;
      }
      this.setResourceName(resourceName);
    }

    // process the resource specific attributes
    ResourceContentProcessor.handleCreate(this, onem2mResponse);
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
      return;
    }
    //        CheckAccessControlProcessor.handleCreate(this, onem2mResponse);
    //        if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) != null) {
    //            return;
    //        }

    // now format a response based on result content desired
    ResultContentProcessor.handleCreate(this, onem2mResponse);

    // not process notifications
    NotificationProcessor.handleCreate(this);

    // TODO: see TS0004 6.8
    // if the create was successful, ie no error has already happened, set CREATED for status code
    // here
    if (onem2mResponse.getPrimitive(ResponsePrimitive.RESPONSE_STATUS_CODE) == null) {
      onem2mResponse.setPrimitive(
          ResponsePrimitive.RESPONSE_STATUS_CODE, Onem2m.ResponseStatusCode.CREATED);
    }
  }