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;
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 <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
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
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<State> lastState = reactionState.loadLastState();
saveStateWithIncreasedFailCount(state);
+ if (thisFailureIsTheFirstFailure(lastState)) {
+ errorEmailAction.execute(createErrorOutput(reaction, state));
+ }
return;
}
Optional<State> lastSuccessfulState = reactionState.loadLastSuccessfulState();
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<State> lastState) {
+ return lastState.map(State::success).orElse(true);
+ }
+
private void saveStateWithIncreasedFailCount(State state) {
Optional<State> 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 {
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);
}
}
}