com.heliosapm.streams.collector.timeout.TimeoutService.java Source code

Java tutorial

Introduction

Here is the source code for com.heliosapm.streams.collector.timeout.TimeoutService.java

Source

/*
 * Copyright 2015 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 com.heliosapm.streams.collector.timeout;

import java.util.Set;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.heliosapm.utils.config.ConfigurationHelper;
import com.heliosapm.utils.jmx.JMXHelper;

import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;

/**
 * <p>Title: TimeoutService</p>
 * <p>Description: </p> 
 * <p>Company: Helios Development Group LLC</p>
 * @author Whitehead (nwhitehead AT heliosdev DOT org)
 * <p><code>com.heliosapm.streams.collector.TimeoutService</code></p>
 */

public class TimeoutService implements TimeoutServiceMBean, ThreadFactory, Timer {
    /** The singleton instance */
    private static volatile TimeoutService instance;
    /** The singleton instance ctor lock */
    private static final Object lock = new Object();

    /** The config key for the tick duration in ms. */
    public static final String CONFIG_TICK_DURATION = "timeoutservice.tick.duration";
    /** The default tick duration in ms. */
    public static final long DEFAULT_TICK_DURATION = 100;
    /** The config key for the ticks per wheel */
    public static final String CONFIG_TICK_COUNT = "timeoutservice.tick.count";
    /** The default ticks per wheel */
    public static final int DEFAULT_TICK_COUNT = 512;

    /** The created thread serial factory */
    private final AtomicInteger serial = new AtomicInteger(0);
    /** Instance logger */
    private final Logger log = LogManager.getLogger(getClass());
    /** The timer */
    private final HashedWheelTimer timer;
    /** The timer tick duration in ms. */
    private final long tickDuration;
    /** The timer ticks per wheel */
    private final int tickCount;
    /** A gauge of pending timeouts */
    protected final AtomicInteger pendingTimeouts = new AtomicInteger();
    /** A counter of timeouts */
    protected final LongAdder timeouts = new LongAdder();
    /** A counter of on time cancellations */
    protected final LongAdder cancellations = new LongAdder();
    /** The timeout thread's thread group */
    protected final ThreadGroup timeoutThreadGroup = new ThreadGroup("HeliosTimeoutService");

    /**
     * Acquires and returns the TimeoutService singleton instance
     * @return the TimeoutService singleton instance
     */
    public static TimeoutService getInstance() {
        if (instance == null) {
            synchronized (lock) {
                if (instance == null) {
                    instance = new TimeoutService();
                }
            }
        }
        return instance;
    }

    private TimeoutService() {
        tickDuration = ConfigurationHelper.getLongSystemThenEnvProperty(CONFIG_TICK_DURATION,
                DEFAULT_TICK_DURATION);
        tickCount = ConfigurationHelper.getIntSystemThenEnvProperty(CONFIG_TICK_COUNT, DEFAULT_TICK_COUNT);
        timer = new HashedWheelTimer(this, tickDuration, TimeUnit.MILLISECONDS, tickCount);
        timer.start();
        JMXHelper.registerMBean(this, OBJECT_NAME);
        log.info("TimeoutService started");
    }

    /**
     * {@inheritDoc}
     * @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
     */
    @Override
    public Thread newThread(final Runnable r) {
        final Thread t = new Thread(timeoutThreadGroup, r, "HeliosTimeoutService#" + serial.incrementAndGet());
        t.setDaemon(true);
        t.setPriority(Thread.MAX_PRIORITY);
        return t;
    }

    private class WrappedTimeout implements Timeout {
        private final Timeout timeout;

        /**
         * Creates a new WrappedTimeout
         * @param timeout the timeout to wrap
         */
        public WrappedTimeout(final Timeout timeout) {
            this.timeout = timeout;
            pendingTimeouts.incrementAndGet();
        }

        /**
         * Returns the hashedwheel timer that created this timeout
         * @return this timeout service
         * @see io.netty.util.Timeout#timer()
         */
        @Override
        public Timer timer() {
            return instance;
        }

        /**
         * Returns the task this timeout will run
         * @return the task this timeout will run
         * @see io.netty.util.Timeout#task()
         */
        @Override
        public TimerTask task() {
            return timeout.task();
        }

        /**
         * Indicates if this task is expired
         * @return true if this task is expired, false otherwise
         * @see io.netty.util.Timeout#isExpired()
         */
        @Override
        public boolean isExpired() {
            return timeout.isExpired();
        }

        /**
         * Indicates if this task is cancelled
         * @return true if this task is cancelled, false otherwise
         * @see io.netty.util.Timeout#isCancelled()
         */
        @Override
        public boolean isCancelled() {
            return timeout.isCancelled();
        }

        /**
         * Cancels this task
         * @return true if the task was cancelled, false if the task was cancelled or already executed
         * @see io.netty.util.Timeout#cancel()
         */
        @Override
        public boolean cancel() {
            final boolean cancelled = timeout.cancel();
            if (cancelled) {
                pendingTimeouts.decrementAndGet();
                cancellations.increment();
            }
            return timeout.cancel();
        }

    }

    /**
     * Schedules a task to run on the timeout period
     * @param delay the timeout period
     * @param unit the timeout unit
     * @param onTimeout the task to execute if the timer expires
     * @return the timeout handle
     */
    public Timeout timeout(final long delay, final TimeUnit unit, final Runnable onTimeout) {
        return new WrappedTimeout(timer.newTimeout(new TimerTask() {
            @Override
            public void run(final Timeout timeout) throws Exception {
                try {
                    onTimeout.run();
                } finally {
                    pendingTimeouts.decrementAndGet();
                    timeouts.increment();
                }
            }
        }, delay, unit));
    }

    /**
     * Schedules a task to run on the timeout period in ms.
     * @param delay the timeout period
     * @param onTimeout the task to execute if the timer expires
     * @return the timeout handle
     */
    public Timeout timeout(final long delay, final Runnable onTimeout) {
        return timeout(delay, TimeUnit.MILLISECONDS, onTimeout);
    }

    /**
     * {@inheritDoc}
     * @see io.netty.util.Timer#newTimeout(io.netty.util.TimerTask, long, java.util.concurrent.TimeUnit)
     */
    @Override
    public Timeout newTimeout(final TimerTask task, final long delay, final TimeUnit unit) {
        final WrappedTimeout[] t = new WrappedTimeout[1];
        t[0] = new WrappedTimeout(timer.newTimeout(new TimerTask() {
            @Override
            public void run(final Timeout timeout) throws Exception {
                try {
                    task.run(t[0]);
                } finally {
                    pendingTimeouts.decrementAndGet();
                    timeouts.increment();
                }
            }
        }, delay, unit));
        return t[0];
    }

    /**
     * <p>Overriden to no op</p>
     * {@inheritDoc}
     * @see io.netty.util.Timer#stop()
     */
    @Override
    public Set<Timeout> stop() {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     * @see com.heliosapm.streams.collector.timeout.TimeoutServiceMBean#getCancellations()
     */
    @Override
    public long getCancellations() {
        return cancellations.longValue();
    }

    /**
     * {@inheritDoc}
     * @see com.heliosapm.streams.collector.timeout.TimeoutServiceMBean#getTimeouts()
     */
    @Override
    public long getTimeouts() {
        return timeouts.longValue();
    }

    /**
     * {@inheritDoc}
     * @see com.heliosapm.streams.collector.timeout.TimeoutServiceMBean#getActiveThreads()
     */
    @Override
    public int getActiveThreads() {
        return timeoutThreadGroup.activeCount();
    }

    /**
     * {@inheritDoc}
     * @see com.heliosapm.streams.collector.timeout.TimeoutServiceMBean#getPending()
     */
    @Override
    public int getPending() {
        return pendingTimeouts.get();
    }

}