@Override
  public Response createPoly(byte[] inputToAutodetectType) {
    log.debug("Creating app from autodetecting input");

    boolean looksLikeLegacy = false;
    Exception legacyFormatException = null;
    // attempt legacy format
    try {
      ApplicationSpec appSpec = mapper().readValue(inputToAutodetectType, ApplicationSpec.class);
      if (appSpec.getType() != null || appSpec.getEntities() != null) {
        looksLikeLegacy = true;
      }
      return createFromAppSpec(appSpec);
    } catch (Exception e) {
      Exceptions.propagateIfFatal(e);
      legacyFormatException = e;
      log.debug("Input is not legacy ApplicationSpec JSON (will try others): " + e, e);
    }

    // TODO infer encoding from request
    String potentialYaml = new String(inputToAutodetectType);
    EntitySpec<? extends Application> spec = createEntitySpecForApplication(potentialYaml);

    // TODO not json - try ZIP, etc

    if (spec != null) {
      return launch(potentialYaml, spec);
    } else if (looksLikeLegacy) {
      throw Throwables.propagate(legacyFormatException);
    } else {
      return Response.serverError().entity("Unsupported format; not able to autodetect.").build();
    }
  }
  private void checkApplicationTypesAreValid(ApplicationSpec applicationSpec) {
    String appType = applicationSpec.getType();
    if (appType != null) {
      checkEntityTypeIsValid(appType);

      if (applicationSpec.getEntities() != null) {
        throw WebResourceUtils.preconditionFailed(
            "Application given explicit type '%s' must not define entities", appType);
      }
      return;
    }

    for (org.apache.brooklyn.rest.domain.EntitySpec entitySpec : applicationSpec.getEntities()) {
      String entityType = entitySpec.getType();
      checkEntityTypeIsValid(checkNotNull(entityType, "entityType"));
    }
  }
 @SuppressWarnings("deprecation")
 private void checkLocationsAreValid(ApplicationSpec applicationSpec) {
   for (String locationId : applicationSpec.getLocations()) {
     locationId = BrooklynRestResourceUtils.fixLocation(locationId);
     if (!brooklyn().getLocationRegistry().canMaybeResolve(locationId)
         && brooklyn().getLocationRegistry().getDefinedLocationById(locationId) == null) {
       throw WebResourceUtils.notFound("Undefined location '%s'", locationId);
     }
   }
 }
@Test(
    singleThreaded = true,
    // by using a different suite name we disallow interleaving other tests between the methods of
    // this test class, which wrecks the test fixtures
    suiteName = "EntityResourceTest")
public class EntityResourceTest extends BrooklynRestResourceTest {

  private static final Logger log = LoggerFactory.getLogger(EntityResourceTest.class);

  private final ApplicationSpec simpleSpec =
      ApplicationSpec.builder()
          .name("simple-app")
          .entities(
              ImmutableSet.of(new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName())))
          .locations(ImmutableSet.of("localhost"))
          .build();

  private EntityInternal entity;

  private static final String entityEndpoint = "/applications/simple-app/entities/simple-ent";

  @BeforeClass(alwaysRun = true)
  public void setUp() throws Exception {
    // Deploy application
    startServer();
    Response deploy = clientDeploy(simpleSpec);
    waitForApplicationToBeRunning(deploy.getLocation());

    // Add tag
    entity =
        (EntityInternal)
            Iterables.find(
                getManagementContext().getEntityManager().getEntities(),
                new Predicate<Entity>() {
                  @Override
                  public boolean apply(@Nullable Entity input) {
                    return "RestMockSimpleEntity".equals(input.getEntityType().getSimpleName());
                  }
                });
  }

  @Test
  public void testGetSpecAcceptingXYaml() throws Exception {
    testGetSpec("text/x-yaml");
  }

  @Test
  public void testGetSpecWithNoExplicitAccepts() throws Exception {
    testGetSpec(null);
  }

  protected void testGetSpec(String acceptMimeType) throws Exception {
    String appName = "ent-with-spec";

    // Create an app with a yaml spec
    String yaml =
        Joiner.on("\n")
            .join("name: " + appName, "services:", "- type: " + BasicEntity.class.getName());
    Response appResponse =
        client().path("/applications").header("Content-Type", "text/x-yaml").post(yaml);
    waitForApplicationToBeRunning(appResponse.getLocation());

    // Retrieve the yaml spec, and confirm it is as expected (not wrapped in quotes, and treating \n
    // sensibly)
    Response response;
    if (acceptMimeType != null) {
      response =
          client()
              .path("/applications/" + appName + "/entities/" + appName + "/spec")
              .accept(acceptMimeType)
              .get();
    } else {
      response = client().path("/applications/" + appName + "/entities/" + appName + "/spec").get();
    }
    String data = response.readEntity(String.class);

    assertEquals(data.trim(), yaml.trim());
  }

  @Test
  public void testTagsSanity() throws Exception {
    entity.tags().addTag("foo");

    Response response =
        client().path(entityEndpoint + "/tags").accept(MediaType.APPLICATION_JSON_TYPE).get();
    String data = response.readEntity(String.class);

    try {
      List<Object> tags = new ObjectMapper().readValue(data, new TypeReference<List<Object>>() {});
      Assert.assertTrue(tags.contains("foo"));
      Assert.assertFalse(tags.contains("bar"));
    } catch (Exception e) {
      Exceptions.propagateIfFatal(e);
      throw new IllegalStateException(
          "Error with deserialization of tags list: " + e + "\n" + data, e);
    }
  }

  @Test
  public void testRename() throws Exception {
    try {
      Response response =
          client().path(entityEndpoint + "/name").query("name", "New Name").post(null);

      HttpAsserts.assertHealthyStatusCode(response.getStatus());
      Assert.assertTrue(entity.getDisplayName().equals("New Name"));
    } finally {
      // restore it for other tests!
      entity.setDisplayName("simple-ent");
    }
  }

  @Test
  public void testAddChild() throws Exception {
    try {
      // to test in GUI:
      // services: [ { type: org.apache.brooklyn.entity.stock.BasicEntity }]
      Response response =
          client()
              .path(entityEndpoint + "/children")
              .query("timeout", "10s")
              .post(
                  javax.ws.rs.client.Entity.entity(
                      "services: [ { type: " + TestEntity.class.getName() + " }]",
                      "application/yaml"));

      HttpAsserts.assertHealthyStatusCode(response.getStatus());
      Assert.assertEquals(entity.getChildren().size(), 1);
      Entity child = Iterables.getOnlyElement(entity.getChildren());
      Assert.assertTrue(Entities.isManaged(child));

      TaskSummary task = response.readEntity(TaskSummary.class);
      Assert.assertEquals(task.getResult(), MutableList.of(child.getId()));

    } finally {
      // restore it for other tests
      Collection<Entity> children = entity.getChildren();
      if (!children.isEmpty()) Entities.unmanage(Iterables.getOnlyElement(children));
    }
  }

  @Test
  public void testTagsDoNotSerializeTooMuch() throws Exception {
    entity.tags().addTag("foo");
    entity.tags().addTag(entity.getParent());

    Response response =
        client().path(entityEndpoint + "/tags").accept(MediaType.APPLICATION_JSON).get();
    String raw = response.readEntity(String.class);
    log.info("TAGS raw: " + raw);
    HttpAsserts.assertHealthyStatusCode(response.getStatus());

    Assert.assertTrue(
        raw.contains(entity.getParent().getId()),
        "unexpected app tag, does not include ID: " + raw);

    Assert.assertTrue(
        raw.length() < 1000,
        "unexpected app tag, includes too much mgmt info (len " + raw.length() + "): " + raw);

    Assert.assertFalse(
        raw.contains(entity.getManagementContext().getManagementNodeId()),
        "unexpected app tag, includes too much mgmt info: " + raw);
    Assert.assertFalse(
        raw.contains("managementContext"),
        "unexpected app tag, includes too much mgmt info: " + raw);
    Assert.assertFalse(
        raw.contains("localhost"), "unexpected app tag, includes too much mgmt info: " + raw);
    Assert.assertFalse(
        raw.contains("catalog"), "unexpected app tag, includes too much mgmt info: " + raw);

    @SuppressWarnings("unchecked")
    List<Object> tags = mapper().readValue(raw, List.class);
    log.info("TAGS are: " + tags);

    Assert.assertEquals(tags.size(), 2, "tags are: " + tags);

    Assert.assertTrue(tags.contains("foo"));
    Assert.assertFalse(tags.contains("bar"));

    MutableList<Object> appTags = MutableList.copyOf(tags);
    appTags.remove("foo");
    Object appTag = Iterables.getOnlyElement(appTags);

    // it's a map at this point, because there was no way to make it something stronger than Object
    Assert.assertTrue(appTag instanceof Map, "Should have deserialized an entity: " + appTag);
    // let's re-serialize it as an entity
    appTag = mapper().readValue(mapper().writeValueAsString(appTag), Entity.class);

    Assert.assertTrue(appTag instanceof Entity, "Should have deserialized an entity: " + appTag);
    Assert.assertEquals(
        ((Entity) appTag).getId(), entity.getApplicationId(), "Wrong ID: " + appTag);
    Assert.assertTrue(
        appTag instanceof BasicApplication, "Should have deserialized BasicApplication: " + appTag);
  }
}