@Test
  public void testMissingEntity() {
    // Update an existing entity, use a URI to a not existing entity
    // Perform the request to a single navigation property and a collection navigation property as
    // well.
    // Expected: Not Found (404)

    final ODataClient client = getClient();
    final URI entityURI =
        client
            .newURIBuilder(SERVICE_URI)
            .appendEntitySetSegment(ES_KEY_NAV)
            .appendKeySegment(1)
            .build();
    final ClientObjectFactory of = client.getObjectFactory();

    // Request to single (non collection) navigation property
    ClientEntity entity = of.newEntity(ET_KEY_NAV);
    final ClientLink navLinkOne =
        of.newEntityNavigationLink(
            NAV_PROPERTY_ET_KEY_NAV_ONE,
            client
                .newURIBuilder(SERVICE_URI)
                .appendEntitySetSegment(ES_KEY_NAV)
                .appendKeySegment(42)
                .build());
    entity.addLink(navLinkOne);

    try {
      client
          .getCUDRequestFactory()
          .getEntityUpdateRequest(entityURI, UpdateType.PATCH, entity)
          .execute();
      fail();
    } catch (ODataClientErrorException e) {
      assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), e.getStatusLine().getStatusCode());
    }

    // Request to collection navigation propetry
    entity = of.newEntity(ET_KEY_NAV);
    final ClientLink navLinkMany =
        of.newEntitySetNavigationLink(
            NAV_PROPERTY_ET_KEY_NAV_MANY,
            client
                .newURIBuilder(SERVICE_URI)
                .appendEntitySetSegment(ES_KEY_NAV)
                .appendKeySegment(3)
                .build());
    entity.addLink(navLinkMany);

    try {
      client
          .getCUDRequestFactory()
          .getEntityUpdateRequest(entityURI, UpdateType.PATCH, entity)
          .execute();
    } catch (ODataClientErrorException e) {
      assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), e.getStatusLine().getStatusCode());
    }
  }
  @Test
  public void errorWithContinueOnErrorPreferHeader() throws Exception {
    ODataClient client = getClient();
    client.getConfiguration().setContinueOnError(true);
    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);

    final BatchManager payload = request.payloadManager();

    appendGetRequest(payload, "ESAllPrim", 32767, false); // Without error
    appendGetRequest(payload, "ESAllPrim", 42, false); // Error ( Key does not exist )
    appendGetRequest(payload, "ESAllPrim", 0, false); // Without error

    // Fetch result
    final ODataBatchResponse response = payload.getResponse();
    assertEquals(HttpStatusCode.ACCEPTED.getStatusCode(), response.getStatusCode());
    assertEquals(
        PreferenceName.CONTINUE_ON_ERROR.getName(),
        response.getHeader(HttpHeader.PREFERENCE_APPLIED).iterator().next());

    final Iterator<ODataBatchResponseItem> bodyIterator = response.getBody();

    // Check first get request
    assertTrue(bodyIterator.hasNext());
    ODataBatchResponseItem item = bodyIterator.next();
    assertFalse(item.isChangeset());

    ODataResponse oDataResponse = item.next();
    assertNotNull(oDataResponse);
    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResponse.getStatusCode());
    assertEquals(1, oDataResponse.getHeader(HttpHeader.ODATA_VERSION).size());
    assertEquals("4.0", oDataResponse.getHeader(HttpHeader.ODATA_VERSION).toArray()[0]);
    assertEquals(1, oDataResponse.getHeader(HttpHeader.CONTENT_LENGTH).size());
    assertEquals("605", oDataResponse.getHeader(HttpHeader.CONTENT_LENGTH).toArray()[0]);
    assertEquals(ContentType.JSON.toContentTypeString(), oDataResponse.getContentType());

    // Check second get request
    assertTrue(bodyIterator.hasNext());
    item = bodyIterator.next();
    assertFalse(item.isChangeset());

    oDataResponse = item.next();
    assertNotNull(oDataResponse);
    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), oDataResponse.getStatusCode());

    // Check if third request is available
    assertTrue(bodyIterator.hasNext());
    item = bodyIterator.next();
    assertFalse(item.isChangeset());

    oDataResponse = item.next();
    assertNotNull(oDataResponse);
    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResponse.getStatusCode());
    assertEquals(1, oDataResponse.getHeader(HttpHeader.ODATA_VERSION).size());
    assertEquals("4.0", oDataResponse.getHeader(HttpHeader.ODATA_VERSION).iterator().next());
    assertEquals(1, oDataResponse.getHeader(HttpHeader.CONTENT_LENGTH).size());
    assertEquals("517", oDataResponse.getHeader(HttpHeader.CONTENT_LENGTH).iterator().next());
    assertEquals(ContentType.JSON.toContentTypeString(), oDataResponse.getContentType());
  }
  @Test
  public void badRequestInChangeSet() {
    /*
     * A bad request (status code >= 400) without "continue on error prefer header" in a changeset
     * should return a single response with Content-Type: application/http
     *
     * See:
     * OData Version 4.0 Part 1: Protocol Plus Errata 01
     * 11.7.4 Responding to a Batch Request
     *
     * When a request within a change set fails, the change set response is not represented using
     * the multipart/mixed media type. Instead, a single response, using the application/http media type
     * and a Content-Transfer-Encoding header with a value of binary, is returned that applies to all requests
     * in the change set and MUST be formatted according to the Error Handling defined
     * for the particular response format.
     */

    // Try to create entity, with invalid type
    ClientObjectFactory factory = getFactory();
    final ClientEntity entity = factory.newEntity(ES_NOT_AVAILABLE);
    entity
        .getProperties()
        .add(
            factory.newPrimitiveProperty(
                PROPERTY_STRING, factory.newPrimitiveValueBuilder().buildString("1")));
    final ODataBatchRequest batchRequest =
        getClient().getBatchRequestFactory().getBatchRequest(SERVICE_URI);
    final BatchManager payloadManager = batchRequest.payloadManager();
    final ODataChangeset changeset = payloadManager.addChangeset();
    final URI targetURI =
        getClient()
            .newURIBuilder(SERVICE_URI)
            .appendEntitySetSegment(ES_NOT_AVAILABLE_NAME)
            .build();
    final ODataEntityCreateRequest<ClientEntity> createRequest =
        getClient().getCUDRequestFactory().getEntityCreateRequest(targetURI, entity);
    changeset.addRequest(createRequest);

    final ODataBatchResponse response = payloadManager.getResponse();
    assertEquals(HttpStatusCode.ACCEPTED.getStatusCode(), response.getStatusCode());

    // Check response items
    final Iterator<ODataBatchResponseItem> responseBodyIter = response.getBody();
    assertTrue(responseBodyIter.hasNext());

    final ODataBatchResponseItem changeSetResponse = responseBodyIter.next();
    assertTrue(changeSetResponse.isChangeset());
    assertTrue(changeSetResponse.hasNext());

    final ODataResponse updateResponse = changeSetResponse.next();
    assertTrue(changeSetResponse.isBreaking());

    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), updateResponse.getStatusCode());
    assertContentType(updateResponse.getContentType());
  }
 @Override
 public void readPrimitiveValue(
     ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType format)
     throws ODataApplicationException, SerializerException {
   // First we have to figure out which entity set the requested entity is in
   final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
   // Next we fetch the requested entity from the database
   final Entity entity;
   try {
     entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
   } catch (DataProviderException e) {
     throw new ODataApplicationException(e.getMessage(), 500, Locale.ENGLISH);
   }
   if (entity == null) {
     // If no entity was found for the given key we throw an exception.
     throw new ODataApplicationException(
         "No entity found for this key", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
   } else {
     // Next we get the property value from the entity and pass the value to serialization
     UriResourceProperty uriProperty =
         (UriResourceProperty)
             uriInfo.getUriResourceParts().get(uriInfo.getUriResourceParts().size() - 1);
     EdmProperty edmProperty = uriProperty.getProperty();
     Property property = entity.getProperty(edmProperty.getName());
     if (property == null) {
       throw new ODataApplicationException(
           "No property found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
     } else {
       if (property.getValue() == null) {
         response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
       } else {
         String value = String.valueOf(property.getValue());
         ByteArrayInputStream serializerContent =
             new ByteArrayInputStream(value.getBytes(Charset.forName("UTF-8")));
         response.setContent(serializerContent);
         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
         response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.TEXT_PLAIN.toContentTypeString());
       }
     }
   }
 }
  @Override
  public void readEntity(
      final ODataRequest request,
      ODataResponse response,
      final UriInfo uriInfo,
      final ContentType requestedContentType)
      throws ODataApplicationException, SerializerException {
    // First we have to figure out which entity set the requested entity is in
    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());

    // Next we fetch the requested entity from the database
    Entity entity;
    try {
      entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
    } catch (DataProviderException e) {
      throw new ODataApplicationException(e.getMessage(), 500, Locale.ENGLISH);
    }

    if (entity == null) {
      // If no entity was found for the given key we throw an exception.
      throw new ODataApplicationException(
          "No entity found for this key", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
    } else {
      // If an entity was found we proceed by serializing it and sending it to the client.
      ODataSerializer serializer = odata.createSerializer(requestedContentType);
      final ExpandOption expand = uriInfo.getExpandOption();
      final SelectOption select = uriInfo.getSelectOption();
      InputStream serializedContent =
          serializer
              .entity(
                  edm,
                  edmEntitySet.getEntityType(),
                  entity,
                  EntitySerializerOptions.with()
                      .contextURL(
                          isODataMetadataNone(requestedContentType)
                              ? null
                              : getContextUrl(edmEntitySet, true, expand, select, null))
                      .expand(expand)
                      .select(select)
                      .build())
              .getContent();
      response.setContent(serializedContent);
      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
      response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
    }
  }
  @Test
  public void errorWithoutContinueOnErrorPreferHeader() throws URISyntaxException {
    final ODataBatchRequest request =
        getClient().getBatchRequestFactory().getBatchRequest(SERVICE_URI);

    final BatchManager payload = request.payloadManager();

    appendGetRequest(payload, "ESAllPrim", 32767, false); // Without error
    appendGetRequest(payload, "ESAllPrim", 42, false); // Error ( Key does not exist )
    appendGetRequest(payload, "ESAllPrim", 0, false); // Without error

    // Fetch result
    final ODataBatchResponse response = payload.getResponse();
    assertEquals(HttpStatusCode.ACCEPTED.getStatusCode(), response.getStatusCode());

    final Iterator<ODataBatchResponseItem> iter = response.getBody();

    // Check first get request
    assertTrue(iter.hasNext());
    ODataBatchResponseItem item = iter.next();
    assertFalse(item.isChangeset());

    ODataResponse oDataResponse = item.next();
    assertNotNull(oDataResponse);
    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResponse.getStatusCode());
    assertEquals(1, oDataResponse.getHeader("OData-Version").size());
    assertEquals("4.0", oDataResponse.getHeader("OData-Version").toArray()[0]);
    assertEquals(1, oDataResponse.getHeader("Content-Length").size());
    assertEquals("605", oDataResponse.getHeader("Content-Length").toArray()[0]);
    assertEquals(ContentType.JSON.toContentTypeString(), oDataResponse.getContentType());

    // Check second get request
    assertTrue(iter.hasNext());
    item = iter.next();
    assertFalse(item.isChangeset());

    oDataResponse = item.next();
    assertNotNull(oDataResponse);
    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), oDataResponse.getStatusCode());

    // Check if third request is available
    assertFalse(iter.hasNext());
  }
  private void readProperty(
      ODataResponse response, UriInfo uriInfo, ContentType contentType, boolean complex)
      throws ODataApplicationException, SerializerException {
    // To read a property we have to first get the entity out of the entity set
    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
    Entity entity;
    try {
      entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
    } catch (DataProviderException e) {
      throw new ODataApplicationException(
          e.getMessage(), HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ENGLISH);
    }

    if (entity == null) {
      // If no entity was found for the given key we throw an exception.
      throw new ODataApplicationException(
          "No entity found for this key", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
    } else {
      // Next we get the property value from the entity and pass the value to serialization
      UriResourceProperty uriProperty =
          (UriResourceProperty)
              uriInfo.getUriResourceParts().get(uriInfo.getUriResourceParts().size() - 1);
      EdmProperty edmProperty = uriProperty.getProperty();
      Property property = entity.getProperty(edmProperty.getName());
      if (property == null) {
        throw new ODataApplicationException(
            "No property found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
      } else {
        if (property.getValue() == null) {
          response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
        } else {
          ODataSerializer serializer = odata.createSerializer(contentType);
          final ContextURL contextURL =
              isODataMetadataNone(contentType)
                  ? null
                  : getContextUrl(edmEntitySet, true, null, null, edmProperty.getName());
          InputStream serializerContent =
              complex
                  ? serializer
                      .complex(
                          edm,
                          (EdmComplexType) edmProperty.getType(),
                          property,
                          ComplexSerializerOptions.with().contextURL(contextURL).build())
                      .getContent()
                  : serializer
                      .primitive(
                          edm,
                          (EdmPrimitiveType) edmProperty.getType(),
                          property,
                          PrimitiveSerializerOptions.with()
                              .contextURL(contextURL)
                              .scale(edmProperty.getScale())
                              .nullable(edmProperty.isNullable())
                              .precision(edmProperty.getPrecision())
                              .maxLength(edmProperty.getMaxLength())
                              .unicode(edmProperty.isUnicode())
                              .build())
                      .getContent();
          response.setContent(serializerContent);
          response.setStatusCode(HttpStatusCode.OK.getStatusCode());
          response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
        }
      }
    }
  }