001/*
002 * Ad Hoc Polling Application
003 * Copyright (C) 2018 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.core.internal;
020
021import java.util.concurrent.Callable;
022import org.jgrapes.core.Channel;
023import org.jgrapes.core.Components;
024import org.jgrapes.core.Event;
025import org.jgrapes.core.EventPipeline;
026
027/**
028 * A base class for events that perform an action instead of being
029 * handled. Use to synchronize some action with the other events on
030 * an {@link EventPipeline}.
031 */
032public abstract class ActionEvent<T> extends Event<T> {
033
034    private static Object defaultCriterion = new Object();
035    protected String name;
036
037    /**
038     * Instantiates a new action event.
039     *
040     * @param name the name
041     */
042    protected ActionEvent(String name) {
043        this.name = name;
044    }
045
046    /* default */ static <V> ActionEvent<V> create(String name,
047            Callable<V> action) {
048        return new CallableActionEvent<>(name, action);
049    }
050
051    /* default */ static ActionEvent<Void> create(String name,
052            Runnable action) {
053        return new RunnableActionEvent(name, action);
054    }
055
056    @SuppressWarnings("PMD.SignatureDeclareThrowsException")
057    /* default */ abstract void execute() throws Exception;
058
059    @Override
060    public boolean isEligibleFor(Object criterion) {
061        return criterion == defaultCriterion; // NOPMD, comparing references
062    }
063
064    @Override
065    public Object defaultCriterion() {
066        return defaultCriterion;
067    }
068
069    @Override
070    public String toString() {
071        StringBuilder builder = new StringBuilder();
072        builder.append(Components.objectName(this));
073        if (name != null) {
074            builder.append('(').append(name).append(')');
075        }
076        builder.append(" [");
077        if (channels() != null) {
078            builder.append("channels=");
079            builder.append(Channel.toString(channels()));
080        }
081        builder.append(']');
082        return builder.toString();
083    }
084
085    /**
086     * An {@link ActionEvent} that executes a {@link Callable}.
087     *
088     * @param <V> the value type
089     */
090    private static class CallableActionEvent<V> extends ActionEvent<V> {
091        private final Callable<V> action;
092
093        /**
094         * Instantiates a new callable action event.
095         *
096         * @param name the name
097         * @param callable the callable
098         */
099        public CallableActionEvent(String name, Callable<V> callable) {
100            super(name);
101            this.action = callable;
102        }
103
104        @SuppressWarnings("PMD.SignatureDeclareThrowsException")
105        /* default */ void execute() throws Exception {
106            setResult(action.call());
107        }
108    }
109
110    /**
111     * An {@link ActionEvent} that executes a {@link Runnable}.
112     */
113    private static class RunnableActionEvent extends ActionEvent<Void> {
114        private final Runnable action;
115
116        /**
117         * Instantiates a new runnable action event.
118         *
119         * @param name the name
120         * @param action the action
121         */
122        public RunnableActionEvent(String name, Runnable action) {
123            super(name);
124            this.action = action;
125        }
126
127        @SuppressWarnings("PMD.SignatureDeclareThrowsException")
128        /* default */ void execute() throws Exception {
129            action.run();
130        }
131
132    }
133}