/*
* Copyright 2011-2017 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.embedded.init;
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 com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.glowroot.agent.config.AdvancedConfig;
import org.glowroot.agent.config.AlertConfig;
import org.glowroot.agent.config.ConfigService;
import org.glowroot.agent.config.GaugeConfig;
import org.glowroot.agent.config.InstrumentationConfig;
import org.glowroot.agent.config.PluginCache;
import org.glowroot.agent.config.PluginConfig;
import org.glowroot.agent.config.PluginDescriptor;
import org.glowroot.agent.config.TransactionConfig;
import org.glowroot.agent.config.UiConfig;
import org.glowroot.agent.config.UserRecordingConfig;
import org.glowroot.common.config.AgentRollupConfig;
import org.glowroot.common.config.CentralStorageConfig;
import org.glowroot.common.config.CentralWebConfig;
import org.glowroot.common.config.EmbeddedStorageConfig;
import org.glowroot.common.config.EmbeddedWebConfig;
import org.glowroot.common.config.ImmutableEmbeddedStorageConfig;
import org.glowroot.common.config.ImmutableEmbeddedWebConfig;
import org.glowroot.common.config.ImmutableLdapConfig;
import org.glowroot.common.config.ImmutableRoleConfig;
import org.glowroot.common.config.ImmutableSmtpConfig;
import org.glowroot.common.config.ImmutableUserConfig;
import org.glowroot.common.config.LdapConfig;
import org.glowroot.common.config.RoleConfig;
import org.glowroot.common.config.SmtpConfig;
import org.glowroot.common.config.StorageConfig;
import org.glowroot.common.config.UserConfig;
import org.glowroot.common.config.WebConfig;
import org.glowroot.common.repo.ConfigRepository;
import org.glowroot.common.repo.util.LazySecretKey;
import org.glowroot.common.util.OnlyUsedByTests;
import org.glowroot.common.util.Versions;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.AlertConfig.AlertKind;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.PluginProperty;
import static com.google.common.base.Preconditions.checkState;
class ConfigRepositoryImpl implements ConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(ConfigRepositoryImpl.class);
private final ConfigService configService;
private final PluginCache pluginCache;
private final ImmutableList<RollupConfig> rollupConfigs;
private final LazySecretKey lazySecretKey;
private final Object writeLock = new Object();
private volatile ImmutableList<UserConfig> userConfigs;
private volatile ImmutableList<RoleConfig> roleConfigs;
private volatile EmbeddedWebConfig webConfig;
private volatile EmbeddedStorageConfig storageConfig;
private volatile SmtpConfig smtpConfig;
private volatile LdapConfig ldapConfig;
static ConfigRepository create(File glowrootDir, ConfigService configService,
PluginCache pluginCache) {
ConfigRepositoryImpl configRepository =
new ConfigRepositoryImpl(glowrootDir, configService, pluginCache);
// it's nice to update admin.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 glowrootDir, ConfigService configService,
PluginCache pluginCache) {
this.configService = configService;
this.pluginCache = pluginCache;
rollupConfigs = ImmutableList.copyOf(RollupConfig.buildRollupConfigs());
lazySecretKey = new LazySecretKeyImpl(new File(glowrootDir, "secret"));
List<ImmutableUserConfig> userConfigs = configService.getAdminConfig(USERS_KEY,
new TypeReference<List<ImmutableUserConfig>>() {});
if (userConfigs == null) {
this.userConfigs = ImmutableList.of();
} else {
this.userConfigs = ImmutableList.<UserConfig>copyOf(userConfigs);
}
if (this.userConfigs.isEmpty()) {
this.userConfigs = ImmutableList.<UserConfig>of(ImmutableUserConfig.builder()
.username("anonymous")
.addRoles("Administrator")
.build());
}
List<ImmutableRoleConfig> roleConfigs = configService.getAdminConfig(ROLES_KEY,
new TypeReference<List<ImmutableRoleConfig>>() {});
if (roleConfigs == null) {
this.roleConfigs = ImmutableList.of();
} else {
this.roleConfigs = ImmutableList.<RoleConfig>copyOf(roleConfigs);
}
if (this.roleConfigs.isEmpty()) {
this.roleConfigs = ImmutableList.<RoleConfig>of(ImmutableRoleConfig.builder()
.name("Administrator")
.addPermissions("agent:transaction", "agent:error", "agent:jvm", "agent:alert",
"agent:config", "admin")
.build());
}
EmbeddedWebConfig webConfig =
configService.getAdminConfig(WEB_KEY, ImmutableEmbeddedWebConfig.class);
if (webConfig == null) {
this.webConfig = ImmutableEmbeddedWebConfig.builder().build();
} else {
this.webConfig = webConfig;
}
EmbeddedStorageConfig storageConfig =
configService.getAdminConfig(STORAGE_KEY, ImmutableEmbeddedStorageConfig.class);
if (storageConfig == null) {
this.storageConfig = ImmutableEmbeddedStorageConfig.builder().build();
} else if (storageConfig.hasListIssues()) {
this.storageConfig = withCorrectedLists(storageConfig);
} else {
this.storageConfig = storageConfig;
}
SmtpConfig smtpConfig = configService.getAdminConfig(SMTP_KEY, ImmutableSmtpConfig.class);
if (smtpConfig == null) {
this.smtpConfig = ImmutableSmtpConfig.builder().build();
} else {
this.smtpConfig = smtpConfig;
}
LdapConfig ldapConfig = configService.getAdminConfig(LDAP_KEY, ImmutableLdapConfig.class);
if (ldapConfig == null) {
this.ldapConfig = ImmutableLdapConfig.builder().build();
} else {
this.ldapConfig = ldapConfig;
}
}
@Override
public AgentConfig.TransactionConfig getTransactionConfig(String agentId) {
return configService.getTransactionConfig().toProto();
}
@Override
public AgentConfig.UiConfig getUiConfig(String agentId) {
return configService.getUiConfig().toProto();
}
@Override
public AgentConfig.UserRecordingConfig getUserRecordingConfig(String agentId) {
return configService.getUserRecordingConfig().toProto();
}
@Override
public AgentConfig.AdvancedConfig getAdvancedConfig(String agentId) {
return configService.getAdvancedConfig().toProto();
}
@Override
public List<AgentConfig.GaugeConfig> getGaugeConfigs(String agentId) {
List<AgentConfig.GaugeConfig> gaugeConfigs = Lists.newArrayList();
for (GaugeConfig gaugeConfig : configService.getGaugeConfigs()) {
gaugeConfigs.add(gaugeConfig.toProto());
}
return gaugeConfigs;
}
@Override
public @Nullable AgentConfig.GaugeConfig getGaugeConfig(String agentId, String version) {
for (GaugeConfig gaugeConfig : configService.getGaugeConfigs()) {
AgentConfig.GaugeConfig config = gaugeConfig.toProto();
if (Versions.getVersion(config).equals(version)) {
return config;
}
}
return null;
}
@Override
public List<AgentConfig.SyntheticMonitorConfig> getSyntheticMonitorConfigs(
String agentRollupId) {
throw new UnsupportedOperationException();
}
@Override
public @Nullable AgentConfig.SyntheticMonitorConfig getSyntheticMonitorConfig(
String agentRollupId, String syntheticMonitorId) {
throw new UnsupportedOperationException();
}
@Override
public List<AgentConfig.AlertConfig> getAlertConfigs(String agentRollupId) throws Exception {
List<AgentConfig.AlertConfig> configs = Lists.newArrayList();
for (AlertConfig config : configService.getAlertConfigs()) {
configs.add(config.toProto());
}
return configs;
}
@Override
public List<AgentConfig.AlertConfig> getAlertConfigs(String agentRollupId,
AlertKind alertKind) {
List<AgentConfig.AlertConfig> configs = Lists.newArrayList();
for (AlertConfig config : configService.getAlertConfigs()) {
if (config.kind() == alertKind) {
configs.add(config.toProto());
}
}
return configs;
}
@Override
public @Nullable AgentConfig.AlertConfig getAlertConfig(String agentRollupId,
String alertVersion) {
for (AlertConfig alertConfig : configService.getAlertConfigs()) {
AgentConfig.AlertConfig config = alertConfig.toProto();
if (Versions.getVersion(config).equals(alertVersion)) {
return config;
}
}
return null;
}
@Override
public List<AgentConfig.PluginConfig> getPluginConfigs(String agentId) {
List<AgentConfig.PluginConfig> configs = Lists.newArrayList();
for (PluginConfig config : configService.getPluginConfigs()) {
configs.add(config.toProto());
}
return configs;
}
@Override
public @Nullable AgentConfig.PluginConfig getPluginConfig(String agentId, String pluginId) {
PluginConfig pluginConfig = configService.getPluginConfig(pluginId);
if (pluginConfig == null) {
return null;
}
return pluginConfig.toProto();
}
@Override
public List<AgentConfig.InstrumentationConfig> getInstrumentationConfigs(String agentId) {
List<AgentConfig.InstrumentationConfig> configs = Lists.newArrayList();
for (InstrumentationConfig config : configService.getInstrumentationConfigs()) {
configs.add(config.toProto());
}
return configs;
}
@Override
public @Nullable AgentConfig.InstrumentationConfig getInstrumentationConfig(String agentId,
String version) {
for (InstrumentationConfig config : configService.getInstrumentationConfigs()) {
AgentConfig.InstrumentationConfig protoConfig = config.toProto();
if (Versions.getVersion(protoConfig).equals(version)) {
return protoConfig;
}
}
return null;
}
@Override
public AgentRollupConfig getAgentRollupConfig(String agentRollup) {
throw new UnsupportedOperationException();
}
@Override
public List<UserConfig> getUserConfigs() {
return userConfigs;
}
@Override
public @Nullable UserConfig getUserConfig(String username) {
for (UserConfig config : userConfigs) {
if (config.username().equals(username)) {
return config;
}
}
return null;
}
@Override
public @Nullable UserConfig getUserConfigCaseInsensitive(String username) {
for (UserConfig config : userConfigs) {
if (config.username().equalsIgnoreCase(username)) {
return config;
}
}
return null;
}
@Override
public boolean namedUsersExist() {
for (UserConfig config : userConfigs) {
if (!config.username().equalsIgnoreCase("anonymous")) {
return true;
}
}
return false;
}
@Override
public List<RoleConfig> getRoleConfigs() {
return roleConfigs;
}
@Override
public @Nullable RoleConfig getRoleConfig(String name) {
for (RoleConfig config : roleConfigs) {
if (config.name().equals(name)) {
return config;
}
}
return null;
}
@Override
public WebConfig getWebConfig() {
return getEmbeddedWebConfig();
}
@Override
public EmbeddedWebConfig getEmbeddedWebConfig() {
return webConfig;
}
@Override
public CentralWebConfig getCentralWebConfig() {
throw new UnsupportedOperationException();
}
@Override
public StorageConfig getStorageConfig() {
return getEmbeddedStorageConfig();
}
@Override
public EmbeddedStorageConfig getEmbeddedStorageConfig() {
return storageConfig;
}
@Override
public CentralStorageConfig getCentralStorageConfig() {
throw new UnsupportedOperationException();
}
@Override
public SmtpConfig getSmtpConfig() {
return smtpConfig;
}
@Override
public LdapConfig getLdapConfig() {
return ldapConfig;
}
@Override
public void updateTransactionConfig(String agentId,
AgentConfig.TransactionConfig protoConfig, String priorVersion) throws Exception {
TransactionConfig config = TransactionConfig.create(protoConfig);
synchronized (writeLock) {
String currVersion =
Versions.getVersion(configService.getTransactionConfig().toProto());
checkVersionsEqual(currVersion, priorVersion);
configService.updateTransactionConfig(config);
}
}
@Override
public void insertGaugeConfig(String agentId, AgentConfig.GaugeConfig protoConfig)
throws Exception {
GaugeConfig config = GaugeConfig.create(protoConfig);
synchronized (writeLock) {
List<GaugeConfig> configs = Lists.newArrayList(configService.getGaugeConfigs());
// check for duplicate mbeanObjectName
for (GaugeConfig loopConfig : configs) {
if (loopConfig.mbeanObjectName().equals(protoConfig.getMbeanObjectName())) {
throw new DuplicateMBeanObjectNameException();
}
}
// no need to check for exact match since redundant with dup mbean object name check
configs.add(config);
configService.updateGaugeConfigs(configs);
}
}
@Override
public void updateGaugeConfig(String agentId, AgentConfig.GaugeConfig protoConfig,
String priorVersion) throws Exception {
GaugeConfig config = GaugeConfig.create(protoConfig);
synchronized (writeLock) {
List<GaugeConfig> configs = Lists.newArrayList(configService.getGaugeConfigs());
boolean found = false;
for (ListIterator<GaugeConfig> i = configs.listIterator(); i.hasNext();) {
GaugeConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (loopVersion.equals(priorVersion)) {
i.set(config);
found = true;
} else if (loopConfig.mbeanObjectName().equals(protoConfig.getMbeanObjectName())) {
throw new DuplicateMBeanObjectNameException();
}
// no need to check for exact match since redundant with dup mbean object name check
}
if (!found) {
throw new OptimisticLockException();
}
configService.updateGaugeConfigs(configs);
}
}
@Override
public void deleteGaugeConfig(String agentId, String version) throws Exception {
synchronized (writeLock) {
List<GaugeConfig> configs = Lists.newArrayList(configService.getGaugeConfigs());
boolean found = false;
for (ListIterator<GaugeConfig> i = configs.listIterator(); i.hasNext();) {
GaugeConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (loopVersion.equals(version)) {
i.remove();
found = true;
break;
}
}
if (!found) {
throw new OptimisticLockException();
}
configService.updateGaugeConfigs(configs);
}
}
@Override
public String insertSyntheticMonitorConfig(String agentRollupId,
AgentConfig.SyntheticMonitorConfig configWithoutId) throws Exception {
throw new UnsupportedOperationException();
}
@Override
public void updateSyntheticMonitorConfig(String agentRollupId,
AgentConfig.SyntheticMonitorConfig config, String priorVersion) throws Exception {
throw new UnsupportedOperationException();
}
@Override
public void deleteSyntheticMonitorConfig(String agentRollupId, String syntheticMonitorId)
throws Exception {
throw new UnsupportedOperationException();
}
@Override
public void insertAlertConfig(String agentRollupId, AgentConfig.AlertConfig configWithoutId)
throws Exception {
synchronized (writeLock) {
List<AlertConfig> configs =
Lists.newArrayList(configService.getAlertConfigs());
// check for exact duplicate
String version = Versions.getVersion(configWithoutId);
for (AlertConfig loopConfig : configs) {
if (Versions.getVersion(loopConfig.toProto()).equals(version)) {
throw new IllegalStateException("This exact alert already exists");
}
}
configs.add(AlertConfig.create(configWithoutId));
configService.updateAlertConfigs(configs);
}
}
@Override
public void updateAlertConfig(String agentRollupId, AgentConfig.AlertConfig config,
String priorVersion) throws Exception {
synchronized (writeLock) {
List<AlertConfig> configs = Lists.newArrayList(configService.getAlertConfigs());
boolean found = false;
for (ListIterator<AlertConfig> i = configs.listIterator(); i.hasNext();) {
AlertConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (loopVersion.equals(priorVersion)) {
i.set(AlertConfig.create(config));
found = true;
break;
}
}
if (!found) {
throw new OptimisticLockException();
}
configService.updateAlertConfigs(configs);
}
}
@Override
public void deleteAlertConfig(String agentRollupId, String version) throws Exception {
List<AlertConfig> configs = Lists.newArrayList(configService.getAlertConfigs());
boolean found = false;
for (ListIterator<AlertConfig> i = configs.listIterator(); i.hasNext();) {
AlertConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (version.equals(loopVersion)) {
i.remove();
found = true;
break;
}
}
if (!found) {
throw new OptimisticLockException();
}
configService.updateAlertConfigs(configs);
}
@Override
public void updateUiConfig(String agentId, AgentConfig.UiConfig protoConfig,
String priorVersion) throws Exception {
UiConfig config = UiConfig.create(protoConfig);
synchronized (writeLock) {
String currVersion = Versions.getVersion(configService.getUiConfig().toProto());
checkVersionsEqual(currVersion, priorVersion);
configService.updateUiConfig(config);
}
}
@Override
public void updatePluginConfig(String agentId, String pluginId,
List<PluginProperty> properties, String priorVersion) throws Exception {
PluginDescriptor pluginDescriptor = getPluginDescriptor(pluginId);
PluginConfig config = PluginConfig.create(pluginDescriptor, properties);
synchronized (writeLock) {
List<PluginConfig> configs = Lists.newArrayList(configService.getPluginConfigs());
boolean found = false;
for (ListIterator<PluginConfig> i = configs.listIterator(); i.hasNext();) {
PluginConfig loopPluginConfig = i.next();
if (pluginId.equals(loopPluginConfig.id())) {
String loopVersion = Versions.getVersion(loopPluginConfig.toProto());
checkVersionsEqual(loopVersion, priorVersion);
i.set(config);
found = true;
break;
}
}
checkState(found, "Plugin config not found: %s", pluginId);
configService.updatePluginConfigs(configs);
}
}
@Override
public void insertInstrumentationConfig(String agentId,
AgentConfig.InstrumentationConfig protoConfig) throws Exception {
InstrumentationConfig config = InstrumentationConfig.create(protoConfig);
synchronized (writeLock) {
List<InstrumentationConfig> configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
checkInstrumentationDoesNotExist(config, configs);
configs.add(config);
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void updateInstrumentationConfig(String agentId,
AgentConfig.InstrumentationConfig protoConfig, String priorVersion) throws Exception {
InstrumentationConfig config = InstrumentationConfig.create(protoConfig);
synchronized (writeLock) {
List<InstrumentationConfig> configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
boolean found = false;
for (ListIterator<InstrumentationConfig> i = configs.listIterator(); i.hasNext();) {
InstrumentationConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (loopVersion.equals(priorVersion)) {
i.set(config);
found = true;
} else if (loopConfig.equals(config)) {
throw new IllegalStateException("This exact instrumentation already exists");
}
}
if (!found) {
throw new OptimisticLockException();
}
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void deleteInstrumentationConfigs(String agentId, List<String> versions)
throws Exception {
synchronized (writeLock) {
List<InstrumentationConfig> configs =
Lists.newArrayList(configService.getInstrumentationConfigs());
List<String> remainingVersions = Lists.newArrayList(versions);
for (ListIterator<InstrumentationConfig> i = configs.listIterator(); i.hasNext();) {
InstrumentationConfig loopConfig = i.next();
String loopVersion = Versions.getVersion(loopConfig.toProto());
if (remainingVersions.contains(loopVersion)) {
i.remove();
remainingVersions.remove(loopVersion);
}
}
if (!remainingVersions.isEmpty()) {
throw new OptimisticLockException();
}
configService.updateInstrumentationConfigs(configs);
}
}
@Override
public void insertInstrumentationConfigs(String agentId,
List<AgentConfig.InstrumentationConfig> protoConfigs) throws Exception {
List<InstrumentationConfig> configs = Lists.newArrayList();
for (AgentConfig.InstrumentationConfig instrumentationConfig : protoConfigs) {
InstrumentationConfig config = InstrumentationConfig.create(instrumentationConfig);
configs.add(config);
}
synchronized (writeLock) {
List<InstrumentationConfig> existingConfigs =
Lists.newArrayList(configService.getInstrumentationConfigs());
for (InstrumentationConfig config : configs) {
checkInstrumentationDoesNotExist(config, existingConfigs);
existingConfigs.add(config);
}
configService.updateInstrumentationConfigs(existingConfigs);
}
}
@Override
public void updateUserRecordingConfig(String agentId,
AgentConfig.UserRecordingConfig protoConfig, String priorVersion)
throws Exception {
UserRecordingConfig config = UserRecordingConfig.create(protoConfig);
synchronized (writeLock) {
String currVersion =
Versions.getVersion(configService.getUserRecordingConfig().toProto());
checkVersionsEqual(currVersion, priorVersion);
configService.updateUserRecordingConfig(config);
}
}
@Override
public void updateAdvancedConfig(String agentId, AgentConfig.AdvancedConfig protoConfig,
String priorVersion) throws Exception {
AdvancedConfig config = AdvancedConfig.create(protoConfig);
synchronized (writeLock) {
String currVersion = Versions.getVersion(configService.getAdvancedConfig().toProto());
checkVersionsEqual(currVersion, priorVersion);
configService.updateAdvancedConfig(config);
}
}
@Override
public void updateAgentRollupConfig(AgentRollupConfig agentRollupConfig, String priorVersion) {
throw new UnsupportedOperationException();
}
@Override
public void deleteAgentRollupConfig(String agentRollup) {
throw new UnsupportedOperationException();
}
@Override
public void insertUserConfig(UserConfig config) throws Exception {
synchronized (writeLock) {
List<UserConfig> configs = Lists.newArrayList(userConfigs);
// check for case-insensitive duplicate
String username = config.username();
for (UserConfig loopConfig : configs) {
if (loopConfig.username().equalsIgnoreCase(username)) {
throw new DuplicateUsernameException();
}
}
configs.add(config);
configService.updateAdminConfig(USERS_KEY, configs);
userConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void updateUserConfig(UserConfig config, String priorVersion) throws Exception {
synchronized (writeLock) {
List<UserConfig> configs = Lists.newArrayList(userConfigs);
String username = config.username();
boolean found = false;
for (ListIterator<UserConfig> i = configs.listIterator(); i.hasNext();) {
UserConfig loopConfig = i.next();
if (loopConfig.username().equals(username)) {
if (loopConfig.version().equals(priorVersion)) {
i.set(config);
found = true;
break;
} else {
throw new OptimisticLockException();
}
}
}
if (!found) {
throw new UserNotFoundException();
}
configService.updateAdminConfig(USERS_KEY, configs);
userConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void deleteUserConfig(String username) throws Exception {
synchronized (writeLock) {
List<UserConfig> configs = Lists.newArrayList(userConfigs);
boolean found = false;
for (ListIterator<UserConfig> i = configs.listIterator(); i.hasNext();) {
UserConfig loopConfig = i.next();
if (loopConfig.username().equals(username)) {
i.remove();
found = true;
break;
}
}
if (!found) {
throw new UserNotFoundException();
}
if (getSmtpConfig().host().isEmpty() && configs.isEmpty()) {
throw new CannotDeleteLastUserException();
}
configService.updateAdminConfig(USERS_KEY, configs);
userConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void insertRoleConfig(RoleConfig config) throws Exception {
synchronized (writeLock) {
List<RoleConfig> configs = Lists.newArrayList(roleConfigs);
// check for case-insensitive duplicate
String name = config.name();
for (RoleConfig loopConfig : configs) {
if (loopConfig.name().equalsIgnoreCase(name)) {
throw new DuplicateRoleNameException();
}
}
configs.add(config);
configService.updateAdminConfig(ROLES_KEY, configs);
roleConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void updateRoleConfig(RoleConfig config, String priorVersion) throws Exception {
synchronized (writeLock) {
List<RoleConfig> configs = Lists.newArrayList(roleConfigs);
String name = config.name();
boolean found = false;
for (ListIterator<RoleConfig> i = configs.listIterator(); i.hasNext();) {
RoleConfig loopConfig = i.next();
if (loopConfig.name().equals(name)) {
if (loopConfig.version().equals(priorVersion)) {
i.set(config);
found = true;
break;
} else {
throw new OptimisticLockException();
}
}
}
if (!found) {
throw new RoleNotFoundException();
}
configService.updateAdminConfig(ROLES_KEY, configs);
roleConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void deleteRoleConfig(String name) throws Exception {
synchronized (writeLock) {
List<RoleConfig> configs = Lists.newArrayList(roleConfigs);
boolean found = false;
for (ListIterator<RoleConfig> i = configs.listIterator(); i.hasNext();) {
RoleConfig loopConfig = i.next();
if (loopConfig.name().equals(name)) {
i.remove();
found = true;
break;
}
}
if (!found) {
throw new RoleNotFoundException();
}
if (configs.isEmpty()) {
throw new CannotDeleteLastRoleException();
}
configService.updateAdminConfig(ROLES_KEY, configs);
roleConfigs = ImmutableList.copyOf(configs);
}
}
@Override
public void updateEmbeddedWebConfig(EmbeddedWebConfig config, String priorVersion)
throws Exception {
synchronized (writeLock) {
checkVersionsEqual(webConfig.version(), priorVersion);
configService.updateAdminConfig(WEB_KEY, config);
webConfig = config;
}
}
@Override
public void updateCentralWebConfig(CentralWebConfig config, String priorVersion) {
throw new UnsupportedOperationException();
}
@Override
public void updateEmbeddedStorageConfig(EmbeddedStorageConfig config, String priorVersion)
throws Exception {
synchronized (writeLock) {
checkVersionsEqual(storageConfig.version(), priorVersion);
configService.updateAdminConfig(STORAGE_KEY, config);
storageConfig = config;
}
}
@Override
public void updateCentralStorageConfig(CentralStorageConfig config, String priorVersion) {
throw new UnsupportedOperationException();
}
@Override
public void updateSmtpConfig(SmtpConfig config, String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(smtpConfig.version(), priorVersion);
configService.updateAdminConfig(SMTP_KEY, config);
smtpConfig = config;
}
}
@Override
public void updateLdapConfig(LdapConfig config, String priorVersion) throws Exception {
synchronized (writeLock) {
checkVersionsEqual(ldapConfig.version(), priorVersion);
configService.updateAdminConfig(LDAP_KEY, config);
ldapConfig = config;
}
}
@Override
public long getGaugeCollectionIntervalMillis() {
return configService.getGaugeCollectionIntervalMillis();
}
@Override
public ImmutableList<RollupConfig> getRollupConfigs() {
return rollupConfigs;
}
@Override
public LazySecretKey getLazySecretKey() throws Exception {
return lazySecretKey;
}
private PluginDescriptor getPluginDescriptor(String pluginId) {
for (PluginDescriptor pluginDescriptor : pluginCache.pluginDescriptors()) {
if (pluginDescriptor.id().equals(pluginId)) {
return pluginDescriptor;
}
}
throw new IllegalStateException("Could not find plugin descriptor: " + pluginId);
}
private void checkVersionsEqual(String version, String priorVersion)
throws OptimisticLockException {
if (!version.equals(priorVersion)) {
throw new OptimisticLockException();
}
}
@OnlyUsedByTests
public void resetAdminConfig() throws IOException {
userConfigs = ImmutableList.<UserConfig>of(ImmutableUserConfig.builder()
.username("anonymous")
.addRoles("Administrator")
.build());
roleConfigs = ImmutableList.<RoleConfig>of(ImmutableRoleConfig.builder()
.name("Administrator")
.addPermissions("agent:transaction", "agent:error", "agent:jvm",
"agent:config:view", "agent:config:edit", "admin")
.build());
webConfig = ImmutableEmbeddedWebConfig.builder().build();
storageConfig = ImmutableEmbeddedStorageConfig.builder().build();
smtpConfig = ImmutableSmtpConfig.builder().build();
ldapConfig = ImmutableLdapConfig.builder().build();
writeAll();
}
private void writeAll() throws IOException {
// linked hash map to preserve ordering when writing to config file
Map<String, Object> configs = Maps.newLinkedHashMap();
configs.put(USERS_KEY, userConfigs);
configs.put(ROLES_KEY, roleConfigs);
configs.put(WEB_KEY, webConfig);
configs.put(STORAGE_KEY, storageConfig);
configs.put(SMTP_KEY, smtpConfig);
configs.put(LDAP_KEY, ldapConfig);
configService.updateAdminConfigs(configs);
}
private static void checkInstrumentationDoesNotExist(
InstrumentationConfig instrumentationConfig,
List<InstrumentationConfig> instrumentationConfigs) {
for (InstrumentationConfig loopInstrumentationConfig : instrumentationConfigs) {
if (loopInstrumentationConfig.equals(instrumentationConfig)) {
throw new IllegalStateException("This exact instrumentation already exists");
}
}
}
private static EmbeddedStorageConfig withCorrectedLists(EmbeddedStorageConfig config) {
EmbeddedStorageConfig defaultConfig = ImmutableEmbeddedStorageConfig.builder().build();
ImmutableList<Integer> rollupExpirationHours =
fix(config.rollupExpirationHours(), defaultConfig.rollupExpirationHours());
ImmutableList<Integer> rollupCappedDatabaseSizesMb = fix(
config.rollupCappedDatabaseSizesMb(), defaultConfig.rollupCappedDatabaseSizesMb());
return ImmutableEmbeddedStorageConfig.builder()
.copyFrom(config)
.rollupExpirationHours(rollupExpirationHours)
.rollupCappedDatabaseSizesMb(rollupCappedDatabaseSizesMb)
.build();
}
private static ImmutableList<Integer> fix(ImmutableList<Integer> thisList,
List<Integer> defaultList) {
if (thisList.size() >= defaultList.size()) {
return thisList.subList(0, defaultList.size());
}
List<Integer> correctedList = Lists.newArrayList(thisList);
for (int i = thisList.size(); i < defaultList.size(); i++) {
correctedList.add(defaultList.get(i));
}
return ImmutableList.copyOf(correctedList);
}
}