http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java index e415a1c..dffa548 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java @@ -19,12 +19,14 @@ package org.apache.brooklyn.config; import java.io.Serializable; -import java.util.Iterator; import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.apache.brooklyn.config.ConfigInheritances.BasicConfigValueAtContainer; import org.apache.brooklyn.util.collections.CollectionMerger; +import org.apache.brooklyn.util.exceptions.ReferenceWithError; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.text.Strings; @@ -33,7 +35,8 @@ import com.google.common.annotations.Beta; @SuppressWarnings("serial") public interface ConfigInheritance extends Serializable { - /** marker interface for inheritance contexts, for keys which can define one or more inheritance patterns */ + /** marker interface for inheritance contexts, for keys which can define one or more inheritance patterns; + * implementers can define their own, e.g. in an enum */ public interface ConfigInheritanceContext {} /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated @@ -54,40 +57,64 @@ public interface ConfigInheritance extends Serializable { @Deprecated InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to); - /** - * given a key and local value, together with an optional record of ancestor containers (eg an entity) and associated data, - * this finds the value for a config key <b>applying the appropriate inheritance strategies</b>. - * for instance this may merge a map throughout a container hierarchy, - * or this may traverse up until a non-reinheritable key definition is found and in the absence of values lower - * in the hierarchy this will return the default value of the key + /** Returns whether any value from the given node or ancestors can be considered + * for inheritance by descendants, according to the {@link ConfigInheritance} defined there. + * Implementations should not normally consider the value here + * as there may be other ancestors whose values have not yet been considered and are not supplied. + * <p> + * If there is a {@link ConfigInheritance} defined at this node, + * this method must be called on that instance and that instance only. + * In that case it is an error to invoke this method on any other {@link ConfigInheritance} instance. + * If there is not one, the config generally should be considered reinheritable. * <p> - * this uses an interface on the input so that: - * - the caller can supply the hierarchy - * - hierarchy is only traversed as far as needed - * - caller can do full resolution as required for local values + * Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ + public <TContainer,TValue> boolean isReinheritable( + @Nullable ConfigValueAtContainer<TContainer,TValue> parent, + ConfigInheritanceContext context); + + /** Returns whether any value from the parent or its ancestors should be considered + * by the given local container, according to the {@link ConfigInheritance} defined there. + * This defines the {@link ConfigInheritance} of the local container typically considering + * the value of the key there. + * Implementations should not normally consider the value of the parent + * as there may be other ancestors whose values have not yet been considered and are not supplied, + * but it may determine that a local value is sufficient to render it unnecessary to consider the parent. + * <p> + * If there is a {@link ConfigInheritance} defined at the local container, + * this method must be called on that instance and that instance only. + * In that case it is an error to invoke this method on any other {@link ConfigInheritance} instance. * <p> - * this returns in interface so that caller can get the value, - * and if needed also find the container where the key is defined. - * that can be useful for when the value needs to be further resolved, - * e.g. a DSL function or a URL. the returned value may be evaluated lazily, - * i.e. the actual traversal and evaluation may be deferred until a method on - * the returned object is invoked. + * Consumers should consider this in conjuction with the + * {@link #isReinheritable(ConfigValueAtContainer, ConfigInheritanceContext)} + * status of the parent (if present). + * Implementers need not duplicate a call to that method. + * Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ + public <TContainer,TValue> boolean considerParent( + @Nonnull ConfigValueAtContainer<TContainer,TValue> local, + @Nullable ConfigValueAtContainer<TContainer,TValue> parent, + ConfigInheritanceContext context); + + /** Returns the result after inheritance between the local container and a "resolveParent" + * representation of the parent's evaluation of the key considering its ancestors. + * The parent here can be assumed to be the result of resolution with its ancestors, + * and reinheritance can be assumed to be permitted. + * Consumers should invoke this only after checking + * {@link #considerParent(ConfigValueAtContainer, ConfigValueAtContainer, ConfigInheritanceContext)} + * on the local node and {@link #isReinheritable(ConfigValueAtContainer, ConfigInheritanceContext)} + * on the original parent node, + * and then {@link #resolveWithParent(ConfigValueAtContainer, ConfigValueAtContainer, ConfigInheritanceContext)} + * on the original parent node with its respective resolvedParent. * <p> - * this object is taken as the default inheritance and used if no inheritance is - * defined on the key. + * If there is a {@link ConfigInheritance} defined at the local container, + * this method must be called on that instance and that instance only. + * In that case it is an error to invoke this method on any other {@link ConfigInheritance} instance. * <p> - * so that the caller can determine if a key/value is to be exported to children from a container, - * this method should accept an iterable whose first entry has a null container - * and whose second entry gives the container, key, and potential value to be exported. - * if null is returned the caller knows nothing is to be exported to children. - */ - <TContainer,TValue> ConfigValueAtContainer<TContainer,TValue> resolveInheriting( - ConfigKey<TValue> key, - @Nullable Maybe<TValue> localValue, - @Nullable TContainer container, - Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> ancestorContainerKeyValues, + * Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ + public <TContainer,TValue> ReferenceWithError<ConfigValueAtContainer<TContainer,TValue>> resolveWithParent( + @Nonnull ConfigValueAtContainer<TContainer,TValue> local, + @Nonnull ConfigValueAtContainer<TContainer,TValue> resolvedParent, ConfigInheritanceContext context); - + /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated public static class Legacy { public static ConfigInheritance fromString(String val) { @@ -105,71 +132,43 @@ public interface ConfigInheritance extends Serializable { } } private abstract static class LegacyAbstractConversion implements ConfigInheritance { - private static class Result<TContainer,TValue> implements ConfigValueAtContainer<TContainer,TValue> { - TContainer container = null; - Maybe<TValue> value = Maybe.absent(); - boolean isValueSet = false; - ConfigKey<TValue> key = null; - @Override public TContainer getContainer() { return container; } - @Override public TValue get() { return value.orNull(); } - @Override public Maybe<TValue> asMaybe() { return value; } - @Override public boolean isValueExplicitlySet() { return isValueSet; } - @Override public ConfigKey<TValue> getKey() { return key; } - @Override public TValue getDefaultValue() { return key==null ? null : key.getDefaultValue(); } + + @Override + public <TContainer, TValue> boolean isReinheritable(ConfigValueAtContainer<TContainer, TValue> parent, ConfigInheritanceContext context) { + return getMode()!=InheritanceMode.NONE; + } + + @Override + public <TContainer,TValue> boolean considerParent( + ConfigValueAtContainer<TContainer,TValue> local, + @Nullable ConfigValueAtContainer<TContainer,TValue> parent, + ConfigInheritanceContext context) { + if (parent==null) return false; + if (getMode()==InheritanceMode.NONE) return false; + if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE) return !local.isValueExplicitlySet(); + return true; } - // close copy of method in BasicConfigInheritance for this legacy compatibility evaluation @Override - public <TContainer,TValue> ConfigValueAtContainer<TContainer,TValue> resolveInheriting( - @Nullable ConfigKey<TValue> key, Maybe<TValue> localValue, TContainer container, - Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> ancestorContainerKeyValues, ConfigInheritanceContext context) { - ConfigInheritance inh = key==null ? null : key.getInheritanceByContext(context); - if (inh==null) inh = this; - if (inh!=this) return inh.resolveInheriting(key, localValue, container, ancestorContainerKeyValues, context); - - ConfigValueAtContainer<TContainer,TValue> v2 = null; - if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE && localValue.isPresent()) { - // don't inherit - } else if (ancestorContainerKeyValues==null || !ancestorContainerKeyValues.hasNext()) { - // nothing to inherit - } else { - // check whether parent allows us to get inherited value - ConfigValueAtContainer<TContainer,TValue> c = ancestorContainerKeyValues.next(); - ConfigInheritance inh2 = c.getKey()==null ? null : c.getKey().getInheritanceByContext(context); - if (inh2==null) inh2 = this; - if (getMode()==InheritanceMode.NONE) { - // can't inherit - } else { - // get inherited value - v2 = inh2.resolveInheriting(c.getKey(), - c.isValueExplicitlySet() ? c.asMaybe() : Maybe.<TValue>absent(), c.getContainer(), - ancestorContainerKeyValues, context); - } - } + public <TContainer,TValue> ReferenceWithError<ConfigValueAtContainer<TContainer,TValue>> resolveWithParent( + ConfigValueAtContainer<TContainer,TValue> local, + ConfigValueAtContainer<TContainer,TValue> parent, + ConfigInheritanceContext context) { + // parent can be assumed to be set, but might not have a value + if (!parent.isValueExplicitlySet()) + return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(local)); + + if (!local.isValueExplicitlySet()) + return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(parent)); - if (v2!=null && v2.isValueExplicitlySet() && !localValue.isPresent()) return v2; - Result<TContainer,TValue> v = new Result<TContainer,TValue>(); - v.container = container; - if (v2==null || !v2.isValueExplicitlySet()) { - v.isValueSet = localValue.isPresent(); - v.value = v.isValueExplicitlySet() ? localValue : - key!=null && key.hasDefaultValue() ? Maybe.of(key.getDefaultValue()) : Maybe.<TValue>absent(); - } else { - v.value = Maybe.of(resolveConflict(key, localValue, v2.asMaybe())); - v.isValueSet = true; - } - return v; - } - /** only invoked if there is an ancestor value; custom strategies can overwrite */ - protected <T> T resolveConflict(ConfigKey<T> key, Maybe<T> localValue, Maybe<T> ancestorValue) { - if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE) { - if (localValue.isPresent()) return localValue.get(); - return ancestorValue.orNull(); - } + // both explicitly set, and not overwrite or none if (getMode()==InheritanceMode.DEEP_MERGE) { - return deepMerge(localValue, ancestorValue).orNull(); + BasicConfigValueAtContainer<TContainer, TValue> result = new BasicConfigValueAtContainer<TContainer,TValue>(local); + result.setValue( deepMerge(local.asMaybe(), parent.asMaybe()) ); + return ReferenceWithError.newInstanceWithoutError(result); } - throw new IllegalStateException("Unknown config conflict resolution strategy '"+getMode()+"' evaluating "+key); + + throw new IllegalStateException("Unknown config conflict resolution strategy '"+getMode()+"' evaluating "+local+"/"+parent); } private static <T> Maybe<? extends T> deepMerge(Maybe<? extends T> val1, Maybe<? extends T> val2) { if (val2.isAbsent() || val2.isNull()) { @@ -187,6 +186,7 @@ public interface ConfigInheritance extends Serializable { return val1; } } + @Override public InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to) { return getMode();
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java new file mode 100644 index 0000000..95d80ff --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java @@ -0,0 +1,185 @@ +/* + * 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.config; + +import java.util.Iterator; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext; +import org.apache.brooklyn.util.exceptions.ReferenceWithError; +import org.apache.brooklyn.util.guava.Maybe; + +public class ConfigInheritances { + + /** + * given a key and local value, together with an optional record of ancestor containers (eg an entity) and associated data, + * this finds the value for a config key <b>applying the appropriate inheritance strategies</b>. + * for instance this may merge a map throughout a container hierarchy, + * or this may traverse up until a non-reinheritable key definition is found and in the absence of values lower + * in the hierarchy this will return the default value of the key + * <p> + * this uses an interface on the input so that: + * - the caller can supply the hierarchy + * - hierarchy is only traversed as far as needed + * - caller can do full resolution as required for local values + * <p> + * this returns in interface so that caller can get the value, + * and if needed also find the container where the key is defined. + * that can be useful for when the value needs to be further resolved, + * e.g. a DSL function or a URL. the returned value may be evaluated lazily, + * i.e. the actual traversal and evaluation may be deferred until a method on + * the returned object is invoked. + * <p> + * this object is taken as the default inheritance and used if no inheritance is + * defined on the key. + * <p> + * so that the caller can determine if a key/value is to be exported to children from a container, + * this method should accept an iterable whose first entry has a null container + * and whose second entry gives the container, key, and potential value to be exported. + * if null is returned the caller knows nothing is to be exported to children. + */ + public static <TContainer,TValue> ReferenceWithError<ConfigValueAtContainer<TContainer,TValue>> resolveInheriting( + @Nullable TContainer container, + ConfigKey<TValue> key, + @Nullable Maybe<TValue> localValue, + @Nullable Maybe<TValue> defaultValue, + + Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> ancestorContainerKeyValues, + ConfigInheritanceContext context, + ConfigInheritance defaultInheritance) { + return resolveInheriting(new BasicConfigValueAtContainer<TContainer,TValue>(container, key, localValue, localValue.isPresent(), defaultValue), + ancestorContainerKeyValues, key, context, defaultInheritance); + } + + /** as {@link #resolveInheriting(Object, ConfigKey, Maybe, Iterator, ConfigInheritanceContext, ConfigInheritance)} + * but convenient when the local info is already in a {@link ConfigValueAtContainer} */ + public static <TContainer,TValue> ReferenceWithError<ConfigValueAtContainer<TContainer,TValue>> resolveInheriting( + ConfigValueAtContainer<TContainer,TValue> local, + Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> ancestorContainerKeyValues, + ConfigKey<TValue> queryKey, + ConfigInheritanceContext context, + ConfigInheritance defaultInheritance) { + + if (ancestorContainerKeyValues.hasNext()) { + ConfigValueAtContainer<TContainer, TValue> parent = ancestorContainerKeyValues.next(); + ConfigInheritance parentInheritance = findInheritance(parent, context, null); + if (parentInheritance==null || parentInheritance.isReinheritable(parent, context)) { + ConfigInheritance currentInheritance = findInheritance(local, context, findInheritance(queryKey, context, defaultInheritance)); + if (currentInheritance.considerParent(local, parent, context)) { + ReferenceWithError<ConfigValueAtContainer<TContainer, TValue>> parentResult = resolveInheriting(parent, ancestorContainerKeyValues, queryKey, context, currentInheritance); + ReferenceWithError<ConfigValueAtContainer<TContainer,TValue>> resultWithParent = currentInheritance.resolveWithParent(local, parentResult.getWithoutError(), context); + if (resultWithParent!=null && resultWithParent.getWithoutError()!=null && resultWithParent.getWithoutError().isValueExplicitlySet()) { + if (!resultWithParent.hasError() && parentResult!=null && parentResult.hasError()) { + return ReferenceWithError.newInstanceThrowingError(resultWithParent.getWithoutError(), parentResult.getError()); + } + return resultWithParent; + } + } + } + } + BasicConfigValueAtContainer<TContainer, TValue> result = new BasicConfigValueAtContainer<TContainer, TValue>(local); + if (!local.isValueExplicitlySet() && local.getDefaultValue().isPresent()) { + result.value = local.getDefaultValue(); + } + return ReferenceWithError.newInstanceWithoutError(result); + } + + /** finds the {@link ConfigInheritance} to use based on the given container, or the default if none is present there */ + public static ConfigInheritance findInheritance(ConfigValueAtContainer<?,?> local, ConfigInheritanceContext context, ConfigInheritance defaultInheritance) { + if (local==null) return defaultInheritance; + return findInheritance(local.getKey(), context, defaultInheritance); + } + public static ConfigInheritance findInheritance(ConfigKey<?> localKey, ConfigInheritanceContext context, ConfigInheritance defaultInheritance) { + if (localKey==null) return defaultInheritance; + ConfigInheritance keyInheritance = localKey.getInheritanceByContext(context); + if (keyInheritance==null) return defaultInheritance; + return keyInheritance; + } + + + public static class BasicConfigValueAtContainer<TContainer,TValue> implements ConfigValueAtContainer<TContainer,TValue> { + + TContainer container = null; + Maybe<? extends TValue> value = Maybe.absent(); + boolean valueWasExplicitlySet = false; + ConfigKey<? extends TValue> key = null; + Maybe<TValue> defaultValue = null; + + public BasicConfigValueAtContainer() {} + public BasicConfigValueAtContainer(ConfigValueAtContainer<TContainer,TValue> toCopy) { + this(toCopy.getContainer(), toCopy.getKey(), toCopy.asMaybe(), toCopy.isValueExplicitlySet(), toCopy.getDefaultValue()); + } + public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value) { + this(container, key, value, value.isPresent()); + } + public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value, boolean isValueSet) { + this(container, key, value, isValueSet, null); + } + public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value, boolean isValueSet, Maybe<TValue> defaultValue) { + this.container = container; + this.key = key; + this.valueWasExplicitlySet = isValueSet; + this.defaultValue = defaultValue; + this.value = value!=null && (value.isPresent() || isValueSet || key==null || !key.hasDefaultValue()) ? value + : getDefaultValue(); + } + + @Override public TContainer getContainer() { return container; } + @Override public TValue get() { return value.orNull(); } + @Override public Maybe<? extends TValue> asMaybe() { return value; } + @Override public boolean isValueExplicitlySet() { return valueWasExplicitlySet; } + @Override public ConfigKey<? extends TValue> getKey() { return key; } + + public void setContainer(TContainer container) { + this.container = container; + } + public void setValue(Maybe<? extends TValue> value) { + this.value = value; + } + public void setValueWasExplicitlySet(boolean valueWasExplicitlySet) { + this.valueWasExplicitlySet = valueWasExplicitlySet; + } + public void setKey(ConfigKey<? extends TValue> key) { + this.key = key; + } + + public Maybe<TValue> getDefaultValue() { + if (defaultValue!=null) return defaultValue; + // explicit absent default value means don't look at key + return key!=null && key.hasDefaultValue() ? Maybe.ofAllowingNull((TValue) key.getDefaultValue()) : Maybe.<TValue>absent(); + } + + } + + /** determine whether a key is reinheritable from the point in the given inheritance hierarchy where it is introduced; + * default is true, but some keys may define not being reinherited or may have that effective result + * <p> + * note that this does not mean a value should never be *inherited*; + * callers should query with the key defined at a given point in a hierarchy, + * so if a key is not defined at some point in the hierarchy + * (eg not on a type in the type hierarchy, or not an an entity in the runtime management hierarchy) + * then null should be passed and values will be reinheritable */ + public static <T> boolean isKeyReinheritable(final ConfigKey<T> key, final ConfigInheritanceContext context) { + ConfigInheritance inh = ConfigInheritances.findInheritance(key, context, null); + if (inh==null) return true; + return inh.isReinheritable(null, null); + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/ConfigKey.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigKey.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigKey.java index 4426aa8..a494c0b 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigKey.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigKey.java @@ -103,9 +103,13 @@ public interface ConfigKey<T> { * @deprecated since 0.10.0 use {@link #getInheritanceByContext()} */ @Deprecated @Nullable ConfigInheritance getInheritance(); - - // TODO javadoc + + /** @return The inheritance model for this key in the given {@link ConfigInheritanceContext} */ @Nullable ConfigInheritance getInheritanceByContext(ConfigInheritanceContext context); + /** @return A summary of the inheritance models for this key in various {@link ConfigInheritanceContext} instances. + * Implementations may have a simple map, whereas others could be more sophisticated. + * {@link #getInheritanceByContext(ConfigInheritanceContext)} may be preferred if inheritance contexts are complex + * (but usually, and in brooklyn, they aren't). */ Map<ConfigInheritanceContext,ConfigInheritance> getInheritanceByContext(); /** http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java index 2cc5068..7b0b576 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java @@ -18,11 +18,15 @@ */ package org.apache.brooklyn.config; +import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; +import org.apache.brooklyn.util.exceptions.ReferenceWithError; import org.apache.brooklyn.util.guava.Maybe; +import com.google.common.annotations.Beta; import com.google.common.base.Predicate; public interface ConfigMap { @@ -42,32 +46,12 @@ public interface ConfigMap { * whether to traverse it or not; has no effects where there is no inheritance * @return raw, unresolved, uncoerced value of key in map, * but <b>not</b> any default on the key + * + * @deprecated since 0.10.0 in favour of {@link ConfigMapWithInheritance} methods */ - // TODO behaviour of this is undefined if the key specifies a merge + @Deprecated // and confirmed no uses public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited); - // TODO sketch of new/better implementations -// /** As {@link #getConfigLocalRaw(ConfigKey)} but respecting the inheritance rules. -// * Because inheritance may not be applicable when working with raw values the result -// * is wrapped in a {@link ReferenceWithError}, and if any aspect of inheritance -// * could not be applied, calls to {@link ReferenceWithError#get()} will throw -// * (but {@link ReferenceWithError#getWithoutError()} will not). -// * <p> -// * Note that most modes (eg overwrite, not-inherit) will not cause issues during inheritance -// * so this method is ordinarily fine to use. Problems arise when a merge inheritance mode -// * is specified and it is attempting to merge a raw value which is not mergeable. -// * <p> -// * See also {@link #getConfigAllInheritedRaw(ConfigKey)} which returns the complete set -// * of inherited values. -// * -// * @param key key to look up -// */ -// public ReferenceWithError<ContainerAndValue<Object>> getConfigInheritedRaw(ConfigKey<?> key); -// -// /** As {@link #getConfigLocalRaw(ConfigKey)} but returning all containers through the inheritance -// * hierarchy where a value is set (but stopping if it encounters a key is not inheritable from a container). */ -// public List<ContainerAndValue<Object>> getConfigAllInheritedRaw(ConfigKey<?> key); - /** returns the value stored against the given key, * <b>not</b> any default, * <b>not</b> inherited (if there is an inheritance hierarchy), @@ -77,20 +61,85 @@ public interface ConfigMap { */ public Maybe<Object> getConfigLocalRaw(ConfigKey<?> key); - /** returns a map of all config keys to their raw (unresolved+uncoerced) contents */ - // TODO deprecate + /** returns a read-only map of all local config keys with their raw (unresolved+uncoerced) contents */ + public Map<ConfigKey<?>,Object> getAllConfigLocalRaw(); + + /** returns a map of all config keys to their raw (unresolved+uncoerced) contents + * + * @deprecated since 0.10.0 in favour of {@link #getAllConfigLocalRaw()} for local + * and {@link ConfigMapWithInheritance} methods for inherited; + * kept on some sub-interfaces (eg Brooklyn properties) */ + @Deprecated // and confirmed no uses (besides sub-interface) public Map<ConfigKey<?>,Object> getAllConfig(); - /** returns submap matching the given filter predicate; see ConfigPredicates for common predicates */ + /** returns submap matching the given filter predicate; see ConfigPredicates for common predicates + * @deprecated since 0.10.0 use {@link #findKeys(Predicate)} then do whatever is desired for the values; + * kept on {@link StringConfigMap} */ + @Deprecated // and confirmed no uses (besides sub-interface) + // deprecated because this becomes irritating to implement in a hierarchical world, it requires caching the predicate; + // also it encourages subsequent calls to deprecated methods such as #getAllConfig public ConfigMap submap(Predicate<ConfigKey<?>> filter); + + /** returns all keys matching the given filter predicate; see ConfigPredicates for common predicates */ + public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter); /** returns a read-only map view which has string keys (corresponding to the config key names); * callers encouraged to use the typed keys (and so not use this method), - * but in some compatibility areas having a Properties-like view is useful */ + * but in some compatibility areas having a Properties-like view is useful + * + * @deprecated since 0.10.0 use the corresponding methods to return {@link ConfigKey}-based maps, + * then pass to a ConfigBag to get a string-map view; kept for {@link StringConfigMap} + */ + @Deprecated // and confirmed no uses (besides sub-interface) public Map<String,Object> asMapWithStringKeys(); public int size(); public boolean isEmpty(); + public interface ConfigMapWithInheritance<TContainer> extends ConfigMap { + + /** Returns the container where a given key is defined, in addition to the value and data on the key it is defined against, + * wrapped in something which will report any error during evaluation (in some cases these errors may otherwise + * be silently ignored) */ + public <T> ReferenceWithError<ConfigValueAtContainer<TContainer,T>> getConfigAndContainer(ConfigKey<T> key); + + /** As {@link #getConfigLocalRaw(ConfigKey)} but respecting the inheritance rules. + * Because inheritance may not be applicable when working with raw values the result + * is wrapped in a {@link ReferenceWithError}, and if any aspect of inheritance + * could not be applied, calls to {@link ReferenceWithError#get()} will throw + * (but {@link ReferenceWithError#getWithoutError()} will not). + * Default values will be available from {@link ConfigValueAtContainer#getDefaultValue()} + * but will not be considered for {@link ConfigValueAtContainer#get()} or {@link ConfigValueAtContainer#asMaybe()}. + * <p> + * Note that most modes (eg overwrite, not-inherit) will not cause issues during inheritance + * so this method is ordinarily fine to use. Problems arise when a merge inheritance mode + * is specified and it is attempting to merge a raw value which is not mergeable. + * <p> + * See also {@link #getConfigAllInheritedRaw(ConfigKey)} which returns the complete set + * of inherited values. + * + * @param key key to look up + */ + public ReferenceWithError<ConfigValueAtContainer<TContainer,?>> getConfigInheritedRaw(ConfigKey<?> key); + + /** As {@link #getConfigLocalRaw(ConfigKey)} but returning all containers through the inheritance + * hierarchy where a value is set (but stopping if it encounters a key is not inheritable from a container). + * <p> + * The list is in order with the highest ancestor first. Config inheritance strategies are not + * applied, apart from aborting ancestor traversal if inheritance of a key is blocked there. */ + public List<ConfigValueAtContainer<TContainer,?>> getConfigAllInheritedRaw(ConfigKey<?> key); + + /** returns a read-only map of all config keys local and inherited together with best-effort raw values + * as per {@link #getConfigAllInheritedRaw(ConfigKey)} */ + @Beta + public Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> getAllConfigInheritedRawWithErrors(); + /** as {@link #getAllConfigInheritedRawWithErrors()} but simplified API, just giving values, ignoring any errors */ + @Beta + public Map<ConfigKey<?>,Object> getAllConfigInheritedRawValuesIgnoringErrors(); + + /** as {@link #getAllConfigInheritedRaw()} but removes any entries which should not be re-inheritable by descendants */ + public Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> getAllReinheritableConfigRaw(); + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java index 38e1259..a4c60ca 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java @@ -24,17 +24,20 @@ import com.google.common.base.Supplier; public interface ConfigValueAtContainer<TContainer,TValue> extends Supplier<TValue> { - /** Returns the value, or null */ + /** Returns the value for this key, or null. Technically this returns {@link #asMaybe()} or null. */ TValue get(); - /** Absent if no value can be found, typically including no default value. */ - Maybe<TValue> asMaybe(); - /** If false, the contents of {@link #get()} will have come from {@link #getDefaultValue()}. */ + /** Absent if no value can be found, typically meaning no default value, but in raw value lookups it may ignore default values. */ + Maybe<? extends TValue> asMaybe(); + /** If false, any contents of {@link #get()} will have come from {@link #getDefaultValue()}. */ boolean isValueExplicitlySet(); /** The container where the value was found (possibly an ancestor of the queried object) */ TContainer getContainer(); - ConfigKey<TValue> getKey(); - TValue getDefaultValue(); - + ConfigKey<? extends TValue> getKey(); + /** The default value on the key, if available and permitted, + * possibly coerced or resolved in the scope of {@link #getContainer()}, + * and possibly absent e.g. in raw value lookups */ + Maybe<TValue> getDefaultValue(); + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/config/StringConfigMap.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/StringConfigMap.java b/utils/common/src/main/java/org/apache/brooklyn/config/StringConfigMap.java index e0e8e8f..b327442 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/StringConfigMap.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/StringConfigMap.java @@ -20,6 +20,8 @@ package org.apache.brooklyn.config; import java.util.Map; +import com.google.common.base.Predicate; + /** convenience extension where map is principally strings or converted to strings * (supporting BrooklynProperties) */ public interface StringConfigMap extends ConfigMap { @@ -32,4 +34,12 @@ public interface StringConfigMap extends ConfigMap { * and 'defaultIfNone' (a default value to return if there is no such property); * defaults to no warning and null default value */ public String getFirst(@SuppressWarnings("rawtypes") Map flags, String... keys); + + /** returns submap matching the given filter predicate; see ConfigPredicates for common predicates */ + public StringConfigMap submap(Predicate<ConfigKey<?>> filter); + + /** returns a read-only map view which has string keys (corresponding to the config key names); + * callers encouraged to use the typed keys (and so not use this method), + * but in some compatibility areas having a Properties-like view is useful */ + public Map<String,Object> asMapWithStringKeys(); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d655e05/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java index 95ddd71..7885659 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java @@ -31,18 +31,20 @@ public class ReferenceWithError<T> implements Supplier<T> { private final Throwable error; private final boolean maskError; - /** returns a reference which includes an error, and where attempts to get the content cause the error to throw */ - public static <T> ReferenceWithError<T> newInstanceThrowingError(T object, Throwable error) { + /** returns a reference which includes an error, and where attempts to get the content cause the error to throw + * (unless the error supplied is null in which case behaviour is as per {@link #newInstanceWithoutError(Object)}) */ + public static <T,U extends T> ReferenceWithError<T> newInstanceThrowingError(@Nullable U object, @Nullable Throwable error) { return new ReferenceWithError<T>(object, error, false); } - /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw */ - public static <T> ReferenceWithError<T> newInstanceMaskingError(T object, Throwable error) { + /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw + * (unless the error supplied is null in which case behaviour is as per {@link #newInstanceWithoutError(Object)}) */ + public static <T,U extends T> ReferenceWithError<T> newInstanceMaskingError(@Nullable U object, @Nullable Throwable error) { return new ReferenceWithError<T>(object, error, true); } /** returns a reference which does not have any error; attempts to get the content are safe */ - public static <T> ReferenceWithError<T> newInstanceWithoutError(T object) { + public static <T,U extends T> ReferenceWithError<T> newInstanceWithoutError(@Nullable U object) { return new ReferenceWithError<T>(object, null, false); } @@ -84,7 +86,7 @@ public class ReferenceWithError<T> implements Supplier<T> { Exceptions.propagate(error); } - /** returns the error (not throwing) */ + /** returns the error (not throwing) or null if no error */ public Throwable getError() { return error; }