001/*
002 * Ad Hoc Polling Application
003 * Copyright (C) 2018-2026 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
013 * License for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License
016 * along 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=").append(Channel.toString(channels()));
079        }
080        builder.append(']');
081        return builder.toString();
082    }
083
084    /**
085     * An {@link ActionEvent} that executes a {@link Callable}.
086     *
087     * @param <V> the value type
088     */
089    private static class CallableActionEvent<V> extends ActionEvent<V> {
090        private final Callable<V> action;
091
092        /**
093         * Instantiates a new callable action event.
094         *
095         * @param name the name
096         * @param callable the callable
097         */
098        public CallableActionEvent(String name, Callable<V> callable) {
099            super(name);
100            this.action = callable;
101        }
102
103        @Override
104        /* default */ void execute() throws Exception {
105            setResult(action.call());
106        }
107    }
108
109    /**
110     * An {@link ActionEvent} that executes a {@link Runnable}.
111     */
112    private static class RunnableActionEvent extends ActionEvent<Void> {
113        private final Runnable action;
114
115        /**
116         * Instantiates a new runnable action event.
117         *
118         * @param name the name
119         * @param action the action
120         */
121        public RunnableActionEvent(String name, Runnable action) {
122            super(name);
123            this.action = action;
124        }
125
126        @Override
127        /* default */ void execute() throws Exception {
128            action.run();
129        }
130
131    }
132}