@PUT
  @Path("/domain")
  @Consumes({ MediaType.APPLICATION_JSON /* , MediaType.APPLICATION_XML */})
  @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8
      /* , MediaType.APPLICATION_XML */})
  public TimelinePutResponse putDomain(
      @Context HttpServletRequest req,
      @Context HttpServletResponse res,
      TimelineDomain domain) {
    init(res);
    UserGroupInformation callerUGI = getUser(req);
    if (callerUGI == null) {
      String msg = "The owner of the posted timeline domain is not set";
      LOG.error(msg);
      throw new ForbiddenException(msg);
    }
    domain.setOwner(callerUGI.getShortUserName());
    try {
      timelineDataManager.putDomain(domain, callerUGI);
    } catch (YarnException e) {
      // The user doesn't have the access to override the existing domain.
      LOG.error(e.getMessage(), e);
      throw new ForbiddenException(e);
    } catch (RuntimeException e) {
      LOG.error("Error putting domain", e);
      throw new WebApplicationException(e,
          Response.Status.INTERNAL_SERVER_ERROR);
    } catch (IOException e) {
      LOG.error("Error putting domain", e);
      throw new WebApplicationException(e,
          Response.Status.INTERNAL_SERVER_ERROR);
    }
    return new TimelinePutResponse();
  }
@Test
  void testPutDomain() throws Exception {
    TimelineDomain domain = new TimelineDomain();
    domain.setId("test_domain_id");
    WebResource r = resource();
    // No owner, will be rejected
    ClientResponse response = r.path("ws").path("v1")
        .path("timeline").path("domain")
        .accept(MediaType.APPLICATION_JSON)
        .type(MediaType.APPLICATION_JSON)
        .put(ClientResponse.class, domain);
    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
        response.getType().toString());
    assertResponseStatusCode(Status.FORBIDDEN, response.getStatusInfo());

    response = r.path("ws").path("v1")
        .path("timeline").path("domain")
        .queryParam("user.name", "tester")
        .accept(MediaType.APPLICATION_JSON)
        .type(MediaType.APPLICATION_JSON)
        .put(ClientResponse.class, domain);
    assertResponseStatusCode(Status.OK, response.getStatusInfo());

    // Verify the domain exists
    response = r.path("ws").path("v1").path("timeline")
        .path("domain").path("test_domain_id")
        .accept(MediaType.APPLICATION_JSON)
        .get(ClientResponse.class);
    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
        response.getType().toString());
    domain = response.getEntity(TimelineDomain.class);
    assertNotNull(domain);
    assertEquals("test_domain_id", domain.getId());
    assertEquals("tester", domain.getOwner());
    assertNull(domain.getDescription());

    // Update the domain
    domain.setDescription("test_description");
    response = r.path("ws").path("v1")
        .path("timeline").path("domain")
        .queryParam("user.name", "tester")
        .accept(MediaType.APPLICATION_JSON)
        .type(MediaType.APPLICATION_JSON)
        .put(ClientResponse.class, domain);
    assertResponseStatusCode(Status.OK, response.getStatusInfo());

    // Verify the domain is updated
    response = r.path("ws").path("v1").path("timeline")
        .path("domain").path("test_domain_id")
        .accept(MediaType.APPLICATION_JSON)
        .get(ClientResponse.class);
    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
        response.getType().toString());
    domain = response.getEntity(TimelineDomain.class);
    assertNotNull(domain);
    assertEquals("test_domain_id", domain.getId());
    assertEquals("test_description", domain.getDescription());
  }