@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); } }