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}