X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Frhynodge%2Fengine%2FReactionRunner.java;h=45642cebc6c696b545540cb271bbded6552feb5b;hb=8aeef90590095a455e2323d70ba8ccae032f4276;hp=37bec1071bc4f65715e31c57db359a4ac265ea13;hpb=09c47ffd3d61d5d8d63e95d253318ec361433c76;p=rhynodge.git diff --git a/src/main/java/net/pterodactylus/rhynodge/engine/ReactionRunner.java b/src/main/java/net/pterodactylus/rhynodge/engine/ReactionRunner.java index 37bec10..45642ce 100644 --- a/src/main/java/net/pterodactylus/rhynodge/engine/ReactionRunner.java +++ b/src/main/java/net/pterodactylus/rhynodge/engine/ReactionRunner.java @@ -5,6 +5,9 @@ import static java.util.Optional.ofNullable; import static net.pterodactylus.rhynodge.states.FailedState.INSTANCE; import static org.apache.log4j.Logger.getLogger; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Optional; import net.pterodactylus.rhynodge.Action; @@ -12,14 +15,17 @@ import net.pterodactylus.rhynodge.Filter; import net.pterodactylus.rhynodge.Query; import net.pterodactylus.rhynodge.Reaction; import net.pterodactylus.rhynodge.State; -import net.pterodactylus.rhynodge.Trigger; +import net.pterodactylus.rhynodge.actions.EmailAction; +import net.pterodactylus.rhynodge.Merger; +import net.pterodactylus.rhynodge.output.DefaultOutput; +import net.pterodactylus.rhynodge.output.Output; import net.pterodactylus.rhynodge.states.FailedState; import org.apache.log4j.Logger; /** * Runs a {@link Reaction}, starting with its {@link Query}, running the {@link - * State} through its {@link Filter}s, and finally checking the {@link Trigger} + * State} through its {@link Filter}s, and finally checking the {@link Merger} * for whether an {@link Action} needs to be executed. * * @author David ‘Bombe’ Roden @@ -29,10 +35,12 @@ public class ReactionRunner implements Runnable { private static final Logger logger = getLogger(ReactionRunner.class); private final Reaction reaction; private final ReactionState reactionState; + private final EmailAction errorEmailAction; - public ReactionRunner(Reaction reaction, ReactionState reactionState) { + public ReactionRunner(Reaction reaction, ReactionState reactionState, EmailAction errorEmailAction) { this.reactionState = reactionState; this.reaction = reaction; + this.errorEmailAction = errorEmailAction; } @Override @@ -40,8 +48,12 @@ public class ReactionRunner implements Runnable { State state = runQuery(); state = runStateThroughFilters(state); if (!state.success()) { - logger.info(format("Reaction %s failed.", reaction.name())); + logger.info(format("Reaction %s failed in %s.", reaction.name(), state)); + Optional lastState = reactionState.loadLastState(); saveStateWithIncreasedFailCount(state); + if (thisFailureIsTheFirstFailure(lastState)) { + errorEmailAction.execute(createErrorOutput(reaction, state)); + } return; } Optional lastSuccessfulState = reactionState.loadLastSuccessfulState(); @@ -50,22 +62,53 @@ public class ReactionRunner implements Runnable { reactionState.saveState(state); return; } - Trigger trigger = reaction.trigger(); - State newState = trigger.mergeStates(lastSuccessfulState.get(), state); + Merger merger = reaction.merger(); + State newState = merger.mergeStates(lastSuccessfulState.get(), state); reactionState.saveState(newState); - if (trigger.triggers()) { + if (newState.triggered()) { logger.info(format("Trigger was hit for %s, executing action...", reaction.name())); - reaction.action().execute(trigger.output(reaction)); + reaction.action().execute(newState.output(reaction)); } logger.info(format("Reaction %s finished.", reaction.name())); } + private static boolean thisFailureIsTheFirstFailure(Optional lastState) { + return lastState.map(State::success).orElse(true); + } + private void saveStateWithIncreasedFailCount(State state) { Optional lastState = reactionState.loadLastState(); state.setFailCount(lastState.map(State::failCount).orElse(0) + 1); reactionState.saveState(state); } + private Output createErrorOutput(Reaction reaction, State state) { + DefaultOutput output = new DefaultOutput(String.format("Error while processing “%s!”", reaction.name())); + output.addText("text/plain", createErrorEmailText(reaction, state)); + output.addText("text/html", createErrorEmailText(reaction, state)); + return output; + } + + private String createErrorEmailText(Reaction reaction, State state) { + StringBuilder emailText = new StringBuilder(); + emailText.append(String.format("An error occured while processing “%s.”\n\n", reaction.name())); + appendExceptionToEmailText(state.exception(), emailText); + return emailText.toString(); + } + + private void appendExceptionToEmailText(Throwable exception, StringBuilder emailText) { + if (exception != null) { + try (StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter)) { + exception.printStackTrace(printWriter); + emailText.append(stringWriter.toString()); + } catch (IOException ioe1) { + /* StringWriter doesn’t throw. */ + throw new RuntimeException(ioe1); + } + } + } + private State runQuery() { logger.info(format("Querying %s...", reaction.name())); try { @@ -85,6 +128,7 @@ public class ReactionRunner implements Runnable { currentState = filter.filter(currentState); } catch (Throwable t1) { logger.warn(format("Error during filter %s for %s.", filter.getClass().getSimpleName(), reaction.name()), t1); + return new FailedState(t1); } } }