/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.monitoring.common.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.configuration.CommandLineArguments; import de.rcenvironment.core.configuration.ConfigurationSegment; import de.rcenvironment.core.configuration.ConfigurationService; import de.rcenvironment.core.monitoring.common.spi.PeriodicMonitoringDataContributor; import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils; import de.rcenvironment.core.utils.common.StringUtils; import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription; import de.rcenvironment.toolkit.modules.objectbindings.api.ObjectBindingsConsumer; import de.rcenvironment.toolkit.modules.objectbindings.api.ObjectBindingsService; /** * Implementation of a background task that collects all existing {@link PeriodicMonitoringDataContributor}s, and periodically calls those * that are enabled by configuration. * * Note that this class is registered as an OSGi-DS component, but provices no service interface at the moment. * * @author Robert Mischke */ public class PeriodicMonitoringServiceImpl { private static final int DEFAULT_MONITORING_INTERVAL_SECS = 15; private ConfigurationService configurationService; private final Map<String, PeriodicMonitoringDataContributor> contributors = new HashMap<>(); private final Set<String> activeTopics = new HashSet<>(); private final Log log = LogFactory.getLog(getClass()); private ScheduledFuture<?> taskFuture; private int intervalSec = DEFAULT_MONITORING_INTERVAL_SECS; private ObjectBindingsService objectBindingsService; /** * The periodic background task performing the actual data collection and dispatch (for example, writing the generated lines to a log * file). * * @author Robert Mischke */ private final class BackgroundTask implements Runnable { @Override @TaskDescription("Periodic background monitoring task") public void run() { final List<String> output; synchronized (activeTopics) { if (activeTopics.isEmpty()) { return; } output = new ArrayList<>(); synchronized (contributors) { // note: using iterator to allow removal of invalid ids for (Iterator<String> iter = activeTopics.iterator(); iter.hasNext();) { final String id = iter.next(); PeriodicMonitoringDataContributor contributor = contributors.get(id); if (contributor != null) { contributor.generateOutput(id, output); } else { log.warn("No monitoring contributor found for configured monitoring id '" + id + "'; deactivating id"); iter.remove(); } } } } for (String line : output) { log.info(line); } } } /** * OSGi-DS life cycle method. */ public void activate() { if (!CommandLineArguments.isNormalOperationRequested()) { log.debug("Not running in standard mode - not starting background monitoring"); return; } synchronized (activeTopics) { loadConfigurationData(); logActiveTopics(); } // always start the task, as topics may be enabled at a later time // TODO leave at this initial delay or start immediately? taskFuture = ConcurrencyUtils.getAsyncTaskService() .scheduleAtFixedRate(new BackgroundTask(), TimeUnit.SECONDS.toMillis(intervalSec)); objectBindingsService.setConsumer(PeriodicMonitoringDataContributor.class, new ObjectBindingsConsumer<PeriodicMonitoringDataContributor>() { @Override public void addInstance(PeriodicMonitoringDataContributor instance) { addContributor(instance); } @Override public void removeInstance(PeriodicMonitoringDataContributor instance) { removeContributor(instance); } }); } /** * OSGi-DS life cycle method. */ public void deactivate() { if (taskFuture != null) { taskFuture.cancel(false); taskFuture = null; } } private void addContributor(PeriodicMonitoringDataContributor contributor) { synchronized (contributors) { for (String id : contributor.getTopicIds()) { // log.debug("Registering monitoring id " + id); contributors.put(id, contributor); logAvailableMonitoringId(id, contributor); } } } private void removeContributor(PeriodicMonitoringDataContributor contributor) { synchronized (contributors) { for (String id : contributor.getTopicIds()) { // note: this assumes unique topic id log.debug("Unregistering monitoring id " + id); contributors.remove(id); } } } /** * OSGi-DS bind method. * * @param newInstance the provided service instance */ public void bindConfigurationService(ConfigurationService newInstance) { configurationService = newInstance; } /** * OSGi-DS bind method. * * @param newInstance the provided service instance */ public void bindObjectBindingsService(ObjectBindingsService newInstance) { objectBindingsService = newInstance; } private void loadConfigurationData() { synchronized (activeTopics) { activeTopics.clear(); ConfigurationSegment configurationSegment = configurationService.getConfigurationSegment("backgroundMonitoring"); if (configurationSegment != null) { // TODO preliminary format String topicsString = configurationSegment.getString("enabledIds", ""); if (topicsString != null) { for (String rawId : topicsString.split(",")) { final String id = rawId.trim(); if (id.isEmpty()) { continue; } activeTopics.add(id); } } intervalSec = configurationSegment.getInteger("intervalSeconds", DEFAULT_MONITORING_INTERVAL_SECS); if (intervalSec < 1) { log.warn(StringUtils.format("Resource monitoring interval (configuration value 'intervalSeconds') is invalid: " + "it is %d seconds but must be >= 1 second; default value of %d seconds is applied", intervalSec, DEFAULT_MONITORING_INTERVAL_SECS)); intervalSec = DEFAULT_MONITORING_INTERVAL_SECS; } if (activeTopics.isEmpty()) { log.debug("No monitoring topics configured"); } } else { intervalSec = DEFAULT_MONITORING_INTERVAL_SECS; } } } private void logAvailableMonitoringId(String id, PeriodicMonitoringDataContributor contributor) { log.debug(StringUtils.format("Monitoring topic available: \"%s\" (\"%s\")", id, contributor.getTopicDescription(id))); } private void logActiveTopics() { log.debug("Active monitoring topics: " + Arrays.toString(activeTopics.toArray())); } }