Copyright 2016 Netflix, Inc. Licensed 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.
/** * Copyright 2016 Netflix, Inc. * * Licensed 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 com.netflix.hystrix.strategy.properties; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.hystrix.strategy.HystrixPlugins;
Chained property allowing a chain of defaults properties which is uses the properties plugin.

Instead of just a single dynamic property with a default this allows a sequence of properties that fallback to the farthest down the chain with a value. TODO This should be replaced by a version in the Archaius library once available.

@ExcludeFromJavadoc
/** * Chained property allowing a chain of defaults properties which is uses the properties plugin. * <p> * Instead of just a single dynamic property with a default this allows a sequence of properties that fallback to the farthest down the chain with a value. * * TODO This should be replaced by a version in the Archaius library once available. * * @ExcludeFromJavadoc */
public abstract class HystrixPropertiesChainedProperty { private static final Logger logger = LoggerFactory.getLogger(HystrixPropertiesChainedProperty.class);
@ExcludeFromJavadoc
/** * @ExcludeFromJavadoc */
private static abstract class ChainLink<T> { private final AtomicReference<ChainLink<T>> pReference; private final ChainLink<T> next; private final List<Runnable> callbacks;
Returns:String
/** * @return String */
public abstract String getName();
Returns:T
/** * @return T */
protected abstract T getValue();
Returns:Boolean
/** * @return Boolean */
public abstract boolean isValueAcceptable();
No arg constructor - used for end node
/** * No arg constructor - used for end node */
public ChainLink() { next = null; pReference = new AtomicReference<ChainLink<T>>(this); callbacks = new ArrayList<Runnable>(); }
Params:
  • nextProperty – next property in the chain
/** * @param nextProperty next property in the chain */
public ChainLink(ChainLink<T> nextProperty) { next = nextProperty; pReference = new AtomicReference<ChainLink<T>>(next); callbacks = new ArrayList<Runnable>(); } protected void checkAndFlip() { // in case this is the end node if (next == null) { pReference.set(this); return; } if (this.isValueAcceptable()) { logger.debug("Flipping property: {} to use its current value: {}", getName(), getValue()); pReference.set(this); } else { logger.debug("Flipping property: {} to use NEXT property: {}", getName(), next); pReference.set(next); } for (Runnable r : callbacks) { r.run(); } }
Returns:T
/** * @return T */
public T get() { if (pReference.get() == this) { return this.getValue(); } else { return pReference.get().get(); } }
Params:
  • r – callback to execut
/** * @param r callback to execut */
public void addCallback(Runnable r) { callbacks.add(r); }
Returns:String
/** * @return String */
public String toString() { return getName() + " = " + get(); } } public static abstract class ChainBuilder<T> { private ChainBuilder() { super(); } private List<HystrixDynamicProperty<T>> properties = new ArrayList<HystrixDynamicProperty<T>>(); public ChainBuilder<T> add(HystrixDynamicProperty<T> property) { properties.add(property); return this; } public ChainBuilder<T> add(String name, T defaultValue) { properties.add(getDynamicProperty(name, defaultValue, getType())); return this; } public HystrixDynamicProperty<T> build() { if (properties.size() < 1) throw new IllegalArgumentException(); if (properties.size() == 1) return properties.get(0); List<HystrixDynamicProperty<T>> reversed = new ArrayList<HystrixDynamicProperty<T>>(properties); Collections.reverse(reversed); ChainProperty<T> current = null; for (HystrixDynamicProperty<T> p : reversed) { if (current == null) { current = new ChainProperty<T>(p); } else { current = new ChainProperty<T>(p, current); } } return new ChainHystrixProperty<T>(current); } protected abstract Class<T> getType(); } private static <T> ChainBuilder<T> forType(final Class<T> type) { return new ChainBuilder<T>() { @Override protected Class<T> getType() { return type; } }; } public static ChainBuilder<String> forString() { return forType(String.class); } public static ChainBuilder<Integer> forInteger() { return forType(Integer.class); } public static ChainBuilder<Boolean> forBoolean() { return forType(Boolean.class); } public static ChainBuilder<Long> forLong() { return forType(Long.class); } private static class ChainHystrixProperty<T> implements HystrixDynamicProperty<T> { private final ChainProperty<T> property; public ChainHystrixProperty(ChainProperty<T> property) { super(); this.property = property; } @Override public String getName() { return property.getName(); } @Override public T get() { return property.get(); } @Override public void addCallback(Runnable callback) { property.addCallback(callback); } } private static class ChainProperty<T> extends ChainLink<T> { private final HystrixDynamicProperty<T> sProp; public ChainProperty(HystrixDynamicProperty<T> sProperty) { super(); sProp = sProperty; } public ChainProperty(HystrixDynamicProperty<T> sProperty, ChainProperty<T> next) { super(next); // setup next pointer sProp = sProperty; sProp.addCallback(new Runnable() { @Override public void run() { logger.debug("Property changed: '{} = {}'", getName(), getValue()); checkAndFlip(); } }); checkAndFlip(); } @Override public boolean isValueAcceptable() { return (sProp.get() != null); } @Override protected T getValue() { return sProp.get(); } @Override public String getName() { return sProp.getName(); } } private static <T> HystrixDynamicProperty<T> getDynamicProperty(String propName, T defaultValue, Class<T> type) { HystrixDynamicProperties properties = HystrixPlugins.getInstance().getDynamicProperties(); HystrixDynamicProperty<T> p = HystrixDynamicProperties.Util.getProperty(properties, propName, defaultValue, type); return p; } }