Skip to content

Commit

Permalink
Merge pull request brooklyncentral#1299 from grkvlt/enhancement/group…
Browse files Browse the repository at this point in the history
…-members-environment-misc

Misc improvements and Tidyup
  • Loading branch information
brooklyn-images committed Apr 8, 2014
2 parents 18252a2 + 6ae9099 commit 6ab2168
Show file tree
Hide file tree
Showing 32 changed files with 767 additions and 673 deletions.
1 change: 0 additions & 1 deletion api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ public static <T extends Entity> EntitySpec<T> create(EntitySpec<T> spec) {
EntitySpec<T> result = create(spec.getType())
.displayName(spec.getDisplayName())
.additionalInterfaces(spec.getAdditionalInterfaces())
.addInitializers(spec.getInitializers())
.configure(spec.getConfig())
.configure(spec.getFlags())
.policySpecs(spec.getPolicySpecs())
Expand Down
13 changes: 10 additions & 3 deletions core/src/main/java/brooklyn/entity/basic/AbstractGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import brooklyn.entity.Entity;
import brooklyn.entity.Group;
import brooklyn.entity.trait.Changeable;
import brooklyn.event.AttributeSensor;
import brooklyn.event.basic.Sensors;

import com.google.common.base.Predicate;
import com.google.common.reflect.TypeToken;


/**
Expand All @@ -21,8 +24,11 @@
*/
public interface AbstractGroup extends Entity, Group, Changeable {

public void setMembers(Collection<Entity> m);

AttributeSensor<Collection<Entity>> GROUP_MEMBERS = Sensors.newSensor(
new TypeToken<Collection<Entity>>() { }, "group.members", "Members of the group");

void setMembers(Collection<Entity> m);

/**
* Removes any existing members that do not match the given filter, and adds those entities in
* the given collection that match the predicate.
Expand All @@ -31,5 +37,6 @@ public interface AbstractGroup extends Entity, Group, Changeable {
* @param filter Filter for entities that are to be members (or null for "all")
*/
// FIXME Do we really want this method? "setMembers" is a misleading name
public void setMembers(Collection<Entity> mm, Predicate<Entity> filter);
void setMembers(Collection<Entity> mm, Predicate<Entity> filter);

}
82 changes: 43 additions & 39 deletions core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,70 +16,73 @@
import brooklyn.util.collections.SetFromLiveMap;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;


/**
* Represents a group of entities - sub-classes can support dynamically changing membership,
* Represents a group of entities - sub-classes can support dynamically changing membership,
* ad hoc groupings, etc.
* <p>
* Synchronization model. When changing and reading the group membership, this class uses internal
* <p>
* Synchronization model. When changing and reading the group membership, this class uses internal
* synchronization to ensure atomic operations and the "happens-before" relationship for reads/updates
* from different threads. Sub-classes should not use this same synchronization mutex when doing
* from different threads. Sub-classes should not use this same synchronization mutex when doing
* expensive operations - e.g. if resizing a cluster, don't block everyone else from asking for the
* current number of members.
*/
public abstract class AbstractGroupImpl extends AbstractEntity implements AbstractGroup {
private static final Logger log = LoggerFactory.getLogger(AbstractGroup.class);

private Set<Entity> members = Sets.newLinkedHashSet();

public AbstractGroupImpl() {
}

@Override
public void setManagementContext(ManagementContextInternal managementContext) {
super.setManagementContext(managementContext);

Set<Entity> oldMembers = members;

members = SetFromLiveMap.create(managementContext.getStorage().<Entity,Boolean>getMap(getId()+"-members"));

// Only override stored defaults if we have actual values. We might be in setManagementContext
// because we are reconstituting an existing entity in a new brooklyn management-node (in which
// case believe what is already in the storage), or we might be in the middle of creating a new
// case believe what is already in the storage), or we might be in the middle of creating a new
// entity. Normally for a new entity (using EntitySpec creation approach), this will get called
// before setting the parent etc. However, for backwards compatibility we still support some
// things calling the entity's constructor directly.
if (oldMembers.size() > 0) members.addAll(oldMembers);
}

@Override
public void init() {
super.init();
setAttribute(Changeable.GROUP_SIZE, 0);
setAttribute(GROUP_SIZE, 0);
setAttribute(GROUP_MEMBERS, ImmutableList.<Entity>of());
}

/**
* Adds the given entity as a member of this group <em>and</em> this group as one of the groups of the child
*/
@Override
public boolean addMember(Entity member) {
synchronized (members) {
member.addGroup((Group)getProxyIfAvailable());
boolean changed = members.add(member);
if (changed) {
member.addGroup((Group)getProxyIfAvailable());
boolean changed = members.add(member);
if (changed) {
log.debug("Group {} got new member {}", this, member);
emit(MEMBER_ADDED, member);
setAttribute(Changeable.GROUP_SIZE, getCurrentSize());

getManagementSupport().getEntityChangeListener().onMembersChanged();
}
return changed;
}
emit(MEMBER_ADDED, member);
setAttribute(GROUP_SIZE, getCurrentSize());
setAttribute(GROUP_MEMBERS, getMembers());

getManagementSupport().getEntityChangeListener().onMembersChanged();
}
return changed;
}
}

/**
* Returns {@code true} if the group was changed as a result of the call.
*/
Expand All @@ -89,21 +92,22 @@ public boolean removeMember(Entity member) {
boolean changed = (member != null && members.remove(member));
if (changed) {
log.debug("Group {} lost member {}", this, member);
emit(MEMBER_REMOVED, member);
setAttribute(Changeable.GROUP_SIZE, getCurrentSize());

getManagementSupport().getEntityChangeListener().onMembersChanged();
}

return changed;
emit(MEMBER_REMOVED, member);
setAttribute(GROUP_SIZE, getCurrentSize());
setAttribute(GROUP_MEMBERS, getMembers());

getManagementSupport().getEntityChangeListener().onMembersChanged();
}

return changed;
}
}

@Override
public void setMembers(Collection<Entity> m) {
setMembers(m, null);
}

@Override
public void setMembers(Collection<Entity> mm, Predicate<Entity> filter) {
synchronized (members) {
Expand All @@ -112,19 +116,19 @@ public void setMembers(Collection<Entity> mm, Predicate<Entity> filter) {
for (Entity m: mmo) {
if (!(mm.contains(m) && (filter==null || filter.apply(m))))
// remove, unless already present, being set, and not filtered out
removeMember(m);
removeMember(m);
}
for (Entity m: mm) {
if ((!mmo.contains(m)) && (filter==null || filter.apply(m))) {
// add if not alrady contained, and not filtered out
addMember(m);
}
}

getManagementSupport().getEntityChangeListener().onMembersChanged();
}
}

@Override
public Collection<Entity> getMembers() {
synchronized (members) {
Expand All @@ -145,19 +149,19 @@ public Integer getCurrentSize() {
return members.size();
}
}

@Override
public <T extends Entity> T addMemberChild(EntitySpec<T> spec) {
T child = addChild(spec);
addMember(child);
return child;
}

@Override
public <T extends Entity> T addMemberChild(T child) {
child = addChild(child);
addMember(child);
return child;
}

}
5 changes: 3 additions & 2 deletions core/src/main/java/brooklyn/entity/basic/BasicGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

@ImplementedBy(BasicGroupImpl.class)
public interface BasicGroup extends AbstractGroup {

@SetFromFlag("childrenAsMembers")
/** @deprecated since 0.7.0 use {@link Group#addMemberChild} */
@Deprecated
public static final ConfigKey<Boolean> CHILDREN_AS_MEMBERS = new BasicConfigKey<Boolean>(
ConfigKey<Boolean> CHILDREN_AS_MEMBERS = new BasicConfigKey<Boolean>(
Boolean.class, "brooklyn.BasicGroup.childrenAsMembers",
"Whether children are automatically added as group members", false);

}
35 changes: 35 additions & 0 deletions core/src/main/java/brooklyn/entity/basic/ConfigKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import javax.annotation.Nonnull;

import brooklyn.config.ConfigKey;
import brooklyn.event.basic.AttributeSensorAndConfigKey;
import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
import brooklyn.event.basic.BasicConfigKey;
import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
import brooklyn.event.basic.PortAttributeSensorAndConfigKey;

import com.google.common.base.CaseFormat;
import com.google.common.base.Preconditions;
Expand Down Expand Up @@ -40,6 +43,38 @@ public static <T> ConfigKey<T> newConfigKey(TypeToken<T> type, String name, Stri
return new BasicConfigKey<T>(type, name, description, defaultValue);
}

public static <T> AttributeSensorAndConfigKey<T,T> newSensorAndConfigKey(Class<T> type, String name, String description) {
return new BasicAttributeSensorAndConfigKey<T>(type, name, description);
}

public static <T> AttributeSensorAndConfigKey<T,T> newSensorAndConfigKey(Class<T> type, String name, String description, T defaultValue) {
return new BasicAttributeSensorAndConfigKey<T>(type, name, description, defaultValue);
}

public static AttributeSensorAndConfigKey<String,String> newStringSensorAndConfigKey(String name, String description) {
return new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(name, description);
}

public static AttributeSensorAndConfigKey<String,String> newStringSensorAndConfigKey(String name, String description, String defaultValue) {
return new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(name, description, defaultValue);
}

public static AttributeSensorAndConfigKey<Integer,Integer> newIntegerSensorAndConfigKey(String name, String description) {
return new BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey(name, description);
}

public static AttributeSensorAndConfigKey<Integer,Integer> newIntegerSensorAndConfigKey(String name, String description, Integer defaultValue) {
return new BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey(name, description, defaultValue);
}

public static PortAttributeSensorAndConfigKey newPortSensorAndConfigKey(String name, String description) {
return new PortAttributeSensorAndConfigKey(name, description);
}

public static PortAttributeSensorAndConfigKey newPortSensorAndConfigKey(String name, String description, Object defaultValue) {
return new PortAttributeSensorAndConfigKey(name, description, defaultValue);
}

/** Infers the type from the default value */
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> ConfigKey<T> newConfigKey(String name, String description, @Nonnull T defaultValue) {
Expand Down
12 changes: 10 additions & 2 deletions core/src/main/java/brooklyn/entity/basic/Entities.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import brooklyn.util.task.DynamicTasks;
import brooklyn.util.task.ParallelTask;
import brooklyn.util.task.Tasks;
import brooklyn.util.time.Duration;

import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
Expand Down Expand Up @@ -800,7 +801,7 @@ public static void warnOnIgnoringConfig(Entity entity, ConfigKey<?> key) {
}

/** waits until {@link Startable#SERVICE_UP} returns true */
public static <E extends Entity & Startable> void waitForServiceUp(final E entity, long duration, TimeUnit units) {
public static void waitForServiceUp(final Entity entity, long duration, TimeUnit units) {
String description = "Waiting for SERVICE_UP on "+entity;
Tasks.setBlockingDetails(description);
if (!Repeater.create(ImmutableMap.of("timeout", units.toMillis(duration), "description", description))
Expand All @@ -815,5 +816,12 @@ public Boolean call() {
Tasks.resetBlockingDetails();
log.debug("Detected SERVICE_UP for software {}", entity);
}

public static void waitForServiceUp(final Entity entity, Duration duration) {
waitForServiceUp(entity, duration.toMilliseconds(), TimeUnit.MILLISECONDS);
}
public static void waitForServiceUp(final Entity entity) {
Integer timeout = entity.getConfig(BrooklynConfigKeys.START_TIMEOUT);
waitForServiceUp(entity, Duration.seconds(timeout));
}

}
2 changes: 2 additions & 0 deletions core/src/main/java/brooklyn/entity/trait/Changeable.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
* A collection of entities that can change.
*/
public interface Changeable {

AttributeSensor<Integer> GROUP_SIZE = Sensors.newIntegerSensor("group.members.count", "Number of members");

BasicNotificationSensor<Entity> MEMBER_ADDED = new BasicNotificationSensor<Entity>(Entity.class, "group.members.added", "Entity added to group members");
BasicNotificationSensor<Entity> MEMBER_REMOVED = new BasicNotificationSensor<Entity>(Entity.class, "group.members.removed", "Entity removed from group members");
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public BasicAttributeSensorAndConfigKey(Class<T> type, String name) {
public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description) {
this(type, name, description, null);
}

public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description, T defaultValue) {
super(type, type, name, description, defaultValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import brooklyn.util.task.system.ProcessTaskWrapper;
import brooklyn.util.text.Strings;

import com.google.common.base.Supplier;
import com.google.common.net.HostAndPort;

public class BrooklynAccessUtils {
Expand Down Expand Up @@ -110,4 +111,13 @@ public static String getResolvedAddress(Entity entity, SshMachineLocation origin
return "";
}

public static Supplier<String> resolvedAddressSupplier(final Entity entity, final SshMachineLocation origin, final String hostnameTarget) {
return new Supplier<String>() {
@Override
public String get() {
return getResolvedAddress(entity, origin, hostnameTarget);
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import brooklyn.event.SensorEvent;
import brooklyn.event.SensorEventListener;
import brooklyn.policy.basic.AbstractPolicy;
import brooklyn.test.Asserts;
import brooklyn.test.EntityTestUtils;
import brooklyn.test.entity.TestApplication;
import brooklyn.test.entity.TestEntity;
import brooklyn.util.javalang.Boxing;

import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;

/**
* tests that a group's membership gets updated using subscriptions
Expand Down Expand Up @@ -58,6 +60,7 @@ public void testGroupFindsElement() {
e1.setAttribute(TestEntity.NAME, "bob");

EntityTestUtils.assertAttributeEqualsEventually(group, BasicGroup.GROUP_SIZE, 1);
Asserts.assertEqualsIgnoringOrder(group.getAttribute(BasicGroup.GROUP_MEMBERS), ImmutableList.of(e1));

TestEntity e2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));

Expand All @@ -72,6 +75,7 @@ public void testGroupFindsElement() {

e2.setAttribute(TestEntity.NAME, "BOB");
EntityTestUtils.assertAttributeEqualsEventually(group, BasicGroup.GROUP_SIZE, 2);
Asserts.assertEqualsIgnoringOrder(group.getAttribute(BasicGroup.GROUP_MEMBERS), ImmutableList.of(e1, e2));
}


Expand Down
Loading

0 comments on commit 6ab2168

Please sign in to comment.