All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kieker.analysis.plugin.reader.timer.TimeReader Maven / Gradle / Ivy

There is a newer version: 1.15.4
Show newest version
/***************************************************************************
 * Copyright 2013 Kieker Project (http://kieker-monitoring.net)
 *
 * 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 kieker.analysis.plugin.reader.timer;

import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import kieker.analysis.IProjectContext;
import kieker.analysis.plugin.annotation.OutputPort;
import kieker.analysis.plugin.annotation.Plugin;
import kieker.analysis.plugin.annotation.Property;
import kieker.analysis.plugin.reader.AbstractReaderPlugin;
import kieker.common.configuration.Configuration;
import kieker.common.logging.Log;
import kieker.common.logging.LogFactory;
import kieker.common.record.misc.TimestampRecord;

/**
 * This plugin provides the current (system) time in regular intervals. The time is delivered to the two output ports as both a timestamp and a
 * {@link TimestampRecord} instance.
*
* * The reader can be configured to emit an arbitrary amount of signals. It can also be configured to emit an infinite amount of signals.
*
* * The sent timestamps are created using {@link System#nanoTime()} as a time source, which is being converted to the global time unit (as defined in the * configuration from the given {@link IProjectContext}). * * @author Nils Christian Ehmke * * @since 1.8 */ @Plugin( description = "Delivers the current (system) time in regular intervals", outputPorts = { @OutputPort(name = TimeReader.OUTPUT_PORT_NAME_TIMESTAMPS, eventTypes = Long.class), @OutputPort(name = TimeReader.OUTPUT_PORT_NAME_TIMESTAMP_RECORDS, eventTypes = TimestampRecord.class) }, configuration = { @Property(name = TimeReader.CONFIG_PROPERTY_NAME_UPDATE_INTERVAL_NS, defaultValue = TimeReader.CONFIG_PROPERTY_VALUE_UPDATE_INTERVAL_NS, description = "Determines the update interval in nano seconds."), @Property(name = TimeReader.CONFIG_PROPERTY_NAME_DELAY_NS, defaultValue = TimeReader.CONFIG_PROPERTY_VALUE_DELAY_NS, description = "Determines the initial delay in nano seconds."), @Property(name = TimeReader.CONFIG_PROPERTY_NAME_NUMBER_IMPULSES, defaultValue = TimeReader.CONFIG_PROPERTY_VALUE_NUMBER_IMPULSES, description = "Determines the number of impulses to emit (0 = infinite).") }) public final class TimeReader extends AbstractReaderPlugin { /** The name of the output port for the timestamps. */ public static final String OUTPUT_PORT_NAME_TIMESTAMPS = "timestamps"; /** The name of the output port for the timestamp records. */ public static final String OUTPUT_PORT_NAME_TIMESTAMP_RECORDS = "timestampRecords"; /** The name of the property determining the update interval in nanoseconds. */ public static final String CONFIG_PROPERTY_NAME_UPDATE_INTERVAL_NS = "updateIntervalNS"; /** The default value for the update interval (1 second). */ public static final String CONFIG_PROPERTY_VALUE_UPDATE_INTERVAL_NS = "1000000000"; /** The name of the property determining the initial delay in nanoseconds. */ public static final String CONFIG_PROPERTY_NAME_DELAY_NS = "delayNS"; /** The default value for the initial delay (0 seconds). */ public static final String CONFIG_PROPERTY_VALUE_DELAY_NS = "0"; /** The name of the property determining the number of impulses to emit. */ public static final String CONFIG_PROPERTY_NAME_NUMBER_IMPULSES = "numberImpulses"; /** The default value for number of impulses (infinite). */ public static final String CONFIG_PROPERTY_VALUE_NUMBER_IMPULSES = "0"; /** A value for the number of impulses. It makes sure that the reader emits an infinite amount of signals. */ public static final long INFINITE_EMITS = 0L; private static final Log LOG = LogFactory.getLog(TimeReader.class); final CountDownLatch impulseEmitLatch = new CountDownLatch(1); // NOCS NOPMD (package visible) private volatile boolean terminated; private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1); private volatile ScheduledFuture result; private final long initialDelay; private final long period; private final long numberImpulses; private final TimeUnit timeunit; /** * Creates a new timer using the given configuration. * * @param configuration * The configuration containing the properties to initialize this timer. * @param projectContext * The project context. */ public TimeReader(final Configuration configuration, final IProjectContext projectContext) { super(configuration, projectContext); this.initialDelay = configuration.getLongProperty(CONFIG_PROPERTY_NAME_DELAY_NS); this.period = configuration.getLongProperty(CONFIG_PROPERTY_NAME_UPDATE_INTERVAL_NS); this.numberImpulses = configuration.getLongProperty(CONFIG_PROPERTY_NAME_NUMBER_IMPULSES); final String recordTimeunitProperty = projectContext.getProperty(IProjectContext.CONFIG_PROPERTY_NAME_RECORDS_TIME_UNIT); TimeUnit recordTimeunit; try { recordTimeunit = TimeUnit.valueOf(recordTimeunitProperty); } catch (final IllegalArgumentException ex) { // already caught in AnalysisController, should never happen LOG.warn(recordTimeunitProperty + " is no valid TimeUnit! Using NANOSECONDS instead."); recordTimeunit = TimeUnit.NANOSECONDS; } this.timeunit = recordTimeunit; } /** * {@inheritDoc} */ public void terminate(final boolean error) { if (!this.terminated) { LOG.info("Shutdown of TimeReader requested."); this.executorService.shutdown(); try { this.terminated = this.executorService.awaitTermination(5, TimeUnit.SECONDS); } catch (final InterruptedException ex) { // ignore } if (!this.terminated) { // problems shutting down this.result.cancel(true); } } } /** * {@inheritDoc} */ public boolean read() { this.result = this.executorService.scheduleAtFixedRate(new TimestampEventTask(this.numberImpulses), this.initialDelay, this.period, TimeUnit.NANOSECONDS); try { if (this.numberImpulses == INFINITE_EMITS) { this.result.get(); } else { this.impulseEmitLatch.await(); } } catch (final ExecutionException ex) { this.terminate(true); throw new RuntimeException(ex.getCause()); // NOPMD (throw RunTimeException) } catch (final InterruptedException ignore) { // NOPMD (ignore exception) // ignore this one } catch (final CancellationException ignore) { // NOPMD (ignore exception) // ignore this one, too } this.terminate(false); return true; } @Override public Configuration getCurrentConfiguration() { final Configuration configuration = new Configuration(); configuration.setProperty(CONFIG_PROPERTY_NAME_DELAY_NS, Long.toString(this.initialDelay)); configuration.setProperty(CONFIG_PROPERTY_NAME_UPDATE_INTERVAL_NS, Long.toString(this.period)); configuration.setProperty(CONFIG_PROPERTY_NAME_NUMBER_IMPULSES, Long.toString(this.numberImpulses)); return configuration; } /** * Sends the current system time as a new timestamp event. */ protected void sendTimestampEvent() { final long timestamp = this.timeunit.convert(System.nanoTime(), TimeUnit.NANOSECONDS); super.deliver(OUTPUT_PORT_NAME_TIMESTAMPS, timestamp); super.deliver(OUTPUT_PORT_NAME_TIMESTAMP_RECORDS, new TimestampRecord(timestamp)); } /** * A simple helper class used to send the current system time. * * @author Nils Christian Ehmke * * @since 1.8 */ protected class TimestampEventTask implements Runnable { private final boolean infinite; private volatile long numberImpulses; /** * Creates a new task. * * @param numberImpulses * 0 = infinite */ public TimestampEventTask(final long numberImpulses) { this.numberImpulses = numberImpulses; if (numberImpulses == 0) { this.infinite = true; } else { this.infinite = false; } } /** * Executes the task. */ public void run() { if (this.infinite || (this.numberImpulses > 0)) { TimeReader.this.sendTimestampEvent(); if (!this.infinite && (0 == --this.numberImpulses)) { // NOPMD TimeReader.this.impulseEmitLatch.countDown(); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy