All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.brooklyn.config.ConfigInheritances Maven / Gradle / Ivy

Go to download

Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else

There is a newer version: 1.1.0
Show newest version
/*
 * 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.Nonnull;
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 applying the appropriate inheritance strategies.
     * 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 
     * 

* 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 *

* 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. *

* this object is taken as the default inheritance and used if no inheritance is * defined on the key. *

* 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 ReferenceWithError> resolveInheriting( @Nullable TContainer container, ConfigKey key, @Nullable Maybe localValue, @Nullable Maybe defaultValue, Iterator> ancestorContainerKeyValues, ConfigInheritanceContext context, ConfigInheritance defaultInheritance) { return resolveInheriting(new BasicConfigValueAtContainer(container, key, localValue, localValue.isPresent(), defaultValue), ancestorContainerKeyValues, key, context, defaultInheritance); } /** as {@link #resolveInheriting(Object, ConfigKey, Maybe, Maybe, Iterator, ConfigInheritanceContext, ConfigInheritance)} * but convenient when the local info is already in a {@link ConfigValueAtContainer} */ public static ReferenceWithError> resolveInheriting( ConfigValueAtContainer local, Iterator> ancestorContainerKeyValues, ConfigKey queryKey, ConfigInheritanceContext context, ConfigInheritance defaultInheritance) { BasicConfigValueAtContainer result = null; if (ancestorContainerKeyValues.hasNext()) { ConfigValueAtContainer 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> parentResult = resolveInheriting(parent, ancestorContainerKeyValues, queryKey, context, currentInheritance); ReferenceWithError> resultWithParent = currentInheritance.resolveWithParent(local, parentResult.getWithoutError(), context); if (resultWithParent!=null) { if (resultWithParent.getWithoutError()!=null && resultWithParent.getWithoutError().isValueExplicitlySet()) { if (!resultWithParent.hasError() && parentResult!=null && parentResult.hasError()) { return ReferenceWithError.newInstanceThrowingError(resultWithParent.getWithoutError(), parentResult.getError()); } return resultWithParent; } else { result = new BasicConfigValueAtContainer( resultWithParent.getWithoutError() ); } } } } } if (result==null) { result = new BasicConfigValueAtContainer(local); if (!local.isValueExplicitlySet() && local.getDefaultValue().isPresent()) { result.value = local.getDefaultValue(); } } else { if (!result.isValueExplicitlySet()) { result.value = result.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 implements ConfigValueAtContainer { @Nullable TContainer container = null; @Nonnull Maybe value = Maybe.absent(); boolean valueWasExplicitlySet = false; @Nullable ConfigKey key = null; @Nullable Maybe defaultValue = null; public BasicConfigValueAtContainer() {} public BasicConfigValueAtContainer(ConfigValueAtContainer toCopy) { this(toCopy.getContainer(), toCopy.getKey(), toCopy.asMaybe(), toCopy.isValueExplicitlySet(), toCopy.getDefaultValue()); } public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey key, @Nullable Maybe value) { this(container, key, value, value.isPresent()); } public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey key, @Nullable Maybe value, boolean isValueSet) { this(container, key, value, isValueSet, null); } /** Creates an instance, configuring all parameters. * * @param container May be null as per contract. * @param key May be null as per contract. * @param value Null means always to take {@link #getDefaultValue()}; if absent and isValueSet is false, it will also take {@link #getDefaultValue()}. * @param isValueSet * @param defaultValue Null means to take a default value from the key ({@link #getKey()}), otherwise this {@link Maybe} will be preferred to that value * (even if absent). */ public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey key, @Nullable Maybe value, boolean isValueSet, @Nullable Maybe defaultValue) { this.container = container; this.key = key; this.valueWasExplicitlySet = isValueSet; this.defaultValue = defaultValue; this.value = value!=null && (value.isPresent() || isValueSet || getDefaultValue().isPresent()) ? value : getDefaultValue(); } @Override public TContainer getContainer() { return container; } @Override public TValue get() { return value.orNull(); } @Override public Maybe asMaybe() { return value; } @Override public boolean isValueExplicitlySet() { return valueWasExplicitlySet; } @Override public ConfigKey getKey() { return key; } public void setContainer(TContainer container) { this.container = container; } public void setValue(Maybe value) { this.value = value; } public void setValueWasExplicitlySet(boolean valueWasExplicitlySet) { this.valueWasExplicitlySet = valueWasExplicitlySet; } public void setKey(ConfigKey key) { this.key = key; } @Override public Maybe 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.absent(); } @Override public String toString() { return super.toString()+"[key="+key+"; value="+value+"; container="+container+"]"; } } /** 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 *

* 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 boolean isKeyReinheritable(final ConfigKey key, final ConfigInheritanceContext context) { ConfigInheritance inh = ConfigInheritances.findInheritance(key, context, null); if (inh==null) return true; return inh.isReinheritable(null, null); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy