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;
022
023import org.jgrapes.core.Channel;
024import org.jgrapes.core.Components;
025import org.jgrapes.core.Event;
026import org.jgrapes.core.EventPipeline;
027
028/**
029 * A base class for events that perform an action instead of being
030 * handled. Use to synchronize some action with th eother events on
031 * an {@link EventPipeline}.
032 */
033public abstract class ActionEvent<T> extends Event<T> {
034
035    private static Object defaultCriterion = new Object();
036    protected String name;
037
038    /**
039     * Instantiates a new action event.
040     *
041     * @param name the name
042     */
043    protected ActionEvent(String name) {
044        this.name = name;
045    }
046
047    /* default */ static <V> ActionEvent<V> create(String name,
048            Callable<V> action) {
049        return new CallableActionEvent<>(name, action);
050    }
051
052    /* default */ static ActionEvent<Void> create(String name,
053            Runnable action) {
054        return new RunnableActionEvent(name, action);
055    }
056
057    @SuppressWarnings("PMD.SignatureDeclareThrowsException")
058    /* default */ abstract void execute() throws Exception;
059
060    @Override
061    public boolean isEligibleFor(Object criterion) {
062        return criterion == defaultCriterion; // NOPMD, comparing references
063    }
064
065    @Override
066    public Object defaultCriterion() {
067        return defaultCriterion;
068    }
069
070    @Override
071    public String toString() {
072        StringBuilder builder = new StringBuilder();
073        builder.append(Components.objectName(this));
074        if (name != null) {
075            builder.append('(').append(name).append(')');
076        }
077        builder.append(" [");
078        if (channels() != null) {
079            builder.append("channels=");
080            builder.append(Channel.toString(channels()));
081        }
082        builder.append(']');
083        return builder.toString();
084    }
085
086    /**
087     * An {@link ActionEvent} that executes a {@link Callable}.
088     *
089     * @param <V> the value type
090     */
091    private static class CallableActionEvent<V> extends ActionEvent<V> {
092        private final Callable<V> action;
093
094        /**
095         * Instantiates a new callable action event.
096         *
097         * @param name the name
098         * @param callable the callable
099         */
100        public CallableActionEvent(String name, Callable<V> callable) {
101            super(name);
102            this.action = callable;
103        }
104
105        @SuppressWarnings("PMD.SignatureDeclareThrowsException")
106        /* default */ void execute() throws Exception {
107            setResult(action.call());
108        }
109    }
110
111    /**
112     * An {@link ActionEvent} that executes a {@link Runnable}.
113     */
114    private static class RunnableActionEvent extends ActionEvent<Void> {
115        private final Runnable action;
116
117        /**
118         * Instantiates a new runnable action event.
119         *
120         * @param name the name
121         * @param action the action
122         */
123        public RunnableActionEvent(String name, Runnable action) {
124            super(name);
125            this.action = action;
126        }
127
128        @SuppressWarnings("PMD.SignatureDeclareThrowsException")
129        /* default */ void execute() throws Exception {
130            action.run();
131        }
132
133    }
134}