/* * Copyright 2013 NGDATA nv * Copyright 2007 Outerthought bvba and Schaubroeck nv * * 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.lilyproject.runtime.configuration; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.lilyproject.runtime.conf.Conf; import org.lilyproject.runtime.module.ModuleConfig; import org.lilyproject.runtime.rapi.ConfRegistry; public class ConfManagerImpl implements ConfManager { private List<File> configLocations; private Map<String, ConfRegistryImpl> registries = new HashMap<String, ConfRegistryImpl>(); private ScheduledExecutorService executor; private State state = State.STOPPED; private static final String RUNTIME_CONF_NAME = "runtime"; private enum State { STOPPED, RUNTIME_CONF_AVAILABLE, MODULES_CONF_AVAILABLE } public ConfManagerImpl() { this(Collections.<File>emptyList()); } public ConfManagerImpl(List<File> configLocations) { this.configLocations = configLocations; } public void shutdown() { if (executor != null) { executor.shutdownNow(); executor = null; } registries.clear(); state = State.STOPPED; } public void initRuntimeConfig() { if (state.ordinal() >= State.RUNTIME_CONF_AVAILABLE.ordinal()) { throw new IllegalStateException("ConfManager: runtime config already initialized."); } List<ConfSource> sources = new ArrayList<ConfSource>(); for (File location : configLocations) { FilesystemConfSource source = new FilesystemConfSource(new File(location, RUNTIME_CONF_NAME)); sources.add(source); } this.registries.put(RUNTIME_CONF_NAME, new ConfRegistryImpl(RUNTIME_CONF_NAME, sources)); refresh(false); state = State.RUNTIME_CONF_AVAILABLE; } public void initModulesConfig(List<ModuleConfig> moduleConfigs) { if (state.ordinal() >= State.MODULES_CONF_AVAILABLE.ordinal()) { throw new IllegalStateException("ConfManager: modules config already initialized."); } for (ModuleConfig moduleConfig : moduleConfigs) { List<ConfSource> sources = new ArrayList<ConfSource>(); for (File location : configLocations) { FilesystemConfSource source = new FilesystemConfSource(new File(location, moduleConfig.getId())); sources.add(source); } sources.add(new ModuleSourceConfSource(moduleConfig)); this.registries.put(moduleConfig.getId(), new ConfRegistryImpl(moduleConfig.getId(), sources)); } refresh(false); state = State.MODULES_CONF_AVAILABLE; } public void startRefreshing() { if (executor != null) { throw new RuntimeException("Unexpected situation: executor is not null. Are you reusing the same " + getClass().getName() + " instance concurrently or sequentially without proper shutdown?"); } executor = Executors.newScheduledThreadPool(1); Conf conf = getConfRegistry(RUNTIME_CONF_NAME).getConfiguration("configuration", true); Conf reloadingConf = conf.getChild("reloading"); boolean reloadingEnabled = reloadingConf.getAttributeAsBoolean("enabled", true); int delay = reloadingConf.getAttributeAsInteger("delay", 5000); if (reloadingEnabled) { executor.scheduleWithFixedDelay(new Runnable() { public void run() { refresh(true); } }, delay, delay, TimeUnit.MILLISECONDS); } } private void refresh(boolean notifyListeners) { final List<Runnable> notifyTasks = new ArrayList<Runnable>(); for (ConfRegistryImpl registry : registries.values()) { Runnable runnable = registry.refresh(); if (runnable != null) { notifyTasks.add(runnable); } } if (notifyListeners) { for (Runnable runnable : notifyTasks) { runnable.run(); } } } public ConfRegistry getConfRegistry(String moduleId) { if (state.ordinal() < State.MODULES_CONF_AVAILABLE.ordinal()) { throw new IllegalStateException("ConfManager: modules configuration not yet available."); } return registries.get(moduleId); } public ConfRegistry getRuntimeConfRegistry() { if (state.ordinal() < State.RUNTIME_CONF_AVAILABLE.ordinal()) { throw new IllegalStateException("ConfManager: runtime configuration not yet available."); } return registries.get(RUNTIME_CONF_NAME); } }