public boolean isReinheritable()

in utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java [78:250]


    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>
     * 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.
     * <p>
     * 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>
     * 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>
     * 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.
     * <p>
     * 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 {
        /** @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<ConfigInheritance,ConfigInheritance> 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 <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;
            }

            @Override
            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));

                // both explicitly set, and not overwrite or none
                if (getMode()==InheritanceMode.DEEP_MERGE) {
                    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 "+local+"/"+parent);
            }
            private static <T> Maybe<? extends T> deepMerge(Maybe<? extends T> val1, Maybe<? extends T> 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<T> 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);
            }
        }
    }