You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/08/19 23:21:02 UTC
[28/62] [abbrv] incubator-brooklyn git commit: rename core’s o.a.b.entity to o.a.b.core.entity
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java
new file mode 100644
index 0000000..7ec70a1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java
@@ -0,0 +1,153 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.objs.Identifiable;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.guava.Functionals;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.Iterables;
+
+public class EntityFunctions {
+
+ public static <T> Function<Entity, T> attribute(final AttributeSensor<T> attribute) {
+ class GetEntityAttributeFunction implements Function<Entity, T> {
+ @Override public T apply(Entity input) {
+ return (input == null) ? null : input.getAttribute(attribute);
+ }
+ };
+ return new GetEntityAttributeFunction();
+ }
+
+ public static <T> Function<Entity, T> config(final ConfigKey<T> key) {
+ class GetEntityConfigFunction implements Function<Entity, T> {
+ @Override public T apply(Entity input) {
+ return (input == null) ? null : input.getConfig(key);
+ }
+ };
+ return new GetEntityConfigFunction();
+ }
+
+ public static Function<Entity, String> displayName() {
+ class GetEntityDisplayName implements Function<Entity, String> {
+ @Override public String apply(Entity input) {
+ return (input == null) ? null : input.getDisplayName();
+ }
+ };
+ return new GetEntityDisplayName();
+ }
+
+ public static Function<Identifiable, String> id() {
+ class GetIdFunction implements Function<Identifiable, String> {
+ @Override public String apply(Identifiable input) {
+ return (input == null) ? null : input.getId();
+ }
+ };
+ return new GetIdFunction();
+ }
+
+ /** returns a function which sets the given sensors on the entity passed in,
+ * with {@link Entities#UNCHANGED} and {@link Entities#REMOVE} doing those actions. */
+ public static Function<Entity,Void> settingSensorsConstant(final Map<AttributeSensor<?>,Object> values) {
+ checkNotNull(values, "values");
+ class SettingSensorsConstantFunction implements Function<Entity, Void> {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override public Void apply(Entity input) {
+ for (Map.Entry<AttributeSensor<?>,Object> entry : values.entrySet()) {
+ AttributeSensor sensor = (AttributeSensor)entry.getKey();
+ Object value = entry.getValue();
+ if (value==Entities.UNCHANGED) {
+ // nothing
+ } else if (value==Entities.REMOVE) {
+ ((EntityInternal)input).removeAttribute(sensor);
+ } else {
+ value = TypeCoercions.coerce(value, sensor.getTypeToken());
+ ((EntityInternal)input).setAttribute(sensor, value);
+ }
+ }
+ return null;
+ }
+ }
+ return new SettingSensorsConstantFunction();
+ }
+
+ /** as {@link #settingSensorsConstant(Map)} but as a {@link Runnable} */
+ public static Runnable settingSensorsConstant(final Entity entity, final Map<AttributeSensor<?>,Object> values) {
+ checkNotNull(entity, "entity");
+ checkNotNull(values, "values");
+ return Functionals.runnable(Suppliers.compose(settingSensorsConstant(values), Suppliers.ofInstance(entity)));
+ }
+
+ public static <K,V> Function<Entity, Void> updatingSensorMapEntry(final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) {
+ class UpdatingSensorMapEntryFunction implements Function<Entity, Void> {
+ @Override public Void apply(Entity input) {
+ ServiceStateLogic.updateMapSensorEntry((EntityLocal)input, mapSensor, key, valueSupplier.get());
+ return null;
+ }
+ }
+ return new UpdatingSensorMapEntryFunction();
+ }
+ public static <K,V> Runnable updatingSensorMapEntry(final Entity entity, final AttributeSensor<Map<K,V>> mapSensor, final K key, final Supplier<? extends V> valueSupplier) {
+ return Functionals.runnable(Suppliers.compose(updatingSensorMapEntry(mapSensor, key, valueSupplier), Suppliers.ofInstance(entity)));
+ }
+
+ public static Supplier<Collection<Application>> applications(final ManagementContext mgmt) {
+ class AppsSupplier implements Supplier<Collection<Application>> {
+ @Override
+ public Collection<Application> get() {
+ return mgmt.getApplications();
+ }
+ }
+ return new AppsSupplier();
+ }
+
+ public static Function<Entity, Location> locationMatching(Predicate<? super Location> filter) {
+ return new LocationMatching(filter);
+ }
+
+ private static class LocationMatching implements Function<Entity, Location> {
+ private Predicate<? super Location> filter;
+
+ private LocationMatching() { /* for xstream */
+ }
+ public LocationMatching(Predicate<? super Location> filter) {
+ this.filter = filter;
+ }
+ @Override public Location apply(Entity input) {
+ return Iterables.find(input.getLocations(), filter);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
new file mode 100644
index 0000000..a258007
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
@@ -0,0 +1,49 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntityLocal;
+
+import com.google.common.collect.ImmutableList;
+
+public class EntityInitializers {
+
+ public static class AddTags implements EntityInitializer {
+ public final List<Object> tags;
+
+ public AddTags(Object... tags) {
+ this.tags = ImmutableList.copyOf(tags);
+ }
+
+ @Override
+ public void apply(EntityLocal entity) {
+ for (Object tag: tags)
+ entity.tags().addTag(tag);
+ }
+ }
+
+
+ public static EntityInitializer addingTags(Object... tags) {
+ return new AddTags(tags);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
new file mode 100644
index 0000000..0147170
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
@@ -0,0 +1,201 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.mgmt.rebind.Rebindable;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.internal.EntityConfigMap;
+import org.apache.brooklyn.core.mgmt.internal.EntityManagementSupport;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Extended Entity interface with additional functionality that is purely-internal (i.e. intended
+ * for the brooklyn framework only).
+ */
+@Beta
+public interface EntityInternal extends BrooklynObjectInternal, EntityLocal, Rebindable {
+
+ void addLocations(Collection<? extends Location> locations);
+
+ void removeLocations(Collection<? extends Location> locations);
+
+ void clearLocations();
+
+ /**
+ *
+ * Like {@link EntityLocal#setAttribute(AttributeSensor, Object)}, except does not publish an attribute-change event.
+ */
+ <T> T setAttributeWithoutPublishing(AttributeSensor<T> sensor, T val);
+
+ /**
+ * @deprecated since 0.7.0; instead just use methods on {@link ConfigurationSupportInternal} returned by {@link #config()}
+ */
+ @Deprecated
+ EntityConfigMap getConfigMap();
+
+ /**
+ * @return a read-only copy of all the config key/value pairs on this entity.
+ *
+ * @deprecated since 0.7.0; instead just use methods on {@link ConfigurationSupportInternal} returned by {@link #config()},
+ * e.g. getBag().getAllConfigAsConfigKeyMap().
+ */
+ @Deprecated
+ @Beta
+ Map<ConfigKey<?>,Object> getAllConfig();
+
+ /**
+ * Returns a read-only view of all the config key/value pairs on this entity, backed by a string-based map,
+ * including config names that did not match anything on this entity.
+ *
+ * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().getBag()}
+ */
+ @Deprecated
+ ConfigBag getAllConfigBag();
+
+ /**
+ * Returns a read-only view of the local (i.e. not inherited) config key/value pairs on this entity,
+ * backed by a string-based map, including config names that did not match anything on this entity.
+ *
+ * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().getLocalBag()}
+ */
+ @Deprecated
+ ConfigBag getLocalConfigBag();
+
+ @Beta
+ Map<AttributeSensor, Object> getAllAttributes();
+
+ @Beta
+ void removeAttribute(AttributeSensor<?> attribute);
+
+ /**
+ *
+ * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().refreshInheritedConfig()}
+ */
+ @Deprecated
+ void refreshInheritedConfig();
+
+ /**
+ * Must be called before the entity is started.
+ *
+ * @return this entity (i.e. itself)
+ */
+ @Beta // for internal use only
+ EntityInternal configure(Map flags);
+
+ /**
+ * @return Routings for accessing and inspecting the management context of the entity
+ */
+ EntityManagementSupport getManagementSupport();
+
+ /**
+ * Should be invoked at end-of-life to clean up the item.
+ */
+ @Beta
+ void destroy();
+
+ /**
+ * Returns the management context for the entity. If the entity is not yet managed, some
+ * operations on the management context will fail.
+ *
+ * Do not cache this object; instead call getManagementContext() each time you need to use it.
+ */
+ ManagementContext getManagementContext();
+
+ /**
+ * Returns the task execution context for the entity. If the entity is not yet managed, some
+ * operations on the management context will fail.
+ *
+ * Do not cache this object; instead call getExecutionContext() each time you need to use it.
+ */
+ ExecutionContext getExecutionContext();
+
+ SubscriptionContext getSubscriptionContext();
+
+ /** returns the dynamic type corresponding to the type of this entity instance */
+ @Beta
+ EntityDynamicType getMutableEntityType();
+
+ /** returns the effector registered against a given name */
+ @Beta
+ Effector<?> getEffector(String effectorName);
+
+ FeedSupport feeds();
+
+ /**
+ * @since 0.7.0-M2
+ * @deprecated since 0.7.0-M2; use {@link #feeds()}
+ */
+ @Deprecated
+ FeedSupport getFeedSupport();
+
+ Map<String, String> toMetadataRecord();
+
+ /**
+ * Users are strongly discouraged from calling or overriding this method.
+ * It is for internal calls only, relating to persisting/rebinding entities.
+ * This method may change (or be removed) in a future release without notice.
+ */
+ @Override
+ @Beta
+ RebindSupport<EntityMemento> getRebindSupport();
+
+ /**
+ * Can be called to request that the entity be persisted.
+ * This persistence may happen asynchronously, or may not happen at all if persistence is disabled.
+ */
+ void requestPersist();
+
+ public interface FeedSupport {
+ Collection<Feed> getFeeds();
+
+ /**
+ * Adds the given feed to this entity. The feed will automatically be re-added on brooklyn restart.
+ */
+ <T extends Feed> T addFeed(T feed);
+
+ /**
+ * Removes the given feed from this entity.
+ * @return True if the feed existed at this entity; false otherwise
+ */
+ boolean removeFeed(Feed feed);
+
+ /**
+ * Removes all feeds from this entity.
+ * Use with caution as some entities automatically register feeds; this will remove those feeds as well.
+ * @return True if any feeds existed at this entity; false otherwise
+ */
+ boolean removeAllFeeds();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityPredicates.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityPredicates.java
new file mode 100644
index 0000000..a618784
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityPredicates.java
@@ -0,0 +1,451 @@
+/*
+ * 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 java.util.Collection;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
+import org.apache.brooklyn.util.collections.CollectionFunctionals;
+import org.apache.brooklyn.util.guava.SerializablePredicate;
+import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.text.StringPredicates;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+@SuppressWarnings("serial")
+public class EntityPredicates {
+
+ public static Predicate<Entity> idEqualTo(final String val) {
+ return idSatisfies(Predicates.equalTo(val));
+ }
+
+ public static Predicate<Entity> idSatisfies(final Predicate<? super String> condition) {
+ return new IdSatisfies(condition);
+ }
+
+ protected static class IdSatisfies implements SerializablePredicate<Entity> {
+ protected final Predicate<? super String> condition;
+ protected IdSatisfies(Predicate<? super String> condition) {
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getId());
+ }
+ @Override
+ public String toString() {
+ return "idSatisfies("+condition+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> idEqualToOld(final T val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getId(), val);
+ }
+ };
+ }
+
+ // ---------------------------
+
+ public static Predicate<Entity> displayNameEqualTo(final String val) {
+ return displayNameSatisfies(Predicates.equalTo(val));
+ }
+
+ public static Predicate<Entity> displayNameSatisfies(final Predicate<? super String> condition) {
+ return new DisplayNameSatisfies(condition);
+ }
+
+ protected static class DisplayNameSatisfies implements SerializablePredicate<Entity> {
+ protected final Predicate<? super String> condition;
+ protected DisplayNameSatisfies(Predicate<? super String> condition) {
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getDisplayName());
+ }
+ @Override
+ public String toString() {
+ return "displayNameSatisfies("+condition+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> displayNameEqualToOld(final T val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getDisplayName(), val);
+ }
+ };
+ }
+
+ /** @deprecated since 0.7.0 use {@link #displayNameSatisfies(Predicate)} to clarify this is *regex* matching
+ * (passing {@link StringPredicates#matchesRegex(String)} as the predicate) */
+ public static Predicate<Entity> displayNameMatches(final String regex) {
+ return displayNameSatisfies(StringPredicates.matchesRegex(regex));
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static class DisplayNameMatches implements SerializablePredicate<Entity> {
+ private final String regex;
+ DisplayNameMatches(String regex) {
+ this.regex = regex;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null && input.getDisplayName() != null) && input.getDisplayName().matches(regex);
+ }
+ @Override
+ public String toString() {
+ return "DisplayNameMatches("+regex+")";
+ }
+ };
+
+ // ---------------------------
+
+ public static Predicate<Entity> applicationIdEqualTo(final String val) {
+ return applicationIdSatisfies(Predicates.equalTo(val));
+ }
+
+ public static Predicate<Entity> applicationIdSatisfies(final Predicate<? super String> condition) {
+ return new ApplicationIdSatisfies(condition);
+ }
+
+ protected static class ApplicationIdSatisfies implements SerializablePredicate<Entity> {
+ protected final Predicate<? super String> condition;
+ protected ApplicationIdSatisfies(Predicate<? super String> condition) {
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getApplicationId());
+ }
+ @Override
+ public String toString() {
+ return "applicationIdSatisfies("+condition+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static Predicate<Entity> applicationIdEqualToOld(final String val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && val.equals(input.getApplicationId());
+ }
+ };
+ }
+
+ // ---------------------------
+
+ public static <T> Predicate<Entity> attributeEqualTo(final AttributeSensor<T> attribute, final T val) {
+ return attributeSatisfies(attribute, Predicates.equalTo(val));
+ }
+
+ public static <T> Predicate<Entity> attributeSatisfies(final AttributeSensor<T> attribute, final Predicate<T> condition) {
+ return new AttributeSatisfies<T>(attribute, condition);
+ }
+
+ protected static class AttributeSatisfies<T> implements SerializablePredicate<Entity> {
+ protected final AttributeSensor<T> attribute;
+ protected final Predicate<T> condition;
+ private AttributeSatisfies(AttributeSensor<T> attribute, Predicate<T> condition) {
+ this.attribute = attribute;
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getAttribute(attribute));
+ }
+ @Override
+ public String toString() {
+ return "attributeSatisfies("+attribute.getName()+","+condition+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> attributeEqualToOld(final AttributeSensor<T> attribute, final T val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getAttribute(attribute), val);
+ }
+ };
+ }
+
+ public static <T> Predicate<Entity> attributeNotEqualTo(final AttributeSensor<T> attribute, final T val) {
+ return attributeSatisfies(attribute, Predicates.not(Predicates.equalTo(val)));
+ }
+
+ // ---------------------------
+
+ public static <T> Predicate<Entity> configEqualTo(final ConfigKey<T> configKey, final T val) {
+ return configSatisfies(configKey, Predicates.equalTo(val));
+ }
+
+ public static <T> Predicate<Entity> configSatisfies(final ConfigKey<T> configKey, final Predicate<T> condition) {
+ return new ConfigKeySatisfies<T>(configKey, condition);
+ }
+
+ public static <T> Predicate<Entity> configEqualTo(final HasConfigKey<T> configKey, final T val) {
+ return configEqualTo(configKey.getConfigKey(), val);
+ }
+
+ public static <T> Predicate<Entity> configSatisfies(final HasConfigKey<T> configKey, final Predicate<T> condition) {
+ return new ConfigKeySatisfies<T>(configKey.getConfigKey(), condition);
+ }
+
+ protected static class ConfigKeySatisfies<T> implements SerializablePredicate<Entity> {
+ protected final ConfigKey<T> configKey;
+ protected final Predicate<T> condition;
+ private ConfigKeySatisfies(ConfigKey<T> configKey, Predicate<T> condition) {
+ this.configKey = configKey;
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getConfig(configKey));
+ }
+ @Override
+ public String toString() {
+ return "configKeySatisfies("+configKey.getName()+","+condition+")";
+ }
+ }
+
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> configEqualToOld(final ConfigKey<T> configKey, final T val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getConfig(configKey), val);
+ }
+ };
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> configEqualToOld(final HasConfigKey<T> configKey, final T val) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getConfig(configKey), val);
+ }
+ };
+ }
+
+ // ---------------------------
+
+ /**
+ * @param typeRegex a regular expression
+ * @return true if any of the interfaces implemented by the entity (including those derived) match typeRegex.
+ */
+ public static Predicate<Entity> hasInterfaceMatching(String typeRegex) {
+ return new ImplementsInterface(typeRegex);
+ }
+
+ protected static class ImplementsInterface implements SerializablePredicate<Entity> {
+ protected final Pattern pattern;
+
+ public ImplementsInterface(String typeRegex) {
+ this.pattern = Pattern.compile(typeRegex);
+ }
+
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ if (input == null) return false;
+ for (Class<?> cls : Reflections.getAllInterfaces(input.getClass())) {
+ if (pattern.matcher(cls.getName()).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ // ---------------------------
+
+ /**
+ * Returns a predicate that determines if a given entity is a direct child of this {@code parent}.
+ */
+ public static Predicate<Entity> isChildOf(final Entity parent) {
+ return new IsChildOf(parent);
+ }
+
+ // if needed, could add parentSatisfies(...)
+
+ protected static class IsChildOf implements SerializablePredicate<Entity> {
+ protected final Entity parent;
+ protected IsChildOf(Entity parent) {
+ this.parent = parent;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getParent(), parent);
+ }
+ @Override
+ public String toString() {
+ return "isChildOf("+parent+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> isChildOfOld(final Entity parent) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Objects.equal(input.getParent(), parent);
+ }
+ };
+ }
+
+ // ---------------------------
+
+ public static Predicate<Entity> isMemberOf(final Group group) {
+ return new IsMemberOf(group);
+ }
+
+ protected static class IsMemberOf implements SerializablePredicate<Entity> {
+ protected final Group group;
+ protected IsMemberOf(Group group) {
+ this.group = group;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (group != null) && (input != null) && group.hasMember(input);
+ }
+ @Override
+ public String toString() {
+ return "isMemberOf("+group+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> isMemberOfOld(final Group group) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && group.hasMember(input);
+ }
+ };
+ }
+
+ // ---------------------------
+
+ /**
+ * Create a predicate that matches any entity who has an exact match for the given location
+ * (i.e. {@code entity.getLocations().contains(location)}).
+ */
+ public static <T> Predicate<Entity> locationsIncludes(Location location) {
+ return locationsSatisfy(CollectionFunctionals.contains(location));
+
+ }
+
+ public static <T> Predicate<Entity> locationsSatisfy(final Predicate<Collection<Location>> condition) {
+ return new LocationsSatisfy(condition);
+ }
+
+ protected static class LocationsSatisfy implements SerializablePredicate<Entity> {
+ protected final Predicate<Collection<Location>> condition;
+ protected LocationsSatisfy(Predicate<Collection<Location>> condition) {
+ this.condition = condition;
+ }
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && condition.apply(input.getLocations());
+ }
+ @Override
+ public String toString() {
+ return "locationsSatisfy("+condition+")";
+ }
+ }
+
+ /** @deprecated since 0.7.0 use {@link #locationsIncludes(Location)} */
+ @Deprecated
+ public static <T> Predicate<Entity> withLocation(final Location location) {
+ return locationsIncludes(location);
+ }
+
+ /** @deprecated since 0.7.0 use {@link #locationsIncludes(Location)}, introduced to allow deserialization of anonymous inner class */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> withLocationOld(final Location location) {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && input.getLocations().contains(location);
+ }
+ };
+ }
+
+ // ---------------------------
+
+ public static <T> Predicate<Entity> isManaged() {
+ return new IsManaged();
+ }
+
+ protected static class IsManaged implements SerializablePredicate<Entity> {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Entities.isManaged(input);
+ }
+ @Override
+ public String toString() {
+ return "isManaged()";
+ }
+ }
+
+ /** @deprecated since 0.7.0 use {@link #isManaged()} */ @Deprecated
+ public static <T> Predicate<Entity> managed() {
+ return isManaged();
+ }
+
+ /** @deprecated since 0.7.0 use {@link #isManaged()}, introduced to allow deserialization of anonymous inner class */
+ @SuppressWarnings("unused") @Deprecated
+ private static <T> Predicate<Entity> managedOld() {
+ return new SerializablePredicate<Entity>() {
+ @Override
+ public boolean apply(@Nullable Entity input) {
+ return (input != null) && Entities.isManaged(input);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntitySuppliers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntitySuppliers.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntitySuppliers.java
new file mode 100644
index 0000000..0e99f27
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntitySuppliers.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.location.core.Machines;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.base.Supplier;
+
+public class EntitySuppliers {
+
+ public static Supplier<SshMachineLocation> uniqueSshMachineLocation(Entity entity) {
+ return new UniqueSshMchineLocation(entity);
+ }
+
+ private static class UniqueSshMchineLocation implements Supplier<SshMachineLocation> {
+ private Entity entity;
+
+ private UniqueSshMchineLocation() { /* for xstream */
+ }
+
+ private UniqueSshMchineLocation(Entity entity) {
+ this.entity = entity;
+ }
+
+ @Override public SshMachineLocation get() {
+ return Machines.findUniqueSshMachineLocation(entity.getLocations()).get();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
new file mode 100644
index 0000000..ba2992f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
@@ -0,0 +1,81 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.sensor.core.DependentConfiguration;
+import org.apache.brooklyn.util.collections.CollectionFunctionals;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+/** Generally useful tasks related to entities */
+public class EntityTasks {
+
+ /** creates an (unsubmitted) task which waits for the attribute to satisfy the given predicate,
+ * returning false if it times out or becomes unmanaged */
+ public static <T> Task<Boolean> testingAttributeEventually(Entity entity, AttributeSensor<T> sensor, Predicate<T> condition, Duration timeout) {
+ return DependentConfiguration.builder().attributeWhenReady(entity, sensor)
+ .readiness(condition)
+ .postProcess(Functions.constant(true))
+ .timeout(timeout)
+ .onTimeoutReturn(false)
+ .onUnmanagedReturn(false)
+ .build();
+ }
+
+ /** creates an (unsubmitted) task which waits for the attribute to satisfy the given predicate,
+ * throwing if it times out or becomes unmanaged */
+ public static <T> Task<Boolean> requiringAttributeEventually(Entity entity, AttributeSensor<T> sensor, Predicate<T> condition, Duration timeout) {
+ return DependentConfiguration.builder().attributeWhenReady(entity, sensor)
+ .readiness(condition)
+ .postProcess(Functions.constant(true))
+ .timeout(timeout)
+ .onTimeoutThrow()
+ .onUnmanagedThrow()
+ .build();
+ }
+
+ /** as {@link #testingAttributeEventually(Entity, AttributeSensor, Predicate, Duration) for multiple entities */
+ public static <T> Task<Boolean> testingAttributeEventually(Iterable<Entity> entities, AttributeSensor<T> sensor, Predicate<T> condition, Duration timeout) {
+ return DependentConfiguration.builder().attributeWhenReadyFromMultiple(entities, sensor, condition)
+ .postProcess(Functions.constant(true))
+ .timeout(timeout)
+ .onTimeoutReturn(false)
+ .onUnmanagedReturn(false)
+ .postProcessFromMultiple(CollectionFunctionals.all(Predicates.equalTo(true)))
+ .build();
+ }
+
+ /** as {@link #requiringAttributeEventually(Entity, AttributeSensor, Predicate, Duration) for multiple entities */
+ public static <T> Task<Boolean> requiringAttributeEventually(Iterable<Entity> entities, AttributeSensor<T> sensor, Predicate<T> condition, Duration timeout) {
+ return DependentConfiguration.builder().attributeWhenReadyFromMultiple(entities, sensor, condition)
+ .postProcess(Functions.constant(true))
+ .timeout(timeout)
+ .onTimeoutThrow()
+ .onUnmanagedThrow()
+ .postProcessFromMultiple(CollectionFunctionals.all(Predicates.equalTo(true)))
+ .build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypeSnapshot.java
new file mode 100644
index 0000000..ef5c710
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypeSnapshot.java
@@ -0,0 +1,126 @@
+/*
+ * 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 java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.EntityType;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.objs.BrooklynTypeSnapshot;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class EntityTypeSnapshot extends BrooklynTypeSnapshot implements EntityType {
+ private static final long serialVersionUID = 4670930188951106009L;
+
+ private final Map<String, Sensor<?>> sensors;
+ private final Set<Effector<?>> effectors;
+ private final Set<Sensor<?>> sensorsSet;
+
+ EntityTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys, Map<String, Sensor<?>> sensors, Collection<Effector<?>> effectors) {
+ super(name, configKeys);
+ this.sensors = ImmutableMap.copyOf(sensors);
+ this.effectors = ImmutableSet.copyOf(effectors);
+ this.sensorsSet = ImmutableSet.copyOf(this.sensors.values());
+ }
+
+ @Override
+ public Set<Sensor<?>> getSensors() {
+ return sensorsSet;
+ }
+
+ @Override
+ public Set<Effector<?>> getEffectors() {
+ return effectors;
+ }
+
+ @Override
+ public Maybe<Effector<?>> getEffectorByName(String name) {
+ for (Effector<?> contender : effectors) {
+ if (name.equals(contender.getName()))
+ return Maybe.<Effector<?>>of(contender);
+ }
+ return Maybe.<Effector<?>>absent("No effector matching '"+name+"'");
+ }
+
+ @Override
+ public Effector<?> getEffector(String name, Class<?>... parameterTypes) {
+ // TODO Could index for more efficient lookup (e.g. by name in a MultiMap, or using name+parameterTypes as a key)
+ // TODO Looks for exact match; could go for what would be valid to call (i.e. if parameterType is sub-class of ParameterType.getParameterClass then ok)
+ // TODO Could take into account ParameterType.getDefaultValue() for what can be omitted
+
+ effectorLoop : for (Effector<?> contender : effectors) {
+ if (name.equals(contender.getName())) {
+ List<ParameterType<?>> contenderParameters = contender.getParameters();
+ if (parameterTypes.length == contenderParameters.size()) {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (parameterTypes[i] != contenderParameters.get(i).getParameterClass()) {
+ continue effectorLoop;
+ }
+ }
+ return contender;
+ }
+ }
+ }
+ throw new NoSuchElementException("No matching effector "+name+"("+Joiner.on(", ").join(parameterTypes)+") on entity "+getName());
+ }
+
+ @Override
+ public Sensor<?> getSensor(String name) {
+ return sensors.get(name);
+ }
+
+ @Override
+ public boolean hasSensor(String name) {
+ return sensors.containsKey(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), sensors, effectors);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof EntityTypeSnapshot)) return false;
+ EntityTypeSnapshot o = (EntityTypeSnapshot) obj;
+
+ return super.equals(obj) && Objects.equal(sensors, o.sensors) && Objects.equal(effectors, o.effectors);
+ }
+
+ @Override
+ protected ToStringHelper toStringHelper() {
+ return super.toStringHelper()
+ .add("sensors", sensors)
+ .add("effectors", effectors);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypes.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypes.java
new file mode 100644
index 0000000..ebedb65
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTypes.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.brooklyn.core.objs.BrooklynTypes;
+
+/**
+ * @deprecated since 0.7.0; use {@link BrooklynTypes}
+ */
+@Deprecated
+public class EntityTypes extends BrooklynTypes {
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/StartableApplication.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/StartableApplication.java b/core/src/main/java/org/apache/brooklyn/core/entity/StartableApplication.java
new file mode 100644
index 0000000..c0e27c0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/StartableApplication.java
@@ -0,0 +1,25 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.core.entity.trait.Startable;
+
+public interface StartableApplication extends Application, Startable {
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManager.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManager.java
new file mode 100644
index 0000000..b7c3bd5
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManager.java
@@ -0,0 +1,56 @@
+/*
+ * 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.drivers;
+
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.entity.drivers.EntityDriverManager;
+import org.apache.brooklyn.api.location.Location;
+
+import com.google.common.annotations.Beta;
+
+public class BasicEntityDriverManager implements EntityDriverManager {
+
+ private final RegistryEntityDriverFactory registry;
+ private final ReflectiveEntityDriverFactory reflective;
+
+ public BasicEntityDriverManager() {
+ registry = new RegistryEntityDriverFactory();
+ reflective = new ReflectiveEntityDriverFactory();
+ }
+
+ /** driver override mechanism; experimental @since 0.7.0 */
+ @Beta
+ public ReflectiveEntityDriverFactory getReflectiveDriverFactory() {
+ return reflective;
+ }
+
+ public <D extends EntityDriver> void registerDriver(Class<D> driverInterface, Class<? extends Location> locationClazz, Class<? extends D> driverClazz) {
+ registry.registerDriver(driverInterface, locationClazz, driverClazz);
+ }
+
+ @Override
+ public <D extends EntityDriver> D build(DriverDependentEntity<D> entity, Location location){
+ if (registry.hasDriver(entity, location)) {
+ return registry.build(entity, location);
+ } else {
+ return reflective.build(entity, location);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
new file mode 100644
index 0000000..19973f2
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
@@ -0,0 +1,277 @@
+/*
+ * 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.drivers;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.location.Location;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.paas.PaasLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.text.Strings;
+
+/**
+ * Follows a class naming convention: the driver interface typically ends in "Driver", and the implementation
+ * must match the driver interface name but with a suffix like "SshDriver" instead of "Driver".
+ * Other rules can be added using {@link #addRule(String, DriverInferenceRule)} or
+ * {@link #addClassFullNameMapping(String, String)}.
+ * <p>
+ * Reflectively instantiates and returns the driver, based on the location passed in,
+ * in {@link #build(DriverDependentEntity, Location)}.
+ *
+ * @author Peter Veentjer, Alex Heneveld
+ */
+public class ReflectiveEntityDriverFactory {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ReflectiveEntityDriverFactory.class);
+
+ /** Rules, keyed by a unique identifier. Executed in order of most-recently added first. */
+ protected final Map<String,DriverInferenceRule> rules = MutableMap.of();
+
+ public ReflectiveEntityDriverFactory() {
+ addRule(DriverInferenceForSshLocation.DEFAULT_IDENTIFIER, new DriverInferenceForSshLocation());
+ addRule(DriverInferenceForPaasLocation.DEFAULT_IDENTIFIER, new DriverInferenceForPaasLocation());
+ addRule(DriverInferenceForWinRmLocation.DEFAULT_IDENTIFIER, new DriverInferenceForWinRmLocation());
+ }
+
+ public interface DriverInferenceRule {
+ public <D extends EntityDriver> ReferenceWithError<Class<? extends D>> resolve(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location);
+ }
+
+ public static abstract class AbstractDriverInferenceRule implements DriverInferenceRule {
+
+ @Override
+ public <D extends EntityDriver> ReferenceWithError<Class<? extends D>> resolve(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ try {
+ String newName = inferDriverClassName(entity, driverInterface, location);
+ if (newName==null) return null;
+
+ return loadDriverClass(newName, entity, driverInterface);
+
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ return ReferenceWithError.newInstanceThrowingError(null, e);
+ }
+ }
+
+ public abstract <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location);
+
+ protected <D extends EntityDriver> ReferenceWithError<Class<? extends D>> loadDriverClass(String className, DriverDependentEntity<D> entity, Class<D> driverInterface) {
+ ReferenceWithError<Class<? extends D>> r1 = loadClass(className, entity.getClass().getClassLoader());
+ if (!r1.hasError()) return r1;
+ ReferenceWithError<Class<? extends D>> r2 = loadClass(className, driverInterface.getClass().getClassLoader());
+ if (!r2.hasError()) return r2;
+ return r1;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected <D extends EntityDriver> ReferenceWithError<Class<? extends D>> loadClass(String className, ClassLoader classLoader) {
+ try {
+ return (ReferenceWithError<Class<? extends D>>)(ReferenceWithError) ReferenceWithError.newInstanceWithoutError((Class<? extends EntityDriver>)classLoader.loadClass(className));
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ return ReferenceWithError.newInstanceThrowingError(null, e);
+ }
+ }
+ }
+
+ public static abstract class AbstractDriverInferenceRenamingInferenceRule extends AbstractDriverInferenceRule {
+
+ protected final String expectedPattern;
+ protected final String replacement;
+
+ public AbstractDriverInferenceRenamingInferenceRule(String expectedPattern, String replacement) {
+ this.expectedPattern = expectedPattern;
+ this.replacement = replacement;
+ }
+
+ public String getIdentifier() {
+ return getClass().getName()+"["+expectedPattern+"]";
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName()+"["+expectedPattern+"->"+replacement+"]";
+ }
+ }
+
+ public static class DriverInferenceByRenamingClassFullName extends AbstractDriverInferenceRenamingInferenceRule {
+
+ public DriverInferenceByRenamingClassFullName(String expectedClassFullName, String newClassFullName) {
+ super(expectedClassFullName, newClassFullName);
+ }
+
+ @Override
+ public <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ if (driverInterface.getName().equals(expectedPattern)) {
+ return replacement;
+ }
+ return null;
+ }
+ }
+
+ public static class DriverInferenceByRenamingClassSimpleName extends AbstractDriverInferenceRenamingInferenceRule {
+
+ public DriverInferenceByRenamingClassSimpleName(String expectedClassSimpleName, String newClassSimpleName) {
+ super(expectedClassSimpleName, newClassSimpleName);
+ }
+
+ @Override
+ public <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ if (driverInterface.getSimpleName().equals(expectedPattern)) {
+ // i'd like to do away with drivers altogether, but if people *really* need to use this and suppress the warning,
+ // they can use the full class rename
+ LOG.warn("Using discouraged driver simple class rename to find "+replacement+" for "+expectedPattern+"; it is recommended to set getDriverInterface() or newDriver() appropriately");
+ return Strings.removeFromEnd(driverInterface.getName(), expectedPattern)+replacement;
+ }
+ return null;
+ }
+ }
+
+ public static class DriverInferenceForSshLocation extends AbstractDriverInferenceRule {
+
+ public static final String DEFAULT_IDENTIFIER = "ssh-location-driver-inference-rule";
+
+ @Override
+ public <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ String driverInterfaceName = driverInterface.getName();
+ if (!(location instanceof SshMachineLocation)) return null;
+ if (!driverInterfaceName.endsWith("Driver")) {
+ throw new IllegalArgumentException(String.format("Driver name [%s] doesn't end with 'Driver'; cannot auto-detect SshDriver class name", driverInterfaceName));
+ }
+ return Strings.removeFromEnd(driverInterfaceName, "Driver")+"SshDriver";
+ }
+ }
+
+ public static class DriverInferenceForPaasLocation extends AbstractDriverInferenceRule {
+
+ public static final String DEFAULT_IDENTIFIER = "paas-location-driver-inference-rule";
+
+ @Override
+ public <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ String driverInterfaceName = driverInterface.getName();
+ if (!(location instanceof PaasLocation)) return null;
+ if (!driverInterfaceName.endsWith("Driver")) {
+ throw new IllegalArgumentException(String.format("Driver name [%s] doesn't end with 'Driver'; cannot auto-detect PaasDriver class name", driverInterfaceName));
+ }
+ return Strings.removeFromEnd(driverInterfaceName, "Driver") + ((PaasLocation) location).getPaasProviderName() + "Driver";
+ }
+ }
+
+ public static class DriverInferenceForWinRmLocation extends AbstractDriverInferenceRule {
+
+ public static final String DEFAULT_IDENTIFIER = "winrm-location-driver-inference-rule";
+
+ @Override
+ public <D extends EntityDriver> String inferDriverClassName(DriverDependentEntity<D> entity, Class<D> driverInterface, Location location) {
+ String driverInterfaceName = driverInterface.getName();
+ if (!(location instanceof WinRmMachineLocation)) return null;
+ if (!driverInterfaceName.endsWith("Driver")) {
+ throw new IllegalArgumentException(String.format("Driver name [%s] doesn't end with 'Driver'; cannot auto-detect WinRmDriver class name", driverInterfaceName));
+ }
+ return Strings.removeFromEnd(driverInterfaceName, "Driver")+"WinRmDriver";
+ }
+ }
+
+ /** adds a rule; possibly replacing an old one if one exists with the given identifier. the new rule is added after all previous ones.
+ * @return the replaced rule, or null if there was no old rule */
+ public DriverInferenceRule addRule(String identifier, DriverInferenceRule rule) {
+ DriverInferenceRule oldRule = rules.remove(identifier);
+ rules.put(identifier, rule);
+ LOG.debug("Added driver mapping rule "+rule);
+ return oldRule;
+ }
+
+ public DriverInferenceRule addClassFullNameMapping(String expectedClassFullName, String newClassFullName) {
+ DriverInferenceByRenamingClassFullName rule = new DriverInferenceByRenamingClassFullName(expectedClassFullName, newClassFullName);
+ return addRule(rule.getIdentifier(), rule);
+ }
+
+ public DriverInferenceRule addClassSimpleNameMapping(String expectedClassSimpleName, String newClassSimpleName) {
+ DriverInferenceByRenamingClassSimpleName rule = new DriverInferenceByRenamingClassSimpleName(expectedClassSimpleName, newClassSimpleName);
+ return addRule(rule.getIdentifier(), rule);
+ }
+
+ public <D extends EntityDriver> D build(DriverDependentEntity<D> entity, Location location){
+ Class<D> driverInterface = entity.getDriverInterface();
+ Class<? extends D> driverClass = null;
+ List<Throwable> exceptions = MutableList.of();
+ if (driverInterface.isInterface()) {
+ List<DriverInferenceRule> ruleListInExecutionOrder = MutableList.copyOf(rules.values());
+ Collections.reverse(ruleListInExecutionOrder);
+ // above puts rules in order with most recently added first
+ for (DriverInferenceRule rule: ruleListInExecutionOrder) {
+ ReferenceWithError<Class<? extends D>> clazzR = rule.resolve(entity, driverInterface, location);
+ if (clazzR!=null) {
+ if (!clazzR.hasError()) {
+ Class<? extends D> clazz = clazzR.get();
+ if (clazz!=null) {
+ driverClass = clazz;
+ break;
+ }
+ } else {
+ exceptions.add(clazzR.getError());
+ }
+ }
+ }
+ } else {
+ driverClass = driverInterface;
+ }
+ LOG.debug("Driver for "+driverInterface.getName()+" in "+location+" is: "+driverClass);
+
+ if (driverClass==null) {
+ if (exceptions.isEmpty())
+ throw new RuntimeException("No drivers could be found for "+driverInterface.getName()+"; "
+ + "currently only SshMachineLocation is supported for autodetection (location "+location+")");
+ else throw Exceptions.create("No drivers could be loaded for "+driverInterface.getName()+" in "+location, exceptions);
+ }
+
+ try {
+ Constructor<? extends D> constructor = getConstructor(driverClass);
+ constructor.setAccessible(true);
+ return constructor.newInstance(entity, location);
+ } catch (Exception e) {
+ LOG.warn("Unable to instantiate "+driverClass+" (rethrowing): "+e);
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <D extends EntityDriver> Constructor<D> getConstructor(Class<D> driverClass) {
+ for (Constructor<?> constructor : driverClass.getConstructors()) {
+ if (constructor.getParameterTypes().length == 2) {
+ return (Constructor<D>) constructor;
+ }
+ }
+
+ throw new RuntimeException(String.format("Class [%s] has no constructor with 2 arguments", driverClass.getName()));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactory.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactory.java
new file mode 100644
index 0000000..d2dd125
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactory.java
@@ -0,0 +1,127 @@
+/*
+ * 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.drivers;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.entity.drivers.EntityDriverManager;
+import org.apache.brooklyn.api.location.Location;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+
+/**
+ * A registry of driver classes, keyed off the driver-interface + location type it is for.
+ *
+ * @author Aled Sage
+ */
+public class RegistryEntityDriverFactory implements EntityDriverManager {
+
+ private final Map<DriverLocationTuple, Class<? extends EntityDriver>> registry = new LinkedHashMap<DriverLocationTuple, Class<? extends EntityDriver>>();
+
+ @Override
+ public <D extends EntityDriver> D build(DriverDependentEntity<D> entity, Location location) {
+ Class<? extends D> driverClass = lookupDriver(entity.getDriverInterface(), location);
+ return newDriverInstance(driverClass, entity, location);
+ }
+
+ public boolean hasDriver(DriverDependentEntity<?> entity, Location location) {
+ return lookupDriver(entity.getDriverInterface(), location) != null;
+ }
+
+ public <D extends EntityDriver> void registerDriver(Class<D> driverInterface, Class<? extends Location> locationClazz, Class<? extends D> driverClazz) {
+ synchronized (registry) {
+ registry.put(new DriverLocationTuple(driverInterface, locationClazz), driverClazz);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <D extends EntityDriver> Class<? extends D> lookupDriver(Class<D> driverInterface, Location location) {
+ synchronized (registry) {
+ for (DriverLocationTuple contender : registry.keySet()) {
+ if (contender.matches(driverInterface, location)) {
+ return (Class<? extends D>) registry.get(contender);
+ }
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private <D> Constructor<D> getConstructor(Class<? extends D> driverClass) {
+ for (Constructor constructor : driverClass.getConstructors()) {
+ if (constructor.getParameterTypes().length == 2) {
+ return constructor;
+ }
+ }
+
+ //TODO:
+ throw new RuntimeException(String.format("Class [%s] has no constructor with 2 arguments",driverClass.getName()));
+ }
+
+ private <D> D newDriverInstance(Class<D> driverClass, Entity entity, Location location) {
+ Constructor<D> constructor = getConstructor(driverClass);
+ try {
+ constructor.setAccessible(true);
+ return constructor.newInstance(entity, location);
+ } catch (InstantiationException e) {
+ throw Throwables.propagate(e);
+ } catch (IllegalAccessException e) {
+ throw Throwables.propagate(e);
+ } catch (InvocationTargetException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ private static class DriverLocationTuple {
+ private final Class<? extends EntityDriver> driverInterface;
+ private final Class<? extends Location> locationClazz;
+
+ public DriverLocationTuple(Class<? extends EntityDriver> driverInterface, Class<? extends Location> locationClazz) {
+ this.driverInterface = checkNotNull(driverInterface, "driver interface");
+ this.locationClazz = checkNotNull(locationClazz, "location class");
+ }
+
+ public boolean matches(Class<? extends EntityDriver> driver, Location location) {
+ return driverInterface.isAssignableFrom(driver) && locationClazz.isInstance(location);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(driverInterface, locationClazz);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof DriverLocationTuple)) {
+ return false;
+ }
+ DriverLocationTuple o = (DriverLocationTuple) other;
+ return driverInterface.equals(o.driverInterface) && locationClazz.equals(o.locationClazz);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadRequirement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadRequirement.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadRequirement.java
new file mode 100644
index 0000000..0a1106b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadRequirement.java
@@ -0,0 +1,85 @@
+/*
+ * 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.drivers.downloads;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadRequirement;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+public class BasicDownloadRequirement implements DownloadRequirement {
+
+ private final EntityDriver entityDriver;
+ private final String addonName;
+ private final Map<String, ?> properties;
+
+ /**
+ * Copies the given DownloadRequirement, but overriding the original properties with the given additional properties.
+ */
+ public static BasicDownloadRequirement copy(DownloadRequirement req, Map<String,?> additionalProperties) {
+ Map<String,?> props = MutableMap.<String,Object>builder().putAll(req.getProperties()).putAll(additionalProperties).build();
+ if (req.getAddonName() == null) {
+ return new BasicDownloadRequirement(req.getEntityDriver(), props);
+ } else {
+ return new BasicDownloadRequirement(req.getEntityDriver(), req.getAddonName(), props);
+ }
+ }
+
+ public BasicDownloadRequirement(EntityDriver driver) {
+ this(driver, ImmutableMap.<String,Object>of());
+ }
+
+ public BasicDownloadRequirement(EntityDriver driver, Map<String, ?> properties) {
+ this.entityDriver = checkNotNull(driver, "entityDriver");
+ this.addonName = null;
+ this.properties = checkNotNull(properties, "properties");
+ }
+
+ public BasicDownloadRequirement(EntityDriver entityDriver, String addonName, Map<String, ?> properties) {
+ this.entityDriver = checkNotNull(entityDriver, "entityDriver");
+ this.addonName = checkNotNull(addonName, "addonName");
+ this.properties = checkNotNull(properties, "properties");
+ }
+
+ @Override
+ public EntityDriver getEntityDriver() {
+ return entityDriver;
+ }
+
+ @Override
+ public String getAddonName() {
+ return addonName;
+ }
+
+ @Override
+ public Map<String, ?> getProperties() {
+ return properties;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("driver", entityDriver).add("addon", addonName).omitNullValues().toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadResolver.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadResolver.java
new file mode 100644
index 0000000..aed8f0b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadResolver.java
@@ -0,0 +1,66 @@
+/*
+ * 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.drivers.downloads;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public class BasicDownloadResolver implements DownloadResolver {
+
+ private final List<String> targets;
+ private final String filename;
+ private final String unpackDirectoryName;
+
+ public BasicDownloadResolver(Iterable<String> targets, String filename) {
+ this(targets, filename, null);
+ }
+
+ public BasicDownloadResolver(Iterable<String> targets, String filename, String unpackDirectoryName) {
+ this.targets = ImmutableList.copyOf(checkNotNull(targets, "targets"));
+ this.filename = checkNotNull(filename, "filename");
+ this.unpackDirectoryName = unpackDirectoryName;
+ }
+
+ @Override
+ public List<String> getTargets() {
+ return targets;
+ }
+
+ @Override
+ public String getFilename() {
+ return filename;
+ }
+
+ @Override
+ public String getUnpackedDirectoryName(String defaultVal) {
+ return unpackDirectoryName == null ? defaultVal : unpackDirectoryName;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("targets", targets).add("filename", filename)
+ .add("unpackDirName", unpackDirectoryName).omitNullValues().toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadTargets.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadTargets.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadTargets.java
new file mode 100644
index 0000000..d8e6599
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadTargets.java
@@ -0,0 +1,121 @@
+/*
+ * 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.drivers.downloads;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
+import org.apache.brooklyn.util.collections.MutableList;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class BasicDownloadTargets implements DownloadTargets {
+
+ private static final DownloadTargets EMPTY = builder().build();
+
+ public static DownloadTargets empty() {
+ return EMPTY;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private List<String> primaries = Lists.newArrayList();
+ private List<String> fallbacks = Lists.newArrayList();
+ private boolean canContinueResolving = true;
+
+ public Builder addAll(DownloadTargets other) {
+ addPrimaries(other.getPrimaryLocations());
+ addFallbacks(other.getFallbackLocations());
+ return this;
+ }
+
+ public Builder addPrimary(String val) {
+ checkNotNull(val, "val");
+ if (!primaries.contains(val)) primaries.add(val);
+ return this;
+ }
+
+ public Builder addPrimaries(Iterable<String> vals) {
+ for (String val : checkNotNull(vals, "vals")) {
+ addPrimary(val);
+ }
+ return this;
+ }
+
+ public Builder addFallback(String val) {
+ checkNotNull(val, "val");
+ if (!fallbacks.contains(val)) fallbacks.add(val);
+ return this;
+ }
+
+ public Builder addFallbacks(Iterable<String> vals) {
+ for (String val : checkNotNull(vals, "vals")) {
+ addFallback(val);
+ }
+ return this;
+ }
+
+ public Builder canContinueResolving(boolean val) {
+ canContinueResolving = val;
+ return this;
+ }
+
+ public BasicDownloadTargets build() {
+ return new BasicDownloadTargets(this);
+ }
+ }
+
+ private final List<String> primaries;
+ private final List<String> fallbacks;
+ private final boolean canContinueResolving;
+
+ protected BasicDownloadTargets(Builder builder) {
+ primaries = ImmutableList.copyOf(builder.primaries);
+ fallbacks = MutableList.<String>builder().addAll(builder.fallbacks).removeAll(builder.primaries).build().asUnmodifiable();
+ canContinueResolving = builder.canContinueResolving;
+ }
+
+ @Override
+ public List<String> getPrimaryLocations() {
+ return primaries;
+ }
+
+ @Override
+ public List<String> getFallbackLocations() {
+ return fallbacks;
+ }
+
+ @Override
+ public boolean canContinueResolving() {
+ return canContinueResolving;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("primaries", primaries).add("fallbacks", fallbacks)
+ .add("canContinueResolving", canContinueResolving).toString();
+ }
+}