com.quartercode.disconnected.sim.run.Ticker.java Source code

Java tutorial

Introduction

Here is the source code for com.quartercode.disconnected.sim.run.Ticker.java

Source

/*
 * This file is part of Disconnected.
 * Copyright (c) 2013 QuarterCode <http://www.quartercode.com/>
 *
 * Disconnected is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Disconnected is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Disconnected. If not, see <http://www.gnu.org/licenses/>.
 */

package com.quartercode.disconnected.sim.run;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.Validate;

/**
 * This class implements the controls for the tick system which then calls several actions.
 * It's like a central hub for controlling the activity of the tick thread.
 * 
 * @see TickThread
 */
public class Ticker {

    /**
     * The amount of milliseconds the ticker will wait from one tick to another by default.
     */
    public static final int DEFAULT_DELAY = 50;

    /**
     * The amount of ticks called in one second by default.
     */
    public static final int DEFAULT_TICKS_PER_SECOND = 1000 / DEFAULT_DELAY;

    private static final Logger LOGGER = Logger.getLogger(Ticker.class.getName());

    private TickThread thread;
    private final List<TickAction> actions = new ArrayList<TickAction>();
    private int delay = DEFAULT_DELAY;

    /**
     * Creates a new ticker without any tick actions.
     */
    public Ticker() {

    }

    /**
     * Creates a new ticker and initalizes some default tick actions.
     * 
     * @param actions A list of default tick actions which get called on every tick.
     */
    public Ticker(TickAction... actions) {

        this.actions.addAll(Arrays.asList(actions));
    }

    /**
     * Returns a list of tick actions which get called on every tick.
     * 
     * @return A list of tick actions which get called on every tick.
     */
    public List<TickAction> getActions() {

        return Collections.unmodifiableList(actions);
    }

    /**
     * Returns the tick actions which has the given type as a superclass.
     * 
     * @param type The type to use.
     * @return The tick actions which has the given type as a superclass.
     */
    public <T> T getAction(Class<T> type) {

        for (TickAction action : actions) {
            if (type.isAssignableFrom(action.getClass())) {
                return type.cast(action);
            }
        }

        return null;
    }

    /**
     * Adds a tick action which gets called on every tick.
     * You can only add actions if there no other action using the same class.
     * 
     * @param action A tick action which gets called on every tick.
     * @throws IllegalStateException If there is already an other action using the same class.
     */
    public void addAction(TickAction action) {

        for (TickAction testAction : actions) {
            if (testAction.getClass().equals(action.getClass())) {
                throw new IllegalStateException(
                        "There is already a tick action using the class " + testAction.getClass().getName());
            }
        }

        actions.add(action);
    }

    /**
     * Removes a tick action from the tick thread.
     * 
     * @param action The tick action to remove from the tick thread.
     */
    public void removeAction(TickAction action) {

        actions.remove(action);
    }

    /**
     * Returns the delay the thread should wait until the next tick.
     * 
     * @return The delay the thread should wait until the next tick.
     */
    public int getDelay() {

        return delay;
    }

    /**
     * Sets the delay the thread should wait until the next tick.
     * 
     * @param delay The delay the thread should wait until the next tick.
     */
    public void setDelay(int delay) {

        Validate.isTrue(delay > 0, "Delay must be > 0: ", delay);
        this.delay = delay;
    }

    /**
     * Returns if the tick thread is currently running.
     * 
     * @return If the tick thread is currently running.
     */
    public boolean isRunning() {

        return thread != null && thread.isAlive();
    }

    /**
     * Changes the status of the tick thread.
     * This can start and stop the tick update.
     * 
     * @param running If the tick thread should run.
     */
    public void setRunning(boolean running) {

        if (running && !isRunning()) {
            thread = new TickThread(this);
            thread.start();
        } else if (!running && isRunning()) {
            thread.interrupt();
            thread = null;
        }
    }

    /**
     * Returns the current tick thread which executes the actual tick update.
     * If the update is not running, this returns null.
     * 
     * @return The current tick thread which executes the actual tick update.
     */
    public TickThread getThread() {

        return thread;
    }

    /**
     * This thread calls the tick update on several tick actions.
     * It's an independent utility.
     */
    public static class TickThread extends Thread {

        private final Ticker ticker;

        /**
         * Creates a new tick thread and sets the ticker to use the informations from.
         * 
         * @param ticker The ticker to use the informations for the actions and the delay from.
         */
        public TickThread(Ticker ticker) {

            super("tick");

            this.ticker = ticker;
        }

        /**
         * Returns the ticker to use the informations for the actions and the delay from.
         * 
         * @return The ticker to use the informations for the actions and the delay from.
         */
        public Ticker getTicker() {

            return ticker;
        }

        @Override
        public void run() {

            while (!isInterrupted()) {
                synchronized (this) {
                    for (TickAction action : new ArrayList<TickAction>(ticker.getActions())) {
                        try {
                            action.update();
                        } catch (Throwable t) {
                            LOGGER.log(Level.SEVERE,
                                    "An exception occurred while executing tick action update (tick action "
                                            + action.getClass().getName() + ")",
                                    t);
                        }
                    }

                    try {
                        Thread.sleep(ticker.getDelay());
                    } catch (InterruptedException e) {
                        LOGGER.log(Level.SEVERE, "Tick thread has been interrupted", e);
                    }
                }
            }
        }

    }

}