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

org.apache.brooklyn.config.ConfigInheritance 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.io.Serializable;
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.collections.MutableMap;
import org.apache.brooklyn.util.exceptions.ReferenceWithError;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;

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;
     * implementers can define their own, e.g. in an enum */
    public interface ConfigInheritanceContext {}

    /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated
    @Beta
    public enum InheritanceMode {
        NONE,
        IF_NO_EXPLICIT_VALUE,
        DEEP_MERGE
    }
    
    /** @deprecated since 0.10.0 see implementations of this interface (look for NOT_REINHERITED, or possibly NEVER_REINHERITED) */ @Deprecated
    public static final ConfigInheritance NONE = new Legacy.None();
    /** @deprecated since 0.10.0 see implementations of this interface (look for OVERWRITE) */ @Deprecated
    public static final ConfigInheritance ALWAYS = new Legacy.Always();
    /** @deprecated since 0.10.0 see implementations of this interface (look for the same name, DEEP_MERGE) */ @Deprecated
    public static final ConfigInheritance DEEP_MERGE = new Legacy.Merged();
    
    /** @deprecated since 0.10.0 more complex inheritance conditions now require other methods */
    @Deprecated
    InheritanceMode isInherited(ConfigKey key, Object from, Object to);

    /** Returns whether any value from the given node or ancestors can be considered 
     * for inheritance by descendants, according to the {@link ConfigInheritance} defined there.
     * The implementation of this method is usually a constant depending on the inheritance in effect;
     * in particular it will not normally consider any values or inform whether something should be inherited:
     * it is only advising whether inheritance is permitted from a given point in the inheritance hierarchy.
     * 

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

* Key inference (continuing from the above): Callers should not try to infer any descendant key and look at * what it says about reinheritability; * if a container does not define a key it would be pointless for it not to be reinheritable). *

* Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ public boolean isReinheritable( @Nullable ConfigValueAtContainer 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. *

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

* Key inference: if a container does not define a key, the inheritance in the key definition in the nearest descendant * of that container should be used. *

* 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 boolean considerParent( @Nonnull ConfigValueAtContainer local, @Nullable ConfigValueAtContainer 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. *

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

* Key inference: if a container does not define a key, the inheritance in the key definition in the nearest descendant * of that container should be used. *

* Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ public ReferenceWithError> resolveWithParent( @Nonnull ConfigValueAtContainer local, @Nonnull ConfigValueAtContainer resolvedParent, ConfigInheritanceContext context); /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated public static class Legacy { /** @deprecated since 0.10.0 see fromString in selected subclasses of {@link ConfigInheritance} eg BasicConfigInheritance */ public static ConfigInheritance fromString(String val) { if (Strings.isBlank(val)) return null; switch (val.toLowerCase().trim()) { case "none": return NONE; case "always": return ALWAYS; case "deepmerge" : case "deep_merge" : return DEEP_MERGE; default: throw new IllegalArgumentException("Invalid config-inheritance '"+val+"' (legal values are none, always or merge)"); } } private static Map REPLACEMENTS = MutableMap.of(); /** used to assist in migration to new classes */ public static void registerReplacement(ConfigInheritance old, ConfigInheritance replacement) { REPLACEMENTS.put(old, replacement); } private static ConfigInheritance orReplacement(ConfigInheritance orig) { ConfigInheritance repl = REPLACEMENTS.get(orig); if (repl!=null) return repl; return orig; } private abstract static class LegacyAbstractConversion implements ConfigInheritance { @Override public boolean isReinheritable(ConfigValueAtContainer parent, ConfigInheritanceContext context) { return getMode()!=InheritanceMode.NONE; } @Override public boolean considerParent( ConfigValueAtContainer local, @Nullable ConfigValueAtContainer 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; } @Override public ReferenceWithError> resolveWithParent( ConfigValueAtContainer local, ConfigValueAtContainer parent, ConfigInheritanceContext context) { // parent can be assumed to be set, but might not have a value if (!parent.isValueExplicitlySet()) return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer(local)); if (!local.isValueExplicitlySet()) return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer(parent)); // both explicitly set, and not overwrite or none if (getMode()==InheritanceMode.DEEP_MERGE) { BasicConfigValueAtContainer result = new BasicConfigValueAtContainer(local); result.setValue( deepMerge(local.asMaybe(), parent.asMaybe()) ); return ReferenceWithError.newInstanceWithoutError(result); } throw new IllegalStateException("Unknown config conflict resolution strategy '"+getMode()+"' evaluating "+local+"/"+parent); } private static Maybe deepMerge(Maybe val1, Maybe val2) { if (val2.isAbsent() || val2.isNull()) { return val1; } else if (val1.isAbsent()) { return val2; } else if (val1.isNull()) { return val1; // an explicit null means an override; don't merge } else if (val1.get() instanceof Map && val2.get() instanceof Map) { @SuppressWarnings({ "unchecked", "rawtypes" }) Maybe result = (Maybe)Maybe.of(CollectionMerger.builder().build().merge((Map)val1.get(), (Map)val2.get())); return result; } else { // cannot merge; just return val1 return val1; } } @Override public InheritanceMode isInherited(ConfigKey key, Object from, Object to) { return getMode(); } protected abstract InheritanceMode getMode(); } private static class Always extends LegacyAbstractConversion { @Override public InheritanceMode getMode() { return InheritanceMode.IF_NO_EXPLICIT_VALUE; } @SuppressWarnings("unused") // standard deserialization method private ConfigInheritance readResolve() { return orReplacement(ConfigInheritance.ALWAYS); } } private static class None extends LegacyAbstractConversion { @Override public InheritanceMode getMode() { return InheritanceMode.NONE; } @SuppressWarnings("unused") // standard deserialization method private ConfigInheritance readResolve() { return orReplacement(ConfigInheritance.NONE); } } private static class Merged extends LegacyAbstractConversion { @Override public InheritanceMode getMode() { return InheritanceMode.DEEP_MERGE; } @SuppressWarnings("unused") // standard deserialization method private ConfigInheritance readResolve() { return orReplacement(ConfigInheritance.DEEP_MERGE); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy