/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat 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 io.fabric8.apmagent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CopyOnWriteArrayList;
public class ApmConfiguration implements ApmConfigurationMBean {
public enum STRATEGY {
TRACE,
SAMPLE;
static STRATEGY getStrategy(String name) {
for (STRATEGY v : values()) {
if (v.name().equals(name.toUpperCase())) {
return v;
}
}
return SAMPLE;
}
}
final static Logger logger = LoggerFactory.getLogger(ApmConfiguration.class);
private boolean trace = false;
private boolean debug = false;
private boolean asyncTransformation = false;
private boolean startJolokiaAgent = false;
private boolean autoStartMetrics = false;
private boolean usePlatformMBeanServer = true;
private boolean verifyClasses = false;
private int methodMetricDepth = 10;
private int threadMetricDepth = 5;
private boolean filterChanged = false;
private boolean methodMetricDepthChanged = false;
private boolean threadMetricDepthChanged = false;
private boolean strategyChanged = false;
private int samplingInterval = 1;
private List<FilterItem> whiteFilterList = new ArrayList<>();
private List<FilterItem> blackFilterList = new ArrayList<>();
private List<ApmConfigurationChangeListener> changeListeners = new CopyOnWriteArrayList<>();
private STRATEGY strategy = STRATEGY.TRACE;
ApmConfiguration() {
addToBlackList("java");
addToBlackList("com.sun");
addToBlackList("sun");
addToBlackList("$Proxy");
addToBlackList("ByCGLIB$$");
addToBlackList("io.fabric8.apmagent");
addToBlackList("org.apache.camel.spring.remoting");
addToBlackList("org.jolokia");
addToBlackList("org.springframework");
addToBlackList("org.eclipse");
addToBlackList("org.apache.xbean");
addToBlackList("org.slf4j");
addToBlackList("org.omg");
addToBlackList("com.apple");
addToBlackList("oracle");
addToBlackList("org.apache.log4j");
addToBlackList("org.objectweb.asm");
addToBlackList("org.apache.commons");
addToBlackList("org.apache.jasper");
addToBlackList("jrockit");
addToBlackList("org.json");
addToBlackList("org.fusesource.hawtbuf");
addToBlackList("com.intellij");
addToBlackList("org.w3c.dom");
addToBlackList("com.codahale");
//for testing only
addToWhiteList("io.fabric8.testApp");
}
@Override
public String getWhiteList() {
return getListAsString(whiteFilterList);
}
@Override
public void setWhiteList(String whiteList) {
whiteFilterList = new ArrayList<>();
initializeList(whiteList, this.whiteFilterList);
filterChanged = true;
fireConfigurationChanged();
}
@Override
public String getBlackList() {
return getListAsString(blackFilterList);
}
@Override
public void setBlackList(String blackList) {
this.blackFilterList = new ArrayList<>();
initializeList(blackList, this.blackFilterList);
filterChanged = true;
fireConfigurationChanged();
}
@Override
public void addToBlackList(String s) {
FilterItem filterItem = new FilterItem();
String[] classAndMethod = s.split("@");
filterItem.setClassName(classAndMethod[0]);
if (classAndMethod.length > 1) {
filterItem.setMethodName(classAndMethod[1]);
}
blackFilterList.add(filterItem);
filterChanged = true;
fireConfigurationChanged();
}
@Override
public void addToWhiteList(String s) {
FilterItem filterItem = new FilterItem();
String[] classAndMethod = s.split("@");
filterItem.setClassName(classAndMethod[0]);
if (classAndMethod.length > 1) {
filterItem.setMethodName(classAndMethod[1]);
}
whiteFilterList.add(filterItem);
filterChanged = true;
fireConfigurationChanged();
}
@Override
public boolean isTrace() {
return trace;
}
@Override
public void setTrace(boolean trace) {
this.trace = trace;
}
@Override
public boolean isDebug() {
return debug;
}
@Override
public void setDebug(boolean debug) {
this.debug = debug;
}
@Override
public boolean isAsyncTransformation() {
return asyncTransformation;
}
@Override
public void setAsyncTransformation(boolean asyncTransformation) {
this.asyncTransformation = asyncTransformation;
}
public boolean isStartJolokiaAgent() {
return startJolokiaAgent;
}
public void setStartJolokiaAgent(boolean startJolokiaAgent) {
this.startJolokiaAgent = startJolokiaAgent;
}
public boolean isAutoStartMetrics() {
return autoStartMetrics;
}
public void setAutoStartMetrics(boolean autoStartMetrics) {
this.autoStartMetrics = autoStartMetrics;
}
public boolean isUsePlatformMBeanServer() {
return usePlatformMBeanServer;
}
public void setUsePlatformMBeanServer(boolean usePlatformMBeanServer) {
this.usePlatformMBeanServer = usePlatformMBeanServer;
}
public boolean isVerifyClasses() {
return verifyClasses;
}
public void setVerifyClasses(boolean verifyClasses) {
this.verifyClasses = verifyClasses;
}
public int getThreadMetricDepth() {
return threadMetricDepth;
}
public void setThreadMetricDepth(int threadMetricDepth) {
this.threadMetricDepth = threadMetricDepth;
this.threadMetricDepthChanged = true;
fireConfigurationChanged();
}
public int getMethodMetricDepth() {
return methodMetricDepth;
}
public void setMethodMetricDepth(int methodMetricDepth) {
this.methodMetricDepth = methodMetricDepth;
this.methodMetricDepthChanged = true;
fireConfigurationChanged();
}
public boolean isStrategyChanged() {
return strategyChanged;
}
public boolean isThreadMetricDepthChanged() {
return threadMetricDepthChanged;
}
public boolean isMethodMetricDepthChanged() {
return methodMetricDepthChanged;
}
public boolean isFilterChanged() {
return filterChanged;
}
public int getSamplingInterval() {
return samplingInterval;
}
public void setSamplingInterval(int samplingInterval) {
this.samplingInterval = samplingInterval;
}
public String getStrategy() {
return strategy.name();
}
public void setStrategy(String name) {
STRATEGY newStrategy = STRATEGY.getStrategy(name);
if (!this.strategy.equals(newStrategy)) {
this.strategy = STRATEGY.getStrategy(name);
this.strategyChanged = true;
fireConfigurationChanged();
}
}
public STRATEGY getStrategyImpl() {
return strategy;
}
public void initalizeFromProperties(Properties properties) {
for (Map.Entry entry : properties.entrySet()) {
if (entry.getKey() != null && entry.getValue() != null) {
setProperty(entry.getKey().toString(), entry.getValue().toString());
}
}
}
public boolean isAudit(String className) {
return isWhiteListed(className) || !isBlackListed(className);
}
public boolean isAudit(String className, String methodName) {
return isWhiteListed(className, methodName) || !isBlackListed(className, methodName);
}
public boolean isBlackListed(String className) {
for (FilterItem item : blackFilterList) {
if (item.matches(className)) {
return true;
}
}
return false;
}
public boolean isBlackListed(String className, String methodName) {
for (FilterItem item : blackFilterList) {
if (item.matches(className, methodName, true)) {
return true;
}
}
return false;
}
public boolean isWhiteListed(String className) {
if (whiteFilterList.isEmpty()) {
return false;
}
for (FilterItem item : whiteFilterList) {
if (className.matches(item.getClassName())) {
return true;
}
}
return false;
}
public boolean isWhiteListed(String className, String methodName) {
for (FilterItem item : whiteFilterList) {
if (item.matches(className, methodName, false)) {
return true;
}
}
return false;
}
public void addChangeListener(ApmConfigurationChangeListener changeListener) {
changeListeners.add(changeListener);
}
public void removeChangeListener(ApmConfigurationChangeListener changeListener) {
changeListeners.remove(changeListener);
}
private void fireConfigurationChanged() {
for (ApmConfigurationChangeListener apmConfigurationChangeListener : this.changeListeners) {
apmConfigurationChangeListener.configurationChanged();
}
resetChanged();
}
private void resetChanged() {
filterChanged = false;
methodMetricDepthChanged = false;
threadMetricDepthChanged = false;
strategyChanged = false;
}
private void setProperty(String name, Object value) {
try {
Method setter = findSetterMethod(name);
if (setter != null) {
if (value == null || value.getClass().equals(setter.getParameterTypes()[0])) {
setter.invoke(this, value);
} else {
setter.invoke(this, convert(value, setter.getParameterTypes()[0]));
}
}
} catch (Throwable e) {
logger.warn("Failed to set property: " + e.getMessage(), e);
}
}
private Method findSetterMethod(String name) {
String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method[] methods = ApmConfiguration.class.getMethods();
for (Method method : methods) {
Class params[] = method.getParameterTypes();
if (method.getName().equals(methodName) && params.length == 1) {
return method;
}
}
return null;
}
private Object convert(Object value, Class type) throws Exception {
PropertyEditor editor = PropertyEditorManager.findEditor(type);
if (editor != null) {
editor.setAsText(value.toString());
return editor.getValue();
}
if (type == URI.class) {
return new URI(value.toString());
}
return null;
}
private void initializeList(String str, List<FilterItem> list) {
String[] split = str.split(",");
for (String s : split) {
FilterItem filterItem = new FilterItem();
String[] classAndMethod = s.split("@");
filterItem.setClassName(classAndMethod[0]);
if (classAndMethod.length > 1) {
filterItem.setMethodName(classAndMethod[1]);
}
list.add(filterItem);
}
}
private String getListAsString(List<FilterItem> list) {
String result = "";
if (list != null && !list.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
FilterItem filterItem = list.get(i);
result += filterItem.getClassName();
String methodName = filterItem.getMethodName();
if (methodName != null && methodName.length() > 0) {
result += "@" + methodName;
}
if (i < (list.size() - 1)) {
result += ",";
}
}
}
return result;
}
}