Skip to content

Commit

Permalink
Make Archaius a soft dependency through reflection and improve plugin…
Browse files Browse the repository at this point in the history
  • Loading branch information
agentgt committed Feb 2, 2016
1 parent 24d9fda commit 5540df7
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
*/
package com.netflix.hystrix.strategy;

import java.io.IOException;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicReference;

import com.netflix.config.ConfigurationManager;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
Expand All @@ -29,6 +27,8 @@
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherDefault;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;
import com.netflix.hystrix.strategy.properties.HystrixArchaiusHelper;
import com.netflix.hystrix.strategy.properties.HystrixDynamicProperties;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategyDefault;

Expand All @@ -50,14 +50,11 @@ public class HystrixPlugins {
/* package */ final AtomicReference<HystrixMetricsPublisher> metricsPublisher = new AtomicReference<HystrixMetricsPublisher>();
/* package */ final AtomicReference<HystrixPropertiesStrategy> propertiesFactory = new AtomicReference<HystrixPropertiesStrategy>();
/* package */ final AtomicReference<HystrixCommandExecutionHook> commandExecutionHook = new AtomicReference<HystrixCommandExecutionHook>();
/* package */ final HystrixDynamicProperties dynamicProperties;

private HystrixPlugins() {
try {
// Load configuration from hystrix-plugins.properties, if that file exists
ConfigurationManager.loadCascadedPropertiesFromResources("hystrix-plugins");
} catch (IOException e) {
// fail silently
}
//This will load Archaius if its in the classpath.
dynamicProperties = resolveDynamicProperties();
}

public static HystrixPlugins getInstance() {
Expand Down Expand Up @@ -87,7 +84,7 @@ public static void reset() {
public HystrixEventNotifier getEventNotifier() {
if (notifier.get() == null) {
// check for an implementation from Archaius first
Object impl = getPluginImplementationViaArchaius(HystrixEventNotifier.class);
Object impl = getPluginImplementation(HystrixEventNotifier.class);
if (impl == null) {
// nothing set via Archaius so initialize with default
notifier.compareAndSet(null, HystrixEventNotifierDefault.getInstance());
Expand Down Expand Up @@ -125,7 +122,7 @@ public void registerEventNotifier(HystrixEventNotifier impl) {
public HystrixConcurrencyStrategy getConcurrencyStrategy() {
if (concurrencyStrategy.get() == null) {
// check for an implementation from Archaius first
Object impl = getPluginImplementationViaArchaius(HystrixConcurrencyStrategy.class);
Object impl = getPluginImplementation(HystrixConcurrencyStrategy.class);
if (impl == null) {
// nothing set via Archaius so initialize with default
concurrencyStrategy.compareAndSet(null, HystrixConcurrencyStrategyDefault.getInstance());
Expand Down Expand Up @@ -163,7 +160,7 @@ public void registerConcurrencyStrategy(HystrixConcurrencyStrategy impl) {
public HystrixMetricsPublisher getMetricsPublisher() {
if (metricsPublisher.get() == null) {
// check for an implementation from Archaius first
Object impl = getPluginImplementationViaArchaius(HystrixMetricsPublisher.class);
Object impl = getPluginImplementation(HystrixMetricsPublisher.class);
if (impl == null) {
// nothing set via Archaius so initialize with default
metricsPublisher.compareAndSet(null, HystrixMetricsPublisherDefault.getInstance());
Expand Down Expand Up @@ -201,7 +198,7 @@ public void registerMetricsPublisher(HystrixMetricsPublisher impl) {
public HystrixPropertiesStrategy getPropertiesStrategy() {
if (propertiesFactory.get() == null) {
// check for an implementation from Archaius first
Object impl = getPluginImplementationViaArchaius(HystrixPropertiesStrategy.class);
Object impl = getPluginImplementation(HystrixPropertiesStrategy.class);
if (impl == null) {
// nothing set via Archaius so initialize with default
propertiesFactory.compareAndSet(null, HystrixPropertiesStrategyDefault.getInstance());
Expand All @@ -213,6 +210,11 @@ public HystrixPropertiesStrategy getPropertiesStrategy() {
}
return propertiesFactory.get();
}


public HystrixDynamicProperties getDynamicProperties() {
return dynamicProperties;
}

/**
* Register a {@link HystrixPropertiesStrategy} implementation as a global override of any injected or default implementations.
Expand Down Expand Up @@ -242,7 +244,7 @@ public void registerPropertiesStrategy(HystrixPropertiesStrategy impl) {
public HystrixCommandExecutionHook getCommandExecutionHook() {
if (commandExecutionHook.get() == null) {
// check for an implementation from Archaius first
Object impl = getPluginImplementationViaArchaius(HystrixCommandExecutionHook.class);
Object impl = getPluginImplementation(HystrixCommandExecutionHook.class);
if (impl == null) {
// nothing set via Archaius so initialize with default
commandExecutionHook.compareAndSet(null, HystrixCommandExecutionHookDefault.getInstance());
Expand Down Expand Up @@ -271,17 +273,29 @@ public void registerCommandExecutionHook(HystrixCommandExecutionHook impl) {
}
}

private static Object getPluginImplementationViaArchaius(Class<?> pluginClass) {

private <T> T getPluginImplementation(Class<T> pluginClass) {
T p = getPluginImplementationViaProperties(pluginClass);
if (p != null) return p;
ServiceLoader<T> sl = ServiceLoader.load(pluginClass);
for(T plugin : sl) {
if (plugin != null) return plugin;
}
return null;
}

@SuppressWarnings("unchecked")
private <T> T getPluginImplementationViaProperties(Class<T> pluginClass) {
String classSimpleName = pluginClass.getSimpleName();
// Check Archaius for plugin class.
String propertyName = "hystrix.plugin." + classSimpleName + ".implementation";
String implementingClass = DynamicPropertyFactory.getInstance().getStringProperty(propertyName, null).get();
String implementingClass = dynamicProperties.getString(propertyName, null).get();
if (implementingClass != null) {
try {
Class<?> cls = Class.forName(implementingClass);
// narrow the scope (cast) to the type we're expecting
cls = cls.asSubclass(pluginClass);
return cls.newInstance();
return (T) cls.newInstance();
} catch (ClassCastException e) {
throw new RuntimeException(classSimpleName + " implementation is not an instance of " + classSimpleName + ": " + implementingClass);
} catch (ClassNotFoundException e) {
Expand All @@ -295,6 +309,16 @@ private static Object getPluginImplementationViaArchaius(Class<?> pluginClass) {
return null;
}
}



private static HystrixDynamicProperties resolveDynamicProperties() {
ServiceLoader<HystrixDynamicProperties> sl = ServiceLoader.load(HystrixDynamicProperties.class);
for(HystrixDynamicProperties hp : sl) {
if (hp != null) return hp;
}
return HystrixArchaiusHelper.createArchaiusDynamicProperties();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.netflix.hystrix.strategy.properties;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class HystrixArchaiusHelper {

private final static Method loadCascadedPropertiesFromResources;
private final static String CONFIG_MANAGER_CLASS = "com.netflix.config.ConfigurationManager";


static {
Method load = null;
try {
Class<?> configManager = Class.forName(CONFIG_MANAGER_CLASS);
load = configManager.getMethod("loadCascadedPropertiesFromResources", String.class);
}
catch (Exception e) {
}

loadCascadedPropertiesFromResources = load;
}

public static boolean isArchaiusV1Available() {
return loadCascadedPropertiesFromResources != null;
}

static void loadCascadedPropertiesFromResources(String name) {
if (isArchaiusV1Available()) {
try {
loadCascadedPropertiesFromResources.invoke(null, name);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
}

public static HystrixDynamicProperties createArchaiusDynamicProperties() {
if (isArchaiusV1Available()) {
loadCascadedPropertiesFromResources("hystrix-plugins");
try {
Class<?> defaultProperties =
Class.forName("com.netflix.hystrix.strategy.properties.archaius"
+ ".HystrixDynamicPropertiesArchaius");
return (HystrixDynamicProperties) defaultProperties.newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
//TODO Using system properties but we could just fail.
return new SystemPropertiesHystrixDynamicProperties();
}

private static class SystemPropertiesHystrixDynamicProperties implements HystrixDynamicProperties {

@Override
public HystrixDynamicProperty<Integer> getInteger(final String name, final Integer fallback) {
return new HystrixDynamicProperty<Integer>() {

@Override
public Integer get() {
return Integer.getInteger(name, fallback);
}
@Override
public void addCallback(Runnable callback) {
}
};
}

@Override
public HystrixDynamicProperty<String> getString(final String name, final String fallback) {
return new HystrixDynamicProperty<String>() {

@Override
public String get() {
return System.getProperty(name, fallback);
}

@Override
public void addCallback(Runnable callback) {
}
};
}

@Override
public HystrixDynamicProperty<Long> getLong(final String name, final Long fallback) {
return new HystrixDynamicProperty<Long>() {

@Override
public Long get() {
return Long.getLong(name, fallback);
}

@Override
public void addCallback(Runnable callback) {
}
};
}

@Override
public HystrixDynamicProperty<Boolean> getBoolean(final String name, final Boolean fallback) {
return new HystrixDynamicProperty<Boolean>() {

@Override
public Boolean get() {
return Boolean.getBoolean(name);
}

@Override
public void addCallback(Runnable callback) {
}
};
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.netflix.hystrix.strategy.properties;

public interface HystrixDynamicProperties {

public HystrixDynamicProperty<String> getString(String name, String fallback);
public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback);
public HystrixDynamicProperty<Long> getLong(String name, Long fallback);
public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback);

public static class Util {
@SuppressWarnings("unchecked")
public static <T> HystrixDynamicProperty<T> getProperty(
HystrixDynamicProperties delegate, String name, T fallback, Class<T> type) {
return (HystrixDynamicProperty<T>) doProperty(delegate, name, fallback, type);
}

private static HystrixDynamicProperty<?> doProperty(
HystrixDynamicProperties delegate,
String name, Object fallback, Class<?> type) {
if(type == String.class) {
return delegate.getString(name, (String) fallback);
}
else if (type == Integer.class) {
return delegate.getInteger(name, (Integer) fallback);
}
else if (type == Long.class) {
return delegate.getLong(name, (Long) fallback);
}
else if (type == Boolean.class) {
return delegate.getBoolean(name, (Boolean) fallback);
}
throw new IllegalStateException();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.netflix.hystrix.strategy.properties;

public interface HystrixDynamicProperty<T> extends HystrixProperty<T>{

public void addCallback(Runnable callback);

}
Loading

0 comments on commit 5540df7

Please sign in to comment.