/**
   * The object will contain metadata properties, including object identifier {@code _id}, and
   * object version {@code _rev} to enable optimistic concurrency supported by OrientDB and OpenIDM.
   *
   * @param request the identifier of the object to retrieve from the object set.
   * @throws NotFoundException if the specified object could not be found.
   * @throws ForbiddenException if access to the object is forbidden.
   * @throws BadRequestException if the passed identifier is invalid
   * @return the requested object.
   */
  @Override
  public ResourceResponse read(ReadRequest request) throws ResourceException {
    if (request.getResourcePathObject().size() < 2) {
      throw new NotFoundException(
          "The object identifier did not include sufficient information to determine the object type and identifier of the object to read: "
              + request.getResourcePath());
    }

    final String type = request.getResourcePathObject().parent().toString();
    final String localId = request.getResourcePathObject().leaf();
    ResourceResponse result = null;
    ODatabaseDocumentTx db = getConnection();
    try {
      ODocument doc = predefinedQueries.getByID(localId, type, db);
      if (doc == null) {
        throw new NotFoundException("Object " + localId + " not found in " + type);
      }
      result = DocumentUtil.toResource(doc);
      logger.trace("Completed get for id: {} result: {}", request.getResourcePath(), result);
      return result;
    } finally {
      if (db != null) {
        db.close();
      }
    }
  }
  @Test
  public void shouldReadResourceSet() throws Exception {

    // Given
    ServerContext context = mock(ServerContext.class);
    ReadRequest request = mock(ReadRequest.class);
    given(request.getFields()).willReturn(Arrays.asList(new JsonPointer("/fred")));
    ResultHandler<Resource> handler = mock(ResultHandler.class);
    ResourceSetDescription resourceSet = new ResourceSetDescription();
    resourceSet.setDescription(json(object()));
    Promise<ResourceSetDescription, ResourceException> resourceSetPromise =
        Promises.newSuccessfulPromise(resourceSet);

    given(contextHelper.getRealm(context)).willReturn("REALM");
    given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID");
    given(
            resourceSetService.getResourceSet(
                context, "REALM", "RESOURCE_SET_ID", "RESOURCE_OWNER_ID", false))
        .willReturn(resourceSetPromise);

    // When
    resource.readInstance(context, "RESOURCE_SET_ID", request, handler);

    // Then
    verify(handler).handleResult(Matchers.<Resource>anyObject());
  }
  void doGet(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);
      rejectIfMatch(req);

      final Map<String, String[]> parameters = req.getParameterMap();
      if (hasParameter(req, PARAM_QUERY_ID)
          || hasParameter(req, PARAM_QUERY_EXPRESSION)
          || hasParameter(req, PARAM_QUERY_FILTER)) {
        // Additional pre-validation for queries.
        rejectIfNoneMatch(req);

        // Query against collection.
        final QueryRequest request = Requests.newQueryRequest(getResourceName(req));

        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_SORT_KEYS)) {
            for (final String s : values) {
              try {
                request.addSortKey(s.split(SORT_KEYS_DELIMITER));
              } catch (final IllegalArgumentException e) {
                // FIXME: i18n.
                throw new BadRequestException(
                    "The value '"
                        + s
                        + "' for parameter '"
                        + name
                        + "' could not be parsed as a comma "
                        + "separated list of sort keys");
              }
            }
          } else if (name.equalsIgnoreCase(PARAM_QUERY_ID)) {
            request.setQueryId(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_QUERY_EXPRESSION)) {
            request.setQueryExpression(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_COOKIE)) {
            request.setPagedResultsCookie(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_OFFSET)) {
            request.setPagedResultsOffset(asIntValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGE_SIZE)) {
            request.setPageSize(asIntValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_QUERY_FILTER)) {
            final String s = asSingleValue(name, values);
            try {
              request.setQueryFilter(QueryFilter.valueOf(s));
            } catch (final IllegalArgumentException e) {
              // FIXME: i18n.
              throw new BadRequestException(
                  "The value '"
                      + s
                      + "' for parameter '"
                      + name
                      + "' could not be parsed as a valid query filter");
            }
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }

        // Check for incompatible arguments.
        if (request.getQueryId() != null && request.getQueryFilter() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_ID
                  + " and "
                  + PARAM_QUERY_FILTER
                  + " are mutually exclusive");
        }

        if (request.getQueryId() != null && request.getQueryExpression() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_ID
                  + " and "
                  + PARAM_QUERY_EXPRESSION
                  + " are mutually exclusive");
        }

        if (request.getQueryFilter() != null && request.getQueryExpression() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_FILTER
                  + " and "
                  + PARAM_QUERY_EXPRESSION
                  + " are mutually exclusive");
        }

        doRequest(req, resp, acceptVersion, request);
      } else {
        // Read of instance within collection or singleton.
        final String rev = getIfNoneMatch(req);
        if (ETAG_ANY.equals(rev)) {
          // FIXME: i18n
          throw new PreconditionFailedException(
              "If-None-Match * not appropriate for " + getMethod(req) + " requests");
        }

        final ReadRequest request = Requests.newReadRequest(getResourceName(req));
        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 (PARAM_MIME_TYPE.equalsIgnoreCase(name)) {
            if (values.length != 1 || values[0].split(FIELDS_DELIMITER).length > 1) {
              // FIXME: i18n.
              throw new BadRequestException("Only one mime type value allowed");
            }
            if (parameters.get(PARAM_FIELDS).length != 1) {
              // FIXME: i18n.
              throw new BadRequestException(
                  "The mime type parameter requires only 1 field to be specified");
            }
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }