org.glowroot.instrumentation.engine.impl.SimpleConfigServiceFactory Maven / Gradle / Ivy
/*
* Copyright 2019 the original author or authors.
*
* 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 org.glowroot.instrumentation.engine.impl;
import java.util.List;
import java.util.Map;
import org.glowroot.instrumentation.test.harness.shaded.com.google.common.base.Joiner;
import org.glowroot.instrumentation.test.harness.shaded.com.google.common.collect.ImmutableMap;
import org.glowroot.instrumentation.test.harness.shaded.com.google.common.collect.Lists;
import org.glowroot.instrumentation.test.harness.shaded.com.google.common.collect.Maps;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.glowroot.instrumentation.api.config.BooleanProperty;
import org.glowroot.instrumentation.api.config.ConfigListener;
import org.glowroot.instrumentation.api.config.ConfigService;
import org.glowroot.instrumentation.api.config.DoubleProperty;
import org.glowroot.instrumentation.api.config.ListProperty;
import org.glowroot.instrumentation.api.config.StringProperty;
import org.glowroot.instrumentation.engine.config.InstrumentationDescriptor;
import org.glowroot.instrumentation.engine.config.PropertyDescriptor;
import org.glowroot.instrumentation.engine.impl.InstrumentationServiceImpl.ConfigServiceFactory;
public class SimpleConfigServiceFactory implements ConfigServiceFactory {
private final List instrumentationDescriptors;
private final Map> overrides;
public SimpleConfigServiceFactory(List instrumentationDescriptors) {
this(instrumentationDescriptors,
ImmutableMap.>of());
}
public SimpleConfigServiceFactory(List instrumentationDescriptors,
Map> overrides) {
this.instrumentationDescriptors = instrumentationDescriptors;
this.overrides = overrides;
}
@Override
public ConfigService create(String instrumentationId) {
InstrumentationDescriptor descriptor =
getDescriptor(instrumentationId, instrumentationDescriptors);
Map overrides = this.overrides.get(instrumentationId);
if (overrides == null) {
overrides = ImmutableMap.of();
}
return new ConfigServiceImpl(descriptor.properties(), overrides);
}
private static InstrumentationDescriptor getDescriptor(String id,
List descriptors) {
for (InstrumentationDescriptor descriptor : descriptors) {
if (id.equals(descriptor.id())) {
return descriptor;
}
}
if (descriptors.isEmpty()) {
throw new IllegalStateException("Unexpected instrumentation id: " + id
+ " (there is no available instrumentation)");
} else {
List ids = Lists.newArrayList();
for (InstrumentationDescriptor descriptor : descriptors) {
ids.add(descriptor.id());
}
throw new IllegalStateException("Unexpected instrumentation id: " + id
+ " (available instrumentation ids are " + Joiner.on(", ").join(ids) + ")");
}
}
private static class ConfigServiceImpl implements ConfigService {
private final Map stringProperties;
private final Map booleanProperties;
private final Map doubleProperties;
private final Map listProperties;
private ConfigServiceImpl(List propertyDescriptors,
Map overrides) {
Map stringProperties = Maps.newHashMap();
Map booleanProperties = Maps.newHashMap();
Map doubleProperties = Maps.newHashMap();
Map listProperties = Maps.newHashMap();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String name = propertyDescriptor.name();
Object value;
// need to check contains since null is a valid value
if (overrides.containsKey(name)) {
value = overrides.get(name);
} else {
value = propertyDescriptor.getValidatedNonNullDefaultValue().value();
}
switch (propertyDescriptor.type()) {
case STRING:
if (value instanceof String) {
stringProperties.put(name, new StringPropertyImpl((String) value));
} else {
throw unexpectedValueType(name, "string", value);
}
break;
case BOOLEAN:
if (value instanceof Boolean) {
booleanProperties.put(name, new BooleanPropertyImpl((Boolean) value));
} else {
throw unexpectedValueType(name, "boolean", value);
}
break;
case DOUBLE:
if (value == null) {
doubleProperties.put(name, new DoublePropertyImpl(null));
} else if (value instanceof Number) {
doubleProperties.put(name,
new DoublePropertyImpl(((Number) value).doubleValue()));
} else {
throw unexpectedValueType(name, "number", value);
}
break;
case LIST:
if (value instanceof List) {
List stringList = Lists.newArrayList();
for (Object val : (List>) value) {
if (val instanceof String) {
stringList.add((String) val);
} else {
throw unexpectedValueTypeForList(name, val);
}
}
listProperties.put(name, new ListPropertyImpl(stringList));
} else {
throw unexpectedValueType(name, "list", value);
}
break;
default:
throw new IllegalStateException("Unexpected property descriptor type: "
+ propertyDescriptor.type());
}
}
this.stringProperties = ImmutableMap.copyOf(stringProperties);
this.booleanProperties = ImmutableMap.copyOf(booleanProperties);
this.doubleProperties = ImmutableMap.copyOf(doubleProperties);
this.listProperties = ImmutableMap.copyOf(listProperties);
}
@Override
public void registerConfigListener(ConfigListener listener) {
listener.onChange();
}
@Override
public StringProperty getStringProperty(String name) {
StringProperty stringProperty = stringProperties.get(name);
if (stringProperty == null) {
throw new IllegalStateException("No such string property: " + name);
}
return stringProperty;
}
@Override
public BooleanProperty getBooleanProperty(String name) {
BooleanProperty booleanProperty = booleanProperties.get(name);
if (booleanProperty == null) {
throw new IllegalStateException("No such boolean property: " + name);
}
return booleanProperty;
}
@Override
public DoubleProperty getDoubleProperty(String name) {
DoubleProperty doubleProperty = doubleProperties.get(name);
if (doubleProperty == null) {
throw new IllegalStateException("No such double property: " + name);
}
return doubleProperty;
}
@Override
public ListProperty getListProperty(String name) {
ListProperty listProperty = listProperties.get(name);
if (listProperty == null) {
throw new IllegalStateException("No such list property: " + name);
}
return listProperty;
}
private static RuntimeException unexpectedValueType(String propertyName,
String propertyType, @Nullable Object value) {
String found = value == null ? "null" : value.getClass().getSimpleName();
return new IllegalStateException("Unexpected value for " + propertyType + " property "
+ propertyName + ": " + found);
}
private static RuntimeException unexpectedValueTypeForList(String propertyName,
@Nullable Object value) {
String found = value == null ? "null" : value.getClass().getSimpleName();
return new IllegalStateException(
"Unexpected value for element of list property " + propertyName + ": " + found);
}
}
private static class StringPropertyImpl implements StringProperty {
private final String value;
private StringPropertyImpl(String value) {
this.value = value;
}
@Override
public String value() {
return value;
}
}
private static class BooleanPropertyImpl implements BooleanProperty {
private final boolean value;
private BooleanPropertyImpl(boolean value) {
this.value = value;
}
@Override
public boolean value() {
return value;
}
}
private static class DoublePropertyImpl implements DoubleProperty {
private final @Nullable Double value;
private DoublePropertyImpl(@Nullable Double value) {
this.value = value;
}
@Override
public @Nullable Double value() {
return value;
}
}
private static class ListPropertyImpl implements ListProperty {
private final List value;
private ListPropertyImpl(List value) {
this.value = value;
}
@Override
public List value() {
return value;
}
}
}