This closes #833
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f9b357d7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f9b357d7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f9b357d7 Branch: refs/heads/master Commit: f9b357d716e28067eed4af3c691b22921a54d296 Parents: 4d0bbce e1a2d66 Author: Hadrian Zbarcea <[email protected]> Authored: Tue Aug 18 02:28:19 2015 -0400 Committer: Hadrian Zbarcea <[email protected]> Committed: Tue Aug 18 02:28:19 2015 -0400 ---------------------------------------------------------------------- .../brooklyn/basic/AbstractBrooklynObject.java | 249 ---------------- .../brooklyn/basic/BasicConfigurableObject.java | 120 -------- .../brooklyn/basic/BrooklynDynamicType.java | 284 ------------------- .../brooklyn/basic/BrooklynObjectInternal.java | 104 ------- .../brooklyn/basic/BrooklynTypeSnapshot.java | 102 ------- .../main/java/brooklyn/basic/BrooklynTypes.java | 132 --------- .../basic/internal/ApiObjectsFactoryImpl.java | 42 --- .../enricher/basic/EnricherDynamicType.java | 2 +- .../enricher/basic/EnricherTypeSnapshot.java | 2 +- .../brooklyn/entity/basic/AbstractEntity.java | 2 +- .../java/brooklyn/entity/basic/Entities.java | 2 +- .../entity/basic/EntityDynamicType.java | 2 +- .../brooklyn/entity/basic/EntityInternal.java | 2 +- .../entity/basic/EntityTypeSnapshot.java | 2 +- .../java/brooklyn/entity/basic/EntityTypes.java | 2 +- .../AbstractBrooklynObjectRebindSupport.java | 2 +- .../rebind/ActivePartialRebindIteration.java | 2 +- .../rebind/ImmediateDeltaChangeListener.java | 2 +- .../rebind/PeriodicDeltaChangeListener.java | 2 +- .../brooklyn/entity/rebind/RebindIteration.java | 4 +- .../entity/rebind/dto/BasicEntityMemento.java | 3 +- .../entity/rebind/dto/MementosGenerators.java | 2 +- .../persister/BrooklynPersistenceUtils.java | 2 +- .../brooklyn/basic/AbstractBrooklynObject.java | 249 ++++++++++++++++ .../brooklyn/basic/BasicConfigurableObject.java | 120 ++++++++ .../brooklyn/basic/BrooklynDynamicType.java | 284 +++++++++++++++++++ .../brooklyn/basic/BrooklynObjectInternal.java | 104 +++++++ .../brooklyn/basic/BrooklynTypeSnapshot.java | 102 +++++++ .../apache/brooklyn/basic/BrooklynTypes.java | 132 +++++++++ .../basic/internal/ApiObjectsFactoryImpl.java | 42 +++ .../catalog/internal/BasicBrooklynCatalog.java | 2 +- .../core/catalog/internal/CatalogItemDo.java | 2 +- .../internal/CatalogItemDtoAbstract.java | 2 +- .../core/catalog/internal/CatalogUtils.java | 2 +- .../catalog/internal/CatalogXmlSerializer.java | 4 +- .../policy/basic/AbstractEntityAdjunct.java | 4 +- .../core/policy/basic/PolicyDynamicType.java | 2 +- .../core/policy/basic/PolicyTypeSnapshot.java | 2 +- .../location/basic/AbstractLocation.java | 2 +- .../location/basic/LocationDynamicType.java | 2 +- .../location/basic/LocationInternal.java | 2 +- .../location/basic/LocationTypeSnapshot.java | 2 +- ...pi.basic.internal.ApiObjectsFactoryInterface | 2 +- .../CatalogOsgiVersionMoreEntityTest.java | 2 +- .../main/java/org/apache/brooklyn/cli/Main.java | 13 +- .../brooklyn/cli/lister/ItemDescriptors.java | 4 +- .../SoftlayerObtainPrivateLiveTest.java | 2 +- .../rest/resources/PolicyConfigResource.java | 2 +- .../rest/transform/CatalogTransformer.java | 2 +- .../rest/util/BrooklynRestResourceUtils.java | 2 +- 50 files changed, 1074 insertions(+), 1084 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/basic/Entities.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/basic/EntityInternal.java ---------------------------------------------------------------------- diff --cc core/src/main/java/brooklyn/entity/basic/EntityInternal.java index 36e6907,f7fa53f..d9967d1 --- a/core/src/main/java/brooklyn/entity/basic/EntityInternal.java +++ b/core/src/main/java/brooklyn/entity/basic/EntityInternal.java @@@ -33,10 -33,10 +33,10 @@@ import org.apache.brooklyn.api.manageme import org.apache.brooklyn.api.management.SubscriptionContext; import org.apache.brooklyn.api.mementos.EntityMemento; import org.apache.brooklyn.core.management.internal.EntityManagementSupport; +import org.apache.brooklyn.core.util.config.ConfigBag; - import brooklyn.basic.BrooklynObjectInternal; + import org.apache.brooklyn.basic.BrooklynObjectInternal; import brooklyn.config.ConfigKey; -import brooklyn.util.config.ConfigBag; import com.google.common.annotations.Beta; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java ---------------------------------------------------------------------- diff --cc core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java index 000a651,f3eca47..aed26d4 --- a/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java +++ b/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java @@@ -26,8 -25,9 +26,8 @@@ import org.apache.brooklyn.core.policy. import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import brooklyn.basic.AbstractBrooklynObject; + import org.apache.brooklyn.basic.AbstractBrooklynObject; import brooklyn.entity.rebind.dto.MementosGenerators; -import brooklyn.policy.basic.AbstractEntityAdjunct.AdjunctTagSupport; import brooklyn.util.text.Strings; public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> implements RebindSupport<T> { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/AbstractBrooklynObject.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/AbstractBrooklynObject.java index 0000000,260c91b..4515492 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/basic/AbstractBrooklynObject.java @@@ -1,0 -1,249 +1,249 @@@ + /* + * 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.basic; + + import java.util.Collections; + import java.util.Map; + import java.util.Set; + + import org.apache.brooklyn.api.basic.internal.ApiObjectsFactory; + import org.apache.brooklyn.api.management.ManagementContext; + import org.apache.brooklyn.core.management.internal.ManagementContextInternal; ++import org.apache.brooklyn.core.util.config.ConfigBag; ++import org.apache.brooklyn.core.util.flags.SetFromFlag; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + import brooklyn.entity.basic.AbstractEntity; + import brooklyn.entity.proxying.InternalFactory; + import brooklyn.entity.rebind.RebindManagerImpl; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.flags.SetFromFlag; + import brooklyn.util.text.Identifiers; + + import com.google.common.collect.ImmutableSet; + import com.google.common.collect.Iterables; + import com.google.common.collect.Maps; + import com.google.common.collect.Sets; + + public abstract class AbstractBrooklynObject implements BrooklynObjectInternal { + + private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynObject.class); + + private boolean _legacyConstruction; + private boolean hasWarnedOfNoManagementContextWhenPersistRequested; + + @SetFromFlag(value = "id") + private String id = Identifiers.makeRandomId(8); + + private String catalogItemId; + + /** subclasses should synchronize on this for all access */ + @SetFromFlag(value = "tags") + private final Set<Object> tags = Sets.newLinkedHashSet(); + + private volatile ManagementContext managementContext; + + public abstract void setDisplayName(String newName); + + public AbstractBrooklynObject() { + this(Maps.newLinkedHashMap()); + } + + public AbstractBrooklynObject(Map<?, ?> properties) { + _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing(); + + if (!_legacyConstruction && properties != null && !properties.isEmpty()) { + log.warn("Forcing use of deprecated old-style construction for {} because properties were " + + "specified ({}); instead use specs (e.g. LocationSpec, EntitySpec, etc)", + getClass().getName(), properties); + if (log.isDebugEnabled()) + log.debug("Source of use of old-style construction", new Throwable("Source of use of old-style construction")); + _legacyConstruction = true; + } + + catalogItemId = ApiObjectsFactory.get().getCatalogItemIdFromContext(); + + // rely on sub-class to call configure(properties), because otherwise its fields will not have been initialised + } + + /** + * See {@link #configure(Map)} + * + * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly + */ + @Deprecated + protected AbstractBrooklynObject configure() { + return configure(Collections.emptyMap()); + } + + /** + * Will set fields from flags, and put the remaining ones into the 'leftovers' map. + * For some types, you can find unused config via {@link ConfigBag#getUnusedConfig()}. + * <p> + * To be overridden by AbstractEntity, AbstractLoation, AbstractPolicy, AbstractEnricher, etc. + * <p> + * But should not be overridden by specific entity types. If you do, the entity may break in + * subsequent releases. Also note that if you require fields to be initialized you must do that + * in this method. You must *not* rely on field initializers because they may not run until *after* + * this method (this method is invoked by the constructor in this class, so initializers + * in subclasses will not have run when this overridden method is invoked.) + * + * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly + */ + @Deprecated + protected abstract AbstractBrooklynObject configure(Map<?, ?> flags); + + protected boolean isLegacyConstruction() { + return _legacyConstruction; + } + + /** + * Called by framework (in new-style instances where spec was used) after configuring etc, + * but before a reference to this instance is shared. + * <p> + * To preserve backwards compatibility for if the instance is constructed directly, one + * can call the code below, but that means it will be called after references to this + * policy have been shared with other entities. + * <pre> + * {@code + * if (isLegacyConstruction()) { + * init(); + * } + * } + * </pre> + */ + public void init() { + // no-op + } + + /** + * Called by framework on rebind (in new-style instances): + * <ul> + * <li> after configuring, but + * <li> before the instance is managed, and + * <li> before adjuncts are attached to entities, and + * <li> before a reference to an object is shared. + * </ul> + * Note that {@link #init()} will not be called on rebind. + * <p> + * If you need to intercept behaviour <i>after</i> adjuncts are attached, + * consider {@link AbstractEntity#onManagementStarting()} + * (but probably worth raising a discussion on the mailing list!) + */ + public void rebind() { + // no-op + } + + public void setManagementContext(ManagementContextInternal managementContext) { + this.managementContext = managementContext; + } + + public ManagementContext getManagementContext() { + return managementContext; + } + + protected boolean isRebinding() { + return RebindManagerImpl.RebindTracker.isRebinding(); + } + + protected void requestPersist() { + if (getManagementContext() != null) { + getManagementContext().getRebindManager().getChangeListener().onChanged(this); + } else { + // Might be nice to log this at debug but it gets hit a lot of times as locations + // are created and destroyed for the API. It also might not be an error - the + // management context might be null if the object is being recreated by persistence. + if (log.isTraceEnabled() && !hasWarnedOfNoManagementContextWhenPersistRequested) { + log.trace("Cannot fulfil request to persist {} because it has no management context. " + + "This warning will not be logged for this object again.", this); + hasWarnedOfNoManagementContextWhenPersistRequested = true; + } + } + } + + @Override + public String getId() { + return id; + } + + @Override + public void setCatalogItemId(String id) { + this.catalogItemId = id; + } + + @Override + public String getCatalogItemId() { + return catalogItemId; + } + + protected void onTagsChanged() { + requestPersist(); + } + + @Override + public TagSupport tags() { + return new BasicTagSupport(); + } + + protected class BasicTagSupport implements TagSupport { + @Override + public Set<Object> getTags() { + synchronized (tags) { + return ImmutableSet.copyOf(tags); + } + } + + @Override + public boolean containsTag(Object tag) { + synchronized (tags) { + return tags.contains(tag); + } + } + + @Override + public boolean addTag(Object tag) { + boolean result; + synchronized (tags) { + result = tags.add(tag); + } + onTagsChanged(); + return result; + } + + @Override + public boolean addTags(Iterable<?> newTags) { + boolean result; + synchronized (tags) { + result = Iterables.addAll(tags, newTags); + } + onTagsChanged(); + return result; + } + + @Override + public boolean removeTag(Object tag) { + boolean result; + synchronized (tags) { + result = tags.remove(tag); + } + onTagsChanged(); + return result; + } + } + + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/BasicConfigurableObject.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/BasicConfigurableObject.java index 0000000,f376d74..f79b1d7 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/BasicConfigurableObject.java +++ b/core/src/main/java/org/apache/brooklyn/basic/BasicConfigurableObject.java @@@ -1,0 -1,120 +1,120 @@@ + /* + * 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.basic; + + import org.apache.brooklyn.api.entity.trait.Configurable; + import org.apache.brooklyn.api.entity.trait.Identifiable; + import org.apache.brooklyn.api.management.ManagementContext; + import org.apache.brooklyn.api.management.Task; + import org.apache.brooklyn.core.management.ManagementContextInjectable; ++import org.apache.brooklyn.core.util.config.ConfigBag; ++import org.apache.brooklyn.core.util.flags.SetFromFlag; + + import brooklyn.camp.brooklyn.api.HasBrooklynManagementContext; + import brooklyn.config.ConfigKey; + import brooklyn.config.ConfigKey.HasConfigKey; + import brooklyn.config.ConfigMap; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.flags.SetFromFlag; + import brooklyn.util.text.Identifiers; + + /** + * A parent class for ancilliary objects that do not require the full heavy lifting of {@link AbstractBrooklynObject} + * or similar, but wish to use {@link ConfigKey} and {@link Configurable} in their construction, via the + * {@code $brooklyn:object} method of the CAMP DSL. + * <p> + * Type coercion of values will occur when the {@link ConfigMap} is accessed, but resolving of {@link Task tasks} and other + * deferred operations are assumed to have occurred prior to calling {@link #setConfig(ConfigKey, Object)} i.e. at + * object construction. + */ + public class BasicConfigurableObject implements Configurable, Identifiable, ManagementContextInjectable, HasBrooklynManagementContext { + + @SetFromFlag("id") + private String id = Identifiers.makeRandomId(8); + + private volatile ManagementContext managementContext; + private BasicConfigurationSupport config; + + public BasicConfigurableObject() { + config = new BasicConfigurationSupport(); + } + + @Override + public void injectManagementContext(ManagementContext managementContext) { + this.managementContext = managementContext; + } + + public ManagementContext getBrooklynManagementContext() { + return managementContext; + } + + @Override + public String getId() { + return id; + } + + @Override + public ConfigurationSupport config() { + return config; + } + + @Override + @Deprecated + public <T> T setConfig(ConfigKey<T> key, T value) { + return config().set(key, value); + } + + public <T> T getConfig(ConfigKey<T> key) { + return config().get(key); + } + + private static class BasicConfigurationSupport implements ConfigurationSupport { + private final ConfigBag config = ConfigBag.newInstance(); + + @Override + public <T> T get(ConfigKey<T> key) { + return config.get(key); + } + + @Override + public <T> T get(HasConfigKey<T> key) { + return get(key.getConfigKey()); + } + + @Override + public <T> T set(ConfigKey<T> key, T val) { + T old = config.get(key); + config.configure(key, val); + return old; + } + + @Override + public <T> T set(HasConfigKey<T> key, T val) { + return set(key.getConfigKey(), val); + } + + @Override + public <T> T set(ConfigKey<T> key, Task<T> val) { + throw new UnsupportedOperationException(); + } + + @Override + public <T> T set(HasConfigKey<T> key, Task<T> val) { + return set(key.getConfigKey(), val); + } + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/BrooklynDynamicType.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/BrooklynDynamicType.java index 0000000,368b035..f6a8893 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/BrooklynDynamicType.java +++ b/core/src/main/java/org/apache/brooklyn/basic/BrooklynDynamicType.java @@@ -1,0 -1,284 +1,284 @@@ + /* + * 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.basic; + + import static com.google.common.base.Preconditions.checkNotNull; + + import java.lang.reflect.Field; + import java.lang.reflect.Modifier; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; + import java.util.LinkedHashMap; + import java.util.LinkedHashSet; + import java.util.List; + import java.util.Map; + import java.util.concurrent.ConcurrentHashMap; + import java.util.concurrent.atomic.AtomicBoolean; + + import org.apache.brooklyn.api.basic.BrooklynObject; + import org.apache.brooklyn.api.basic.BrooklynType; ++import org.apache.brooklyn.core.util.flags.FlagUtils; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + import brooklyn.config.ConfigKey; + import brooklyn.config.ConfigKey.HasConfigKey; + import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting; -import brooklyn.util.flags.FlagUtils; + import brooklyn.util.javalang.Reflections; + import brooklyn.util.text.Strings; + + import com.google.common.base.Joiner; + import com.google.common.base.Objects; + import com.google.common.collect.ArrayListMultimap; + import com.google.common.collect.ListMultimap; + import com.google.common.collect.Lists; + + /** + * This is the actual type of a brooklyn object instance at runtime, + * which can change from the static {@link BrooklynType}, and can change over time; + * for this reason it does *not* implement BrooklynType, but + * callers can call {@link #getSnapshot()} to get a snapshot such instance. + */ + public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT extends AbstractBrooklynObject> { + + private static final Logger LOG = LoggerFactory.getLogger(BrooklynDynamicType.class); + + protected final Class<? extends T> brooklynClass; + protected final AbstractT instance; + protected volatile String name; + + /** + * Map of config keys (and their fields) on this instance, by name. + */ + protected final Map<String,FieldAndValue<ConfigKey<?>>> configKeys = new ConcurrentHashMap<String, FieldAndValue<ConfigKey<?>>>(); + + private volatile BrooklynTypeSnapshot snapshot; + private final AtomicBoolean snapshotValid = new AtomicBoolean(false); + + @SuppressWarnings("unchecked") + public BrooklynDynamicType(AbstractT instance) { + this((Class<? extends T>) instance.getClass(), instance); + } + public BrooklynDynamicType(Class<? extends T> clazz) { + this(clazz, null); + } + protected BrooklynDynamicType(Class<? extends T> clazz, AbstractT instance) { + this.brooklynClass = checkNotNull(clazz, "brooklyn class"); + this.instance = instance; + // NB: official name is usually injected later, e.g. from AbstractEntity.setManagementContext + this.name = (clazz.getCanonicalName() == null) ? clazz.getName() : clazz.getCanonicalName(); + + buildConfigKeys(clazz, null, configKeys); + if (LOG.isTraceEnabled()) + LOG.trace("Entity {} config keys: {}", (instance==null ? clazz.getName() : instance.getId()), Joiner.on(", ").join(configKeys.keySet())); + } + + protected abstract BrooklynTypeSnapshot newSnapshot(); + + protected void invalidateSnapshot() { + snapshotValid.set(false); + } + + public void setName(String name) { + if (Strings.isBlank(name)) { + throw new IllegalArgumentException("Invalid name "+(name == null ? "null" : "'"+name+"'")+"; name must be non-empty and not just white space"); + } + this.name = name; + invalidateSnapshot(); + } + + public synchronized BrooklynType getSnapshot() { + return refreshSnapshot(); + } + + public Class<? extends T> getBrooklynClass() { + return brooklynClass; + } + + // -------------------------------------------------- + + /** + * ConfigKeys available on this entity. + */ + public Map<String,ConfigKey<?>> getConfigKeys() { + return Collections.unmodifiableMap(value(configKeys)); + } + + /** + * ConfigKeys available on this entity. + */ + public ConfigKey<?> getConfigKey(String keyName) { + return value(configKeys.get(keyName)); + } + + /** field where a config key is defined, for use getting annotations. note annotations are not inherited. */ + public Field getConfigKeyField(String keyName) { + return field(configKeys.get(keyName)); + } + + protected BrooklynTypeSnapshot refreshSnapshot() { + if (snapshotValid.compareAndSet(false, true)) { + snapshot = newSnapshot(); + } + return snapshot; + } + + /** + * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged). + * Prefers keys which overwrite other keys, and prefers keys which are lower in the hierarchy; + * logs warnings if there are two conflicting keys which don't have an overwriting relationship. + */ + protected static void buildConfigKeys(Class<? extends BrooklynObject> clazz, AbstractBrooklynObject optionalInstance, + Map<String, FieldAndValue<ConfigKey<?>>> configKeys) { + ListMultimap<String,FieldAndValue<ConfigKey<?>>> configKeysAll = + ArrayListMultimap.<String, FieldAndValue<ConfigKey<?>>>create(); + + for (Field f : FlagUtils.getAllFields(clazz)) { + boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType()); + if (!isConfigKey) { + if (!HasConfigKey.class.isAssignableFrom(f.getType())) { + // neither ConfigKey nor HasConfigKey + continue; + } + } + if (!Modifier.isStatic(f.getModifiers())) { + // require it to be static or we have an instance + LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalInstance!=null ? optionalInstance : clazz)); + if (optionalInstance==null) continue; + } + try { + Object v = f.get(optionalInstance); + + if (v == null) { + LOG.warn("no value defined for config key field (skipping): "+f); + } else { + ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) v : ((HasConfigKey<?>) v).getConfigKey(); + configKeysAll.put(k.getName(), new FieldAndValue<ConfigKey<?>>(f, k)); + } + } catch (IllegalAccessException e) { + LOG.warn("cannot access config key (skipping): "+f); + } + } + LinkedHashSet<String> keys = new LinkedHashSet<String>(configKeysAll.keys()); + for (String kn: keys) { + List<FieldAndValue<ConfigKey<?>>> kk = Lists.newArrayList(configKeysAll.get(kn)); + if (kk.size()>1) { + // remove anything which extends another value in the list + for (FieldAndValue<ConfigKey<?>> k: kk) { + ConfigKey<?> key = value(k); + if (key instanceof BasicConfigKeyOverwriting) { + ConfigKey<?> parent = ((BasicConfigKeyOverwriting<?>)key).getParentKey(); + // find and remove the parent from consideration + for (FieldAndValue<ConfigKey<?>> k2: kk) { + if (value(k2) == parent) + configKeysAll.remove(kn, k2); + } + } + } + kk = Lists.newArrayList(configKeysAll.get(kn)); + } + // multiple keys, not overwriting; if their values are the same then we don't mind + FieldAndValue<ConfigKey<?>> best = null; + for (FieldAndValue<ConfigKey<?>> k: kk) { + if (best==null) { + best=k; + } else { + Field lower = Reflections.inferSubbestField(k.field, best.field); + ConfigKey<? extends Object> lowerV = lower==null ? null : lower.equals(k.field) ? k.value : best.value; + if (best.value == k.value) { + // same value doesn't matter which we take (but take lower if there is one) + if (LOG.isTraceEnabled()) + LOG.trace("multiple definitions for config key {} on {}; same value {}; " + + "from {} and {}, preferring {}", + new Object[] { + best.value.getName(), optionalInstance!=null ? optionalInstance : clazz, + best.value.getDefaultValue(), + k.field, best.field, lower}); + best = new FieldAndValue<ConfigKey<?>>(lower!=null ? lower : best.field, best.value); + } else if (lower!=null) { + // different value, but one clearly lower (in type hierarchy) + if (LOG.isTraceEnabled()) + LOG.trace("multiple definitions for config key {} on {}; " + + "from {} and {}, preferring lower {}, value {}", + new Object[] { + best.value.getName(), optionalInstance!=null ? optionalInstance : clazz, + k.field, best.field, lower, + lowerV.getDefaultValue() }); + best = new FieldAndValue<ConfigKey<?>>(lower, lowerV); + } else { + // different value, neither one lower than another in hierarchy + LOG.warn("multiple ambiguous definitions for config key {} on {}; " + + "from {} and {}, values {} and {}; " + + "keeping latter (arbitrarily)", + new Object[] { + best.value.getName(), optionalInstance!=null ? optionalInstance : clazz, + k.field, best.field, + k.value.getDefaultValue(), best.value.getDefaultValue() }); + // (no change) + } + } + } + if (best==null) { + // shouldn't happen + LOG.error("Error - no matching config key from "+kk+" in class "+clazz+", even though had config key name "+kn); + continue; + } else { + configKeys.put(best.value.getName(), best); + } + } + } + + protected static class FieldAndValue<V> { + public final Field field; + public final V value; + public FieldAndValue(Field field, V value) { + this.field = field; + this.value = value; + } + @Override + public String toString() { + return Objects.toStringHelper(this).add("field", field).add("value", value).toString(); + } + } + + protected static <V> V value(FieldAndValue<V> fv) { + if (fv==null) return null; + return fv.value; + } + + protected static Field field(FieldAndValue<?> fv) { + if (fv==null) return null; + return fv.field; + } + + protected static <V> Collection<V> value(Collection<FieldAndValue<V>> fvs) { + List<V> result = new ArrayList<V>(); + for (FieldAndValue<V> fv: fvs) result.add(value(fv)); + return result; + } + + protected static <K,V> Map<K,V> value(Map<K,FieldAndValue<V>> fvs) { + Map<K,V> result = new LinkedHashMap<K,V>(); + for (K key: fvs.keySet()) + result.put(key, value(fvs.get(key))); + return result; + } + + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/BrooklynObjectInternal.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/BrooklynObjectInternal.java index 0000000,8109b78..eacb1e1 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/basic/BrooklynObjectInternal.java @@@ -1,0 -1,104 +1,104 @@@ + /* + * 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.basic; + + import java.util.Map; + + import org.apache.brooklyn.api.basic.BrooklynObject; + import org.apache.brooklyn.api.entity.rebind.RebindSupport; + import org.apache.brooklyn.api.entity.rebind.Rebindable; + import org.apache.brooklyn.api.entity.trait.Configurable; ++import org.apache.brooklyn.core.util.config.ConfigBag; + + import brooklyn.config.ConfigKey; + import brooklyn.config.ConfigKey.HasConfigKey; -import brooklyn.util.config.ConfigBag; + import brooklyn.util.guava.Maybe; + + import com.google.common.annotations.Beta; + + public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { + + void setCatalogItemId(String id); + + @SuppressWarnings("rawtypes") // subclasses typically apply stronger typing + RebindSupport getRebindSupport(); + + ConfigurationSupportInternal config(); + + @Beta + public interface ConfigurationSupportInternal extends Configurable.ConfigurationSupport { + + /** + * 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. + * + * TODO This method gives no information about which config is inherited versus local; + * this means {@link ConfigKey#getInheritance()} cannot be respected. This is an unsolvable problem + * for "config names that did not match anything on this entity". Therefore consider using + * alternative getters. + */ + @Beta + ConfigBag getBag(); + + /** + * 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. + */ + @Beta + ConfigBag getLocalBag(); + + /** + * Returns the uncoerced value for this config key, if available, not taking any default. + * If there is no local value and there is an explicit inherited value, will return the inherited. + */ + @Beta + Maybe<Object> getRaw(ConfigKey<?> key); + + /** + * @see {@link #getConfigRaw(ConfigKey)} + */ + @Beta + Maybe<Object> getRaw(HasConfigKey<?> key); + + /** + * Returns the uncoerced value for this config key, if available, + * not following any inheritance chains and not taking any default. + */ + @Beta + Maybe<Object> getLocalRaw(ConfigKey<?> key); + + /** + * @see {@link #getLocalConfigRaw(ConfigKey)} + */ + @Beta + Maybe<Object> getLocalRaw(HasConfigKey<?> key); + + @Beta + void addToLocalBag(Map<String, ?> vals); + + @Beta + void removeFromLocalBag(String key); + + @Beta + void refreshInheritedConfig(); + + @Beta + void refreshInheritedConfigOfChildren(); + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/BrooklynTypes.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/BrooklynTypes.java index 0000000,f64c8f9..d199686 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/BrooklynTypes.java +++ b/core/src/main/java/org/apache/brooklyn/basic/BrooklynTypes.java @@@ -1,0 -1,132 +1,132 @@@ + /* + * 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.basic; + + import java.util.Map; + + import org.apache.brooklyn.api.basic.BrooklynObject; + import org.apache.brooklyn.api.entity.Entity; + import org.apache.brooklyn.api.event.Sensor; + import org.apache.brooklyn.api.location.Location; + import org.apache.brooklyn.api.policy.Enricher; + import org.apache.brooklyn.api.policy.Policy; ++import org.apache.brooklyn.core.policy.basic.PolicyDynamicType; + + import brooklyn.config.ConfigKey; + import brooklyn.enricher.basic.EnricherDynamicType; + import brooklyn.entity.basic.EntityDynamicType; -import brooklyn.policy.basic.PolicyDynamicType; + import brooklyn.util.exceptions.Exceptions; + + import com.google.common.collect.Maps; + + public class BrooklynTypes { + + private static class ImmutableEntityType extends EntityDynamicType { + public ImmutableEntityType(Class<? extends Entity> clazz) { + super(clazz); + } + @Override + public void setName(String name) { + throw new UnsupportedOperationException(); + } + @Override + public void addSensor(Sensor<?> newSensor) { + throw new UnsupportedOperationException(); + } + @Override + public void addSensorIfAbsent(Sensor<?> newSensor) { + throw new UnsupportedOperationException(); + } + @Override + public Sensor<?> addSensorIfAbsentWithoutPublishing(Sensor<?> newSensor) { + throw new UnsupportedOperationException(); + } + @Override + public void addSensors(Iterable<? extends Sensor<?>> newSensors) { + throw new UnsupportedOperationException(); + } + @Override + public boolean removeSensor(Sensor<?> sensor) { + throw new UnsupportedOperationException(); + } + @Override + public Sensor<?> removeSensor(String sensorName) { + throw new UnsupportedOperationException(); + } + } + + @SuppressWarnings("rawtypes") + private static final Map<Class,BrooklynDynamicType<?,?>> cache = Maps.newConcurrentMap(); + + public static EntityDynamicType getDefinedEntityType(Class<? extends Entity> entityClass) { + return (EntityDynamicType) BrooklynTypes.getDefinedBrooklynType(entityClass); + } + + public static BrooklynDynamicType<?,?> getDefinedBrooklynType(Class<? extends BrooklynObject> brooklynClass) { + BrooklynDynamicType<?,?> t = cache.get(brooklynClass); + if (t!=null) return t; + return loadDefinedBrooklynType(brooklynClass); + } + + @SuppressWarnings("unchecked") + private static synchronized BrooklynDynamicType<?,?> loadDefinedBrooklynType(Class<? extends BrooklynObject> brooklynClass) { + BrooklynDynamicType<?,?> type = cache.get(brooklynClass); + if (type != null) return type; + + if (Entity.class.isAssignableFrom(brooklynClass)) { + type = new ImmutableEntityType((Class<? extends Entity>)brooklynClass); + } else if (Location.class.isAssignableFrom(brooklynClass)) { + type = new ImmutableEntityType((Class<? extends Entity>)brooklynClass); + } else if (Policy.class.isAssignableFrom(brooklynClass)) { + type = new PolicyDynamicType((Class<? extends Policy>)brooklynClass); // TODO immutable? + } else if (Enricher.class.isAssignableFrom(brooklynClass)) { + type = new EnricherDynamicType((Class<? extends Enricher>)brooklynClass); // TODO immutable? + } else { + throw new IllegalStateException("Invalid brooklyn type "+brooklynClass); + } + cache.put(brooklynClass, type); + return type; + } + + public static Map<String, ConfigKey<?>> getDefinedConfigKeys(Class<? extends BrooklynObject> brooklynClass) { + return getDefinedBrooklynType(brooklynClass).getConfigKeys(); + } + + @SuppressWarnings("unchecked") + public static Map<String, ConfigKey<?>> getDefinedConfigKeys(String brooklynTypeName) { + try { + return getDefinedConfigKeys((Class<? extends BrooklynObject>) Class.forName(brooklynTypeName)); + } catch (ClassNotFoundException e) { + throw Exceptions.propagate(e); + } + } + + public static Map<String, Sensor<?>> getDefinedSensors(Class<? extends Entity> entityClass) { + return getDefinedEntityType(entityClass).getSensors(); + } + + @SuppressWarnings("unchecked") + public static Map<String, Sensor<?>> getDefinedSensors(String entityTypeName) { + try { + return getDefinedSensors((Class<? extends Entity>) Class.forName(entityTypeName)); + } catch (ClassNotFoundException e) { + throw Exceptions.propagate(e); + } + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/basic/internal/ApiObjectsFactoryImpl.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/basic/internal/ApiObjectsFactoryImpl.java index 0000000,d200a3c..a51ee39 mode 000000,100644..100644 --- a/core/src/main/java/org/apache/brooklyn/basic/internal/ApiObjectsFactoryImpl.java +++ b/core/src/main/java/org/apache/brooklyn/basic/internal/ApiObjectsFactoryImpl.java @@@ -1,0 -1,42 +1,42 @@@ + /* + * 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.basic.internal; + + import org.apache.brooklyn.api.basic.internal.ApiObjectsFactoryInterface; + import org.apache.brooklyn.api.entity.Entity; + import org.apache.brooklyn.api.management.Task; ++import org.apache.brooklyn.core.util.task.Tasks; + + import brooklyn.entity.basic.BrooklynTaskTags; -import brooklyn.util.task.Tasks; + + public class ApiObjectsFactoryImpl implements ApiObjectsFactoryInterface { + + @Override + public String getCatalogItemIdFromContext() { + Task<?> currentTask = Tasks.current(); + if (currentTask != null) { + Entity contextEntity = BrooklynTaskTags.getContextEntity(currentTask); + if (contextEntity != null) { + return contextEntity.getCatalogItemId(); + } + } + return null; + } + + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java index 836cac3,ede8bde..49462e2 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java @@@ -24,10 -24,10 +24,12 @@@ import java.util.List import java.util.Map; import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes; +import org.apache.brooklyn.core.util.xstream.EnumCaseForgivingSingleValueConverter; +import org.apache.brooklyn.core.util.xstream.XmlSerializer; - import brooklyn.basic.AbstractBrooklynObject; + import org.apache.brooklyn.basic.AbstractBrooklynObject; + import brooklyn.util.xstream.EnumCaseForgivingSingleValueConverter; + import brooklyn.util.xstream.XmlSerializer; public class CatalogXmlSerializer extends XmlSerializer<Object> { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java index eda106f,0000000..f5c36aa mode 100644,000000..100644 --- a/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java @@@ -1,510 -1,0 +1,510 @@@ +/* + * 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.policy.basic; + +import static brooklyn.util.GroovyJavaMethods.truth; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.entity.Group; +import org.apache.brooklyn.api.entity.basic.EntityLocal; +import org.apache.brooklyn.api.entity.trait.Configurable; +import org.apache.brooklyn.api.event.AttributeSensor; +import org.apache.brooklyn.api.event.Sensor; +import org.apache.brooklyn.api.event.SensorEventListener; +import org.apache.brooklyn.api.management.ExecutionContext; +import org.apache.brooklyn.api.management.SubscriptionContext; +import org.apache.brooklyn.api.management.SubscriptionHandle; +import org.apache.brooklyn.api.management.Task; +import org.apache.brooklyn.api.policy.EntityAdjunct; +import org.apache.brooklyn.core.management.internal.SubscriptionTracker; +import org.apache.brooklyn.core.util.config.ConfigBag; +import org.apache.brooklyn.core.util.flags.FlagUtils; +import org.apache.brooklyn.core.util.flags.SetFromFlag; +import org.apache.brooklyn.core.util.flags.TypeCoercions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + - import brooklyn.basic.AbstractBrooklynObject; - import brooklyn.basic.BrooklynObjectInternal; ++import org.apache.brooklyn.basic.AbstractBrooklynObject; ++import org.apache.brooklyn.basic.BrooklynObjectInternal; +import brooklyn.config.ConfigKey; +import brooklyn.config.ConfigKey.HasConfigKey; +import brooklyn.config.ConfigMap; +import brooklyn.enricher.basic.AbstractEnricher; +import brooklyn.entity.basic.ConfigKeys; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityInternal; +import brooklyn.util.guava.Maybe; +import brooklyn.util.text.Strings; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + + +/** + * Common functionality for policies and enrichers + */ +public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable { + private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class); + + private boolean _legacyNoConstructionInit; + + /** + * @deprecated since 0.7.0; leftover properties are put into config, since when coming from yaml this is normal. + */ + @Deprecated + protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap(); + + protected transient ExecutionContext execution; + + private final BasicConfigurationSupport config = new BasicConfigurationSupport(); + + /** + * The config values of this entity. Updating this map should be done + * via {@link #config()}. + * + * @deprecated since 0.7.0; use {@link #config()} instead; this field may be made private or deleted in a future release. + */ + @Deprecated + protected final ConfigMapImpl configsInternal = new ConfigMapImpl(this); + + /** + * @deprecated since 0.7.0; use {@link #getAdjunctType()} instead; this field may be made private or deleted in a future release. + */ + @Deprecated + protected final AdjunctType adjunctType = new AdjunctType(this); + + @SetFromFlag + protected String name; + + protected transient EntityLocal entity; + + /** not for direct access; refer to as 'subscriptionTracker' via getter so that it is initialized */ + protected transient SubscriptionTracker _subscriptionTracker; + + private AtomicBoolean destroyed = new AtomicBoolean(false); + + @SetFromFlag(value="uniqueTag") + protected String uniqueTag; + + public AbstractEntityAdjunct() { + this(Collections.emptyMap()); + } + + public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map properties) { + super(properties); + _legacyNoConstructionInit = (properties != null) && Boolean.TRUE.equals(properties.get("noConstructionInit")); + + if (isLegacyConstruction()) { + AbstractBrooklynObject checkWeGetThis = configure(properties); + assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this; + + boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class)); + if (!deferConstructionChecks) { + FlagUtils.checkRequiredFields(this); + } + } + } + + /** + * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly + */ + @Override + @Deprecated + @SuppressWarnings({ "unchecked", "rawtypes" }) + public AbstractEntityAdjunct configure(Map flags) { + // TODO only set on first time through + boolean isFirstTime = true; + + // allow config keys, and fields, to be set from these flags if they have a SetFromFlag annotation + // or if the value is a config key + for (Iterator<Map.Entry> iter = flags.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); + if (entry.getKey() instanceof ConfigKey) { + ConfigKey key = (ConfigKey)entry.getKey(); + if (adjunctType.getConfigKeys().contains(key)) { + setConfig(key, entry.getValue()); + } else { + log.warn("Unknown configuration key {} for policy {}; ignoring", key, this); + iter.remove(); + } + } + } + + ConfigBag bag = new ConfigBag().putAll(flags); + FlagUtils.setFieldsFromFlags(this, bag, isFirstTime); + FlagUtils.setAllConfigKeys(this, bag, false); + leftoverProperties.putAll(bag.getUnusedConfig()); + + //replace properties _contents_ with leftovers so subclasses see leftovers only + flags.clear(); + flags.putAll(leftoverProperties); + leftoverProperties = flags; + + if (!truth(name) && flags.containsKey("displayName")) { + //TODO inconsistent with entity and location, where name is legacy and displayName is encouraged! + //'displayName' is a legacy way to refer to a policy's name + Preconditions.checkArgument(flags.get("displayName") instanceof CharSequence, "'displayName' property should be a string"); + setDisplayName(flags.remove("displayName").toString()); + } + + // set leftover flags should as config items; particularly useful when these have come from a brooklyn.config map + for (Object flag: flags.keySet()) { + ConfigKey<Object> key = ConfigKeys.newConfigKey(Object.class, Strings.toString(flag)); + if (config().getRaw(key).isPresent()) { + log.warn("Config '"+flag+"' on "+this+" conflicts with key already set; ignoring"); + } else { + config().set(key, flags.get(flag)); + } + } + + return this; + } + + /** + * Used for legacy-style policies/enrichers on rebind, to indicate that init() should not be called. + * Will likely be deleted in a future release; should not be called apart from by framework code. + */ + @Beta + protected boolean isLegacyNoConstructionInit() { + return _legacyNoConstructionInit; + } + + @Override + public ConfigurationSupportInternal config() { + return config; + } + + private class BasicConfigurationSupport implements ConfigurationSupportInternal { + + @Override + public <T> T get(ConfigKey<T> key) { + return configsInternal.getConfig(key); + } + + @Override + public <T> T get(HasConfigKey<T> key) { + return get(key.getConfigKey()); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T set(ConfigKey<T> key, T val) { + if (entity != null && isRunning()) { + doReconfigureConfig(key, val); + } + T result = (T) configsInternal.setConfig(key, val); + onChanged(); + return result; + } + + @Override + public <T> T set(HasConfigKey<T> key, T val) { + return setConfig(key.getConfigKey(), val); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T set(ConfigKey<T> key, Task<T> val) { + if (entity != null && isRunning()) { + // TODO Support for AbstractEntityAdjunct + throw new UnsupportedOperationException(); + } + T result = (T) configsInternal.setConfig(key, val); + onChanged(); + return result; + } + + @Override + public <T> T set(HasConfigKey<T> key, Task<T> val) { + return set(key.getConfigKey(), val); + } + + @Override + public ConfigBag getBag() { + return getLocalBag(); + } + + @Override + public ConfigBag getLocalBag() { + return ConfigBag.newInstance(configsInternal.getAllConfig()); + } + + @Override + public Maybe<Object> getRaw(ConfigKey<?> key) { + return configsInternal.getConfigRaw(key, true); + } + + @Override + public Maybe<Object> getRaw(HasConfigKey<?> key) { + return getRaw(key.getConfigKey()); + } + + @Override + public Maybe<Object> getLocalRaw(ConfigKey<?> key) { + return configsInternal.getConfigRaw(key, false); + } + + @Override + public Maybe<Object> getLocalRaw(HasConfigKey<?> key) { + return getLocalRaw(key.getConfigKey()); + } + + @Override + public void addToLocalBag(Map<String, ?> vals) { + configsInternal.addToLocalBag(vals); + } + + @Override + public void removeFromLocalBag(String key) { + configsInternal.removeFromLocalBag(key); + } + + @Override + public void refreshInheritedConfig() { + // no-op for location + } + + @Override + public void refreshInheritedConfigOfChildren() { + // no-op for location + } + } + + public <T> T getConfig(ConfigKey<T> key) { + return config().get(key); + } + + protected <K> K getRequiredConfig(ConfigKey<K> key) { + K result = config().get(key); + if (result==null) + throw new NullPointerException("Value required for '"+key.getName()+"' in "+this); + return result; + } + + @Override + @Deprecated + public <T> T setConfig(ConfigKey<T> key, T val) { + return config().set(key, val); + } + + // TODO make immutable + /** for inspection only */ + @Beta + @Deprecated + public ConfigMap getConfigMap() { + return configsInternal; + } + + /** + * Invoked whenever a config change is applied after management is started. + * Default implementation throws an exception to disallow the change. + * Can be overridden to return (allowing the change) or to make other changes + * (if necessary), and of course it can do this selectively and call the super to disallow any others. */ + protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) { + throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this); + } + + @Override + protected void onTagsChanged() { + onChanged(); + } + + protected abstract void onChanged(); + + protected AdjunctType getAdjunctType() { + return adjunctType; + } + + @Override + public String getDisplayName() { + if (name!=null && name.length()>0) return name; + return getClass().getCanonicalName(); + } + + public void setDisplayName(String name) { + this.name = name; + } + + public void setEntity(EntityLocal entity) { + if (destroyed.get()) throw new IllegalStateException("Cannot set entity on a destroyed entity adjunct"); + this.entity = entity; + if (entity!=null && getCatalogItemId() == null) { + setCatalogItemId(entity.getCatalogItemId()); + } + } + + /** @deprecated since 0.7.0 only {@link AbstractEnricher} has emit convenience */ + protected <T> void emit(Sensor<T> sensor, Object val) { + checkState(entity != null, "entity must first be set"); + if (val == Entities.UNCHANGED) { + return; + } + if (val == Entities.REMOVE) { + ((EntityInternal)entity).removeAttribute((AttributeSensor<T>) sensor); + return; + } + + T newVal = TypeCoercions.coerce(val, sensor.getTypeToken()); + if (sensor instanceof AttributeSensor) { + entity.setAttribute((AttributeSensor<T>)sensor, newVal); + } else { + entity.emit(sensor, newVal); + } + } + + protected synchronized SubscriptionTracker getSubscriptionTracker() { + if (_subscriptionTracker!=null) return _subscriptionTracker; + if (entity==null) return null; + _subscriptionTracker = new SubscriptionTracker(((EntityInternal)entity).getManagementSupport().getSubscriptionContext()); + return _subscriptionTracker; + } + + /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */ + protected <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) { + if (!checkCanSubscribe()) return null; + return getSubscriptionTracker().subscribe(producer, sensor, listener); + } + + /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */ + protected <T> SubscriptionHandle subscribeToMembers(Group producerGroup, Sensor<T> sensor, SensorEventListener<? super T> listener) { + if (!checkCanSubscribe(producerGroup)) return null; + return getSubscriptionTracker().subscribeToMembers(producerGroup, sensor, listener); + } + + /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */ + protected <T> SubscriptionHandle subscribeToChildren(Entity producerParent, Sensor<T> sensor, SensorEventListener<? super T> listener) { + if (!checkCanSubscribe(producerParent)) return null; + return getSubscriptionTracker().subscribeToChildren(producerParent, sensor, listener); + } + + /** @deprecated since 0.7.0 use {@link #checkCanSubscribe(Entity)} */ + @Deprecated + protected boolean check(Entity requiredEntity) { + return checkCanSubscribe(requiredEntity); + } + /** returns false if deleted, throws exception if invalid state, otherwise true. + * okay if entity is not yet managed (but not if entity is no longer managed). */ + protected boolean checkCanSubscribe(Entity producer) { + if (destroyed.get()) return false; + if (producer==null) throw new IllegalStateException(this+" given a null target for subscription"); + if (entity==null) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because it is not associated to an entity"); + if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because the associated entity "+entity+" is no longer managed"); + return true; + } + protected boolean checkCanSubscribe() { + if (destroyed.get()) return false; + if (entity==null) throw new IllegalStateException(this+" cannot subscribe because it is not associated to an entity"); + if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe because the associated entity "+entity+" is no longer managed"); + return true; + } + + /** + * Unsubscribes the given producer. + * + * @see SubscriptionContext#unsubscribe(SubscriptionHandle) + */ + protected boolean unsubscribe(Entity producer) { + if (destroyed.get()) return false; + return getSubscriptionTracker().unsubscribe(producer); + } + + /** + * Unsubscribes the given producer. + * + * @see SubscriptionContext#unsubscribe(SubscriptionHandle) + */ + protected boolean unsubscribe(Entity producer, SubscriptionHandle handle) { + if (destroyed.get()) return false; + return getSubscriptionTracker().unsubscribe(producer, handle); + } + + /** + * @return a list of all subscription handles + */ + protected Collection<SubscriptionHandle> getAllSubscriptions() { + SubscriptionTracker tracker = getSubscriptionTracker(); + return (tracker != null) ? tracker.getAllSubscriptions() : Collections.<SubscriptionHandle>emptyList(); + } + + /** + * Unsubscribes and clears all managed subscriptions; is called by the owning entity when a policy is removed + * and should always be called by any subclasses overriding this method + */ + public void destroy() { + destroyed.set(true); + SubscriptionTracker tracker = getSubscriptionTracker(); + if (tracker != null) tracker.unsubscribeAll(); + } + + @Override + public boolean isDestroyed() { + return destroyed.get(); + } + + @Override + public boolean isRunning() { + return !isDestroyed(); + } + + @Override + public String getUniqueTag() { + return uniqueTag; + } + + public TagSupport tags() { + return new AdjunctTagSupport(); + } + + public class AdjunctTagSupport extends BasicTagSupport { + @Override + public Set<Object> getTags() { + ImmutableSet.Builder<Object> rb = ImmutableSet.builder().addAll(super.getTags()); + if (getUniqueTag()!=null) rb.add(getUniqueTag()); + return rb.build(); + } + public String getUniqueTag() { + return AbstractEntityAdjunct.this.getUniqueTag(); + } + public void setUniqueTag(String uniqueTag) { + AbstractEntityAdjunct.this.uniqueTag = uniqueTag; + } + } + + @Override + public String toString() { + return Objects.toStringHelper(getClass()).omitNullValues() + .add("name", name) + .add("uniqueTag", uniqueTag) + .add("running", isRunning()) + .add("entity", entity) + .add("id", getId()) + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java index 315d03d,0000000..a98aead mode 100644,000000..100644 --- a/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java +++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java @@@ -1,44 -1,0 +1,44 @@@ +/* + * 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.policy.basic; + +import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.policy.PolicyType; + - import brooklyn.basic.BrooklynDynamicType; ++import org.apache.brooklyn.basic.BrooklynDynamicType; + +public class PolicyDynamicType extends BrooklynDynamicType<Policy, AbstractPolicy> { + + public PolicyDynamicType(Class<? extends Policy> type) { + super(type); + } + + public PolicyDynamicType(AbstractPolicy policy) { + super(policy); + } + + public PolicyType getSnapshot() { + return (PolicyType) super.getSnapshot(); + } + + @Override + protected PolicyTypeSnapshot newSnapshot() { + return new PolicyTypeSnapshot(name, value(configKeys)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java index 0e655b6,0000000..6604350 mode 100644,000000..100644 --- a/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java +++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java @@@ -1,40 -1,0 +1,40 @@@ +/* + * 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.policy.basic; + +import java.util.Map; + +import org.apache.brooklyn.api.policy.PolicyType; + - import brooklyn.basic.BrooklynTypeSnapshot; ++import org.apache.brooklyn.basic.BrooklynTypeSnapshot; +import brooklyn.config.ConfigKey; + +public class PolicyTypeSnapshot extends BrooklynTypeSnapshot implements PolicyType { + private static final long serialVersionUID = 4670930188951106009L; + + PolicyTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) { + super(name, configKeys); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + return (obj instanceof PolicyTypeSnapshot) && super.equals(obj); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java index 4a444c7,0082b9a..5d2e18e --- a/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java +++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java @@@ -24,9 -24,8 +24,9 @@@ import org.apache.brooklyn.api.entity.r import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.management.ManagementContext; import org.apache.brooklyn.api.mementos.LocationMemento; +import org.apache.brooklyn.core.util.config.ConfigBag; - import brooklyn.basic.BrooklynObjectInternal; + import org.apache.brooklyn.basic.BrooklynObjectInternal; import brooklyn.config.ConfigInheritance; import brooklyn.config.ConfigKey; import brooklyn.entity.basic.ConfigKeys; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java ---------------------------------------------------------------------- diff --cc usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java index 95c10a1,8cce298..7293abf --- a/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java +++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java @@@ -66,19 -65,8 +65,9 @@@ import org.apache.brooklyn.cli.CloudExp import org.apache.brooklyn.cli.CloudExplorer.ComputeListInstancesCommand; import org.apache.brooklyn.cli.CloudExplorer.ComputeTerminateInstancesCommand; import org.apache.brooklyn.cli.ItemLister.ListAllCommand; - import org.apache.brooklyn.cli.CloudExplorer.BlobstoreGetBlobCommand; - import org.apache.brooklyn.cli.CloudExplorer.BlobstoreListContainerCommand; - import org.apache.brooklyn.cli.CloudExplorer.BlobstoreListContainersCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeDefaultTemplateCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeGetImageCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeListHardwareProfilesCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeListImagesCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeListInstancesCommand; - import org.apache.brooklyn.cli.CloudExplorer.ComputeTerminateInstancesCommand; - import org.apache.brooklyn.cli.ItemLister.ListAllCommand; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; import org.apache.brooklyn.core.management.ha.OsgiManager; +import org.apache.brooklyn.core.util.ResourceUtils; import brooklyn.entity.basic.AbstractApplication; import brooklyn.entity.basic.AbstractEntity; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f9b357d7/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java ----------------------------------------------------------------------
