blob: 4a9816347eac2a4c95bf572efca741cd3c62c251 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2014 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
package org.eclipse.osee.config.admin.internal;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.osee.framework.core.JaxRsApi;
import org.eclipse.osee.framework.jdk.core.util.Compare;
import org.eclipse.osee.framework.jdk.core.util.Lib;
import org.eclipse.osee.framework.jdk.core.util.io.UriWatcher;
import org.eclipse.osee.framework.jdk.core.util.io.UriWatcher.UriWatcherListener;
import org.eclipse.osee.logger.Log;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
/**
* @author Roberto E. Escobar
*/
public class ConfigManagerImpl implements UriWatcherListener {
private final AtomicReference<UriWatcher> watcherRef = new AtomicReference<>();
private final Map<String, ServiceConfig> services = new HashMap<>();
private ConfigParser parser;
private JaxRsApi jaxRsApi;
private Log logger;
private ConfigurationAdmin configAdmin;
private ConfigManagerConfiguration config;
public void bindJaxRsApi(JaxRsApi jaxRsApi) {
this.jaxRsApi = jaxRsApi;
}
public void setLogger(Log logger) {
this.logger = logger;
}
public void setConfigAdmin(ConfigurationAdmin configAdmin) {
this.configAdmin = configAdmin;
}
public void start(Map<String, Object> properties) {
logger.trace("Starting ConfigurationManagerImpl...");
parser = new ConfigParser(jaxRsApi);
update(properties);
}
public void stop() {
logger.trace("Stopping ConfigurationManagerImpl...");
UriWatcher watcher = watcherRef.get();
close(watcher);
}
public void update(Map<String, Object> properties) {
logger.trace("Configuring ConfigurationManagerImpl...");
ConfigManagerConfiguration newConfig = ConfigManagerConfigurationBuilder.newBuilder()//
.properties(properties) //
.build();
if (Compare.isDifferent(config, newConfig)) {
configure(newConfig);
config = newConfig;
}
}
private void configure(ConfigManagerConfiguration config) {
logger.info("Configuration Manager settings: [%s]", config);
logger.warn("configuration file [" + config.getConfigUri() + "]");
URI configUri = ConfigUtil.asUri(config.getConfigUri());
if (configUri != null) {
long pollTime = config.getPollTime();
TimeUnit timeUnit = config.getTimeUnit();
logger.warn("Reading configuration from: [%s] every [%s %s]", configUri, pollTime, timeUnit);
UriWatcher newWatcher = new UriWatcher(pollTime, timeUnit);
newWatcher.addUri(configUri);
newWatcher.addListener(this);
UriWatcher oldWatcher = watcherRef.getAndSet(newWatcher);
close(oldWatcher);
newWatcher.start();
processUri(configUri);
} else {
logger.warn("Invalid configuration file");
}
}
private void close(UriWatcher watcher) {
if (watcher != null) {
watcher.stop();
watcher.removeListener(this);
}
}
private void processUri(URI uri) {
try {
String source = Lib.inputStreamToString(uri.toURL().openStream());
final Map<String, Dictionary<String, Object>> newConfigs = new HashMap<>();
parser.process(new ConfigWriter() {
@Override
public void write(String serviceId, Dictionary<String, Object> props) {
newConfigs.put(serviceId, props);
}
}, source);
configureServices(newConfigs);
} catch (Exception ex) {
logger.error(ex, "Error processing config [%s]", uri);
}
}
@Override
public void handleException(Exception ex) {
logger.error(ex, "Error monitoring framework configuration [%s]", config);
}
@Override
public void modificationDateChanged(Collection<URI> uris) {
for (URI uri : uris) {
processUri(uri);
}
}
private void configureServices(Map<String, Dictionary<String, Object>> newConfigs) {
Iterable<String> removed =
org.eclipse.osee.framework.jdk.core.util.Collections.setComplement(services.keySet(), newConfigs.keySet());
for (String id : removed) {
ServiceConfig component = services.remove(id);
if (component != null) {
component.stop();
}
}
for (Entry<String, Dictionary<String, Object>> entry : newConfigs.entrySet()) {
String serviceId = entry.getKey();
ServiceConfig component = services.get(serviceId);
if (component == null) {
component = new ServiceConfig(serviceId);
services.put(serviceId, component);
}
component.update(entry.getValue());
}
}
private final class ServiceConfig {
private final AtomicBoolean isRegistered = new AtomicBoolean(false);
private final String serviceId;
private Dictionary<String, Object> properties;
public ServiceConfig(String serviceId) {
super();
this.serviceId = serviceId;
}
public void update(Dictionary<String, Object> config) {
if (!isRegistered.getAndSet(true) || Compare.isDifferent(config, properties)) {
properties = config;
try {
Configuration configuration = configAdmin.getConfiguration(serviceId, null);
configuration.update(config);
if (logger.isDebugEnabled()) {
StringBuilder builder = new StringBuilder();
ConfigUtil.writeConfig(configuration, builder);
logger.debug(builder.toString());
}
} catch (IOException ex) {
logger.error(ex, "Error configuring [%s] - config [%s]", serviceId, config);
}
}
}
public void stop() {
if (isRegistered.getAndSet(false)) {
try {
Configuration configuration = configAdmin.getConfiguration(serviceId, null);
configuration.delete();
} catch (IOException ex) {
logger.error(ex, "Error removing config [%s]", serviceId);
}
}
}
}
}