Repository: incubator-brooklyn Updated Branches: refs/heads/master ddc3dd9ff -> f1d90c638
BROOKLYN-184: Entities auto-managed - Deprecates Entities.manage - Deprecates ApplicationBuilder - Deprecates BrooklynLauncher.application(Application) - BrooklynRestResourceUtils uses EntitySpec (with DslComponent for soleChild ref) Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/5f2a296b Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/5f2a296b Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/5f2a296b Branch: refs/heads/master Commit: 5f2a296b572fd858766031a386682806ad8edead Parents: 9402f85 Author: Aled Sage <[email protected]> Authored: Thu Oct 15 16:34:09 2015 +0200 Committer: Aled Sage <[email protected]> Committed: Thu Oct 15 21:19:34 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/core/entity/AbstractEntity.java | 7 +- .../apache/brooklyn/core/entity/Entities.java | 41 ++- .../core/entity/factory/ApplicationBuilder.java | 6 +- .../core/mgmt/EntityManagementUtils.java | 2 - .../core/mgmt/internal/LocalEntityManager.java | 6 +- .../entity/group/AbstractGroupImpl.java | 1 - .../entity/group/DynamicClusterImpl.java | 5 +- .../entity/group/DynamicFabricImpl.java | 4 + .../entity/group/DynamicMultiGroupImpl.java | 1 - .../core/entity/EntityAutomanagedTest.java | 329 +++++++++++++++++++ .../BrooklynNodeUpgradeEffectorBody.java | 2 +- .../messaging/activemq/ActiveMQBrokerImpl.java | 2 - .../messaging/kafka/KafkaClusterImpl.java | 2 - .../entity/messaging/qpid/QpidBrokerImpl.java | 2 - .../messaging/rabbit/RabbitBrokerImpl.java | 1 - .../ControlledDynamicWebAppClusterImpl.java | 7 +- .../BrooklynAssemblyTemplateInstantiator.java | 3 +- .../brooklyn/launcher/BrooklynLauncher.java | 4 + .../rest/util/BrooklynRestResourceUtils.java | 20 +- 19 files changed, 411 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java index 49afc60..65ec72f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java @@ -662,13 +662,16 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E @Override public <T extends Entity> T addChild(EntitySpec<T> spec) { if (spec.getParent()==null) { - spec = EntitySpec.create(spec).parent(this); + spec = EntitySpec.create(spec).parent(getProxyIfAvailable()); } if (!this.equals(spec.getParent())) { throw new IllegalArgumentException("Attempt to create child of "+this+" with entity spec "+spec+ " failed because spec has different parent: "+spec.getParent()); } - return addChild(getEntityManager().createEntity(spec)); + + // The spec now includes this as the parent, so no need to call addChild; + // that is done by InternalEntityFactory. + return getEntityManager().createEntity(spec); } @Override http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java index a9616d8..0120fd7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java @@ -49,6 +49,7 @@ import org.apache.brooklyn.api.entity.drivers.EntityDriver; import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.api.mgmt.EntityManager; import org.apache.brooklyn.api.mgmt.ExecutionContext; import org.apache.brooklyn.api.mgmt.LocationManager; import org.apache.brooklyn.api.mgmt.ManagementContext; @@ -695,7 +696,7 @@ public class Entities { * (after the application is started) */ public static void start(Entity e, Collection<? extends Location> locations) { if (!isManaged(e) && !manage(e)) { - log.warn("Using discouraged mechanism to start management -- Entities.start(Application, Locations) -- caller should create and use the preferred management context"); + log.warn("Using deprecated discouraged mechanism to start management -- Entities.start(Application, Locations) -- caller should create and use the preferred management context"); startManagement(e); } if (e instanceof Startable) Entities.invokeEffector((EntityLocal)e, e, Startable.START, @@ -871,8 +872,18 @@ public class Entities { * * @throws IllegalStateException if {@literal e} is an {@link Application}. * @see #startManagement(Entity) + * + * @deprecated since 0.9.0; entities are automatically managed when created via {@link Entity#addChild(EntitySpec)}, + * or with {@link EntityManager#createEntity(EntitySpec)} (it is strongly encouraged to include the parent + * if using the latter for anything but a top-level app). */ + @Deprecated public static boolean manage(Entity e) { + if (Entities.isManaged(e)) { + return true; // no-op + } + + log.warn("Deprecated use of Entities.manage(Entity), for unmanaged entity "+e); Entity o = e.getParent(); Entity eum = e; // Highest unmanaged ancestor if (o==null) throw new IllegalArgumentException("Can't manage "+e+" because it is an orphan"); @@ -901,9 +912,15 @@ public class Entities { * <p> * <b>NOTE</b> This method may change, but is provided as a stop-gap to prevent ad-hoc things * being done in the code which are even more likely to break! + * + * @deprecated since 0.9.0; entities are automatically managed when created via {@link Entity#addChild(EntitySpec)}, + * or with {@link EntityManager#createEntity(EntitySpec)}. */ + @Deprecated @Beta public static ManagementContext startManagement(Entity e) { + log.warn("Deprecated use of Entities.startManagement(Entity), for entity "+e); + Entity o = e; Entity eum = e; // Highest unmanaged ancestor while (o.getParent()!=null) { @@ -929,11 +946,24 @@ public class Entities { * Starts managing the given (unmanaged) app, using the given management context. * * @see #startManagement(Entity) + * + * @deprecated since 0.9.0; entities are automatically managed when created with + * {@link EntityManager#createEntity(EntitySpec)}. For top-level apps, use code like + * {@code managementContext.getEntityManager().createEntity(EntitySpec.create(...))}. */ + @Deprecated public static ManagementContext startManagement(Application app, ManagementContext mgmt) { + log.warn("Deprecated use of Entities.startManagement(Application, ManagementContext), for app "+app); + if (isManaged(app)) { - throw new IllegalStateException("Application "+app+" is already managed, so can't set brooklyn properties"); + if (app.getManagementContext() == mgmt) { + // no-op; app was presumably auto-managed + return mgmt; + } else { + throw new IllegalStateException("Application "+app+" is already managed by "+app.getManagementContext()+", so cannot be managed by "+mgmt); + } } + mgmt.getEntityManager().manage(app); return mgmt; } @@ -943,8 +973,15 @@ public class Entities { * management context. * * @see #startManagement(Entity) + * + * @deprecated since 0.9.0; entities are automatically managed when created via {@link Entity#addChild(EntitySpec)}, + * or with {@link EntityManager#createEntity(EntitySpec)}. For top-level apps, use code like + * {@code managementContext.getEntityManager().createEntity(EntitySpec.create(...))}. */ + @Deprecated public static ManagementContext startManagement(Application app, BrooklynProperties props) { + log.warn("Deprecated use of Entities.startManagement(Application, BrooklynProperties), for app "+app); + if (isManaged(app)) { throw new IllegalStateException("Application "+app+" is already managed, so can't set brooklyn properties"); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/core/entity/factory/ApplicationBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/factory/ApplicationBuilder.java b/core/src/main/java/org/apache/brooklyn/core/entity/factory/ApplicationBuilder.java index 7e00305..2d3ee08 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/factory/ApplicationBuilder.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/factory/ApplicationBuilder.java @@ -63,7 +63,11 @@ import com.google.common.annotations.Beta; * </pre> * * @author aled + * + * @deprecated since 0.9.0; use {@link EntitySpec} and {@link EntityManager#createEntity(EntitySpec)}, having + * added the children to the spec etc. */ +@Deprecated @Beta public abstract class ApplicationBuilder { @@ -213,8 +217,8 @@ public abstract class ApplicationBuilder { } try { checkNotManaged(); - this.app = managementContext.getEntityManager().createEntity(appSpec); this.managementContext = managementContext; + this.app = managementContext.getEntityManager().createEntity(appSpec); doBuild(); Entities.startManagement(app, managementContext); managed = true; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java index 5536a1e..889f74f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java @@ -79,7 +79,6 @@ public class EntityManagementUtils { /** creates an application from the given app spec, managed by the given management context */ public static <T extends Application> T createUnstarted(ManagementContext mgmt, EntitySpec<T> spec) { T app = mgmt.getEntityManager().createEntity(spec); - Entities.startManagement(app, mgmt); return app; } @@ -188,7 +187,6 @@ public class EntityManagementUtils { final List<Entity> children = MutableList.of(); for (EntitySpec<?> spec: specs) { Entity child = (Entity)parent.addChild(spec); - Entities.manage(child); children.add(child); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java index 6c9022d..7d3b705 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java @@ -144,7 +144,11 @@ public class LocalEntityManager implements EntityManagerInternal { try { T entity = entityFactory.createEntity(spec); Entity proxy = ((AbstractEntity)entity).getProxy(); - return (T) checkNotNull(proxy, "proxy for entity %s, spec %s", entity, spec); + checkNotNull(proxy, "proxy for entity %s, spec %s", entity, spec); + + manage(entity); + + return (T) proxy; } catch (Throwable e) { log.warn("Failed to create entity using spec "+spec+" (rethrowing)", e); throw Exceptions.propagate(e); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java index 7ece9bf..8108c9f 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java @@ -152,7 +152,6 @@ public abstract class AbstractGroupImpl extends AbstractEntity implements Abstra DelegateEntity child = addChild(EntitySpec.create(DelegateEntity.class) .configure(DelegateEntity.DELEGATE_ENTITY, member) .displayName(String.format(nameFormat, member.getDisplayName()))); - Entities.manage(child); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java index 3fcebdf..004a537 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java @@ -293,7 +293,6 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus QuarantineGroup quarantineGroup = getAttribute(QUARANTINE_GROUP); if (quarantineGroup==null || !Entities.isManaged(quarantineGroup)) { quarantineGroup = addChild(EntitySpec.create(QuarantineGroup.class).displayName("quarantine")); - Entities.manage(quarantineGroup); sensors().set(QUARANTINE_GROUP, quarantineGroup); } } @@ -770,12 +769,16 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus LOG.debug("Creating and adding a node to cluster {}({}) with properties {}", new Object[] { this, getId(), createFlags }); } + // TODO should refactor to have a createNodeSpec; and spec should support initial sensor values Entity entity = createNode(loc, createFlags); entity.sensors().set(CLUSTER_MEMBER, true); entity.sensors().set(CLUSTER, this); + // Continue to call manage(), because some uses of NodeFactory (in tests) still instantiate the + // entity via its constructor Entities.manage(entity); + addMember(entity); return entity; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java index 23c05b5..67c4c79 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java @@ -247,7 +247,11 @@ public class DynamicFabricImpl extends AbstractGroupImpl implements DynamicFabri ((EntityLocal)entity).setDisplayName(entity.getDisplayName() +" ("+locationName+")"); } if (entity.getParent()==null) entity.setParent(this); + + // Continue to call manage(), because some uses of NodeFactory (in tests) still instantiate the + // entity via its constructor Entities.manage(entity); + addMember(entity); return entity; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java index b6f5d55..5c507a3 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java @@ -181,7 +181,6 @@ public class DynamicMultiGroupImpl extends DynamicGroupImpl implements DynamicMu BasicGroup bucket = buckets.get(name); if (bucket == null) { bucket = addChild(EntitySpec.create(bucketSpec).displayName(name)); - Entities.manage(bucket); buckets.put(name, bucket); } bucket.setMembers(entityMapping.get(name)); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/core/src/test/java/org/apache/brooklyn/core/entity/EntityAutomanagedTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityAutomanagedTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityAutomanagedTest.java new file mode 100644 index 0000000..a940a11 --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityAutomanagedTest.java @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.core.entity; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.util.List; +import java.util.Set; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.core.entity.EntityAutomanagedTest.RecordingCollectionChangeListener.ChangeEvent; +import org.apache.brooklyn.core.entity.EntityAutomanagedTest.RecordingCollectionChangeListener.ChangeType; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.test.Asserts; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class EntityAutomanagedTest extends BrooklynAppUnitTestSupport { + + // TODO Want to use a RecordingCollectionChangeListener to ensure on auto-manage + // we are notified of the entity being added etc, but compilation fails on command line, + // running `mvn clean install` (using 1.7.0_65, build 24.65-b04)! + // - when written "properly", it complains about the @Override annotation on onItemAdded(Entity item) + // - when that is removed, it complains about the call to mgmt.addEntitySetListener not being compatible + // - when try stripping out generics, it complains that "cannot find symbol" for the declaration of this class + // + // In your IDE (at least in Eclipse), you can uncomment the bits beside the TODO and run it + // with those insertions! + + protected RecordingCollectionChangeListener listener; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + listener = new RecordingCollectionChangeListener(); + + // TODO Compiler problems - see comment at top of class + //mgmt.addEntitySetListener((CollectionChangeListener)listener); + } + + + ////////////////////////////////////// + // Variants of addChild(EntitySpec) // + ////////////////////////////////////// + + @Test + public void testAddedChildSpec() throws Exception { + TestEntity e = app.addChild(EntitySpec.create(TestEntity.class)); + assertTrue(Entities.isManaged(e)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, e))); + } + + @Test + public void testAddedChildHierarchySpec() throws Exception { + TestEntity e = app.addChild(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class)))); + TestEntity e2 = (TestEntity) Iterables.getOnlyElement(e.getChildren()); + TestEntity e3 = (TestEntity) Iterables.getOnlyElement(e2.getChildren()); + + assertTrue(Entities.isManaged(e)); + assertTrue(Entities.isManaged(e2)); + assertTrue(Entities.isManaged(e3)); + assertEquals(e.getParent(), app); + assertEquals(e2.getParent(), e); + assertEquals(e3.getParent(), e2); + listener.assertEventsEqualsEventually(ImmutableList.of( + new ChangeEvent(ChangeType.ADDED, e), + new ChangeEvent(ChangeType.ADDED, e2), + new ChangeEvent(ChangeType.ADDED, e3))); + } + + @Test + public void testNewEntityWithParent() throws Exception { + TestEntity e = app.addChild(EntitySpec.create(TestEntity.class) + .parent(app)); + assertTrue(Entities.isManaged(e)); + assertEquals(e.getParent(), app); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, e))); + } + + @Test + public void testNewEntityHierarchyWithParent() throws Exception { + TestEntity e = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class))) + .parent(app)); + TestEntity e2 = (TestEntity) Iterables.getOnlyElement(e.getChildren()); + TestEntity e3 = (TestEntity) Iterables.getOnlyElement(e2.getChildren()); + + assertTrue(Entities.isManaged(e)); + assertTrue(Entities.isManaged(e2)); + assertTrue(Entities.isManaged(e3)); + assertEquals(e.getParent(), app); + assertEquals(e2.getParent(), e); + assertEquals(e3.getParent(), e2); + listener.assertEventsEqualsEventually(ImmutableList.of( + new ChangeEvent(ChangeType.ADDED, e), + new ChangeEvent(ChangeType.ADDED, e2), + new ChangeEvent(ChangeType.ADDED, e3))); + } + + @Test + public void testAddingSameChildAgainIsNoop() throws Exception { + TestEntity e = app.addChild(EntitySpec.create(TestEntity.class) + .parent(app)); + + app.addChild(e); + assertTrue(Entities.isManaged(e)); + assertEquals(e.getParent(), app); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, e))); + } + + + ////////////////////////////////////// + // Variants of createEntity for app // + ////////////////////////////////////// + + @Test + public void testNewApp() throws Exception { + TestApplication app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)); + assertTrue(Entities.isManaged(app2)); + + assertTrue(mgmt.getApplications().contains(app2), "app="+app2+"; apps="+mgmt.getApplications()); + app.addChild(app2); + assertTrue(Entities.isManaged(app2)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, app2))); + } + + + //////////////////////////////////////////////////////////////// + // Variants of Entities.startManagement and Entities.manage() // + //////////////////////////////////////////////////////////////// + + @Test + public void testManageIsNoop() throws Exception { + TestEntity child = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class) + .parent(app)); + + Entities.manage(child); + assertTrue(Entities.isManaged(child)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, child))); + } + + @Test + public void testStartManagementIsNoop() throws Exception { + TestApplication app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)); + assertTrue(Entities.isManaged(app2)); + + Entities.startManagement(app2, mgmt); + assertTrue(Entities.isManaged(app2)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, app2))); + } + + @Test + public void testStartManagementOfEntityIsNoop() throws Exception { + Entity app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)); + assertTrue(Entities.isManaged(app2)); + + Entities.startManagement(app2); + assertTrue(Entities.isManaged(app2)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, app2))); + } + + @Test + public void testStartManagementFailsIfAppDeleted() throws Exception { + TestApplication app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)); + Entities.unmanage(app2); + + try { + Entities.startManagement(app2, mgmt); + fail("Managed deleted app "+app2+" in "+mgmt); + } catch (IllegalStateException e) { + if (!(e.toString().contains("No concrete entity known"))) throw e; + } + } + + @Test + public void testManageFailsIfEntityDeleted() throws Exception { + TestEntity child = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class) + .parent(app)); + Entities.unmanage(child); + + try { + Entities.manage(child); + fail("Managed deleted entity "+child+" in "+mgmt); + } catch (IllegalStateException e) { + if (!(e.toString().contains("No concrete entity known"))) throw e; + } + } + + + /////////////////////////////////////////// + // Variants of createEntity for non-apps // + /////////////////////////////////////////// + + // TODO Controversial? Should it be based on reachability from parent? Can entities be (temporarily) top-level? + // But management model is simpler if it becomes managed immediately. + @Test + public void testNewOrphanedEntityIsManaged() throws Exception { + TestEntity e = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class)); + assertTrue(Entities.isManaged(e)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, e))); + + // Check that orphaned entity doesn't interfere with getApplications + Asserts.assertEqualsIgnoringOrder(mgmt.getApplications(), ImmutableList.of(app)); + } + + @Test + public void testOrphanedEntityHierarchyIsManaged() throws Exception { + TestEntity e = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class) + .child(EntitySpec.create(TestEntity.class)))); + TestEntity e2 = (TestEntity) Iterables.getOnlyElement(e.getChildren()); + TestEntity e3 = (TestEntity) Iterables.getOnlyElement(e2.getChildren()); + + assertTrue(Entities.isManaged(e)); + assertTrue(Entities.isManaged(e2)); + assertTrue(Entities.isManaged(e3)); + assertEquals(e.getParent(), null); + assertEquals(e2.getParent(), e); + assertEquals(e3.getParent(), e2); + listener.assertEventsEqualsEventually(ImmutableList.of( + new ChangeEvent(ChangeType.ADDED, e), + new ChangeEvent(ChangeType.ADDED, e2), + new ChangeEvent(ChangeType.ADDED, e3))); + } + + @Test + public void testNewOrphanedEntityCanBeAddedToChild() throws Exception { + TestEntity e = mgmt.getEntityManager().createEntity(EntitySpec.create(TestEntity.class)); + + app.addChild(e); + assertTrue(Entities.isManaged(e)); + listener.assertEventsEqualsEventually(ImmutableList.of(new ChangeEvent(ChangeType.ADDED, e))); + } + + // TODO Compiler problems - see comment at top of class + public static class RecordingCollectionChangeListener { // FIXME implements CollectionChangeListener<Entity> { + public enum ChangeType { + ADDED, REMOVED; + } + public static class ChangeEvent { + public final ChangeType type; + public final Entity entity; + + ChangeEvent(ChangeType type, Entity entity) { + this.type = checkNotNull(type, "type"); + this.entity = checkNotNull(entity, "entity"); + } + + @Override + public int hashCode() { + return Objects.hashCode(type, entity); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ChangeEvent)) return false; + ChangeEvent o = (ChangeEvent) obj; + return type.equals(o.type) && entity.equals(o.entity); + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("type", type).add("entity", entity).toString(); + } + } + + private final List<ChangeEvent> events = Lists.newCopyOnWriteArrayList(); + private final Set<Entity> items = Sets.newConcurrentHashSet(); + + public void assertEventsEqualsEventually(final Iterable<? extends ChangeEvent> expected) { + // TODO Compiler problems - see comment at top of class +// Asserts.succeedsEventually(new Runnable() { +// public void run() { +// assertEquals(events, ImmutableList.copyOf(expected)); +// }}); + } + + public void assertItemsEqualsEventually(final Iterable<? extends Entity> expected) { + // TODO Compiler problems - see comment at top of class +// Asserts.succeedsEventually(new Runnable() { +// public void run() { +// assertEquals(items, ImmutableSet.copyOf(expected)); +// }}); + } + + // TODO Want to include @Override; compiler problems - see comment at top of class + public void onItemAdded(Entity item) { + items.add(item); + events.add(new ChangeEvent(ChangeType.ADDED, item)); + } + + // TODO Want to include @Override; compiler problems - see comment at top of class + public void onItemRemoved(Entity item) { + items.remove(item); + events.add(new ChangeEvent(ChangeType.REMOVED, item)); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java index 021da69..4e75121 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java @@ -174,13 +174,13 @@ public class BrooklynNodeUpgradeEffectorBody extends EffectorBody<Void> { //force this to start as hot-standby // TODO alternatively could use REST API as in BrooklynClusterUpgradeEffectorBody + // TODO Want better way to append to the config (so can do it all in the spec) String launchParameters = dryRunChild.getConfig(BrooklynNode.EXTRA_LAUNCH_PARAMETERS); if (Strings.isBlank(launchParameters)) launchParameters = ""; else launchParameters += " "; launchParameters += "--highAvailability "+HighAvailabilityMode.HOT_STANDBY; ((EntityInternal)dryRunChild).config().set(BrooklynNode.EXTRA_LAUNCH_PARAMETERS, launchParameters); - Entities.manage(dryRunChild); final String dryRunNodeUid = dryRunChild.getId(); ((EntityInternal)dryRunChild).setDisplayName("Dry-Run Upgraded Brooklyn Node ("+dryRunNodeUid+")"); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java index 22719d0..6954e81 100644 --- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java +++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java @@ -74,7 +74,6 @@ public class ActiveMQBrokerImpl extends JMSBrokerImpl<ActiveMQQueue, ActiveMQTop @Override public ActiveMQQueue createQueue(Map properties) { ActiveMQQueue result = addChild(EntitySpec.create(ActiveMQQueue.class).configure(properties)); - Entities.manage(result); result.create(); return result; } @@ -82,7 +81,6 @@ public class ActiveMQBrokerImpl extends JMSBrokerImpl<ActiveMQQueue, ActiveMQTop @Override public ActiveMQTopic createTopic(Map properties) { ActiveMQTopic result = addChild(EntitySpec.create(ActiveMQTopic.class).configure(properties)); - Entities.manage(result); result.create(); return result; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java index cb4481c..8f4e7fb 100644 --- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java +++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java @@ -72,7 +72,6 @@ public class KafkaClusterImpl extends AbstractEntity implements KafkaCluster { log.debug("creating zookeeper using custom spec for {}", this); } zookeeper = addChild(zookeeperSpec); - if (Entities.isManaged(this)) Entities.manage(zookeeper); sensors().set(ZOOKEEPER, zookeeper); } @@ -87,7 +86,6 @@ public class KafkaClusterImpl extends AbstractEntity implements KafkaCluster { // We add the zookeeper configuration to the KafkaBroker specification here DynamicCluster cluster = addChild(EntitySpec.create(DynamicCluster.class) .configure("memberSpec", EntitySpec.create(brokerSpec).configure(KafkaBroker.ZOOKEEPER, zookeeper))); - if (Entities.isManaged(this)) Entities.manage(cluster); sensors().set(CLUSTER, cluster); connectSensors(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java index 5b2529c..67b132c 100644 --- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java +++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java @@ -90,14 +90,12 @@ public class QpidBrokerImpl extends JMSBrokerImpl<QpidQueue, QpidTopic> implemen public QpidQueue createQueue(Map properties) { QpidQueue result = addChild(EntitySpec.create(QpidQueue.class).configure(properties)); - Entities.manage(result); result.create(); return result; } public QpidTopic createTopic(Map properties) { QpidTopic result = addChild(EntitySpec.create(QpidTopic.class).configure(properties)); - Entities.manage(result); result.create(); return result; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java index 1227365..bdf7299 100644 --- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java +++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java @@ -76,7 +76,6 @@ public class RabbitBrokerImpl extends SoftwareProcessImpl implements RabbitBroke public RabbitQueue createQueue(Map properties) { RabbitQueue result = addChild(EntitySpec.create(RabbitQueue.class).configure(properties)); - Entities.manage(result); result.create(); return result; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java index be7b5a7..78898bd 100644 --- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java +++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java @@ -117,7 +117,6 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme sensors().set(WEB_CLUSTER_SPEC, webClusterSpec); DynamicWebAppCluster cluster = addChild(webClusterSpec); - if (Entities.isManaged(this)) Entities.manage(cluster); sensors().set(CLUSTER, cluster); setEntityFilter(EntityPredicates.isMemberOf(cluster)); @@ -132,8 +131,10 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme log.debug("creating controller using custom spec for {}", this); } controller = addChild(controllerSpec); - enrichers().add(Enrichers.builder().propagating(LoadBalancer.PROXY_HTTP_PORT, LoadBalancer.PROXY_HTTPS_PORT).from(controller).build()); - if (Entities.isManaged(this)) Entities.manage(controller); + enrichers().add(Enrichers.builder() + .propagating(LoadBalancer.PROXY_HTTP_PORT, LoadBalancer.PROXY_HTTPS_PORT) + .from(controller) + .build()); sensors().set(CONTROLLER, controller); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java index f295e90..1876e99 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java @@ -66,8 +66,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt); EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader); Application instance = mgmt.getEntityManager().createEntity(spec); - log.info("CAMP placing '{}' under management", instance); - Entities.startManagement(instance, mgmt); + log.info("CAMP created '{}'", instance); return instance; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java ---------------------------------------------------------------------- diff --git a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java index 7425865..ca5cda4 100644 --- a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java +++ b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java @@ -192,7 +192,11 @@ public class BrooklynLauncher { * subsequently call {@link #start()} or {@link #getApplications()}. * * @see #application(ApplicationBuilder) + * + * @deprecated since 0.9.0; instead use {@link #application(String)} for YAML apps, or {@link #application(EntitySpec)}. + * Note that apps are now auto-managed on construction through EntitySpec/YAML. */ + @Deprecated public BrooklynLauncher application(Application app) { if (Entities.isManaged(app)) throw new IllegalArgumentException("Application must not already be managed"); appsToManage.add(checkNotNull(app, "app")); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f2a296b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java index 2d6802e..157ba67 100644 --- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java +++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java @@ -50,6 +50,9 @@ import org.apache.brooklyn.api.location.LocationRegistry; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.Task; import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.AbstractEntity; @@ -268,14 +271,13 @@ public class BrooklynRestResourceUtils { } else if (Application.class.isAssignableFrom(clazz)) { org.apache.brooklyn.api.entity.EntitySpec<?> coreSpec = toCoreEntitySpec(clazz, name, configO, catalogItemId); configureRenderingMetadata(spec, coreSpec); - instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); for (EntitySpec entitySpec : entities) { log.info("REST creating instance for entity {}", entitySpec.getType()); - instance.addChild(mgmt.getEntityManager().createEntity(toCoreEntitySpec(entitySpec))); + coreSpec.child(toCoreEntitySpec(entitySpec)); } log.info("REST placing '{}' under management", spec.getName() != null ? spec.getName() : spec); - Entities.startManagement(instance, mgmt); + instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); } else if (Entity.class.isAssignableFrom(clazz)) { if (entities.size() > 0) @@ -284,19 +286,17 @@ public class BrooklynRestResourceUtils { org.apache.brooklyn.api.entity.EntitySpec<?> coreSpec = toCoreEntitySpec(BasicApplication.class, name, configO, catalogItemId); configureRenderingMetadata(spec, coreSpec); - instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); - - Entity soleChild = mgmt.getEntityManager().createEntity(toCoreEntitySpec(clazz, name, configO, catalogItemId)); - instance.addChild(soleChild); - instance.enrichers().add(Enrichers.builder() + coreSpec.child(toCoreEntitySpec(clazz, name, configO, catalogItemId) + .configure(BrooklynCampConstants.PLAN_ID, "soleChildId")); + coreSpec.enricher(Enrichers.builder() .propagatingAllBut(Attributes.SERVICE_UP, Attributes.SERVICE_NOT_UP_INDICATORS, Attributes.SERVICE_STATE_ACTUAL, Attributes.SERVICE_STATE_EXPECTED, Attributes.SERVICE_PROBLEMS) - .from(soleChild) + .from(new DslComponent(Scope.CHILD, "soleChildId").newTask()) .build()); log.info("REST placing '{}' under management", spec.getName()); - Entities.startManagement(instance, mgmt); + instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); } else { throw new IllegalArgumentException("Class " + clazz + " must extend one of ApplicationBuilder, Application or Entity");
