Tidy up the Entities class - Rename supplier to attributeSupplier - Add newDownloader method to get DownloadResolver for a driver - Better javadoc
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b3a1b050 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b3a1b050 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b3a1b050 Branch: refs/heads/0.5.0 Commit: b3a1b05048e5550c0bdffe7e0df24240701560f6 Parents: ca17797 Author: Andrew Kennedy <[email protected]> Authored: Wed Apr 3 23:13:48 2013 +0100 Committer: Andrew Kennedy <[email protected]> Committed: Fri Apr 19 10:37:17 2013 +0100 ---------------------------------------------------------------------- .../java/brooklyn/entity/basic/Entities.java | 271 ++++++++++--------- .../java/brooklyn/event/feed/http/HttpFeed.java | 2 +- .../brooklyn/event/feed/http/HttpFeedTest.java | 4 +- .../enricher/HttpLatencyDetectorTest.java | 6 +- 4 files changed, 150 insertions(+), 133 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b3a1b050/core/src/main/java/brooklyn/entity/basic/Entities.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java index 9c97195..774ee0a 100644 --- a/core/src/main/java/brooklyn/entity/basic/Entities.java +++ b/core/src/main/java/brooklyn/entity/basic/Entities.java @@ -25,7 +25,10 @@ import brooklyn.entity.Application; import brooklyn.entity.Effector; import brooklyn.entity.Entity; import brooklyn.entity.Group; +import brooklyn.entity.drivers.EntityDriver; +import brooklyn.entity.drivers.downloads.DownloadResolver; import brooklyn.entity.trait.Startable; +import brooklyn.entity.trait.StartableMethods; import brooklyn.event.AttributeSensor; import brooklyn.event.Sensor; import brooklyn.location.Location; @@ -49,14 +52,16 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - -/** Convenience methods for working with entities. - * Also see the various *Methods classes for traits - * (eg StartableMethods for Startable implementations). */ +/** + * Convenience methods for working with entities. + * <p> + * Also see the various {@code *Methods} classes for traits, + * such as {@link StartableMethods} for {@link Startable} implementations. + */ public class Entities { private static final Logger log = LoggerFactory.getLogger(Entities.class); - + /** * Names that, if they appear anywhere in an attribute/config/field indicates that it * may be private, so should not be logged etc. @@ -69,63 +74,70 @@ public class Entities { "private", "access.cert", "access.key"); - - /** invokes the given effector with the given named arguments on the entitiesToCall, from the calling context of the callingEntity; - * intended for use only from the callingEntity. - * @return ParallelTask containing a results from each invocation; calling get() on the result will block until all complete, - * and throw error if any threw error - */ - public static <T> Task<List<T>> invokeEffectorList(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, - final Effector<T> effector, final Map<String,?> parameters) { + + /** + * Invokes an {@link Effector} on multiple entities, with the named arguments from the parameters {@link Map} + * using the context of the provided {@link Entity}. + * <p> + * Intended for use only from the callingEntity. + * <p> + * Returns a {@link ParallelTask} containing the results from each tasks invocation. Calling + * {@link java.util.concurrent.Future#get() get()} on this will block until all tasks are complete, + * and will throw an exception if any task resulted in an error. + * + * @return {@link ParallelTask} containing results from each invocation + */ + public static <T> Task<List<T>> invokeEffectorList(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, + final Effector<T> effector, final Map<String,?> parameters) { // formulation is complicated, but it is building up a list of tasks, without blocking on them initially, // but ensuring that when the parallel task is gotten it does block on all of them - // TODO why not just get list of tasks with `entity.invoke(effector, parameters))`? - // What is advantage of invoking in callingEntity's context? - - if (entitiesToCall == null || Iterables.isEmpty(entitiesToCall)) return null; - List<Task<T>> tasks = Lists.newArrayList(); - - for (final Entity entity : entitiesToCall) { - tasks.add(new BasicTask<T>( - MutableMap.of("displayName", "invoke", "description", "invoke effector \""+effector.getName()+"\" on entity "+entity), - new Callable<T>() { - public T call() throws Exception { - return entity.invoke(effector, parameters).get(); - } - })); - } - ParallelTask<T> invoke = new ParallelTask<T>( - MutableMap.of( - "displayName", "compound-invoke", - "description", "invoke effector \""+effector.getName()+"\" on "+tasks.size()+(tasks.size() == 1 ? " entity" : " entities")), - tasks); - ((EntityInternal)callingEntity).getManagementSupport().getExecutionContext().submit(invoke); - return invoke; - } - public static <T> Task<List<T>> invokeEffectorListWithMap(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, + // TODO why not just get list of tasks with `entity.invoke(effector, parameters))`? + // What is advantage of invoking in callingEntity's context? + + if (entitiesToCall == null || Iterables.isEmpty(entitiesToCall)) return null; + List<Task<T>> tasks = Lists.newArrayList(); + + for (final Entity entity : entitiesToCall) { + tasks.add(new BasicTask<T>( + MutableMap.of("displayName", "invoke", "description", "invoke effector \""+effector.getName()+"\" on entity "+entity), + new Callable<T>() { + public T call() throws Exception { + return entity.invoke(effector, parameters).get(); + } + })); + } + ParallelTask<T> invoke = new ParallelTask<T>( + MutableMap.of( + "displayName", "compound-invoke", + "description", "invoke effector \""+effector.getName()+"\" on "+tasks.size()+(tasks.size() == 1 ? " entity" : " entities")), + tasks); + ((EntityInternal)callingEntity).getManagementSupport().getExecutionContext().submit(invoke); + return invoke; + } + public static <T> Task<List<T>> invokeEffectorListWithMap(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, final Effector<T> effector, final Map<String,?> parameters) { return invokeEffectorList(callingEntity, entitiesToCall, effector, parameters); } @SuppressWarnings("unchecked") - public static <T> Task<List<T>> invokeEffectorListWithArgs(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, + public static <T> Task<List<T>> invokeEffectorListWithArgs(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, final Effector<T> effector, Object ...args) { return invokeEffectorListWithMap(callingEntity, entitiesToCall, effector, // putting into a map, unnecessarily, as it ends up being the array again... EffectorUtils.prepareArgsForEffectorAsMapFromArray(effector, args)); } - public static <T> Task<List<T>> invokeEffectorList(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, + public static <T> Task<List<T>> invokeEffectorList(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall, final Effector<T> effector) { return invokeEffectorList(callingEntity, entitiesToCall, effector, Collections.<String,Object>emptyMap()); } - public static <T> Task<List<T>> invokeEffectorWithMap(EntityLocal callingEntity, Entity entityToCall, + public static <T> Task<List<T>> invokeEffectorWithMap(EntityLocal callingEntity, Entity entityToCall, final Effector<T> effector, final Map<String,?> parameters) { return invokeEffectorList(callingEntity, ImmutableList.of(entityToCall), effector, parameters); } - public static <T> Task<List<T>> invokeEffectorWithArgs(EntityLocal callingEntity, Entity entityToCall, + public static <T> Task<List<T>> invokeEffectorWithArgs(EntityLocal callingEntity, Entity entityToCall, final Effector<T> effector, Object ...args) { - return invokeEffectorListWithArgs(callingEntity, ImmutableList.of(entityToCall), effector, args); + return invokeEffectorListWithArgs(callingEntity, ImmutableList.of(entityToCall), effector, args); } - public static <T> Task<List<T>> invokeEffector(EntityLocal callingEntity, Entity entityToCall, + public static <T> Task<List<T>> invokeEffector(EntityLocal callingEntity, Entity entityToCall, final Effector<T> effector) { return invokeEffectorWithMap(callingEntity, entityToCall, effector, Collections.<String,Object>emptyMap()); } @@ -143,7 +155,7 @@ public class Entities { (v instanceof Collection && ((Collection<?>)v).isEmpty()) || (v instanceof CharSequence&& ((CharSequence)v).length() == 0); } - + public static <K> Map<K,Object> sanitize(Map<K,?> input) { Map<K,Object> result = Maps.newLinkedHashMap(); for (Map.Entry<K,?> e: input.entrySet()) { @@ -158,7 +170,7 @@ public class Entities { dumpInfo(e); } } - + public static void dumpInfo(Entity e) { try { dumpInfo(e, new PrintWriter(System.out), "", " "); @@ -173,12 +185,12 @@ public class Entities { public static void dumpInfo(Entity e, String currentIndentation, String tab) throws IOException { dumpInfo(e, new PrintWriter(System.out), currentIndentation, tab); } - public static void dumpInfo(Entity e, Writer out, String currentIndentation, String tab) throws IOException { - out.append(currentIndentation+e.toString()+"\n"); - + public static void dumpInfo(Entity e, Writer out, String currentIndentation, String tab) throws IOException { + out.append(currentIndentation+e.toString()+"\n"); + out.append(currentIndentation+tab+tab+"locations = "+e.getLocations()+"\n"); - for (ConfigKey<?> it : sortConfigKeys(e.getEntityType().getConfigKeys())) { + for (ConfigKey<?> it : sortConfigKeys(e.getEntityType().getConfigKeys())) { Object v = ((EntityInternal)e).getConfigMap().getRawConfig(it); if (!isTrivial(v)) { out.append(currentIndentation+tab+tab+it.getName()); @@ -200,10 +212,10 @@ public class Entities { } else out.append(""+v); out.append("\n"); } - } - - for (Sensor<?> it : sortSensors(e.getEntityType().getSensors())) { - if (it instanceof AttributeSensor) { + } + + for (Sensor<?> it : sortSensors(e.getEntityType().getSensors())) { + if (it instanceof AttributeSensor) { Object v = e.getAttribute((AttributeSensor<?>)it); if (!isTrivial(v)) { out.append(currentIndentation+tab+tab+it.getName()); @@ -212,28 +224,28 @@ public class Entities { else out.append(""+v); out.append("\n"); } - } - } - - if (e instanceof Group) { - StringBuilder members = new StringBuilder(); - for (Entity it : ((Group)e).getMembers()) { + } + } + + if (e instanceof Group) { + StringBuilder members = new StringBuilder(); + for (Entity it : ((Group)e).getMembers()) { members.append(it.getId()+", "); } - out.append(currentIndentation+tab+tab+"Members: "+members.toString()+"\n"); - } - - out.append(currentIndentation+tab+tab+"Policies:\n"); + out.append(currentIndentation+tab+tab+"Members: "+members.toString()+"\n"); + } + + out.append(currentIndentation+tab+tab+"Policies:\n"); for (Policy policy : e.getPolicies()) { dumpInfo(policy, out, currentIndentation+tab+tab+tab, tab); } - - for (Entity it : e.getChildren()) { - dumpInfo(it, out, currentIndentation+tab, tab); - } - - out.flush(); - } + + for (Entity it : e.getChildren()) { + dumpInfo(it, out, currentIndentation+tab, tab); + } + + out.flush(); + } public static void dumpInfo(Location loc) { try { @@ -252,11 +264,11 @@ public class Entities { @SuppressWarnings("rawtypes") public static void dumpInfo(Location loc, Writer out, String currentIndentation, String tab) throws IOException { out.append(currentIndentation+loc.toString()+"\n"); - + for (Object entryO : loc.getAllConfig().entrySet()) { Map.Entry entry = (Map.Entry)entryO; Object keyO = entry.getKey(); - String key = + String key = keyO instanceof HasConfigKey ? ((HasConfigKey)keyO).getConfigKey().getName() : keyO instanceof ConfigKey ? ((ConfigKey)keyO).getName() : keyO == null ? null : @@ -270,8 +282,8 @@ public class Entities { out.append("\n"); } } - - + + for (Map.Entry<String,?> entry : sortMap(FlagUtils.getFieldsWithFlags(loc)).entrySet()) { String key = entry.getKey(); Object val = entry.getValue(); @@ -283,11 +295,11 @@ public class Entities { out.append("\n"); } } - + for (Location it : loc.getChildLocations()) { dumpInfo(it, out, currentIndentation+tab, tab); } - + out.flush(); } @@ -307,7 +319,7 @@ public class Entities { } public static void dumpInfo(Policy pol, Writer out, String currentIndentation, String tab) throws IOException { out.append(currentIndentation+pol.toString()+"\n"); - + for (ConfigKey<?> key : sortConfigKeys(pol.getPolicyType().getConfigKeys())) { Object val = ((AbstractPolicy)pol).getConfigMap().getRawConfig(key); if (!isTrivial(val)) { @@ -318,23 +330,23 @@ public class Entities { out.append("\n"); } } - + out.flush(); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes", "unchecked" }) public static List<Sensor<?>> sortSensors(Set<Sensor<?>> sensors) { - List result = new ArrayList(sensors); - Collections.sort(result, new Comparator<Sensor>() { + List result = new ArrayList(sensors); + Collections.sort(result, new Comparator<Sensor>() { @Override public int compare(Sensor arg0, Sensor arg1) { return arg0.getName().compareTo(arg1.getName()); } - - }); - return result; + + }); + return result; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) public static List<ConfigKey<?>> sortConfigKeys(Set<ConfigKey<?>> configs) { List result = new ArrayList(configs); @@ -343,53 +355,53 @@ public class Entities { public int compare(ConfigKey arg0, ConfigKey arg1) { return arg0.getName().compareTo(arg1.getName()); } - + }); return result; } - + public static <T> Map<String, T> sortMap(Map<String, T> map) { Map<String,T> result = Maps.newLinkedHashMap(); List<String> order = Lists.newArrayList(map.keySet()); Collections.sort(order, String.CASE_INSENSITIVE_ORDER); - + for (String key : order) { result.put(key, map.get(key)); } return result; } - + public static boolean isAncestor(Entity descendant, Entity potentialAncestor) { - Entity ancestor = descendant.getParent(); - while (ancestor != null) { - if (ancestor.equals(potentialAncestor)) return true; - ancestor = ancestor.getParent(); - } - return false; - } - - /** note, it is usually preferred to use isAncestor() and swap the order, it is a cheaper method */ - public static boolean isDescendant(Entity ancestor, Entity potentialDescendant) { - Set<Entity> inspected = Sets.newLinkedHashSet(); - Stack<Entity> toinspect = new Stack<Entity>(); - toinspect.add(ancestor); - - while (!toinspect.isEmpty()) { - Entity e = toinspect.pop(); - if (e.getChildren().contains(potentialDescendant)) { - return true; - } - inspected.add(e); - toinspect.addAll(e.getChildren()); - toinspect.removeAll(inspected); - } - - return false; - } + Entity ancestor = descendant.getParent(); + while (ancestor != null) { + if (ancestor.equals(potentialAncestor)) return true; + ancestor = ancestor.getParent(); + } + return false; + } + + /** note, it is usually preferred to use isAncestor() and swap the order, it is a cheaper method */ + public static boolean isDescendant(Entity ancestor, Entity potentialDescendant) { + Set<Entity> inspected = Sets.newLinkedHashSet(); + Stack<Entity> toinspect = new Stack<Entity>(); + toinspect.add(ancestor); + + while (!toinspect.isEmpty()) { + Entity e = toinspect.pop(); + if (e.getChildren().contains(potentialDescendant)) { + return true; + } + inspected.add(e); + toinspect.addAll(e.getChildren()); + toinspect.removeAll(inspected); + } + + return false; + } private static final List<Entity> entitiesToStopOnShutdown = Lists.newArrayList(); private static final AtomicBoolean isShutdownHookRegistered = new AtomicBoolean(); - + public static void invokeStopOnShutdown(Entity entity) { if (isShutdownHookRegistered.compareAndSet(false, true)) { ResourceUtils.addShutdownHook(new Runnable() { @@ -405,9 +417,9 @@ public class Entities { log.debug("stopOnShutdown of "+entity+" returned error: "+exc, exc); } } - for (Task t: stops) { + for (Task t: stops) { try { - log.debug("stopOnShutdown of {} completed: {}", t, t.get()); + log.debug("stopOnShutdown of {} completed: {}", t, t.get()); } catch (Exception exc) { log.debug("stopOnShutdown of "+t+" returned error: "+exc, exc); } @@ -472,10 +484,10 @@ public class Entities { public static boolean isManaged(Entity e) { return ((EntityInternal)e).getManagementSupport().isDeployed() && ((EntityInternal)e).getManagementContext().isRunning(); } - + /** brings this entity under management iff its ancestor is managed, returns true in that case; * otherwise returns false in the expectation that the ancestor will become managed, - * or throws exception if it has no parent or a non-application root + * or throws exception if it has no parent or a non-application root * (will throw if e is an Application; see also {@link #startManagement(Entity)} ) */ public static boolean manage(Entity e) { Entity o = e.getParent(); @@ -498,7 +510,7 @@ public class Entities { * (assuming root is an application). * returns existing management context if there is one (non-deployment), * or new local mgmt context if not, - * or throwing exception if root is not an application + * or throwing exception if root is not an application * <p> * callers are recommended to use {@link #manage(Entity)} instead unless they know * a plain-vanilla non-root management context is sufficient (e.g. in tests) @@ -526,7 +538,7 @@ public class Entities { /** * Starts managing the given (unmanaged) app, using the given management context. - * + * * @see startManagement(Entity) */ public static ManagementContext startManagement(Application app, ManagementContext mgmt) { @@ -536,11 +548,11 @@ public class Entities { mgmt.getEntityManager().manage(app); return mgmt; } - + /** * Starts managing the given (unmanaged) app, setting the given brooklyn properties on the new * management context. - * + * * @see startManagement(Entity) */ public static ManagementContext startManagement(Application app, BrooklynProperties props) { @@ -551,11 +563,11 @@ public class Entities { mgmt.getEntityManager().manage(app); return mgmt; } - + public static ManagementContext newManagementContext() { return new LocalManagementContext(); } - + public static ManagementContext newManagementContext(BrooklynProperties props) { return new LocalManagementContext(props); } @@ -570,7 +582,12 @@ public class Entities { } } - public static <T> Supplier<T> supplier(final Entity entity, final AttributeSensor<T> sensor) { + public static DownloadResolver newDownloader(EntityDriver driver) { + EntityInternal internal = (EntityInternal) driver.getEntity(); + return internal.getManagementContext().getEntityDownloadsManager().newDownloader(driver); + } + + public static <T> Supplier<T> attributeSupplier(final Entity entity, final AttributeSensor<T> sensor) { return new Supplier<T>() { public T get() { return entity.getAttribute(sensor); } }; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b3a1b050/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java b/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java index 4133b58..06081a6 100644 --- a/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java +++ b/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java @@ -81,7 +81,7 @@ import com.google.common.collect.Sets; * <p> * * This also supports giving a Supplier for the URL - * (e.g. {@link Entities#supplier(brooklyn.entity.Entity, brooklyn.event.AttributeSensor)}) + * (e.g. {@link Entities#attributeSupplier(brooklyn.entity.Entity, brooklyn.event.AttributeSensor)}) * from a sensor. Note however that if a Supplier-based sensor is *https*, * https-specific initialization may not occur if the URL is not available at start time, * and it may report errors if that sensor is not available. http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b3a1b050/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java b/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java index d1eeab7..d438571 100644 --- a/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java +++ b/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java @@ -167,10 +167,10 @@ public class HttpFeedTest { .suspended() .build(); Asserts.continually(MutableMap.of("timeout", 500), - Entities.supplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(null)); + Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(null)); int countWhenSuspended = server.getRequestCount(); feed.resume(); - Asserts.eventually(Entities.supplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(200)); + Asserts.eventually(Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(200)); if (server.getRequestCount() <= countWhenSuspended) Assert.fail("Request count failed to increment when feed was resumed, from "+countWhenSuspended+", still at "+server.getRequestCount()); log.info("RUN: "+countWhenSuspended+" - "+server.getRequestCount()); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b3a1b050/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java b/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java index df9fdb0..5b92252 100644 --- a/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java +++ b/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java @@ -54,15 +54,15 @@ public class HttpLatencyDetectorTest { build()); // nothing until url is set TestUtils.assertContinuallyFromJava(MutableMap.of("timeout", 200), - Entities.supplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT), + Entities.attributeSupplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT), Predicates.equalTo(null)); entity.setAttribute(TEST_URL, "http://www.google.com"); TestUtils.assertEventually(MutableMap.of("timeout", 10000), - Entities.supplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT), + Entities.attributeSupplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT), Predicates.notNull()); log.info("Latency to "+entity.getAttribute(TEST_URL)+" is "+entity.getAttribute(HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT)); TestUtils.assertEventually(MutableMap.of("timeout", 10000), - Entities.supplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW), + Entities.attributeSupplier(entity, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW), Predicates.notNull()); log.info("Mean latency to "+entity.getAttribute(TEST_URL)+" is "+entity.getAttribute(HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW)); }
