
org.glowroot.agent.init.fat.ConfigRepositoryImpl Maven / Gradle / Ivy
/*
* Copyright 2011-2015 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.agent.init.fat;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.annotation.Nullable;
import javax.crypto.SecretKey;
import org.glowroot.agent.shaded.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.google.common.collect.Lists;
import org.glowroot.agent.shaded.google.common.collect.Maps;
import org.glowroot.agent.shaded.google.common.io.Files;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.glowroot.agent.shaded.slf4j.Logger;
import org.glowroot.agent.shaded.slf4j.LoggerFactory;
import org.glowroot.agent.config.ConfigService;
import org.glowroot.agent.config.ConfigService.ShadeProtectedTypeReference;
import org.glowroot.common.config.AdvancedConfig;
import org.glowroot.common.config.GaugeConfig;
import org.glowroot.common.config.InstrumentationConfig;
import org.glowroot.common.config.PluginConfig;
import org.glowroot.common.config.TransactionConfig;
import org.glowroot.common.config.UserRecordingConfig;
import org.glowroot.storage.repo.ConfigRepository;
import org.glowroot.storage.repo.config.AlertConfig;
import org.glowroot.storage.repo.config.ImmutableAlertConfig;
import org.glowroot.storage.repo.config.ImmutableSmtpConfig;
import org.glowroot.storage.repo.config.ImmutableStorageConfig;
import org.glowroot.storage.repo.config.ImmutableUserInterfaceConfig;
import org.glowroot.storage.repo.config.SmtpConfig;
import org.glowroot.storage.repo.config.StorageConfig;
import org.glowroot.storage.repo.config.UserInterfaceConfig;
import org.glowroot.storage.util.Encryption;
import static org.glowroot.agent.shaded.google.common.base.Preconditions.checkState;
class ConfigRepositoryImpl implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(ConfigRepositoryImpl.class);
private final ConfigService configService;
private final File secretFile;
private final Object writeLock = new Object();
private final ImmutableList rollupConfigs;
private volatile UserInterfaceConfig userInterfaceConfig;
private volatile StorageConfig storageConfig;
private volatile SmtpConfig smtpConfig;
private volatile ImmutableList alertConfigs;
// volatile not needed as access is guarded by secretFile
private @MonotonicNonNull SecretKey secretKey;
static ConfigRepository create(File baseDir, ConfigService configService) {
ConfigRepositoryImpl configRepository =
new ConfigRepositoryImpl(baseDir, configService);
// it's nice to update config.json on startup if it is missing some/all config
// properties so that the file contents can be reviewed/updated/copied if desired
try {
configRepository.writeAll();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return configRepository;
}
private ConfigRepositoryImpl(File baseDir, ConfigService configService) {
this.configService = configService;
secretFile = new File(baseDir, "secret");
rollupConfigs = RollupConfig.buildRollupConfigs();
UserInterfaceConfig userInterfaceConfig =
configService.getOtherConfig(UI_KEY, ImmutableUserInterfaceConfig.class);
if (userInterfaceConfig == null) {
this.userInterfaceConfig = ImmutableUserInterfaceConfig.builder().build();
} else {
this.userInterfaceConfig = userInterfaceConfig;
}
StorageConfig storageConfig =
configService.getOtherConfig(STORAGE_KEY, ImmutableStorageConfig.class);
if (storageConfig == null) {
this.storageConfig = ImmutableStorageConfig.builder().build();
} else if (storageConfig.hasListIssues()) {
this.storageConfig = withCorrectedLists(storageConfig);
} else {
this.storageConfig = storageConfig;
}
SmtpConfig smtpConfig = configService.getOtherConfig(SMTP_KEY, ImmutableSmtpConfig.class);
if (smtpConfig == null) {
this.smtpConfig = ImmutableSmtpConfig.builder().build();
} else {
this.smtpConfig = smtpConfig;
}
List alertConfigs = configService.getOtherConfig(ALERTS_KEY,
new ShadeProtectedTypeReference>() {});
if (alertConfigs == null) {
this.alertConfigs = ImmutableList.of();
} else {
this.alertConfigs = ImmutableList.copyOf(alertConfigs);
}
}
@Override
public TransactionConfig getTransactionConfig(String serverId) {
return configService.getTransactionConfig();
}
@Override
public UserRecordingConfig getUserRecordingConfig(String serverId) {
return configService.getUserRecordingConfig();
}
@Override
public AdvancedConfig getAdvancedConfig(String serverId) {
return configService.getAdvancedConfig();
}
@Override
public @Nullable PluginConfig getPluginConfig(String serverId, String pluginId) {
return configService.getPluginConfig(pluginId);
}
@Override
public List getInstrumentationConfigs(String serverId) {
return configService.getInstrumentationConfigs();
}
@Override
public @Nullable InstrumentationConfig getInstrumentationConfig(String serverId,
String version) {
for (InstrumentationConfig instrumentationConfig : configService
.getInstrumentationConfigs()) {
if (instrumentationConfig.version().equals(version)) {
return instrumentationConfig;
}
}
return null;
}
@Override
public List getGaugeConfigs(String serverId) {
return configService.getGaugeConfigs();
}
@Override
public @Nullable GaugeConfig getGaugeConfig(String serverId, String version) {
for (GaugeConfig gaugeConfig : configService.getGaugeConfigs()) {
if (gaugeConfig.version().equals(version)) {
return gaugeConfig;
}
}
return null;
}
@Override
public UserInterfaceConfig getUserInterfaceConfig() {
return userInterfaceConfig;
}
@Override
public StorageConfig getStorageConfig() {
return storageConfig;
}
@Override
public SmtpConfig getSmtpConfig() {
return smtpConfig;
}
@Override
public List getAlertConfigs(String serverId) {
return alertConfigs;
}
@Override
public @Nullable AlertConfig getAlertConfig(String serverId, String version) {
for (AlertConfig alertConfig : alertConfigs) {
if (alertConfig.version().equals(version)) {
return alertConfig;
}
}
return null;
}
@Override
public void updateTransactionConfig(String serverId, TransactionConfig updatedConfig,
String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(configService.getTransactionConfig().version(), priorVersion);
configService.updateTransactionConfig(updatedConfig);
}
}
@Override
public void updateUserRecordingConfig(String serverId, UserRecordingConfig userRecordingConfig,
String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(configService.getUserRecordingConfig().version(), priorVersion);
configService.updateUserRecordingConfig(userRecordingConfig);
}
}
@Override
public void updateAdvancedConfig(String serverId, AdvancedConfig advancedConfig,
String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(configService.getAdvancedConfig().version(), priorVersion);
configService.updateAdvancedConfig(advancedConfig);
}
}
@Override
public void updatePluginConfig(String serverId, PluginConfig pluginConfig, String priorVersion)
throws Exception {
synchronized (writeLock) {
List configs = Lists.newArrayList(configService.getPluginConfigs());
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
PluginConfig loopPluginConfig = i.next();
if (pluginConfig.id().equals(loopPluginConfig.id())) {
checkVersionsEqual(loopPluginConfig.version(), priorVersion);
i.set(pluginConfig);
found = true;
break;
}
}
checkState(found, "Plugin config not found: %s", pluginConfig.id());
configService.updatePluginConfigs(configs);
}
}
@Override
public void insertInstrumentationConfig(String serverId,
InstrumentationConfig instrumentationConfig) throws IOException {
synchronized (writeLock) {
List configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
configs.add(instrumentationConfig);
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void updateInstrumentationConfig(String serverId,
InstrumentationConfig instrumentationConfig, String priorVersion) throws IOException {
synchronized (writeLock) {
List configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
if (priorVersion.equals(i.next().version())) {
i.set(instrumentationConfig);
found = true;
break;
}
}
checkState(found, "Instrumentation config not found: %s", priorVersion);
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void deleteInstrumentationConfig(String serverId, String version) throws IOException {
synchronized (writeLock) {
List configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
if (version.equals(i.next().version())) {
i.remove();
found = true;
break;
}
}
checkState(found, "Instrumentation config not found: %s", version);
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void insertGaugeConfig(String serverId, GaugeConfig gaugeConfig) throws Exception {
synchronized (writeLock) {
List configs = Lists.newArrayList(configService.getGaugeConfigs());
// check for duplicate mbeanObjectName
for (GaugeConfig loopConfig : configs) {
if (loopConfig.mbeanObjectName().equals(gaugeConfig.mbeanObjectName())) {
throw new DuplicateMBeanObjectNameException();
}
}
configs.add(gaugeConfig);
configService.updateGaugeConfigs(configs);
}
}
@Override
public void updateGaugeConfig(String serverId, GaugeConfig gaugeConfig, String priorVersion)
throws Exception {
synchronized (writeLock) {
List configs = Lists.newArrayList(configService.getGaugeConfigs());
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
GaugeConfig loopConfig = i.next();
if (priorVersion.equals(loopConfig.version())) {
i.set(gaugeConfig);
found = true;
break;
} else if (loopConfig.mbeanObjectName().equals(gaugeConfig.mbeanObjectName())) {
throw new DuplicateMBeanObjectNameException();
}
}
checkState(found, "Gauge config not found: %s", priorVersion);
configService.updateGaugeConfigs(configs);
}
}
@Override
public void deleteGaugeConfig(String serverId, String version) throws IOException {
synchronized (writeLock) {
List configs = Lists.newArrayList(configService.getGaugeConfigs());
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
if (version.equals(i.next().version())) {
i.remove();
found = true;
break;
}
}
checkState(found, "Gauge config not found: %s", version);
configService.updateGaugeConfigs(configs);
}
}
@Override
public void updateUserInterfaceConfig(UserInterfaceConfig updatedConfig, String priorVersion)
throws Exception {
synchronized (writeLock) {
checkVersionsEqual(userInterfaceConfig.version(), priorVersion);
configService.updateOtherConfig(UI_KEY, updatedConfig);
userInterfaceConfig = updatedConfig;
}
}
@Override
public void updateStorageConfig(StorageConfig updatedConfig, String priorVersion)
throws Exception {
synchronized (writeLock) {
checkVersionsEqual(storageConfig.version(), priorVersion);
configService.updateOtherConfig(STORAGE_KEY, updatedConfig);
storageConfig = updatedConfig;
}
}
@Override
public void updateSmtpConfig(SmtpConfig updatedConfig, String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(smtpConfig.version(), priorVersion);
configService.updateOtherConfig(SMTP_KEY, updatedConfig);
smtpConfig = updatedConfig;
}
}
@Override
public void insertAlertConfig(String serverId, AlertConfig alertConfig) throws Exception {
synchronized (writeLock) {
List configs = Lists.newArrayList(alertConfigs);
configs.add(alertConfig);
configService.updateOtherConfig(ALERTS_KEY, configs);
this.alertConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void updateAlertConfig(String serverId, AlertConfig alertConfig, String priorVersion)
throws IOException {
synchronized (writeLock) {
List configs = Lists.newArrayList(alertConfigs);
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
if (priorVersion.equals(i.next().version())) {
i.set(alertConfig);
found = true;
break;
}
}
checkState(found, "Alert config not found: %s", priorVersion);
configService.updateOtherConfig(ALERTS_KEY, configs);
alertConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void deleteAlertConfig(String serverId, String version) throws IOException {
synchronized (writeLock) {
List configs = Lists.newArrayList(alertConfigs);
boolean found = false;
for (ListIterator i = configs.listIterator(); i.hasNext();) {
if (version.equals(i.next().version())) {
i.remove();
found = true;
break;
}
}
checkState(found, "Alert config not found: %s", version);
configService.updateOtherConfig(ALERTS_KEY, configs);
alertConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public long getGaugeCollectionIntervalMillis() {
return configService.getGaugeCollectionIntervalMillis();
}
@Override
public ImmutableList getRollupConfigs() {
return rollupConfigs;
}
// lazy create secret file only when needed
@Override
public SecretKey getSecretKey() throws Exception {
synchronized (secretFile) {
if (secretKey == null) {
if (secretFile.exists()) {
secretKey = Encryption.loadKey(secretFile);
} else {
secretKey = Encryption.generateNewKey();
Files.write(secretKey.getEncoded(), secretFile);
}
}
return secretKey;
}
}
private void checkVersionsEqual(String version, String priorVersion)
throws OptimisticLockException {
if (!version.equals(priorVersion)) {
throw new OptimisticLockException();
}
}
private void writeAll() throws IOException {
// linked hash map to preserve ordering when writing to config file
Map configs = Maps.newLinkedHashMap();
configs.put(UI_KEY, userInterfaceConfig);
configs.put(STORAGE_KEY, storageConfig);
configs.put(SMTP_KEY, smtpConfig);
configs.put(ALERTS_KEY, alertConfigs);
configService.updateOtherConfigs(configs);
}
private static StorageConfig withCorrectedLists(StorageConfig storageConfig) {
StorageConfig defaultConfig = ImmutableStorageConfig.builder().build();
ImmutableList rollupExpirationHours =
fix(storageConfig.rollupExpirationHours(), defaultConfig.rollupExpirationHours());
ImmutableList rollupCappedDatabaseSizesMb =
fix(storageConfig.rollupCappedDatabaseSizesMb(),
defaultConfig.rollupCappedDatabaseSizesMb());
return ImmutableStorageConfig.builder()
.copyFrom(storageConfig)
.rollupExpirationHours(rollupExpirationHours)
.rollupCappedDatabaseSizesMb(rollupCappedDatabaseSizesMb)
.build();
}
private static ImmutableList fix(ImmutableList thisList,
List defaultList) {
if (thisList.size() >= defaultList.size()) {
return thisList.subList(0, defaultList.size());
}
List correctedList = Lists.newArrayList(thisList);
for (int i = thisList.size(); i < defaultList.size(); i++) {
correctedList.add(defaultList.get(i));
}
return ImmutableList.copyOf(correctedList);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy