diff --git a/src/main/java/org/elasticsearch/watcher/WatcherModule.java b/src/main/java/org/elasticsearch/watcher/WatcherModule.java index 5e6261dd034..c7bd278e300 100644 --- a/src/main/java/org/elasticsearch/watcher/WatcherModule.java +++ b/src/main/java/org/elasticsearch/watcher/WatcherModule.java @@ -17,7 +17,6 @@ import org.elasticsearch.watcher.condition.ConditionModule; import org.elasticsearch.watcher.history.HistoryModule; import org.elasticsearch.watcher.input.InputModule; import org.elasticsearch.watcher.rest.WatcherRestModule; -import org.elasticsearch.watcher.scheduler.SchedulerModule; import org.elasticsearch.watcher.shield.WatcherShieldModule; import org.elasticsearch.watcher.support.TemplateUtils; import org.elasticsearch.watcher.support.clock.ClockModule; @@ -25,6 +24,7 @@ import org.elasticsearch.watcher.support.init.InitializingModule; import org.elasticsearch.watcher.support.template.TemplateModule; import org.elasticsearch.watcher.transform.TransformModule; import org.elasticsearch.watcher.transport.WatcherTransportModule; +import org.elasticsearch.watcher.trigger.TriggerModule; import org.elasticsearch.watcher.watch.WatchModule; @@ -46,7 +46,7 @@ public class WatcherModule extends AbstractModule implements SpawnModules { new WatcherClientModule(), new TransformModule(), new WatcherRestModule(), - new SchedulerModule(), + new TriggerModule(), new WatcherTransportModule(), new ConditionModule(), new InputModule(), diff --git a/src/main/java/org/elasticsearch/watcher/client/WatchSourceBuilder.java b/src/main/java/org/elasticsearch/watcher/client/WatchSourceBuilder.java index 5d6c62df393..b241d83e378 100644 --- a/src/main/java/org/elasticsearch/watcher/client/WatchSourceBuilder.java +++ b/src/main/java/org/elasticsearch/watcher/client/WatchSourceBuilder.java @@ -5,13 +5,13 @@ */ package org.elasticsearch.watcher.client; +import org.elasticsearch.watcher.trigger.Trigger; import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.ConditionBuilders; import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.NoneInput; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; import org.elasticsearch.watcher.transform.Transform; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.unit.TimeValue; @@ -35,7 +35,7 @@ public class WatchSourceBuilder implements ToXContent { return new WatchSourceBuilder(); } - private Schedule schedule; + private Trigger.SourceBuilder trigger; private Input.SourceBuilder input = NoneInput.SourceBuilder.INSTANCE; private Condition.SourceBuilder condition = ConditionBuilders.alwaysTrueCondition(); private Transform.SourceBuilder transform = null; @@ -43,8 +43,8 @@ public class WatchSourceBuilder implements ToXContent { private TimeValue throttlePeriod = null; private Map metadata; - public WatchSourceBuilder schedule(Schedule schedule) { - this.schedule = schedule; + public WatchSourceBuilder trigger(Trigger.SourceBuilder trigger) { + this.trigger = trigger; return this; } @@ -82,8 +82,8 @@ public class WatchSourceBuilder implements ToXContent { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.startObject(Watch.Parser.SCHEDULE_FIELD.getPreferredName()) - .field(schedule.type(), schedule) + builder.startObject(Watch.Parser.TRIGGER_FIELD.getPreferredName()) + .field(trigger.type(), trigger) .endObject(); builder.startObject(Watch.Parser.INPUT_FIELD.getPreferredName()) diff --git a/src/main/java/org/elasticsearch/watcher/history/HistoryService.java b/src/main/java/org/elasticsearch/watcher/history/HistoryService.java index a5d36babce5..46c4d82e2bf 100644 --- a/src/main/java/org/elasticsearch/watcher/history/HistoryService.java +++ b/src/main/java/org/elasticsearch/watcher/history/HistoryService.java @@ -6,23 +6,24 @@ package org.elasticsearch.watcher.history; import org.elasticsearch.ElasticsearchIllegalStateException; -import org.elasticsearch.watcher.actions.Action; -import org.elasticsearch.watcher.condition.Condition; -import org.elasticsearch.watcher.input.Input; -import org.elasticsearch.watcher.scheduler.Scheduler; -import org.elasticsearch.watcher.support.Callback; -import org.elasticsearch.watcher.support.clock.Clock; -import org.elasticsearch.watcher.throttle.Throttler; -import org.elasticsearch.watcher.transform.Transform; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateListener; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; +import org.elasticsearch.watcher.actions.Action; +import org.elasticsearch.watcher.condition.Condition; +import org.elasticsearch.watcher.input.Input; +import org.elasticsearch.watcher.support.Callback; +import org.elasticsearch.watcher.support.clock.Clock; +import org.elasticsearch.watcher.throttle.Throttler; +import org.elasticsearch.watcher.transform.Transform; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.TriggerEvent; +import org.elasticsearch.watcher.trigger.TriggerService; import org.elasticsearch.watcher.watch.*; import java.io.IOException; @@ -48,7 +49,7 @@ public class HistoryService extends AbstractComponent { @Inject public HistoryService(Settings settings, HistoryStore historyStore, WatchExecutor executor, - WatchStore watchStore, WatchLockService watchLockService, Scheduler scheduler, + WatchStore watchStore, WatchLockService watchLockService, TriggerService triggerService, ClusterService clusterService, Clock clock) { super(settings); this.historyStore = historyStore; @@ -57,7 +58,7 @@ public class HistoryService extends AbstractComponent { this.watchLockService = watchLockService; this.clusterService = clusterService; this.clock = clock; - scheduler.addListener(new SchedulerListener()); + triggerService.register(new SchedulerListener()); } public void start(ClusterState state, Callback callback) { @@ -106,11 +107,11 @@ public class HistoryService extends AbstractComponent { return executor.largestPoolSize(); } - void execute(Watch watch, DateTime scheduledFireTime, DateTime fireTime) throws HistoryException { + void execute(Watch watch, TriggerEvent event) throws HistoryException { if (!started.get()) { throw new ElasticsearchIllegalStateException("not started"); } - WatchRecord watchRecord = new WatchRecord(watch, scheduledFireTime, fireTime); + WatchRecord watchRecord = new WatchRecord(watch, event); logger.debug("saving watch record [{}]", watch.name()); historyStore.put(watchRecord); executeAsync(watchRecord, watch); @@ -223,7 +224,7 @@ public class HistoryService extends AbstractComponent { try { watchRecord.update(WatchRecord.State.CHECKING, null); logger.debug("checking watch [{}]", watchRecord.name()); - WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, clock.now(), watchRecord.fireTime(), watchRecord.scheduledTime()); + WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, clock.now(), watchRecord.triggerEvent()); WatchExecution execution = execute(ctx); watchRecord.seal(execution); historyStore.update(watchRecord); @@ -247,9 +248,10 @@ public class HistoryService extends AbstractComponent { } - private class SchedulerListener implements Scheduler.Listener { + private class SchedulerListener implements TriggerEngine.Listener { + @Override - public void fire(String name, DateTime scheduledFireTime, DateTime fireTime) { + public void triggered(String name, TriggerEvent event) { if (!started.get()) { throw new ElasticsearchIllegalStateException("not started"); } @@ -259,7 +261,7 @@ public class HistoryService extends AbstractComponent { return; } try { - HistoryService.this.execute(watch, scheduledFireTime, fireTime); + HistoryService.this.execute(watch, event); } catch (Exception e) { logger.error("failed to execute watch [{}]", e, name); } diff --git a/src/main/java/org/elasticsearch/watcher/history/HistoryStore.java b/src/main/java/org/elasticsearch/watcher/history/HistoryStore.java index d5393e3a679..e44f063c34c 100644 --- a/src/main/java/org/elasticsearch/watcher/history/HistoryStore.java +++ b/src/main/java/org/elasticsearch/watcher/history/HistoryStore.java @@ -58,7 +58,7 @@ public class HistoryStore extends AbstractComponent { } public void put(WatchRecord watchRecord) throws HistoryException { - String index = getHistoryIndexNameForTime(watchRecord.scheduledTime()); + String index = getHistoryIndexNameForTime(watchRecord.triggerEvent().triggeredTime()); try { IndexRequest request = new IndexRequest(index, DOC_TYPE, watchRecord.id()) .source(XContentFactory.jsonBuilder().value(watchRecord)) @@ -74,7 +74,7 @@ public class HistoryStore extends AbstractComponent { logger.debug("updating watch record [{}]...", watchRecord); try { BytesReference bytes = XContentFactory.jsonBuilder().value(watchRecord).bytes(); - IndexRequest request = new IndexRequest(getHistoryIndexNameForTime(watchRecord.scheduledTime()), DOC_TYPE, watchRecord.id()) + IndexRequest request = new IndexRequest(getHistoryIndexNameForTime(watchRecord.triggerEvent().triggeredTime()), DOC_TYPE, watchRecord.id()) .source(bytes, true) .version(watchRecord.version()); IndexResponse response = client.index(request); diff --git a/src/main/java/org/elasticsearch/watcher/history/WatchRecord.java b/src/main/java/org/elasticsearch/watcher/history/WatchRecord.java index 9e6521d6ccf..4e547802ca3 100644 --- a/src/main/java/org/elasticsearch/watcher/history/WatchRecord.java +++ b/src/main/java/org/elasticsearch/watcher/history/WatchRecord.java @@ -6,8 +6,16 @@ package org.elasticsearch.watcher.history; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.watcher.watch.Watch; -import org.elasticsearch.watcher.watch.WatchExecution; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.watcher.WatcherException; import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.watcher.actions.ActionRegistry; @@ -16,17 +24,10 @@ import org.elasticsearch.watcher.condition.ConditionRegistry; import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.InputRegistry; import org.elasticsearch.watcher.transform.TransformRegistry; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.component.AbstractComponent; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentHelper; -import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.trigger.TriggerEvent; +import org.elasticsearch.watcher.trigger.TriggerService; +import org.elasticsearch.watcher.watch.Watch; +import org.elasticsearch.watcher.watch.WatchExecution; import java.io.IOException; import java.util.Locale; @@ -37,8 +38,7 @@ public class WatchRecord implements ToXContent { private String id; private String name; - private DateTime fireTime; - private DateTime scheduledTime; + private TriggerEvent triggerEvent; private Input input; private Condition condition; private State state; @@ -55,11 +55,10 @@ public class WatchRecord implements ToXContent { WatchRecord() { } - public WatchRecord(Watch watch, DateTime scheduledTime, DateTime fireTime) { - this.id = watch.name() + "#" + scheduledTime.toDateTimeISO(); + public WatchRecord(Watch watch, TriggerEvent triggerEvent) { + this.id = watch.name() + "#" + triggerEvent.triggeredTime().toDateTimeISO(); this.name = watch.name(); - this.fireTime = fireTime; - this.scheduledTime = scheduledTime; + this.triggerEvent = triggerEvent; this.condition = watch.condition(); this.input = watch.input(); this.state = State.AWAITS_EXECUTION; @@ -71,18 +70,14 @@ public class WatchRecord implements ToXContent { return id; } - public DateTime scheduledTime() { - return scheduledTime; + public TriggerEvent triggerEvent() { + return triggerEvent; } public String name() { return name; } - public DateTime fireTime() { - return fireTime; - } - public Input input() { return input; } public Condition condition() { @@ -129,27 +124,28 @@ public class WatchRecord implements ToXContent { } @Override - public XContentBuilder toXContent(XContentBuilder historyEntry, Params params) throws IOException { - historyEntry.startObject(); - historyEntry.field(Parser.WATCH_NAME_FIELD.getPreferredName(), name); - historyEntry.field(Parser.FIRE_TIME_FIELD.getPreferredName(), fireTime.toDateTimeISO()); - historyEntry.field(Parser.SCHEDULED_FIRE_TIME_FIELD.getPreferredName(), scheduledTime.toDateTimeISO()); - historyEntry.startObject(Watch.Parser.CONDITION_FIELD.getPreferredName()).field(condition.type(), condition, params).endObject(); - historyEntry.field(Parser.STATE_FIELD.getPreferredName(), state.id()); + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Parser.WATCH_NAME_FIELD.getPreferredName(), name); + builder.startObject(Parser.TRIGGER_EVENT_FIELD.getPreferredName()) + .field(triggerEvent.type(), triggerEvent) + .endObject(); + builder.startObject(Watch.Parser.CONDITION_FIELD.getPreferredName()).field(condition.type(), condition, params).endObject(); + builder.field(Parser.STATE_FIELD.getPreferredName(), state.id()); if (message != null) { - historyEntry.field(Parser.MESSAGE_FIELD.getPreferredName(), message); + builder.field(Parser.MESSAGE_FIELD.getPreferredName(), message); } if (metadata != null) { - historyEntry.field(Parser.METADATA_FIELD.getPreferredName(), metadata); + builder.field(Parser.METADATA_FIELD.getPreferredName(), metadata); } if (execution != null) { - historyEntry.field(Parser.WATCH_EXECUTION_FIELD.getPreferredName(), execution); + builder.field(Parser.WATCH_EXECUTION_FIELD.getPreferredName(), execution); } - historyEntry.endObject(); - return historyEntry; + builder.endObject(); + return builder; } @Override @@ -203,8 +199,7 @@ public class WatchRecord implements ToXContent { public static class Parser extends AbstractComponent { public static final ParseField WATCH_NAME_FIELD = new ParseField("watch_name"); - public static final ParseField FIRE_TIME_FIELD = new ParseField("fire_time"); - public static final ParseField SCHEDULED_FIRE_TIME_FIELD = new ParseField("scheduled_fire_time"); + public static final ParseField TRIGGER_EVENT_FIELD = new ParseField("trigger_event"); public static final ParseField MESSAGE_FIELD = new ParseField("message"); public static final ParseField STATE_FIELD = new ParseField("state"); public static final ParseField METADATA_FIELD = new ParseField("meta"); @@ -214,15 +209,17 @@ public class WatchRecord implements ToXContent { private final ActionRegistry actionRegistry; private final InputRegistry inputRegistry; private final TransformRegistry transformRegistry; + private final TriggerService triggerService; @Inject public Parser(Settings settings, ConditionRegistry conditionRegistry, ActionRegistry actionRegistry, - InputRegistry inputRegistry, TransformRegistry transformRegistry) { + InputRegistry inputRegistry, TransformRegistry transformRegistry, TriggerService triggerService) { super(settings); this.conditionRegistry = conditionRegistry; this.actionRegistry = actionRegistry; this.inputRegistry = inputRegistry; this.transformRegistry = transformRegistry; + this.triggerService = triggerService; } public WatchRecord parse(BytesReference source, String historyId, long version) { @@ -253,16 +250,14 @@ public class WatchRecord implements ToXContent { record.metadata = parser.map(); } else if (WATCH_EXECUTION_FIELD.match(currentFieldName)) { record.execution = WatchExecution.Parser.parse(parser, conditionRegistry, actionRegistry, inputRegistry, transformRegistry); + } else if (TRIGGER_EVENT_FIELD.match(currentFieldName)) { + record.triggerEvent = triggerService.parseTriggerEvent(id, parser); } else { throw new WatcherException("unable to parse watch record. unexpected field [" + currentFieldName + "]"); } } else if (token.isValue()) { if (WATCH_NAME_FIELD.match(currentFieldName)) { record.name = parser.text(); - } else if (FIRE_TIME_FIELD.match(currentFieldName)) { - record.fireTime = DateTime.parse(parser.text()); - } else if (SCHEDULED_FIRE_TIME_FIELD.match(currentFieldName)) { - record.scheduledTime = DateTime.parse(parser.text()); } else if (MESSAGE_FIELD.match(currentFieldName)) { record.message = parser.textOrNull(); } else if (STATE_FIELD.match(currentFieldName)) { diff --git a/src/main/java/org/elasticsearch/watcher/input/search/SearchInput.java b/src/main/java/org/elasticsearch/watcher/input/search/SearchInput.java index c46747607c5..f23a016b3b7 100644 --- a/src/main/java/org/elasticsearch/watcher/input/search/SearchInput.java +++ b/src/main/java/org/elasticsearch/watcher/input/search/SearchInput.java @@ -8,22 +8,11 @@ package org.elasticsearch.watcher.input.search; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; -import org.elasticsearch.watcher.watch.WatchExecutionContext; -import org.elasticsearch.watcher.watch.Payload; -import org.elasticsearch.watcher.input.Input; -import org.elasticsearch.watcher.input.InputException; -import org.elasticsearch.watcher.support.WatcherUtils; -import org.elasticsearch.watcher.support.SearchRequestEquivalence; -import org.elasticsearch.watcher.support.Variables; -import org.elasticsearch.watcher.support.init.proxy.ClientProxy; -import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -32,13 +21,19 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.SearchHit; +import org.elasticsearch.watcher.input.Input; +import org.elasticsearch.watcher.input.InputException; +import org.elasticsearch.watcher.support.SearchRequestEquivalence; +import org.elasticsearch.watcher.support.Variables; +import org.elasticsearch.watcher.support.WatcherUtils; +import org.elasticsearch.watcher.support.init.proxy.ClientProxy; +import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; +import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.watcher.watch.WatchExecutionContext; import java.io.IOException; -import java.util.HashMap; import java.util.Map; -import static org.elasticsearch.watcher.support.WatcherDateUtils.formatDate; - /** * An input that executes search and returns the search response as the initial payload */ @@ -68,7 +63,7 @@ public class SearchInput extends Input { @Override public Result execute(WatchExecutionContext ctx) throws IOException { - SearchRequest request = createSearchRequestWithTimes(this.searchRequest, ctx.scheduledTime(), ctx.fireTime(), ctx.executionTime(), scriptService); + SearchRequest request = createSearchRequestWithTimes(this.searchRequest, ctx, scriptService); if (logger.isTraceEnabled()) { logger.trace("[{}] running query for [{}] [{}]", ctx.id(), ctx.watch().name(), XContentHelper.convertToJson(request.source(), false, true)); } @@ -111,25 +106,20 @@ public class SearchInput extends Input { /** * Creates a new search request applying the scheduledFireTime and fireTime to the original request */ - public static SearchRequest createSearchRequestWithTimes(SearchRequest requestPrototype, DateTime scheduledFireTime, DateTime fireTime, DateTime executionTime, ScriptServiceProxy scriptService) throws IOException { + public static SearchRequest createSearchRequestWithTimes(SearchRequest requestPrototype, WatchExecutionContext ctx, ScriptServiceProxy scriptService) throws IOException { SearchRequest request = new SearchRequest(requestPrototype) .indicesOptions(requestPrototype.indicesOptions()) .searchType(requestPrototype.searchType()) .indices(requestPrototype.indices()); if (Strings.hasLength(requestPrototype.source())) { - Map templateParams = new HashMap<>(); - templateParams.put(Variables.SCHEDULED_FIRE_TIME, formatDate(scheduledFireTime)); - templateParams.put(Variables.FIRE_TIME, formatDate(fireTime)); - templateParams.put(Variables.EXECUTION_TIME, formatDate(executionTime)); + Map templateParams = Variables.createCtxModel(ctx, null); String requestSource = XContentHelper.convertToJson(requestPrototype.source(), false); ExecutableScript script = scriptService.executable("mustache", requestSource, ScriptService.ScriptType.INLINE, templateParams); request.source((BytesReference) script.unwrap(script.run()), false); } else if (requestPrototype.templateName() != null) { - MapBuilder templateParams = MapBuilder.newMapBuilder(requestPrototype.templateParams()) - .put(Variables.SCHEDULED_FIRE_TIME, formatDate(scheduledFireTime)) - .put(Variables.FIRE_TIME, formatDate(fireTime)) - .put(Variables.EXECUTION_TIME, formatDate(executionTime)); - request.templateParams(templateParams.map()); + Map templateParams = Variables.createCtxModel(ctx, null); + templateParams.putAll(requestPrototype.templateParams()); + request.templateParams(templateParams); request.templateName(requestPrototype.templateName()); request.templateType(requestPrototype.templateType()); } diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/Scheduler.java b/src/main/java/org/elasticsearch/watcher/scheduler/Scheduler.java deleted file mode 100644 index a3aa6aaa3f4..00000000000 --- a/src/main/java/org/elasticsearch/watcher/scheduler/Scheduler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.watcher.scheduler; - -import org.elasticsearch.watcher.scheduler.schedule.Schedule; -import org.elasticsearch.common.joda.time.DateTime; - -import java.util.Collection; - -/** - * - */ -public interface Scheduler { - - /** - * Starts the scheduler and schedules the specified jobs before returning. - */ - void start(Collection jobs); - - /** - * Stops the scheduler. - */ - void stop(); - - /** - * Adds and schedules the give job - */ - void add(Job job); - - /** - * Removes the scheduled job that is associated with the given name - */ - boolean remove(String jobName); - - void addListener(Listener listener); - - public static interface Listener { - - void fire(String jobName, DateTime scheduledFireTime, DateTime fireTime); - - } - - public static interface Job { - - String name(); - - Schedule schedule(); - - } -} diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/SchedulerModule.java b/src/main/java/org/elasticsearch/watcher/scheduler/SchedulerModule.java deleted file mode 100644 index 25ce63eb77b..00000000000 --- a/src/main/java/org/elasticsearch/watcher/scheduler/SchedulerModule.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.watcher.scheduler; - -import org.elasticsearch.watcher.scheduler.schedule.*; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.multibindings.MapBinder; - -import java.util.HashMap; -import java.util.Map; - -/** - * - */ -public class SchedulerModule extends AbstractModule { - - private final Class schedulerClass; - - private final Map> parsers = new HashMap<>(); - - public SchedulerModule() { - this(InternalScheduler.class); - } - - protected SchedulerModule(Class schedulerClass) { - this.schedulerClass = schedulerClass; - } - - @Override - protected void configure() { - - MapBinder mbinder = MapBinder.newMapBinder(binder(), String.class, Schedule.Parser.class); - bind(IntervalSchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(IntervalSchedule.TYPE).to(IntervalSchedule.Parser.class); - bind(CronSchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(CronSchedule.TYPE).to(CronSchedule.Parser.class); - bind(HourlySchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(HourlySchedule.TYPE).to(HourlySchedule.Parser.class); - bind(DailySchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(DailySchedule.TYPE).to(DailySchedule.Parser.class); - bind(WeeklySchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(WeeklySchedule.TYPE).to(WeeklySchedule.Parser.class); - bind(MonthlySchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(MonthlySchedule.TYPE).to(MonthlySchedule.Parser.class); - bind(YearlySchedule.Parser.class).asEagerSingleton(); - mbinder.addBinding(YearlySchedule.TYPE).to(YearlySchedule.Parser.class); - - for (Map.Entry> entry : parsers.entrySet()) { - bind(entry.getValue()).asEagerSingleton(); - mbinder.addBinding(entry.getKey()).to(entry.getValue()); - } - - bind(ScheduleRegistry.class).asEagerSingleton(); - bind(schedulerClass).asEagerSingleton(); - bind(Scheduler.class).to(schedulerClass); - } -} diff --git a/src/main/java/org/elasticsearch/watcher/support/Variables.java b/src/main/java/org/elasticsearch/watcher/support/Variables.java index 0f0e6dfe7b3..7d3b60d774e 100644 --- a/src/main/java/org/elasticsearch/watcher/support/Variables.java +++ b/src/main/java/org/elasticsearch/watcher/support/Variables.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.watcher.support; +import org.elasticsearch.watcher.trigger.TriggerEvent; import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.common.joda.time.DateTime; @@ -20,21 +21,21 @@ public final class Variables { public static final String CTX = "ctx"; public static final String WATCH_NAME = "watch_name"; public static final String EXECUTION_TIME = "execution_time"; - public static final String FIRE_TIME = "fire_time"; - public static final String SCHEDULED_FIRE_TIME = "scheduled_fire_time"; + public static final String TRIGGER = "trigger"; public static final String PAYLOAD = "payload"; public static Map createCtxModel(WatchExecutionContext ctx, Payload payload) { - return createCtxModel(ctx.watch().name(), ctx.executionTime(), ctx.fireTime(), ctx.scheduledTime(), payload); + return createCtxModel(ctx.watch().name(), ctx.executionTime(), ctx.triggerEvent(), payload); } - public static Map createCtxModel(String watchName, DateTime executionTime, DateTime fireTime, DateTime scheduledTime, Payload payload) { + public static Map createCtxModel(String watchName, DateTime executionTime, TriggerEvent triggerEvent, Payload payload) { Map vars = new HashMap<>(); vars.put(WATCH_NAME, watchName); vars.put(EXECUTION_TIME, executionTime); - vars.put(FIRE_TIME, fireTime); - vars.put(SCHEDULED_FIRE_TIME, scheduledTime); - vars.put(PAYLOAD, payload.data()); + vars.put(TRIGGER, triggerEvent.data()); + if (payload != null) { + vars.put(PAYLOAD, payload.data()); + } Map model = new HashMap<>(); model.put(CTX, vars); return model; diff --git a/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java b/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java index 689ad6cca41..3fcc16f9d73 100644 --- a/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java +++ b/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java @@ -36,7 +36,7 @@ public class ScriptServiceProxy implements InitializingService.Initializable { this.service = injector.getInstance(ScriptService.class); } - public ExecutableScript executable(String lang, String script, ScriptService.ScriptType scriptType, Map vars) { + public ExecutableScript executable(String lang, String script, ScriptService.ScriptType scriptType, Map vars) { return service.executable(lang, script, scriptType, vars); } diff --git a/src/main/java/org/elasticsearch/watcher/trigger/AbstractTriggerEngine.java b/src/main/java/org/elasticsearch/watcher/trigger/AbstractTriggerEngine.java new file mode 100644 index 00000000000..874e896b774 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/AbstractTriggerEngine.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.settings.Settings; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * + */ +public abstract class AbstractTriggerEngine extends AbstractComponent implements TriggerEngine { + + protected final List listeners = new CopyOnWriteArrayList<>(); + + public AbstractTriggerEngine(Settings settings) { + super(settings); + } + + @Override + public void register(Listener listener) { + listeners.add(listener); + } +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/Trigger.java b/src/main/java/org/elasticsearch/watcher/trigger/Trigger.java new file mode 100644 index 00000000000..2bdb8028057 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/Trigger.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; + +/** + * + */ +public interface Trigger extends ToXContent { + + String type(); + + public static interface Parser { + + String type(); + + T parse(XContentParser parser) throws IOException; + } + + public static interface SourceBuilder extends ToXContent { + + String type(); + } + +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/TriggerBuilders.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerBuilders.java new file mode 100644 index 00000000000..f13534fd141 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerBuilders.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.watcher.trigger.schedule.Schedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; + +/** + * + */ +public final class TriggerBuilders { + + private TriggerBuilders() { + } + + public static ScheduleTrigger.SourceBuilder schedule(Schedule schedule) { + return new ScheduleTrigger.SourceBuilder(schedule); + } +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/TriggerEngine.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerEngine.java new file mode 100644 index 00000000000..4fb6d9233f9 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerEngine.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.Collection; + +/** + * + */ +public interface TriggerEngine { + + String type(); + + /** + * It's the responsibility of the trigger engine implementation to select the appropriate jobs + * from the given list of jobs + */ + void start(Collection jobs); + + void stop(); + + void register(Listener listener); + + void add(Job job); + + boolean remove(String jobName); + + T parseTrigger(String context, XContentParser parser) throws IOException; + + E parseTriggerEvent(String context, XContentParser parser) throws IOException; + + public static interface Listener { + + void triggered(String jobName, TriggerEvent event); + } + + public static interface Job { + + String name(); + + Trigger trigger(); + } + + +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/TriggerEvent.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerEvent.java new file mode 100644 index 00000000000..3d1db67192c --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerEvent.java @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.watcher.support.WatcherDateUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public abstract class TriggerEvent implements ToXContent { + + public static final ParseField TRIGGERED_TIME_FIELD = new ParseField("triggered_time"); + + protected final DateTime triggeredTime; + protected final Map data; + + public TriggerEvent(DateTime triggeredTime) { + this.triggeredTime = triggeredTime; + this.data = new HashMap<>(); + data.put(TRIGGERED_TIME_FIELD.getPreferredName(), triggeredTime); + } + + public abstract String type(); + + public DateTime triggeredTime() { + return triggeredTime; + } + + public final Map data() { + return data; + } + +} diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/SchedulerException.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerException.java similarity index 63% rename from src/main/java/org/elasticsearch/watcher/scheduler/SchedulerException.java rename to src/main/java/org/elasticsearch/watcher/trigger/TriggerException.java index 25cd748f733..54b5f751c01 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/SchedulerException.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerException.java @@ -3,20 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler; +package org.elasticsearch.watcher.trigger; import org.elasticsearch.watcher.WatcherException; /** * */ -public class SchedulerException extends WatcherException { +public class TriggerException extends WatcherException { - public SchedulerException(String msg) { + public TriggerException(String msg) { super(msg); } - public SchedulerException(String msg, Throwable cause) { + public TriggerException(String msg, Throwable cause) { super(msg, cause); } } diff --git a/src/main/java/org/elasticsearch/watcher/trigger/TriggerModule.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerModule.java new file mode 100644 index 00000000000..edad08b70b7 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerModule.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.collect.ImmutableSet; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.Module; +import org.elasticsearch.common.inject.SpawnModules; +import org.elasticsearch.common.inject.multibindings.Multibinder; +import org.elasticsearch.watcher.trigger.schedule.ScheduleModule; + +import java.util.HashSet; +import java.util.Set; + +/** + * + */ +public class TriggerModule extends AbstractModule implements SpawnModules { + + private final Set> engines = new HashSet<>(); + + public TriggerModule() { + registerStandardEngines(); + } + + public void registerEngine(Class engineType) { + engines.add(engineType); + } + + protected void registerStandardEngines() { + registerEngine(ScheduleModule.triggerEngineType()); + } + + @Override + public Iterable spawnModules() { + return ImmutableSet.of(new ScheduleModule()); + } + + @Override + protected void configure() { + + Multibinder mbinder = Multibinder.newSetBinder(binder(), TriggerEngine.class); + for (Class engine : engines) { + bind(engine).asEagerSingleton(); + mbinder.addBinding().to(engine); + } + + bind(TriggerService.class).asEagerSingleton(); + } +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/TriggerService.java b/src/main/java/org/elasticsearch/watcher/trigger/TriggerService.java new file mode 100644 index 00000000000..7aaa147bed1 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/TriggerService.java @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger; + +import org.elasticsearch.common.collect.ImmutableMap; +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * + */ +public class TriggerService extends AbstractComponent { + + private final Listeners listeners; + private final ImmutableMap engines; + + @Inject + public TriggerService(Settings settings, Set engines) { + super(settings); + listeners = new Listeners(); + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (TriggerEngine engine : engines) { + builder.put(engine.type(), engine); + engine.register(listeners); + } + this.engines = builder.build(); + } + + public synchronized void start(Collection jobs) { + for (TriggerEngine engine : engines.values()) { + engine.start(jobs); + } + } + + public synchronized void stop() { + for (TriggerEngine engine : engines.values()) { + engine.stop(); + } + } + + public void add(TriggerEngine.Job job) { + engines.get(job.trigger().type()).add(job); + } + + public boolean remove(String jobName) { + for (TriggerEngine engine : engines.values()) { + if (engine.remove(jobName)) { + return true; + } + } + return false; + } + + public void register(TriggerEngine.Listener listener) { + listeners.add(listener); + } + + public Trigger parseTrigger(String jobName, XContentParser parser) throws IOException { + XContentParser.Token token = parser.currentToken(); + assert token == XContentParser.Token.START_OBJECT; + token = parser.nextToken(); + if (token != XContentParser.Token.FIELD_NAME) { + throw new WatcherSettingsException("could not parse trigger for [" + jobName + "]. expected trigger type string field, but found [" + token + "]"); + } + String type = parser.text(); + token = parser.nextToken(); + if (token != XContentParser.Token.START_OBJECT) { + throw new WatcherSettingsException("could not parse trigger [" + type + "] for [" + jobName + "]. expected trigger an object as the trigger body, but found [" + token + "]"); + } + Trigger trigger = parseTrigger(jobName, type, parser); + token = parser.nextToken(); + assert token == XContentParser.Token.END_OBJECT; + return trigger; + } + + public Trigger parseTrigger(String jobName, String type, XContentParser parser) throws IOException { + TriggerEngine engine = engines.get(type); + assert engine != null; + return engine.parseTrigger(jobName, parser); + } + + public TriggerEvent parseTriggerEvent(String historyRecordId, XContentParser parser) throws IOException { + XContentParser.Token token = parser.currentToken(); + assert token == XContentParser.Token.START_OBJECT; + token = parser.nextToken(); + if (token != XContentParser.Token.FIELD_NAME) { + throw new TriggerException("could not parse trigger event for [" + historyRecordId + "]. expected trigger type string field, but found [" + token + "]"); + } + String type = parser.text(); + token = parser.nextToken(); + if (token != XContentParser.Token.START_OBJECT) { + throw new WatcherSettingsException("could not parse trigger event [" + type + "] for [" + historyRecordId + "]. expected trigger an object as the trigger body, but found [" + token + "]"); + } + TriggerEvent trigger = parseTriggerEvent(historyRecordId, type, parser); + token = parser.nextToken(); + assert token == XContentParser.Token.END_OBJECT; + return trigger; + } + + public TriggerEvent parseTriggerEvent(String context, String type, XContentParser parser) throws IOException { + TriggerEngine engine = engines.get(type); + assert engine != null; + return engine.parseTriggerEvent(context, parser); + } + + static class Listeners implements TriggerEngine.Listener { + + private List listeners = new CopyOnWriteArrayList<>(); + + public void add(TriggerEngine.Listener listener) { + listeners.add(listener); + } + + @Override + public void triggered(String jobName, TriggerEvent event) { + for (TriggerEngine.Listener listener : listeners) { + listener.triggered(jobName, event); + } + } + } + +} diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronSchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/CronSchedule.java similarity index 98% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronSchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/CronSchedule.java index 7c1746a1be2..4c0fc2bf5b3 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronSchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/CronSchedule.java @@ -3,11 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; import org.quartz.CronExpression; import java.io.IOException; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronnableSchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/CronnableSchedule.java similarity index 94% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronnableSchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/CronnableSchedule.java index 9210d07cd83..0efce2f37a9 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/CronnableSchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/CronnableSchedule.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import java.util.Arrays; import java.util.Objects; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/DailySchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/DailySchedule.java similarity index 97% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/DailySchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/DailySchedule.java index 01ac6dcfc2f..a136466b592 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/DailySchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/DailySchedule.java @@ -3,13 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/HourlySchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/HourlySchedule.java similarity index 97% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/HourlySchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/HourlySchedule.java index 085342867dd..1bca83ebc16 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/HourlySchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/HourlySchedule.java @@ -3,14 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/IntervalSchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/IntervalSchedule.java similarity index 99% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/IntervalSchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/IntervalSchedule.java index bd97f57b824..11b8441d127 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/IntervalSchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/IntervalSchedule.java @@ -3,12 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; import java.io.IOException; import java.util.Locale; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/MonthlySchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/MonthlySchedule.java similarity index 96% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/MonthlySchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/MonthlySchedule.java index 389d47aa971..4156299c6d2 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/MonthlySchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/MonthlySchedule.java @@ -3,12 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.MonthTimes; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.trigger.schedule.support.MonthTimes; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedule.java similarity index 83% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedule.java index 7fa21786bd4..d275c233086 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedule.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentParser; @@ -17,11 +17,10 @@ public interface Schedule extends ToXContent { String type(); - static interface Parser { + public static interface Parser { String type(); S parse(XContentParser parser) throws IOException; - } } diff --git a/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleModule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleModule.java new file mode 100644 index 00000000000..13b755e0258 --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleModule.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger.schedule; + +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.multibindings.MapBinder; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.schedule.quartz.QuartzScheduleTriggerEngine; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class ScheduleModule extends AbstractModule { + + private final Map> parsers = new HashMap<>(); + + public ScheduleModule() { + registerScheduleParser(CronSchedule.TYPE, CronSchedule.Parser.class); + registerScheduleParser(DailySchedule.TYPE, DailySchedule.Parser.class); + registerScheduleParser(HourlySchedule.TYPE, HourlySchedule.Parser.class); + registerScheduleParser(IntervalSchedule.TYPE, IntervalSchedule.Parser.class); + registerScheduleParser(MonthlySchedule.TYPE, MonthlySchedule.Parser.class); + registerScheduleParser(WeeklySchedule.TYPE, WeeklySchedule.Parser.class); + registerScheduleParser(YearlySchedule.TYPE, YearlySchedule.Parser.class); + } + + public static Class triggerEngineType() { + return QuartzScheduleTriggerEngine.class; + } + + public void registerScheduleParser(String parserType, Class parserClass) { + parsers.put(parserType, parserClass); + } + + @Override + protected void configure() { + + MapBinder mbinder = MapBinder.newMapBinder(binder(), String.class, Schedule.Parser.class); + for (Map.Entry> entry : parsers.entrySet()) { + bind(entry.getValue()).asEagerSingleton(); + mbinder.addBinding(entry.getKey()).to(entry.getValue()); + } + + bind(ScheduleRegistry.class).asEagerSingleton(); + } + +} diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistry.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistry.java similarity index 83% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistry.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistry.java index f8dcabadedb..99040606b96 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistry.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistry.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.collect.ImmutableMap; @@ -30,7 +30,7 @@ public class ScheduleRegistry { return parsers.keySet(); } - public Schedule parse(XContentParser parser) throws IOException { + public Schedule parse(String context, XContentParser parser) throws IOException { String type = null; XContentParser.Token token; Schedule schedule = null; @@ -38,7 +38,7 @@ public class ScheduleRegistry { if (token == XContentParser.Token.FIELD_NAME) { type = parser.currentName(); } else if (type != null) { - schedule = parse(type, parser); + schedule = parse(context, type, parser); } else { throw new WatcherSettingsException("could not parse schedule. expected a schedule type field, but found [" + token + "]"); } @@ -49,10 +49,10 @@ public class ScheduleRegistry { return schedule; } - public Schedule parse(String type, XContentParser parser) throws IOException { + public Schedule parse(String context, String type, XContentParser parser) throws IOException { Schedule.Parser scheduleParser = parsers.get(type); if (scheduleParser == null) { - throw new WatcherSettingsException("could not parse schedule. unknown schedule type [" + type + "]"); + throw new WatcherSettingsException("could not parse schedule for [" + context + "]. unknown schedule type [" + type + "]"); } return scheduleParser.parse(parser); } diff --git a/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTrigger.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTrigger.java new file mode 100644 index 00000000000..a6631a28dca --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTrigger.java @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger.schedule; + +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.watcher.trigger.Trigger; + +import java.io.IOException; + +/** + * + */ +public class ScheduleTrigger implements Trigger { + + public static final String TYPE = "schedule"; + + private final Schedule schedule; + + public ScheduleTrigger(Schedule schedule) { + this.schedule = schedule; + } + + @Override + public String type() { + return TYPE; + } + + public Schedule schedule() { + return schedule; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject().field(schedule.type(), schedule).endObject(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ScheduleTrigger trigger = (ScheduleTrigger) o; + + if (!schedule.equals(trigger.schedule)) return false; + + return true; + } + + @Override + public int hashCode() { + return schedule.hashCode(); + } + + public static class SourceBuilder implements Trigger.SourceBuilder { + + private final Schedule schedule; + + public SourceBuilder(Schedule schedule) { + this.schedule = schedule; + } + + @Override + public String type() { + return TYPE; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject() + .field(schedule.type(), schedule) + .endObject(); + } + } +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEngine.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEngine.java new file mode 100644 index 00000000000..26d1ceb4b0d --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEngine.java @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger.schedule; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.watcher.trigger.AbstractTriggerEngine; + +/** + * + */ +public abstract class ScheduleTriggerEngine extends AbstractTriggerEngine { + + public static final String TYPE = ScheduleTrigger.TYPE; + + public ScheduleTriggerEngine(Settings settings) { + super(settings); + } + + @Override + public String type() { + return TYPE; + } +} diff --git a/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEvent.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEvent.java new file mode 100644 index 00000000000..77ad32cad6e --- /dev/null +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTriggerEvent.java @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.watcher.trigger.schedule; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.shield.ShieldException; +import org.elasticsearch.watcher.support.WatcherDateUtils; +import org.elasticsearch.watcher.trigger.TriggerEvent; + +import java.io.IOException; + +/** + * + */ +public class ScheduleTriggerEvent extends TriggerEvent { + + public static final ParseField SCHEDULED_TIME_FIELD = new ParseField("scheduled_time"); + + private final DateTime scheduledTime; + + public ScheduleTriggerEvent(DateTime triggeredTime, DateTime scheduledTime) { + super(triggeredTime); + this.scheduledTime = scheduledTime; + data.put(SCHEDULED_TIME_FIELD.getPreferredName(), scheduledTime); + } + + @Override + public String type() { + return ScheduleTrigger.TYPE; + } + + public DateTime scheduledTime() { + return scheduledTime; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject() + .field(TRIGGERED_TIME_FIELD.getPreferredName(), WatcherDateUtils.formatDate(triggeredTime)) + .field(SCHEDULED_TIME_FIELD.getPreferredName(), WatcherDateUtils.formatDate(scheduledTime)) + .endObject(); + } + + public static ScheduleTriggerEvent parse(String context, XContentParser parser) throws IOException { + DateTime triggeredTime = null; + DateTime scheduledTime = null; + + String currentFieldName = null; + XContentParser.Token token = null; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else { + if (token == XContentParser.Token.VALUE_STRING) { + if (TRIGGERED_TIME_FIELD.match(currentFieldName)) { + triggeredTime = WatcherDateUtils.parseDate(parser.text()); + } else if (SCHEDULED_TIME_FIELD.match(currentFieldName)) { + scheduledTime = WatcherDateUtils.parseDate(parser.text()); + } else { + throw new ParseException("could not parse trigger event for [" + context + "]. unknown string value field [" + currentFieldName + "]"); + } + } else { + throw new ParseException("could not parse trigger event for [" + context + "]. unexpected token [" + token + "]"); + } + } + } + + // should never be, it's fully controlled internally (not coming from the user) + assert triggeredTime != null && scheduledTime != null; + return new ScheduleTriggerEvent(triggeredTime, scheduledTime); + } + + public static class ParseException extends ShieldException { + + public ParseException(String msg) { + super(msg); + } + + public ParseException(String msg, Throwable cause) { + super(msg, cause); + } + } +} diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedules.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedules.java similarity index 93% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedules.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedules.java index a605b90b40a..ef8779f7278 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/Schedules.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/Schedules.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; /** * A static factory for all available schedules. @@ -46,7 +46,7 @@ public class Schedules { * * @param cronExpressions one or more cron expressions * @return the newly created cron schedule. - * @throws org.elasticsearch.watcher.scheduler.schedule.CronSchedule.ValidationException if any of the given expression is invalid + * @throws CronSchedule.ValidationException if any of the given expression is invalid */ public static CronSchedule cron(String... cronExpressions) { return new CronSchedule(cronExpressions); diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/WeeklySchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/WeeklySchedule.java similarity index 96% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/WeeklySchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/WeeklySchedule.java index a4990b1dccc..a48839c7706 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/WeeklySchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/WeeklySchedule.java @@ -3,12 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.WeekTimes; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.trigger.schedule.support.WeekTimes; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/YearlySchedule.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/YearlySchedule.java similarity index 96% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/YearlySchedule.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/YearlySchedule.java index 98a05d7f906..a3847da7a9a 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/YearlySchedule.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/YearlySchedule.java @@ -3,12 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.YearTimes; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.trigger.schedule.support.YearTimes; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/InternalScheduler.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleTriggerEngine.java similarity index 72% rename from src/main/java/org/elasticsearch/watcher/scheduler/InternalScheduler.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleTriggerEngine.java index 9a4f4e5acd7..bf83f33408d 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/InternalScheduler.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleTriggerEngine.java @@ -3,31 +3,35 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler; +package org.elasticsearch.watcher.trigger.schedule.quartz; -import org.elasticsearch.watcher.WatcherPlugin; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.CronnableSchedule; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; -import org.elasticsearch.watcher.support.clock.Clock; -import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.joda.time.DateTimeZone; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.watcher.WatcherPlugin; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.support.clock.Clock; +import org.elasticsearch.watcher.trigger.TriggerException; +import org.elasticsearch.watcher.trigger.schedule.*; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.simpl.SimpleJobFactory; +import java.io.IOException; import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; -import static org.elasticsearch.watcher.scheduler.WatcherQuartzJob.jobDetail; +import static org.elasticsearch.watcher.trigger.schedule.quartz.WatcherQuartzJob.jobDetail; -public class InternalScheduler extends AbstractComponent implements Scheduler { +/** + * + */ +public class QuartzScheduleTriggerEngine extends ScheduleTriggerEngine { + + private final ScheduleRegistry scheduleRegistry; // Not happy about it, but otherwise we're stuck with Quartz's SimpleThreadPool private volatile static ThreadPool threadPool; @@ -36,15 +40,13 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { private final DateTimeZone defaultTimeZone; private volatile org.quartz.Scheduler scheduler; - private List listeners; - @Inject - public InternalScheduler(Settings settings, ThreadPool threadPool, Clock clock) { + public QuartzScheduleTriggerEngine(Settings settings, ScheduleRegistry scheduleRegistry, ThreadPool threadPool, Clock clock) { super(settings); - InternalScheduler.threadPool = threadPool; + this.scheduleRegistry = scheduleRegistry; + QuartzScheduleTriggerEngine.threadPool = threadPool; this.clock = clock; - this.listeners = new CopyOnWriteArrayList<>(); String timeZoneStr = componentSettings.get("time_zone", "UTC"); try { this.defaultTimeZone = DateTimeZone.forID(timeZoneStr); @@ -54,7 +56,12 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { } @Override - public synchronized void start(Collection jobs) { + public String type() { + return ScheduleTrigger.TYPE; + } + + @Override + public void start(Collection jobs) { try { logger.info("Starting scheduler"); // Can't start a scheduler that has been shutdown, so we need to re-create each time start() is invoked @@ -68,7 +75,10 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { scheduler.setJobFactory(new SimpleJobFactory()); Map> quartzJobs = new HashMap<>(); for (Job job : jobs) { - quartzJobs.put(jobDetail(job.name(), this), createTrigger(job.schedule(), defaultTimeZone, clock)); + if (job.trigger() instanceof ScheduleTrigger) { + ScheduleTrigger trigger = (ScheduleTrigger) job.trigger(); + quartzJobs.put(jobDetail(job.name(), this), createTrigger(trigger.schedule(), defaultTimeZone, clock)); + } } scheduler.scheduleJobs(quartzJobs, false); scheduler.start(); @@ -77,7 +87,8 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { } } - public synchronized void stop() { + @Override + public void stop() { try { org.quartz.Scheduler scheduler = this.scheduler; if (scheduler != null) { @@ -92,39 +103,28 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { } @Override - public void addListener(Listener listener) { - listeners.add(listener); - } - - void notifyListeners(String name, JobExecutionContext ctx) { - DateTime scheduledTime = new DateTime(ctx.getScheduledFireTime()); - DateTime fireTime = new DateTime(ctx.getFireTime()); - for (Listener listener : listeners) { - listener.fire(name, scheduledTime, fireTime); - } - } - - /** - * Schedules the given job - */ public void add(Job job) { + assert job.trigger() instanceof ScheduleTrigger; + ScheduleTrigger trigger = (ScheduleTrigger) job.trigger(); try { - logger.trace("scheduling [{}] with schedule [{}]", job.name(), job.schedule()); - scheduler.scheduleJob(jobDetail(job.name(), this), createTrigger(job.schedule(), defaultTimeZone, clock), true); + logger.trace("scheduling [{}] with schedule [{}]", job.name(), trigger.schedule()); + scheduler.scheduleJob(jobDetail(job.name(), this), createTrigger(trigger.schedule(), defaultTimeZone, clock), true); } catch (org.quartz.SchedulerException se) { - logger.error("Failed to schedule job",se); - throw new SchedulerException("Failed to schedule job", se); + logger.error("failed to schedule job",se); + throw new TriggerException("failed to schedule job", se); } } + @Override public boolean remove(String jobName) { try { return scheduler.deleteJob(new JobKey(jobName)); } catch (org.quartz.SchedulerException se){ - throw new SchedulerException("Failed to remove [" + jobName + "] from the scheduler", se); + throw new TriggerException("failed to remove [" + jobName + "] from the scheduler", se); } } + static Set createTrigger(Schedule schedule, DateTimeZone timeZone, Clock clock) { HashSet triggers = new HashSet<>(); if (schedule instanceof CronnableSchedule) { @@ -147,6 +147,25 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { } + + @Override + public ScheduleTrigger parseTrigger(String context, XContentParser parser) throws IOException { + Schedule schedule = scheduleRegistry.parse(context, parser); + return new ScheduleTrigger(schedule); + } + + @Override + public ScheduleTriggerEvent parseTriggerEvent(String context, XContentParser parser) throws IOException { + return ScheduleTriggerEvent.parse(context, parser); + } + + void notifyListeners(String name, JobExecutionContext ctx) { + ScheduleTriggerEvent event = new ScheduleTriggerEvent(new DateTime(ctx.getFireTime()), new DateTime(ctx.getScheduledFireTime())); + for (Listener listener : listeners) { + listener.triggered(name, event); + } + } + // This Quartz thread pool will always accept. On this thread we will only index a watch record and add it to the work queue public static final class WatcherQuartzThreadPool implements org.quartz.spi.ThreadPool { @@ -190,5 +209,4 @@ public class InternalScheduler extends AbstractComponent implements Scheduler { public void setInstanceName(String schedName) { } } - } diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/WatcherQuartzJob.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/WatcherQuartzJob.java similarity index 68% rename from src/main/java/org/elasticsearch/watcher/scheduler/WatcherQuartzJob.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/WatcherQuartzJob.java index deba6626e52..7039d556b58 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/WatcherQuartzJob.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/quartz/WatcherQuartzJob.java @@ -3,13 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler; +package org.elasticsearch.watcher.trigger.schedule.quartz; import org.quartz.*; public class WatcherQuartzJob implements Job { - static final String SCHEDULER_KEY = "scheduler"; + static final String ENGINE_KEY = "engine"; public WatcherQuartzJob() { } @@ -17,7 +17,7 @@ public class WatcherQuartzJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { String watchName = jobExecutionContext.getJobDetail().getKey().getName(); - InternalScheduler scheduler = (InternalScheduler) jobExecutionContext.getJobDetail().getJobDataMap().get(SCHEDULER_KEY); + QuartzScheduleTriggerEngine scheduler = (QuartzScheduleTriggerEngine) jobExecutionContext.getJobDetail().getJobDataMap().get(ENGINE_KEY); scheduler.notifyListeners(watchName, jobExecutionContext); } @@ -25,9 +25,9 @@ public class WatcherQuartzJob implements Job { return new JobKey(watchName); } - static JobDetail jobDetail(String watchName, InternalScheduler scheduler) { + static JobDetail jobDetail(String watchName, QuartzScheduleTriggerEngine engine) { JobDetail job = JobBuilder.newJob(WatcherQuartzJob.class).withIdentity(watchName).build(); - job.getJobDataMap().put("scheduler", scheduler); + job.getJobDataMap().put(ENGINE_KEY, engine); return job; } } diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayOfWeek.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayOfWeek.java similarity index 97% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayOfWeek.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayOfWeek.java index ef63d232c3b..7fd51832c4b 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayOfWeek.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayOfWeek.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayTimes.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayTimes.java similarity index 99% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayTimes.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayTimes.java index 9a5280c193d..ae716ebee5b 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/DayTimes.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/DayTimes.java @@ -3,13 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; -import org.elasticsearch.watcher.WatcherException; -import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherException; +import org.elasticsearch.watcher.WatcherSettingsException; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Month.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Month.java similarity index 98% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Month.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Month.java index 18da8532eac..f3566d4864e 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Month.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Month.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/MonthTimes.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/MonthTimes.java similarity index 99% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/MonthTimes.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/MonthTimes.java index 8926c022725..e6a3300252b 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/MonthTimes.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/MonthTimes.java @@ -3,15 +3,15 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; -import org.elasticsearch.watcher.WatcherException; -import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.base.Joiner; import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherException; +import org.elasticsearch.watcher.WatcherSettingsException; import java.io.IOException; import java.util.Arrays; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Times.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Times.java similarity index 92% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Times.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Times.java index 5ebea4e812a..734710332f2 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/Times.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/Times.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ToXContent; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/WeekTimes.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/WeekTimes.java similarity index 99% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/WeekTimes.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/WeekTimes.java index d03248ad64d..ac85072df41 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/WeekTimes.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/WeekTimes.java @@ -3,13 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; -import org.elasticsearch.watcher.WatcherException; import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherException; import java.io.IOException; import java.util.*; diff --git a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/YearTimes.java b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/YearTimes.java similarity index 99% rename from src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/YearTimes.java rename to src/main/java/org/elasticsearch/watcher/trigger/schedule/support/YearTimes.java index 7a6a4e85818..0afe03327ff 100644 --- a/src/main/java/org/elasticsearch/watcher/scheduler/schedule/support/YearTimes.java +++ b/src/main/java/org/elasticsearch/watcher/trigger/schedule/support/YearTimes.java @@ -3,15 +3,15 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule.support; +package org.elasticsearch.watcher.trigger.schedule.support; -import org.elasticsearch.watcher.WatcherException; -import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.base.Joiner; import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherException; +import org.elasticsearch.watcher.WatcherSettingsException; import java.io.IOException; import java.util.*; diff --git a/src/main/java/org/elasticsearch/watcher/watch/Watch.java b/src/main/java/org/elasticsearch/watcher/watch/Watch.java index d69f4221982..6ee3b42da97 100644 --- a/src/main/java/org/elasticsearch/watcher/watch/Watch.java +++ b/src/main/java/org/elasticsearch/watcher/watch/Watch.java @@ -5,24 +5,6 @@ */ package org.elasticsearch.watcher.watch; -import org.elasticsearch.watcher.WatcherException; -import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.actions.ActionRegistry; -import org.elasticsearch.watcher.actions.Actions; -import org.elasticsearch.watcher.condition.Condition; -import org.elasticsearch.watcher.condition.ConditionRegistry; -import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; -import org.elasticsearch.watcher.input.Input; -import org.elasticsearch.watcher.input.InputRegistry; -import org.elasticsearch.watcher.input.NoneInput; -import org.elasticsearch.watcher.scheduler.Scheduler; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; -import org.elasticsearch.watcher.scheduler.schedule.ScheduleRegistry; -import org.elasticsearch.watcher.support.clock.Clock; -import org.elasticsearch.watcher.throttle.WatchThrottler; -import org.elasticsearch.watcher.throttle.Throttler; -import org.elasticsearch.watcher.transform.Transform; -import org.elasticsearch.watcher.transform.TransformRegistry; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.bytes.BytesReference; @@ -39,6 +21,24 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.WatcherException; +import org.elasticsearch.watcher.WatcherSettingsException; +import org.elasticsearch.watcher.actions.ActionRegistry; +import org.elasticsearch.watcher.actions.Actions; +import org.elasticsearch.watcher.condition.Condition; +import org.elasticsearch.watcher.condition.ConditionRegistry; +import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; +import org.elasticsearch.watcher.input.Input; +import org.elasticsearch.watcher.input.InputRegistry; +import org.elasticsearch.watcher.input.NoneInput; +import org.elasticsearch.watcher.support.clock.Clock; +import org.elasticsearch.watcher.throttle.Throttler; +import org.elasticsearch.watcher.throttle.WatchThrottler; +import org.elasticsearch.watcher.transform.Transform; +import org.elasticsearch.watcher.transform.TransformRegistry; +import org.elasticsearch.watcher.trigger.Trigger; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.TriggerService; import java.io.IOException; import java.util.Locale; @@ -46,10 +46,10 @@ import java.util.Map; import static org.elasticsearch.watcher.support.WatcherDateUtils.*; -public class Watch implements Scheduler.Job, ToXContent { +public class Watch implements TriggerEngine.Job, ToXContent { private final String name; - private final Schedule schedule; + private final Trigger trigger; private final Input input; private final Condition condition; private final Actions actions; @@ -63,9 +63,9 @@ public class Watch implements Scheduler.Job, ToXContent { @Nullable private final Transform transform; - public Watch(String name, Clock clock, Schedule schedule, Input input, Condition condition, @Nullable Transform transform, Actions actions, @Nullable Map metadata, @Nullable TimeValue throttlePeriod, @Nullable Status status) { + public Watch(String name, Clock clock, Trigger trigger, Input input, Condition condition, @Nullable Transform transform, Actions actions, @Nullable Map metadata, @Nullable TimeValue throttlePeriod, @Nullable Status status) { this.name = name; - this.schedule = schedule; + this.trigger = trigger; this.input = input; this.condition = condition; this.actions = actions; @@ -80,8 +80,8 @@ public class Watch implements Scheduler.Job, ToXContent { return name; } - public Schedule schedule() { - return schedule; + public Trigger trigger() { + return trigger; } public Input input() { return input;} @@ -144,7 +144,7 @@ public class Watch implements Scheduler.Job, ToXContent { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(Parser.SCHEDULE_FIELD.getPreferredName()).startObject().field(schedule.type(), schedule).endObject(); + builder.field(Parser.TRIGGER_FIELD.getPreferredName()).startObject().field(trigger.type(), trigger).endObject(); builder.field(Parser.INPUT_FIELD.getPreferredName()).startObject().field(input.type(), input).endObject(); builder.field(Parser.CONDITION_FIELD.getPreferredName()).startObject().field(condition.type(), condition).endObject(); if (transform != null) { @@ -164,7 +164,7 @@ public class Watch implements Scheduler.Job, ToXContent { public static class Parser extends AbstractComponent { - public static final ParseField SCHEDULE_FIELD = new ParseField("schedule"); + public static final ParseField TRIGGER_FIELD = new ParseField("trigger"); public static final ParseField INPUT_FIELD = new ParseField("input"); public static final ParseField CONDITION_FIELD = new ParseField("condition"); public static final ParseField ACTIONS_FIELD = new ParseField("actions"); @@ -174,7 +174,7 @@ public class Watch implements Scheduler.Job, ToXContent { public static final ParseField THROTTLE_PERIOD_FIELD = new ParseField("throttle_period"); private final ConditionRegistry conditionRegistry; - private final ScheduleRegistry scheduleRegistry; + private final TriggerService triggerService; private final TransformRegistry transformRegistry; private final ActionRegistry actionRegistry; private final InputRegistry inputRegistry; @@ -184,14 +184,14 @@ public class Watch implements Scheduler.Job, ToXContent { private final Condition defaultCondition; @Inject - public Parser(Settings settings, ConditionRegistry conditionRegistry, ScheduleRegistry scheduleRegistry, + public Parser(Settings settings, ConditionRegistry conditionRegistry, TriggerService triggerService, TransformRegistry transformRegistry, ActionRegistry actionRegistry, InputRegistry inputRegistry, Clock clock) { super(settings); this.conditionRegistry = conditionRegistry; - this.scheduleRegistry = scheduleRegistry; this.transformRegistry = transformRegistry; + this.triggerService = triggerService; this.actionRegistry = actionRegistry; this.inputRegistry = inputRegistry; this.clock = clock; @@ -212,7 +212,7 @@ public class Watch implements Scheduler.Job, ToXContent { } public Watch parse(String name, boolean includeStatus, XContentParser parser) throws IOException { - Schedule schedule = null; + Trigger trigger = null; Input input = defaultInput; Condition condition = defaultCondition; Actions actions = null; @@ -229,8 +229,8 @@ public class Watch implements Scheduler.Job, ToXContent { } else if (token == null ){ throw new WatcherException("could not parse watch [" + name + "]. null token"); } else if ((token.isValue() || token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) && currentFieldName !=null ) { - if (SCHEDULE_FIELD.match(currentFieldName)) { - schedule = scheduleRegistry.parse(parser); + if (TRIGGER_FIELD.match(currentFieldName)) { + trigger = triggerService.parseTrigger(name, parser); } else if (INPUT_FIELD.match(currentFieldName)) { input = inputRegistry.parse(parser); } else if (CONDITION_FIELD.match(currentFieldName)) { @@ -254,14 +254,14 @@ public class Watch implements Scheduler.Job, ToXContent { } } } - if (schedule == null) { - throw new WatcherSettingsException("could not parse watch [" + name + "]. missing watch schedule"); + if (trigger == null) { + throw new WatcherSettingsException("could not parse watch [" + name + "]. missing watch trigger"); } if (actions == null) { throw new WatcherSettingsException("could not parse watch [" + name + "]. missing watch actions"); } - return new Watch(name, clock, schedule, input, condition, transform, actions, metatdata, throttlePeriod, status); + return new Watch(name, clock, trigger, input, condition, transform, actions, metatdata, throttlePeriod, status); } } diff --git a/src/main/java/org/elasticsearch/watcher/watch/WatchExecutionContext.java b/src/main/java/org/elasticsearch/watcher/watch/WatchExecutionContext.java index 1dbff27429a..1cb69025b77 100644 --- a/src/main/java/org/elasticsearch/watcher/watch/WatchExecutionContext.java +++ b/src/main/java/org/elasticsearch/watcher/watch/WatchExecutionContext.java @@ -5,12 +5,13 @@ */ package org.elasticsearch.watcher.watch; +import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.throttle.Throttler; import org.elasticsearch.watcher.transform.Transform; -import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.watcher.trigger.TriggerEvent; import java.util.HashMap; import java.util.Map; @@ -23,8 +24,7 @@ public class WatchExecutionContext { private final String id; private final Watch watch; private final DateTime executionTime; - private final DateTime fireTime; - private final DateTime scheduledTime; + private final TriggerEvent triggerEvent; private Input.Result inputResult; private Condition.Result conditionResult; @@ -34,12 +34,11 @@ public class WatchExecutionContext { private Payload payload; - public WatchExecutionContext(String id, Watch watch, DateTime executionTime, DateTime fireTime, DateTime scheduledTime) { + public WatchExecutionContext(String id, Watch watch, DateTime executionTime, TriggerEvent triggerEvent) { this.id = id; this.watch = watch; this.executionTime = executionTime; - this.fireTime = fireTime; - this.scheduledTime = scheduledTime; + this.triggerEvent = triggerEvent; } public String id() { @@ -54,12 +53,8 @@ public class WatchExecutionContext { return executionTime; } - public DateTime fireTime() { - return fireTime; - } - - public DateTime scheduledTime() { - return scheduledTime; + public TriggerEvent triggerEvent() { + return triggerEvent; } public Payload payload() { diff --git a/src/main/java/org/elasticsearch/watcher/watch/WatchService.java b/src/main/java/org/elasticsearch/watcher/watch/WatchService.java index d8587236a9f..d0b74bee88e 100644 --- a/src/main/java/org/elasticsearch/watcher/watch/WatchService.java +++ b/src/main/java/org/elasticsearch/watcher/watch/WatchService.java @@ -10,13 +10,13 @@ import org.elasticsearch.ElasticsearchIllegalStateException; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.watcher.WatcherException; import org.elasticsearch.watcher.history.HistoryService; -import org.elasticsearch.watcher.scheduler.Scheduler; import org.elasticsearch.watcher.support.Callback; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.watcher.trigger.TriggerService; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -24,17 +24,17 @@ import java.util.concurrent.atomic.AtomicReference; public class WatchService extends AbstractComponent { - private final Scheduler scheduler; + private final TriggerService triggerService; private final WatchStore watchStore; private final WatchLockService watchLockService; private final HistoryService historyService; private final AtomicReference state = new AtomicReference<>(State.STOPPED); @Inject - public WatchService(Settings settings, Scheduler scheduler, WatchStore watchStore, HistoryService historyService, + public WatchService(Settings settings, TriggerService triggerService, WatchStore watchStore, HistoryService historyService, WatchLockService watchLockService) { super(settings); - this.scheduler = scheduler; + this.triggerService = triggerService; this.watchStore = watchStore; this.watchLockService = watchLockService; this.historyService = historyService; @@ -54,7 +54,7 @@ public class WatchService extends AbstractComponent { @Override public void onSuccess(ClusterState clusterState) { - scheduler.start(watchStore.watches().values()); + triggerService.start(watchStore.watches().values()); state.set(State.STARTED); logger.info("watch service has started"); } @@ -79,7 +79,7 @@ public class WatchService extends AbstractComponent { logger.info("stopping watch service..."); watchLockService.stop(); historyService.stop(); - scheduler.stop(); + triggerService.stop(); watchStore.stop(); state.set(State.STOPPED); logger.info("watch service has stopped"); @@ -92,7 +92,7 @@ public class WatchService extends AbstractComponent { try { WatchStore.WatchDelete delete = watchStore.delete(name); if (delete.deleteResponse().isFound()) { - scheduler.remove(name); + triggerService.remove(name); } return delete; } finally { @@ -105,8 +105,8 @@ public class WatchService extends AbstractComponent { WatchLockService.Lock lock = watchLockService.acquire(name); try { WatchStore.WatchPut result = watchStore.put(name, watchSource); - if (result.previous() == null || !result.previous().schedule().equals(result.current().schedule())) { - scheduler.add(result.current()); + if (result.previous() == null || !result.previous().trigger().equals(result.current().trigger())) { + triggerService.add(result.current()); } return result.indexResponse(); } finally { diff --git a/src/main/resources/watch_history.json b/src/main/resources/watch_history.json index 8c8d170544a..1205a2ee71e 100644 --- a/src/main/resources/watch_history.json +++ b/src/main/resources/watch_history.json @@ -15,11 +15,10 @@ "type": "string", "index": "not_analyzed" }, - "fire_time": { - "type": "date" - }, - "scheduled_fire_time": { - "type": "date" + "trigger_event" : { + "type" : "object", + "enabled" : false, + "dynamic" : true }, "state": { "type": "string", diff --git a/src/main/resources/watches.json b/src/main/resources/watches.json index bc5d2c4a4af..86e3ba82841 100644 --- a/src/main/resources/watches.json +++ b/src/main/resources/watches.json @@ -11,7 +11,7 @@ "watch": { "dynamic" : "strict", "properties": { - "schedule": { + "trigger" : { "type": "object", "enabled" : false, "dynamic" : true diff --git a/src/test/java/org/elasticsearch/watcher/actions/email/EmailActionTests.java b/src/test/java/org/elasticsearch/watcher/actions/email/EmailActionTests.java index b635f0cba5c..ef35e906e61 100644 --- a/src/test/java/org/elasticsearch/watcher/actions/email/EmailActionTests.java +++ b/src/test/java/org/elasticsearch/watcher/actions/email/EmailActionTests.java @@ -6,8 +6,14 @@ package org.elasticsearch.watcher.actions.email; import com.carrotsearch.randomizedtesting.annotations.Repeat; -import org.elasticsearch.watcher.watch.WatchExecutionContext; -import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.collect.ImmutableMap; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.watcher.actions.ActionSettingsException; import org.elasticsearch.watcher.actions.email.service.*; import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; @@ -15,23 +21,17 @@ import org.elasticsearch.watcher.support.template.ScriptTemplate; import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.transform.Transform; import org.elasticsearch.watcher.transform.TransformRegistry; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.collect.ImmutableMap; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.joda.time.DateTimeZone; -import org.elasticsearch.common.settings.ImmutableSettings; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.json.JsonXContent; -import org.elasticsearch.test.ElasticsearchTestCase; +import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static org.elasticsearch.watcher.test.WatcherTestUtils.mockExecutionContext; +import static org.elasticsearch.common.joda.time.DateTimeZone.UTC; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.watcher.test.WatcherTestUtils.mockExecutionContext; import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -79,10 +79,10 @@ public class EmailActionTests extends ElasticsearchTestCase { } }; - DateTime now = DateTime.now(DateTimeZone.UTC); + DateTime now = DateTime.now(UTC); String ctxId = randomAsciiOfLength(5); - WatchExecutionContext ctx = mockExecutionContext(now, "watch1", payload); + WatchExecutionContext ctx = mockExecutionContext("watch1", now, payload); when(ctx.id()).thenReturn(ctxId); if (transform != null) { Transform.Result transformResult = mock(Transform.Result.class); @@ -92,11 +92,14 @@ public class EmailActionTests extends ElasticsearchTestCase { } Map expectedModel = ImmutableMap.builder() .put("ctx", ImmutableMap.builder() - .put("watch_name", "watch1") - .put("payload", transform == null ? data : new Payload.Simple("_key", "_value").data()) - .put("execution_time", now) - .put("fire_time", now) - .put("scheduled_fire_time", now).build()) + .put("watch_name", "watch1") + .put("payload", transform == null ? data : new Payload.Simple("_key", "_value").data()) + .put("execution_time", now) + .put("trigger", ImmutableMap.builder() + .put("triggered_time", now) + .put("scheduled_time", now) + .build()) + .build()) .build(); if (subject != null) { diff --git a/src/test/java/org/elasticsearch/watcher/history/HistoryServiceTests.java b/src/test/java/org/elasticsearch/watcher/history/HistoryServiceTests.java index 75a9d89bf28..f1a63918ce1 100644 --- a/src/test/java/org/elasticsearch/watcher/history/HistoryServiceTests.java +++ b/src/test/java/org/elasticsearch/watcher/history/HistoryServiceTests.java @@ -5,20 +5,22 @@ */ package org.elasticsearch.watcher.history; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.joda.time.DateTimeZone; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.simple.AlwaysFalseCondition; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.input.Input; -import org.elasticsearch.watcher.scheduler.Scheduler; import org.elasticsearch.watcher.support.clock.SystemClock; import org.elasticsearch.watcher.throttle.Throttler; import org.elasticsearch.watcher.transform.Transform; -import org.elasticsearch.cluster.ClusterService; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.settings.ImmutableSettings; -import org.elasticsearch.test.ElasticsearchTestCase; +import org.elasticsearch.watcher.trigger.TriggerService; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.*; import org.junit.Before; import org.junit.Test; @@ -52,9 +54,9 @@ public class HistoryServiceTests extends ElasticsearchTestCase { WatchExecutor executor = mock(WatchExecutor.class); WatchStore watchStore = mock(WatchStore.class); WatchLockService watchLockService = mock(WatchLockService.class); - Scheduler scheduler = mock(Scheduler.class); + TriggerService triggerService = mock(TriggerService.class); ClusterService clusterService = mock(ClusterService.class); - historyService = new HistoryService(ImmutableSettings.EMPTY, historyStore, executor, watchStore, watchLockService, scheduler, clusterService, SystemClock.INSTANCE); + historyService = new HistoryService(ImmutableSettings.EMPTY, historyStore, executor, watchStore, watchLockService, triggerService, clusterService, SystemClock.INSTANCE); } @Test @@ -85,7 +87,10 @@ public class HistoryServiceTests extends ElasticsearchTestCase { when(watch.actions()).thenReturn(actions); when(watch.status()).thenReturn(watchStatus); - WatchExecutionContext context = new WatchExecutionContext("1", watch, DateTime.now(), DateTime.now(), DateTime.now()); + DateTime now = DateTime.now(DateTimeZone.UTC); + + ScheduleTriggerEvent event = new ScheduleTriggerEvent(now, now); + WatchExecutionContext context = new WatchExecutionContext("1", watch, now, event); WatchExecution watchExecution = historyService.execute(context); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); assertThat(watchExecution.transformResult(), sameInstance(transformResult)); @@ -128,7 +133,10 @@ public class HistoryServiceTests extends ElasticsearchTestCase { when(watch.actions()).thenReturn(actions); when(watch.status()).thenReturn(watchStatus); - WatchExecutionContext context = new WatchExecutionContext("1", watch, DateTime.now(), DateTime.now(), DateTime.now()); + DateTime now = DateTime.now(DateTimeZone.UTC); + + ScheduleTriggerEvent event = new ScheduleTriggerEvent(now, now); + WatchExecutionContext context = new WatchExecutionContext("1", watch, now, event); WatchExecution watchExecution = historyService.execute(context); assertThat(watchExecution.inputResult(), sameInstance(inputResult)); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); @@ -171,7 +179,10 @@ public class HistoryServiceTests extends ElasticsearchTestCase { when(watch.actions()).thenReturn(actions); when(watch.status()).thenReturn(watchStatus); - WatchExecutionContext context = new WatchExecutionContext("1", watch, DateTime.now(), DateTime.now(), DateTime.now()); + DateTime now = DateTime.now(DateTimeZone.UTC); + + ScheduleTriggerEvent event = new ScheduleTriggerEvent(now, now); + WatchExecutionContext context = new WatchExecutionContext("1", watch, now, event); WatchExecution watchExecution = historyService.execute(context); assertThat(watchExecution.inputResult(), sameInstance(inputResult)); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); diff --git a/src/test/java/org/elasticsearch/watcher/history/HistoryStoreLifeCycleTest.java b/src/test/java/org/elasticsearch/watcher/history/HistoryStoreLifeCycleTest.java index b275183e473..68c9c5e34f3 100644 --- a/src/test/java/org/elasticsearch/watcher/history/HistoryStoreLifeCycleTest.java +++ b/src/test/java/org/elasticsearch/watcher/history/HistoryStoreLifeCycleTest.java @@ -13,6 +13,7 @@ import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.support.clock.SystemClock; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.Watch; import org.junit.Test; @@ -34,7 +35,8 @@ public class HistoryStoreLifeCycleTest extends AbstractWatcherIntegrationTests { WatchRecord[] watchRecords = new WatchRecord[randomIntBetween(1, 50)]; for (int i = 0; i < watchRecords.length; i++) { DateTime dateTime = new DateTime(i, DateTimeZone.UTC); - watchRecords[i] = new WatchRecord(watch, dateTime, dateTime); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(dateTime, dateTime); + watchRecords[i] = new WatchRecord(watch, event); historyStore.put(watchRecords[i]); GetResponse getResponse = client().prepareGet(HistoryStore.getHistoryIndexNameForTime(dateTime), HistoryStore.DOC_TYPE, watchRecords[i].id()) .setVersion(1) @@ -54,7 +56,7 @@ public class HistoryStoreLifeCycleTest extends AbstractWatcherIntegrationTests { assertThat(watchRecord.version(), equalTo(1l)); watchRecord.update(WatchRecord.State.EXECUTED, "_message"); historyStore.update(watchRecord); - GetResponse getResponse = client().prepareGet(HistoryStore.getHistoryIndexNameForTime(watchRecord.scheduledTime()), HistoryStore.DOC_TYPE, watchRecord.id()) + GetResponse getResponse = client().prepareGet(HistoryStore.getHistoryIndexNameForTime(watchRecord.triggerEvent().triggeredTime()), HistoryStore.DOC_TYPE, watchRecord.id()) .setVersion(2l) .get(); assertThat(getResponse.isExists(), equalTo(true)); diff --git a/src/test/java/org/elasticsearch/watcher/history/HistoryStoreTests.java b/src/test/java/org/elasticsearch/watcher/history/HistoryStoreTests.java index 9d96242dd09..0cb11294e6a 100644 --- a/src/test/java/org/elasticsearch/watcher/history/HistoryStoreTests.java +++ b/src/test/java/org/elasticsearch/watcher/history/HistoryStoreTests.java @@ -34,6 +34,7 @@ import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.support.TemplateUtils; import org.elasticsearch.watcher.support.init.proxy.ClientProxy; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.Watch; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -73,7 +74,8 @@ public class HistoryStoreTests extends ElasticsearchTestCase { when(watch.condition()).thenReturn(new AlwaysTrueCondition(logger)); when(watch.input()).thenReturn(null); when(watch.metadata()).thenReturn(null); - WatchRecord watchRecord = new WatchRecord(watch, new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + WatchRecord watchRecord = new WatchRecord(watch, event); IndexResponse indexResponse = mock(IndexResponse.class); long version = randomLong(); @@ -91,7 +93,8 @@ public class HistoryStoreTests extends ElasticsearchTestCase { when(watch.condition()).thenReturn(new AlwaysTrueCondition(logger)); when(watch.input()).thenReturn(null); when(watch.metadata()).thenReturn(null); - WatchRecord watchRecord = new WatchRecord(watch, new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + WatchRecord watchRecord = new WatchRecord(watch, event); watchRecord.version(4l); IndexResponse indexResponse = mock(IndexResponse.class); diff --git a/src/test/java/org/elasticsearch/watcher/history/WatchRecordTests.java b/src/test/java/org/elasticsearch/watcher/history/WatchRecordTests.java index 3ce129d867f..a0d05946c7d 100644 --- a/src/test/java/org/elasticsearch/watcher/history/WatchRecordTests.java +++ b/src/test/java/org/elasticsearch/watcher/history/WatchRecordTests.java @@ -5,10 +5,10 @@ */ package org.elasticsearch.watcher.history; -import org.elasticsearch.watcher.watch.Watch; -import org.elasticsearch.watcher.watch.WatchExecution; -import org.elasticsearch.watcher.watch.WatchExecutionContext; -import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.watcher.actions.email.EmailAction; import org.elasticsearch.watcher.actions.webhook.WebhookAction; import org.elasticsearch.watcher.condition.Condition; @@ -19,12 +19,14 @@ import org.elasticsearch.watcher.input.simple.SimpleInput; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.test.WatcherTestUtils; import org.elasticsearch.watcher.throttle.Throttler; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; +import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.watcher.watch.Watch; +import org.elasticsearch.watcher.watch.WatchExecution; +import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.junit.Test; +import static org.elasticsearch.common.joda.time.DateTimeZone.UTC; import static org.hamcrest.Matchers.equalTo; /** @@ -34,7 +36,8 @@ public class WatchRecordTests extends AbstractWatcherIntegrationTests { @Test public void testParser() throws Exception { Watch watch = WatcherTestUtils.createTestWatch("fired_test", scriptService(), httpClient(), noopEmailService(), logger); - WatchRecord watchRecord = new WatchRecord(watch, new DateTime(), new DateTime()); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC)); + WatchRecord watchRecord = new WatchRecord(watch, event); XContentBuilder jsonBuilder = XContentFactory.jsonBuilder(); watchRecord.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS); WatchRecord parsedWatchRecord = watchRecordParser().parse(jsonBuilder.bytes(), watchRecord.id(), 0); @@ -48,8 +51,9 @@ public class WatchRecordTests extends AbstractWatcherIntegrationTests { @Test public void testParser_WithSealedWatchRecord() throws Exception { Watch watch = WatcherTestUtils.createTestWatch("fired_test", scriptService(), httpClient(), noopEmailService(), logger); - WatchRecord watchRecord = new WatchRecord(watch, new DateTime(), new DateTime()); - WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), new DateTime(), new DateTime()); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC)); + WatchRecord watchRecord = new WatchRecord(watch, event); + WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event); ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah")); ctx.onActionResult(new WebhookAction.Result.Executed(300, "http://localhost:8000/watchfoo", "{'awesome' : 'us'}")); Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple()); @@ -72,8 +76,9 @@ public class WatchRecordTests extends AbstractWatcherIntegrationTests { @Test public void testParser_WithSealedWatchRecord_WithScriptSearchCondition() throws Exception { Watch watch = WatcherTestUtils.createTestWatch("fired_test", scriptService(), httpClient(), noopEmailService(), logger); - WatchRecord watchRecord = new WatchRecord(watch, new DateTime(), new DateTime()); - WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), new DateTime(), new DateTime()); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC)); + WatchRecord watchRecord = new WatchRecord(watch, event); + WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event); ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah")); ctx.onActionResult(new WebhookAction.Result.Executed(300, "http://localhost:8000/watchfoo", "{'awesome' : 'us'}")); Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple()); diff --git a/src/test/java/org/elasticsearch/watcher/input/search/SearchInputTests.java b/src/test/java/org/elasticsearch/watcher/input/search/SearchInputTests.java index 52469bfde47..82f40aa6abc 100644 --- a/src/test/java/org/elasticsearch/watcher/input/search/SearchInputTests.java +++ b/src/test/java/org/elasticsearch/watcher/input/search/SearchInputTests.java @@ -25,12 +25,13 @@ import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.InputException; import org.elasticsearch.watcher.input.simple.SimpleInput; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule; -import org.elasticsearch.watcher.support.Variables; import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.support.clock.ClockMock; import org.elasticsearch.watcher.support.init.proxy.ClientProxy; import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; +import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.WatchExecutionContext; @@ -56,7 +57,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { @Test public void testExecute() throws Exception { SearchSourceBuilder searchSourceBuilder = searchSource().query( - filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}"))); + filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))); SearchRequest request = client() .prepareSearch() .setSearchType(SearchInput.DEFAULT_SEARCH_TYPE) @@ -69,7 +70,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { WatchExecutionContext ctx = new WatchExecutionContext("test-watch", new Watch("test-alert", new ClockMock(), - new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES)), + new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))), new SimpleInput(logger, new Payload.Simple()), new AlwaysTrueCondition(logger), null, @@ -77,7 +78,8 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { null, null, new Watch.Status()), - new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + new DateTime(0, DateTimeZone.UTC), + new ScheduleTriggerEvent(new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC))); SearchInput.Result result = searchInput.execute(ctx); assertThat((Integer) XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0)); @@ -90,7 +92,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { @Test public void testDifferentSearchType() throws Exception { SearchSourceBuilder searchSourceBuilder = searchSource().query( - filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}")) + filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")) ); SearchType searchType = randomFrom(SearchType.values()); SearchRequest request = client() @@ -105,7 +107,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { WatchExecutionContext ctx = new WatchExecutionContext("test-watch", new Watch("test-alert", new ClockMock(), - new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES)), + new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))), new SimpleInput(logger, new Payload.Simple()), new AlwaysTrueCondition(logger), null, @@ -113,7 +115,8 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { null, null, new Watch.Status()), - new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)); + new DateTime(0, DateTimeZone.UTC), + new ScheduleTriggerEvent(new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC))); SearchInput.Result result = searchInput.execute(ctx); assertThat((Integer) XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0)); @@ -129,7 +132,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { .setSearchType(SearchInput.DEFAULT_SEARCH_TYPE) .request() .source(searchSource() - .query(filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}")))); + .query(filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")))); XContentBuilder builder = WatcherUtils.writeSearchRequest(request, jsonBuilder(), ToXContent.EMPTY_PARAMS); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); @@ -169,7 +172,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest { data.put("baz", new ArrayList() ); SearchSourceBuilder searchSourceBuilder = searchSource().query( - filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}"))); + filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{ctx.triggered.scheduled_time}}||-30s").to("{{ctx.triggered.triggered_time}}"))); SearchRequest request = client() .prepareSearch() .setSearchType(SearchInput.DEFAULT_SEARCH_TYPE) diff --git a/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTests.java b/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTests.java index 6e2646dc30e..03313184fd0 100644 --- a/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTests.java @@ -12,7 +12,6 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.Client; -import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.cluster.routing.IndexRoutingTable; @@ -45,15 +44,16 @@ import org.elasticsearch.watcher.actions.webhook.HttpClient; import org.elasticsearch.watcher.client.WatcherClient; import org.elasticsearch.watcher.history.HistoryStore; import org.elasticsearch.watcher.history.WatchRecord; -import org.elasticsearch.watcher.scheduler.Scheduler; -import org.elasticsearch.watcher.scheduler.SchedulerMock; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; -import org.elasticsearch.watcher.scheduler.schedule.Schedules; import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.support.clock.ClockMock; import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse; +import org.elasticsearch.watcher.trigger.ScheduleTriggerEngineMock; +import org.elasticsearch.watcher.trigger.TriggerService; +import org.elasticsearch.watcher.trigger.schedule.Schedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.Schedules; import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.WatchService; import org.junit.After; @@ -83,8 +83,6 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg private TimeWarp timeWarp; boolean shieldEnabled = shieldEnabled(); - private TransportClient shieldWatcherTransportClient; - private WatcherClient shieldWatcherClient; @Override protected Settings nodeSettings(int nodeOrdinal) { @@ -127,9 +125,6 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg // Clear all internal watcher state for the next test method: logger.info("[{}#{}]: clearing watches", getTestClass().getSimpleName(), getTestName()); stopWatcher(); - if (shieldWatcherTransportClient != null) { - shieldWatcherTransportClient.close(); - } } @Override @@ -150,9 +145,7 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg private void setupTimeWarp() throws Exception { if (timeWarped()) { - timeWarp = new TimeWarp( - internalTestCluster().getInstance(SchedulerMock.class, internalTestCluster().getMasterName()), - internalTestCluster().getInstance(ClockMock.class, internalTestCluster().getMasterName())); + timeWarp = new TimeWarp(getInstanceFromMaster(ScheduleTriggerEngineMock.class), getInstanceFromMaster(ClockMock.class)); } } @@ -213,11 +206,12 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg } protected BytesReference createWatchSource(Schedule schedule, SearchRequest conditionRequest, String conditionScript, Map metadata) throws IOException { + ScheduleTrigger trigger = new ScheduleTrigger(schedule); XContentBuilder builder = jsonBuilder(); builder.startObject(); { - builder.startObject("schedule") - .field(schedule.type(), schedule) + builder.startObject("trigger") + .field(trigger.type(), trigger) .endObject(); if (metadata != null) { @@ -266,22 +260,18 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg return getInstanceFromMaster(Watch.Parser.class); } - protected Scheduler scheduler() { - return getInstanceFromMaster(Scheduler.class); + protected TriggerService triggerService() { + return getInstanceFromMaster(TriggerService.class); + } + + public AbstractWatcherIntegrationTests() { + super(); } protected WatcherClient watcherClient() { return shieldEnabled ? new WatcherClient(internalTestCluster().transportClient()) : new WatcherClient(client()); -// if (shieldEnabled) { -// if (shieldWatcherClient == null) { -// shieldWatcherClient = createShieldWatcherClient(); -// } -// return shieldWatcherClient; -// } -// WatcherClient client = internalTestCluster().getInstance(WatcherClient.class); -// return client; } protected ScriptServiceProxy scriptService() { @@ -521,15 +511,15 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg protected static class TimeWarp { - protected final SchedulerMock scheduler; + protected final ScheduleTriggerEngineMock scheduler; protected final ClockMock clock; - public TimeWarp(SchedulerMock scheduler, ClockMock clock) { + public TimeWarp(ScheduleTriggerEngineMock scheduler, ClockMock clock) { this.scheduler = scheduler; this.clock = clock; } - public SchedulerMock scheduler() { + public ScheduleTriggerEngineMock scheduler() { return scheduler; } diff --git a/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java b/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java index 479a1cb2a37..fa3a9da5f33 100644 --- a/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java +++ b/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java @@ -5,18 +5,18 @@ */ package org.elasticsearch.watcher.test; -import org.elasticsearch.watcher.WatcherPlugin; -import org.elasticsearch.watcher.history.WatchExecutor; -import org.elasticsearch.watcher.history.HistoryModule; -import org.elasticsearch.watcher.scheduler.SchedulerMock; -import org.elasticsearch.watcher.scheduler.SchedulerModule; -import org.elasticsearch.watcher.support.clock.Clock; -import org.elasticsearch.watcher.support.clock.ClockMock; -import org.elasticsearch.watcher.support.clock.ClockModule; import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.watcher.WatcherPlugin; +import org.elasticsearch.watcher.history.HistoryModule; +import org.elasticsearch.watcher.history.WatchExecutor; +import org.elasticsearch.watcher.support.clock.Clock; +import org.elasticsearch.watcher.support.clock.ClockMock; +import org.elasticsearch.watcher.support.clock.ClockModule; +import org.elasticsearch.watcher.trigger.ScheduleTriggerEngineMock; +import org.elasticsearch.watcher.trigger.TriggerModule; import java.util.ArrayList; import java.util.Collection; @@ -54,10 +54,10 @@ public class TimeWarpedWatcherPlugin extends WatcherPlugin { List modules = new ArrayList<>(); for (Module module : super.spawnModules()) { - if (module instanceof SchedulerModule) { + if (module instanceof TriggerModule) { // replacing scheduler module so we'll // have control on when it fires a job - modules.add(new MockSchedulerModule()); + modules.add(new MockTriggerModule()); } else if (module instanceof ClockModule) { // replacing the clock module so we'll be able @@ -76,12 +76,12 @@ public class TimeWarpedWatcherPlugin extends WatcherPlugin { return modules; } - public static class MockSchedulerModule extends SchedulerModule { + public static class MockTriggerModule extends TriggerModule { - public MockSchedulerModule() { - super(SchedulerMock.class); + @Override + protected void registerStandardEngines() { + registerEngine(ScheduleTriggerEngineMock.class); } - } public static class MockClockModule extends ClockModule { diff --git a/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java b/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java index 468d1ee755b..40fde1abff7 100644 --- a/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java +++ b/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java @@ -5,12 +5,12 @@ */ package org.elasticsearch.watcher.test; -import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.joda.time.DateTimeZone; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.netty.handler.codec.http.HttpMethod; import org.elasticsearch.common.unit.TimeValue; @@ -28,7 +28,6 @@ import org.elasticsearch.watcher.actions.webhook.HttpClient; import org.elasticsearch.watcher.actions.webhook.WebhookAction; import org.elasticsearch.watcher.condition.script.ScriptCondition; import org.elasticsearch.watcher.input.search.SearchInput; -import org.elasticsearch.watcher.scheduler.schedule.CronSchedule; import org.elasticsearch.watcher.support.Script; import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.support.clock.SystemClock; @@ -37,11 +36,13 @@ import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; import org.elasticsearch.watcher.support.template.ScriptTemplate; import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.transform.SearchTransform; +import org.elasticsearch.watcher.trigger.TriggerEvent; +import org.elasticsearch.watcher.trigger.schedule.CronSchedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.WatchExecutionContext; -import org.hamcrest.Description; -import org.hamcrest.TypeSafeMatcher; import javax.mail.internet.AddressException; import java.util.ArrayList; @@ -49,6 +50,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import static org.elasticsearch.common.joda.time.DateTimeZone.UTC; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource; import static org.mockito.Mockito.mock; @@ -89,18 +91,17 @@ public final class WatcherTestUtils { } public static WatchExecutionContext mockExecutionContext(String watchName, Payload payload) { - return mockExecutionContext(DateTime.now(), watchName, payload); + return mockExecutionContext(watchName, DateTime.now(UTC), payload); } - public static WatchExecutionContext mockExecutionContext(DateTime time, String watchName, Payload payload) { - return mockExecutionContext(time, time, time, watchName, payload); + public static WatchExecutionContext mockExecutionContext(String watchName, DateTime time, Payload payload) { + return mockExecutionContext(watchName, time, new ScheduleTriggerEvent(time, time), payload); } - public static WatchExecutionContext mockExecutionContext(DateTime executionTime, DateTime firedTime, DateTime scheduledTime, String watchName, Payload payload) { + public static WatchExecutionContext mockExecutionContext(String watchName, DateTime executionTime, TriggerEvent event, Payload payload) { WatchExecutionContext ctx = mock(WatchExecutionContext.class); when(ctx.executionTime()).thenReturn(executionTime); - when(ctx.fireTime()).thenReturn(firedTime); - when(ctx.scheduledTime()).thenReturn(scheduledTime); + when(ctx.triggerEvent()).thenReturn(event); Watch watch = mock(Watch.class); when(watch.name()).thenReturn(watchName); when(ctx.watch()).thenReturn(watch); @@ -143,7 +144,7 @@ public final class WatcherTestUtils { return new Watch( watchName, SystemClock.INSTANCE, - new CronSchedule("0/5 * * * * ? *"), + new ScheduleTrigger(new CronSchedule("0/5 * * * * ? *")), new SearchInput(logger, scriptService, ClientProxy.of(ElasticsearchIntegrationTest.client()), conditionRequest), new ScriptCondition(logger, scriptService, new Script("return true")), new SearchTransform(logger, scriptService, ClientProxy.of(ElasticsearchIntegrationTest.client()), transformRequest), diff --git a/src/test/java/org/elasticsearch/watcher/test/bench/WatcherBenchmark.java b/src/test/java/org/elasticsearch/watcher/test/bench/WatcherBenchmark.java index 0f93e8e7056..7f7606daa1e 100644 --- a/src/test/java/org/elasticsearch/watcher/test/bench/WatcherBenchmark.java +++ b/src/test/java/org/elasticsearch/watcher/test/bench/WatcherBenchmark.java @@ -17,10 +17,9 @@ import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.watcher.WatcherPlugin; import org.elasticsearch.watcher.client.WatchSourceBuilder; import org.elasticsearch.watcher.client.WatcherClient; -import org.elasticsearch.watcher.scheduler.Scheduler; -import org.elasticsearch.watcher.scheduler.SchedulerMock; -import org.elasticsearch.watcher.scheduler.SchedulerModule; import org.elasticsearch.watcher.transport.actions.put.PutWatchRequest; +import org.elasticsearch.watcher.trigger.ScheduleTriggerEngineMock; +import org.elasticsearch.watcher.trigger.TriggerModule; import java.util.ArrayList; import java.util.Collection; @@ -29,7 +28,8 @@ import java.util.List; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.input.InputBuilders.searchInput; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.interval; +import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval; /** */ @@ -51,7 +51,7 @@ public class WatcherBenchmark { for (int i = 0; i < numAlerts; i++) { final String name = "_name" + i; PutWatchRequest putAlertRequest = new PutWatchRequest(name, new WatchSourceBuilder() - .schedule(interval("5s")) + .trigger(schedule(interval("5s"))) .input(searchInput(new SearchRequest().source( new SearchSourceBuilder() ))) @@ -63,7 +63,7 @@ public class WatcherBenchmark { int numThreads = 50; int watchersPerThread = numAlerts / numThreads; - final SchedulerMock scheduler = (SchedulerMock) node.injector().getInstance(Scheduler.class); + final ScheduleTriggerEngineMock scheduler = node.injector().getInstance(ScheduleTriggerEngineMock.class); Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { final int begin = i * watchersPerThread; @@ -73,7 +73,7 @@ public class WatcherBenchmark { public void run() { while (true) { for (int j = begin; j < end; j++) { - scheduler.fire("_name" + j); + scheduler.trigger("_name" + j); } } } @@ -110,10 +110,10 @@ public class WatcherBenchmark { public Iterable spawnModules() { List modules = new ArrayList<>(); for (Module module : super.spawnModules()) { - if (module instanceof SchedulerModule) { + if (module instanceof TriggerModule) { // replacing scheduler module so we'll // have control on when it fires a job - modules.add(new MockSchedulerModule()); + modules.add(new MockTriggerModule()); } else { modules.add(module); @@ -122,10 +122,11 @@ public class WatcherBenchmark { return modules; } - public static class MockSchedulerModule extends SchedulerModule { + public static class MockTriggerModule extends TriggerModule { - public MockSchedulerModule() { - super(SchedulerMock.class); + @Override + protected void registerStandardEngines() { + registerEngine(ScheduleTriggerEngineMock.class); } } diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/BasicWatcherTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/BasicWatcherTests.java index 66e80625e90..cd61a0f13d3 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/BasicWatcherTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/BasicWatcherTests.java @@ -13,12 +13,13 @@ import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.watcher.WatcherException; import org.elasticsearch.watcher.client.WatchSourceBuilder; import org.elasticsearch.watcher.client.WatcherClient; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule; import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.transport.actions.delete.DeleteWatchResponse; import org.elasticsearch.watcher.transport.actions.get.GetWatchResponse; import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse; +import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule; +import org.elasticsearch.watcher.trigger.schedule.Schedules; import org.elasticsearch.watcher.watch.WatchStore; import org.junit.Test; @@ -32,10 +33,9 @@ import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.input.InputBuilders.searchInput; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.cron; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.interval; -import static org.elasticsearch.watcher.support.Variables.*; import static org.elasticsearch.watcher.test.WatcherTestUtils.newInputSearchRequest; +import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval; import static org.hamcrest.Matchers.*; /** @@ -52,13 +52,13 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value"))); watcherClient.preparePutWatch("_name") .source(watchSourceBuilder() - .schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)) + .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .input(searchInput(searchRequest)) .condition(scriptCondition("ctx.payload.hits.total == 1"))) .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } @@ -75,13 +75,13 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value"))); watcherClient.preparePutWatch("_name") .source(watchSourceBuilder() - .schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)) + .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .input(searchInput(searchRequest)) .condition(scriptCondition("ctx.payload.hits.total == 1"))) .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } @@ -93,7 +93,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { refresh(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } @@ -106,7 +106,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(matchAllQuery())); PutWatchResponse indexResponse = watcherClient.preparePutWatch("_name") .source(watchSourceBuilder() - .schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)) + .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .input(searchInput(searchRequest)) .condition(scriptCondition("ctx.payload.hits.total == 1"))) .get(); @@ -174,7 +174,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { .source(searchSource().query(matchAllQuery())); WatchSourceBuilder source = watchSourceBuilder() - .schedule(interval("5s")) + .trigger(schedule(interval("5s"))) .input(searchInput(searchRequest)) .addAction(indexAction("idx", "action")); @@ -183,7 +183,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } assertWatchWithMinimumPerformedActionsCount("_name", 0, false); @@ -193,17 +193,19 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } assertWatchWithMinimumPerformedActionsCount("_name", 1, false); watcherClient().preparePutWatch("_name") - .source(source.schedule(cron("0/1 * * * * ? 2020")).condition(scriptCondition("ctx.payload.hits.total == 0"))) + .source(source + .trigger(schedule(Schedules.cron("0/1 * * * * ? 2020"))) + .condition(scriptCondition("ctx.payload.hits.total == 0"))) .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } else { Thread.sleep(1000); @@ -212,7 +214,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { long count = findNumberOfPerformedActions("_name"); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); } else { Thread.sleep(1000); @@ -223,7 +225,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { @Test public void testConditionSearchWithSource() throws Exception { - String variable = randomFrom(EXECUTION_TIME, SCHEDULED_FIRE_TIME, FIRE_TIME); + String variable = randomFrom("ctx.execution_time", "ctx.trigger.scheduled_time", "ctx.trigger.triggered_time"); SearchSourceBuilder searchSourceBuilder = searchSource().query(filteredQuery( matchQuery("level", "a"), rangeFilter("_timestamp") @@ -235,7 +237,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { @Test public void testConditionSearchWithIndexedTemplate() throws Exception { - String variable = randomFrom(EXECUTION_TIME, SCHEDULED_FIRE_TIME, FIRE_TIME); + String variable = randomFrom("ctx.execution_time", "ctx.trigger.scheduled_time", "ctx.trigger.triggered_time"); SearchSourceBuilder searchSourceBuilder = searchSource().query(filteredQuery( matchQuery("level", "a"), rangeFilter("_timestamp") @@ -274,7 +276,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { refresh(); if (timeWarped()) { timeWarp().clock().fastForwardSeconds(5); - timeWarp().scheduler().fire(watchName); + timeWarp().scheduler().trigger(watchName); refresh(); } else { Thread.sleep(5000); @@ -288,7 +290,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { refresh(); if (timeWarped()) { timeWarp().clock().fastForwardSeconds(5); - timeWarp().scheduler().fire(watchName); + timeWarp().scheduler().trigger(watchName); refresh(); } else { Thread.sleep(5000); @@ -302,7 +304,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests { refresh(); if (timeWarped()) { timeWarp().clock().fastForwardSeconds(5); - timeWarp().scheduler().fire(watchName); + timeWarp().scheduler().trigger(watchName); refresh(); } else { Thread.sleep(5000); diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/BootStrapTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/BootStrapTests.java index e550d57fff5..5c2fa22578b 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/BootStrapTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/BootStrapTests.java @@ -8,16 +8,19 @@ package org.elasticsearch.watcher.test.integration; import org.elasticsearch.action.WriteConsistencyLevel; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.watcher.watch.Watch; -import org.elasticsearch.watcher.watch.WatchService; -import org.elasticsearch.watcher.watch.WatchStore; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.joda.time.DateTimeZone; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.condition.script.ScriptCondition; -import org.elasticsearch.watcher.history.WatchRecord; import org.elasticsearch.watcher.history.HistoryStore; +import org.elasticsearch.watcher.history.WatchRecord; import org.elasticsearch.watcher.input.search.SearchInput; -import org.elasticsearch.watcher.scheduler.schedule.CronSchedule; import org.elasticsearch.watcher.support.Script; import org.elasticsearch.watcher.support.clock.SystemClock; import org.elasticsearch.watcher.support.init.proxy.ClientProxy; @@ -26,13 +29,12 @@ import org.elasticsearch.watcher.test.WatcherTestUtils; import org.elasticsearch.watcher.transform.SearchTransform; import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse; import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.joda.time.DateTimeZone; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.test.junit.annotations.TestLogging; +import org.elasticsearch.watcher.trigger.schedule.CronSchedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; +import org.elasticsearch.watcher.watch.Watch; +import org.elasticsearch.watcher.watch.WatchService; +import org.elasticsearch.watcher.watch.WatchStore; import org.junit.Test; import java.util.ArrayList; @@ -82,7 +84,7 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests { Watch watch = new Watch( "test-serialization", SystemClock.INSTANCE, - new CronSchedule("0/5 * * * * ? 2035"), //Set this into the future so we don't get any extra runs + new ScheduleTrigger(new CronSchedule("0/5 * * * * ? 2035")), //Set this into the future so we don't get any extra runs new SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest), new ScriptCondition(logger, scriptService(), new Script("return true")), new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest), @@ -98,9 +100,10 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests { refresh(); assertThat(indexResponse.isCreated(), is(true)); - DateTime scheduledFireTime = new DateTime(DateTimeZone.UTC); - WatchRecord watchRecord = new WatchRecord(watch, scheduledFireTime, scheduledFireTime); - String actionHistoryIndex = HistoryStore.getHistoryIndexNameForTime(scheduledFireTime); + DateTime now = DateTime.now(DateTimeZone.UTC); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(now, now); + WatchRecord watchRecord = new WatchRecord(watch, event); + String actionHistoryIndex = HistoryStore.getHistoryIndexNameForTime(now); createIndex(actionHistoryIndex); ensureGreen(actionHistoryIndex); @@ -141,7 +144,7 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests { Watch watch = new Watch( "action-test-" + i + " " + j, SystemClock.INSTANCE, - new CronSchedule("0/5 * * * * ? 2035"), //Set a cron schedule far into the future so this watch is never scheduled + new ScheduleTrigger(new CronSchedule("0/5 * * * * ? 2035")), //Set a cron schedule far into the future so this watch is never scheduled new SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest), new ScriptCondition(logger, scriptService(), new Script("return true")), @@ -156,7 +159,8 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests { PutWatchResponse putWatchResponse = watcherClient().preparePutWatch(watch.name()).source(jsonBuilder.bytes()).get(); assertThat(putWatchResponse.indexResponse().isCreated(), is(true)); - WatchRecord watchRecord = new WatchRecord(watch, historyIndexDate, historyIndexDate); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(historyIndexDate, historyIndexDate); + WatchRecord watchRecord = new WatchRecord(watch, event); XContentBuilder jsonBuilder2 = jsonBuilder(); watchRecord.toXContent(jsonBuilder2, ToXContent.EMPTY_PARAMS); diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/TransformSearchTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/TransformSearchTests.java index e7e31f7dda9..ce00c8bed6d 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/TransformSearchTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/TransformSearchTests.java @@ -7,13 +7,13 @@ package org.elasticsearch.watcher.test.integration; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule.Interval; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.test.WatcherTestUtils; import org.elasticsearch.watcher.transform.SearchTransform; import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.search.SearchHit; +import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule; import org.junit.Test; import java.util.HashMap; @@ -22,10 +22,11 @@ import java.util.Map; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.input.InputBuilders.searchInput; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.interval; import static org.elasticsearch.watcher.transform.TransformBuilders.searchTransform; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource; +import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval; import static org.hamcrest.Matchers.*; /** @@ -50,17 +51,17 @@ public class TransformSearchTests extends AbstractWatcherIntegrationTests { PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("test-payload") .source(watchSourceBuilder() - .schedule(interval(5, Interval.Unit.SECONDS)) + .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .input(searchInput(inputRequest)) .transform(searchTransform(transformRequest)) .addAction(indexAction("my-payload-output", "result")) .metadata(metadata) .throttlePeriod(TimeValue.timeValueSeconds(0))) - .get(); + .get(); assertThat(putWatchResponse.indexResponse().isCreated(), is(true)); if (timeWarped()) { - timeWarp().scheduler().fire("test-payload"); + timeWarp().scheduler().trigger("test-payload"); refresh(); } diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/WatchMetadataTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/WatchMetadataTests.java index b84e677da3a..446e7eb7364 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/WatchMetadataTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/WatchMetadataTests.java @@ -19,10 +19,11 @@ import java.util.Map; import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.input.InputBuilders.searchInput; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.cron; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource; +import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.cron; import static org.hamcrest.Matchers.greaterThan; /** @@ -43,14 +44,14 @@ public class WatchMetadataTests extends AbstractWatcherIntegrationTests { metadata.put("baz", metaList); watcherClient().preparePutWatch("_name") .source(watchSourceBuilder() - .schedule(cron("0/5 * * * * ? *")) + .trigger(schedule(cron("0/5 * * * * ? *"))) .input(searchInput(WatcherTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery())))) .condition(scriptCondition("ctx.payload.hits.total == 1")) .metadata(metadata)) - .get(); + .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); } else { // Wait for a no action entry to be added. (the condition search request will not match, because there are no docs in my-index) assertWatchWithNoActionNeeded("_name", 1); diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/WatchStatsTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/WatchStatsTests.java index 7dd1372131a..36a45b08636 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/WatchStatsTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/WatchStatsTests.java @@ -63,7 +63,7 @@ public class WatchStatsTests extends AbstractWatcherIntegrationTests { .get(); if (timeWarped()) { - timeWarp().scheduler().fire("_name", 30, TimeValue.timeValueSeconds(1)); + timeWarp().scheduler().trigger("_name", 30, TimeValue.timeValueSeconds(1)); } else { //Wait a little until we should have queued an action Thread.sleep(TimeUnit.SECONDS.toMillis(5)); diff --git a/src/test/java/org/elasticsearch/watcher/test/integration/WatchThrottleTests.java b/src/test/java/org/elasticsearch/watcher/test/integration/WatchThrottleTests.java index 42369d4415d..19202a6bb6f 100644 --- a/src/test/java/org/elasticsearch/watcher/test/integration/WatchThrottleTests.java +++ b/src/test/java/org/elasticsearch/watcher/test/integration/WatchThrottleTests.java @@ -7,30 +7,31 @@ package org.elasticsearch.watcher.test.integration; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.index.IndexResponse; -import org.elasticsearch.watcher.watch.Watch; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.watcher.actions.ActionBuilders; import org.elasticsearch.watcher.client.WatcherClient; -import org.elasticsearch.watcher.history.WatchRecord; import org.elasticsearch.watcher.history.HistoryStore; +import org.elasticsearch.watcher.history.WatchRecord; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.transport.actions.ack.AckWatchResponse; import org.elasticsearch.watcher.transport.actions.get.GetWatchResponse; import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse; -import org.elasticsearch.common.joda.time.DateTime; -import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.watcher.watch.Watch; import org.junit.Test; import java.util.concurrent.TimeUnit; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.input.InputBuilders.searchInput; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.cron; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.interval; import static org.elasticsearch.watcher.test.WatcherTestUtils.matchAllRequest; import static org.elasticsearch.watcher.transform.TransformBuilders.searchTransform; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.cron; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.IsEqual.equalTo; @@ -53,7 +54,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { PutWatchResponse putWatchResponse = watcherClient.preparePutWatch() .watchName("_name") .source(watchSourceBuilder() - .schedule(cron("0/5 * * * * ? *")) + .trigger(schedule(cron("0/5 * * * * ? *"))) .input(searchInput(matchAllRequest().indices("events"))) .condition(scriptCondition("ctx.payload.hits.total > 0")) .transform(searchTransform(matchAllRequest().indices("events"))) @@ -63,7 +64,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { assertThat(putWatchResponse.indexResponse().isCreated(), is(true)); if (timeWarped()) { - timeWarp().scheduler().fire("_name", 4, TimeValue.timeValueSeconds(5)); + timeWarp().scheduler().trigger("_name", 4, TimeValue.timeValueSeconds(5)); } else { Thread.sleep(20000); } @@ -75,7 +76,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { assertThat(countAfterAck, greaterThanOrEqualTo((long) 1)); if (timeWarped()) { - timeWarp().scheduler().fire("_name", 4, TimeValue.timeValueSeconds(5)); + timeWarp().scheduler().trigger("_name", 4, TimeValue.timeValueSeconds(5)); } else { Thread.sleep(20000); } @@ -91,7 +92,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { refresh(); if (timeWarped()) { - timeWarp().scheduler().fire("_name", 4, TimeValue.timeValueSeconds(5)); + timeWarp().scheduler().trigger("_name", 4, TimeValue.timeValueSeconds(5)); } else { Thread.sleep(20000); } @@ -124,7 +125,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { PutWatchResponse putWatchResponse = watcherClient.preparePutWatch() .watchName("_name") .source(watchSourceBuilder() - .schedule(interval("5s")) + .trigger(schedule(interval("5s"))) .input(searchInput(matchAllRequest().indices("events"))) .condition(scriptCondition("ctx.payload.hits.total > 0")) .transform(searchTransform(matchAllRequest().indices("events"))) @@ -136,7 +137,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { if (timeWarped()) { timeWarp().clock().setTime(DateTime.now()); - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); // the first fire should work @@ -144,7 +145,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { assertThat(actionsCount, is(1L)); timeWarp().clock().fastForwardSeconds(5); - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); // the last fire should have been throttled, so number of actions shouldn't change @@ -152,7 +153,7 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests { assertThat(actionsCount, is(1L)); timeWarp().clock().fastForwardSeconds(10); - timeWarp().scheduler().fire("_name"); + timeWarp().scheduler().trigger("_name"); refresh(); // the last fire occurred passed the throttle period, so a new action should have been added diff --git a/src/test/java/org/elasticsearch/watcher/transform/ChainTransformTests.java b/src/test/java/org/elasticsearch/watcher/transform/ChainTransformTests.java index 845fb6e754e..90bb4bb68d1 100644 --- a/src/test/java/org/elasticsearch/watcher/transform/ChainTransformTests.java +++ b/src/test/java/org/elasticsearch/watcher/transform/ChainTransformTests.java @@ -5,14 +5,14 @@ */ package org.elasticsearch.watcher.transform; -import org.elasticsearch.watcher.watch.WatchExecutionContext; -import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.test.ElasticsearchTestCase; +import org.elasticsearch.watcher.watch.Payload; +import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/org/elasticsearch/watcher/transform/SearchTransformTests.java b/src/test/java/org/elasticsearch/watcher/transform/SearchTransformTests.java index 388fb3fb6d5..eae425ea394 100644 --- a/src/test/java/org/elasticsearch/watcher/transform/SearchTransformTests.java +++ b/src/test/java/org/elasticsearch/watcher/transform/SearchTransformTests.java @@ -15,9 +15,9 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.script.ScriptService; -import org.elasticsearch.watcher.support.Variables; import org.elasticsearch.watcher.support.init.proxy.ClientProxy; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.junit.Test; @@ -104,13 +104,14 @@ public class SearchTransformTests extends AbstractWatcherIntegrationTests { refresh(); SearchRequest request = Requests.searchRequest("idx").source(searchSource().query(filteredQuery(matchAllQuery(), boolFilter() - .must(rangeFilter("date").gt("{{" + Variables.CTX + "." + Variables.SCHEDULED_FIRE_TIME + "}}")) - .must(rangeFilter("date").lt("{{" + Variables.CTX + "." + Variables.EXECUTION_TIME + "}}")) - .must(termFilter("value", "{{" + Variables.CTX + "." + Variables.PAYLOAD + ".value}}"))))); + .must(rangeFilter("date").gt("{{ctx.trigger.scheduled_time}}")) + .must(rangeFilter("date").lt("{{ctx.execution_time}}")) + .must(termFilter("value", "{{ctx.payload.value}}"))))); SearchTransform transform = new SearchTransform(logger, scriptService(), ClientProxy.of(client()), request); - WatchExecutionContext ctx = mockExecutionContext(parseDate("2015-01-04T00:00:00"), parseDate("2015-01-04T00:00:00"), parseDate("2015-01-01T00:00:00"), "_name", EMPTY_PAYLOAD); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(parseDate("2015-01-04T00:00:00"), parseDate("2015-01-01T00:00:00")); + WatchExecutionContext ctx = mockExecutionContext("_name", parseDate("2015-01-04T00:00:00"), event, EMPTY_PAYLOAD); Payload payload = simplePayload("value", "val_3"); @@ -140,7 +141,6 @@ public class SearchTransformTests extends AbstractWatcherIntegrationTests { SearchType searchType = randomBoolean() ? null : randomFrom(SearchType.values()); String templateName = randomBoolean() ? null : "template1"; ScriptService.ScriptType templateType = templateName != null && randomBoolean() ? randomFrom(ScriptService.ScriptType.values()) : null; - BytesReference source = null; XContentBuilder builder = jsonBuilder().startObject(); if (indices != null) { builder.array("indices", indices); @@ -163,7 +163,7 @@ public class SearchTransformTests extends AbstractWatcherIntegrationTests { .endObject() .endObject() .endObject(); - source = sourceBuilder.bytes(); + BytesReference source = sourceBuilder.bytes(); builder.startObject("body") .startObject("query") diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/SchedulerMock.java b/src/test/java/org/elasticsearch/watcher/trigger/ScheduleTriggerEngineMock.java similarity index 55% rename from src/test/java/org/elasticsearch/watcher/scheduler/SchedulerMock.java rename to src/test/java/org/elasticsearch/watcher/trigger/ScheduleTriggerEngineMock.java index 4f8d0958100..d3d47802f0c 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/SchedulerMock.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/ScheduleTriggerEngineMock.java @@ -3,42 +3,58 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler; +package org.elasticsearch.watcher.trigger; -import org.elasticsearch.watcher.support.clock.Clock; -import org.elasticsearch.watcher.support.clock.ClockMock; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.watcher.support.clock.Clock; +import org.elasticsearch.watcher.support.clock.ClockMock; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEngine; +import org.elasticsearch.watcher.trigger.schedule.ScheduleRegistry; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; +import java.io.IOException; import java.util.Collection; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; /** - * A mock scheduler to help with unit testing. Provide {@link SchedulerMock#fire} method to manually trigger + * A mock scheduler to help with unit testing. Provide {@link ScheduleTriggerEngineMock#trigger} method to manually trigger * jobs. */ -public class SchedulerMock implements Scheduler { +public class ScheduleTriggerEngineMock extends ScheduleTriggerEngine { private final ESLogger logger; - private final List listeners = new CopyOnWriteArrayList<>(); private final ConcurrentMap jobs = new ConcurrentHashMap<>(); private final Clock clock; + private final ScheduleRegistry scheduleRegistry; @Inject - public SchedulerMock(Settings settings, Clock clock) { - this.logger = Loggers.getLogger(SchedulerMock.class, settings); + public ScheduleTriggerEngineMock(Settings settings, ScheduleRegistry scheduleRegistry, Clock clock) { + super(settings); + this.logger = Loggers.getLogger(ScheduleTriggerEngineMock.class, settings); + this.scheduleRegistry = scheduleRegistry; this.clock = clock; } @Override - public void start(Collection jobs) { + public ScheduleTrigger parseTrigger(String context, XContentParser parser) throws IOException { + return new ScheduleTrigger(scheduleRegistry.parse(context, parser)); + } + + @Override + public ScheduleTriggerEvent parseTriggerEvent(String context, XContentParser parser) throws IOException { + return ScheduleTriggerEvent.parse(context, parser); + } + + @Override + public void start(Collection jobs) { } @Override @@ -55,25 +71,21 @@ public class SchedulerMock implements Scheduler { return jobs.remove(jobName) != null; } - @Override - public void addListener(Listener listener) { - listeners.add(listener); + public void trigger(String jobName) { + trigger(jobName, 1, null); } - public void fire(String jobName) { - fire(jobName, 1, null); + public void trigger(String jobName, int times) { + trigger(jobName, times, null); } - public void fire(String jobName, int times) { - fire(jobName, times, null); - } - - public void fire(String jobName, int times, TimeValue interval) { + public void trigger(String jobName, int times, TimeValue interval) { for (int i = 0; i < times; i++) { DateTime now = clock.now(); logger.debug("firing [" + jobName + "] at [" + now + "]"); + ScheduleTriggerEvent event = new ScheduleTriggerEvent(now, now); for (Listener listener : listeners) { - listener.fire(jobName, now, now); + listener.triggered(jobName, event); } if (clock instanceof ClockMock) { ((ClockMock) clock).fastForward(interval == null ? TimeValue.timeValueMillis(10) : interval); diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/CronScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/CronScheduleTests.java similarity index 98% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/CronScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/CronScheduleTests.java index 916f4bb2560..b662c7e2f0f 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/CronScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/CronScheduleTests.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.watcher.WatcherSettingsException; import org.elasticsearch.common.bytes.BytesReference; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/DailyScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/DailyScheduleTests.java similarity index 98% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/DailyScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/DailyScheduleTests.java index 9abddc2a2d2..b34bf605ce5 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/DailyScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/DailyScheduleTests.java @@ -3,16 +3,16 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; import org.junit.Test; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/HourlyScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/HourlyScheduleTests.java similarity index 99% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/HourlyScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/HourlyScheduleTests.java index fe7d3928239..3047b98a829 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/HourlyScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/HourlyScheduleTests.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.watcher.WatcherSettingsException; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/IntervalScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/IntervalScheduleTests.java similarity index 93% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/IntervalScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/IntervalScheduleTests.java index a4dc5497b3e..5477d7f1204 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/IntervalScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/IntervalScheduleTests.java @@ -3,10 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule.Interval.Unit; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -66,7 +65,7 @@ public class IntervalScheduleTests extends ElasticsearchTestCase { } private static IntervalSchedule.Interval randomTimeValue() { - Unit unit = Unit.values()[randomIntBetween(0, Unit.values().length - 1)]; + IntervalSchedule.Interval.Unit unit = IntervalSchedule.Interval.Unit.values()[randomIntBetween(0, IntervalSchedule.Interval.Unit.values().length - 1)]; return new IntervalSchedule.Interval(randomIntBetween(1, 100), unit); } } diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/MonthlyScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/MonthlyScheduleTests.java similarity index 97% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/MonthlyScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/MonthlyScheduleTests.java index 5966d2a4b6c..6610877f9ea 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/MonthlyScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/MonthlyScheduleTests.java @@ -3,17 +3,17 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; -import org.elasticsearch.watcher.scheduler.schedule.support.MonthTimes; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; +import org.elasticsearch.watcher.trigger.schedule.support.MonthTimes; import org.junit.Test; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistryTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistryTests.java similarity index 90% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistryTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistryTests.java index e199e0e0ed8..b467a3d2a85 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleRegistryTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleRegistryTests.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.common.bytes.BytesReference; @@ -16,7 +16,6 @@ import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.cron; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.*; @@ -49,7 +48,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(IntervalSchedule.class)); assertThat((IntervalSchedule) schedule, is(interval)); @@ -58,8 +57,8 @@ public class ScheduleRegistryTests extends ScheduleTestCase { @Test @Repeat(iterations = 20) public void testParse_Cron() throws Exception { Object cron = randomBoolean() ? - cron("* 0/5 * * * ?") : - cron("* 0/2 * * * ?", "* 0/3 * * * ?", "* 0/5 * * * ?"); + Schedules.cron("* 0/5 * * * ?") : + Schedules.cron("* 0/2 * * * ?", "* 0/3 * * * ?", "* 0/5 * * * ?"); XContentBuilder builder = jsonBuilder() .startObject() .field(CronSchedule.TYPE, cron) @@ -67,7 +66,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(CronSchedule.class)); assertThat(schedule, is(cron)); @@ -83,7 +82,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(HourlySchedule.class)); assertThat((HourlySchedule) schedule, equalTo(hourly)); @@ -99,7 +98,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(DailySchedule.class)); assertThat((DailySchedule) schedule, equalTo(daily)); @@ -115,7 +114,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(WeeklySchedule.class)); assertThat((WeeklySchedule) schedule, equalTo(weekly)); @@ -131,7 +130,7 @@ public class ScheduleRegistryTests extends ScheduleTestCase { BytesReference bytes = builder.bytes(); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); parser.nextToken(); - Schedule schedule = registry.parse(parser); + Schedule schedule = registry.parse("ctx", parser); assertThat(schedule, notNullValue()); assertThat(schedule, instanceOf(MonthlySchedule.class)); assertThat((MonthlySchedule) schedule, equalTo(monthly)); diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleTestCase.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTestCase.java similarity index 96% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleTestCase.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTestCase.java index b217a1a4c2b..b805c1e6c79 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/ScheduleTestCase.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/ScheduleTestCase.java @@ -3,21 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import org.elasticsearch.common.primitives.Ints; -import org.elasticsearch.watcher.scheduler.schedule.IntervalSchedule.Interval.Unit; -import org.elasticsearch.watcher.scheduler.schedule.support.*; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.test.ElasticsearchTestCase; +import org.elasticsearch.watcher.trigger.schedule.support.*; import java.io.IOException; import java.util.EnumSet; import java.util.HashSet; import java.util.Set; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.*; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.*; /** * @@ -72,8 +71,8 @@ public abstract class ScheduleTestCase extends ElasticsearchTestCase { return new IntervalSchedule.Interval(randomIntBetween(1, 100), randomIntervalUnit()); } - protected static Unit randomIntervalUnit() { - return Unit.values()[randomIntBetween(0, Unit.values().length - 1)]; + protected static IntervalSchedule.Interval.Unit randomIntervalUnit() { + return IntervalSchedule.Interval.Unit.values()[randomIntBetween(0, IntervalSchedule.Interval.Unit.values().length - 1)]; } protected static YearTimes validYearTime() { diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/WeeklyScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/WeeklyScheduleTests.java similarity index 95% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/WeeklyScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/WeeklyScheduleTests.java index 4a847df4bf7..091ccefdfc8 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/WeeklyScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/WeeklyScheduleTests.java @@ -3,19 +3,19 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; -import org.elasticsearch.watcher.scheduler.schedule.support.DayOfWeek; -import org.elasticsearch.watcher.scheduler.schedule.support.WeekTimes; import org.elasticsearch.common.base.Joiner; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.watcher.trigger.schedule.support.DayOfWeek; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; +import org.elasticsearch.watcher.trigger.schedule.support.WeekTimes; import org.junit.Test; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/YearlyScheduleTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/YearlyScheduleTests.java similarity index 97% rename from src/test/java/org/elasticsearch/watcher/scheduler/schedule/YearlyScheduleTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/YearlyScheduleTests.java index 758fdcc334e..93f8b0b139f 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/schedule/YearlyScheduleTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/YearlyScheduleTests.java @@ -3,18 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler.schedule; +package org.elasticsearch.watcher.trigger.schedule; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.elasticsearch.watcher.WatcherSettingsException; -import org.elasticsearch.watcher.scheduler.schedule.support.DayTimes; -import org.elasticsearch.watcher.scheduler.schedule.support.YearTimes; import org.elasticsearch.common.base.Joiner; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.primitives.Ints; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.watcher.trigger.schedule.support.DayTimes; +import org.elasticsearch.watcher.trigger.schedule.support.YearTimes; import org.junit.Test; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; diff --git a/src/test/java/org/elasticsearch/watcher/scheduler/InternalSchedulerTests.java b/src/test/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleEngineTests.java similarity index 78% rename from src/test/java/org/elasticsearch/watcher/scheduler/InternalSchedulerTests.java rename to src/test/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleEngineTests.java index 2ad2fb50584..746b396c2dd 100644 --- a/src/test/java/org/elasticsearch/watcher/scheduler/InternalSchedulerTests.java +++ b/src/test/java/org/elasticsearch/watcher/trigger/schedule/quartz/QuartzScheduleEngineTests.java @@ -3,20 +3,25 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.watcher.scheduler; +package org.elasticsearch.watcher.trigger.schedule.quartz; import org.apache.lucene.util.LuceneTestCase.Slow; -import org.elasticsearch.watcher.WatcherPlugin; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; -import org.elasticsearch.watcher.scheduler.schedule.support.DayOfWeek; -import org.elasticsearch.watcher.scheduler.schedule.support.WeekTimes; -import org.elasticsearch.watcher.support.clock.SystemClock; import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.joda.time.DateTimeZone; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.watcher.WatcherPlugin; +import org.elasticsearch.watcher.support.clock.SystemClock; +import org.elasticsearch.watcher.trigger.Trigger; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.TriggerEvent; +import org.elasticsearch.watcher.trigger.schedule.Schedule; +import org.elasticsearch.watcher.trigger.schedule.ScheduleRegistry; +import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger; +import org.elasticsearch.watcher.trigger.schedule.support.DayOfWeek; +import org.elasticsearch.watcher.trigger.schedule.support.WeekTimes; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -28,17 +33,18 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.elasticsearch.watcher.scheduler.schedule.Schedules.*; +import static org.elasticsearch.watcher.trigger.schedule.Schedules.*; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; /** * */ @Slow -public class InternalSchedulerTests extends ElasticsearchTestCase { +public class QuartzScheduleEngineTests extends ElasticsearchTestCase { private ThreadPool threadPool; - private InternalScheduler scheduler; + private QuartzScheduleTriggerEngine engine; @Before public void init() throws Exception { @@ -48,12 +54,12 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { .put("name", "test") .build(); threadPool = new ThreadPool(settings, null); - scheduler = new InternalScheduler(ImmutableSettings.EMPTY, threadPool, SystemClock.INSTANCE); + engine = new QuartzScheduleTriggerEngine(ImmutableSettings.EMPTY, mock(ScheduleRegistry.class), threadPool, SystemClock.INSTANCE); } @After public void cleanup() throws Exception { - scheduler.stop(); + engine.stop(); threadPool.shutdownNow(); } @@ -61,14 +67,14 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { public void testStart() throws Exception { int count = randomIntBetween(2, 5); final CountDownLatch latch = new CountDownLatch(count); - List jobs = new ArrayList<>(); + List jobs = new ArrayList<>(); for (int i = 0; i < count; i++) { jobs.add(new SimpleJob(String.valueOf(i), interval("3s"))); } final BitSet bits = new BitSet(count); - scheduler.addListener(new Scheduler.Listener() { + engine.register(new TriggerEngine.Listener() { @Override - public void fire(String jobName, DateTime scheduledFireTime, DateTime fireTime) { + public void triggered(String jobName, TriggerEvent event) { int index = Integer.parseInt(jobName); if (!bits.get(index)) { logger.info("job [" + index + "] first fire: " + new DateTime()); @@ -79,11 +85,11 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { } } }); - scheduler.start(jobs); + engine.start(jobs); if (!latch.await(5, TimeUnit.SECONDS)) { fail("waiting too long for all watches to be triggered"); } - scheduler.stop(); + engine.stop(); assertThat(bits.cardinality(), is(count)); } @@ -91,10 +97,10 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { public void testAdd_Hourly() throws Exception { final String name = "job_name"; final CountDownLatch latch = new CountDownLatch(1); - scheduler.start(Collections.emptySet()); - scheduler.addListener(new Scheduler.Listener() { + engine.start(Collections.emptySet()); + engine.register(new TriggerEngine.Listener() { @Override - public void fire(String jobName, DateTime scheduledFireTime, DateTime fireTime) { + public void triggered(String jobName, TriggerEvent event) { assertThat(jobName, is(name)); logger.info("triggered job on [{}]", new DateTime()); latch.countDown(); @@ -110,7 +116,7 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { int minute = minOfHour.value; logger.info("scheduling hourly job [{}]", minute); logger.info("current date [{}]", now); - scheduler.add(new SimpleJob(name, hourly(minute))); + engine.add(new SimpleJob(name, hourly(minute))); long secondsToWait = now.getSecondOfMinute() < 29 ? 62 - now.getSecondOfMinute() : 122 - now.getSecondOfMinute(); logger.info("waiting at least [{}] seconds for response", secondsToWait); if (!latch.await(secondsToWait, TimeUnit.SECONDS)) { @@ -122,10 +128,10 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { public void testAdd_Daily() throws Exception { final String name = "job_name"; final CountDownLatch latch = new CountDownLatch(1); - scheduler.start(Collections.emptySet()); - scheduler.addListener(new Scheduler.Listener() { + engine.start(Collections.emptySet()); + engine.register(new TriggerEngine.Listener() { @Override - public void fire(String jobName, DateTime scheduledFireTime, DateTime fireTime) { + public void triggered(String jobName, TriggerEvent event) { assertThat(jobName, is(name)); logger.info("triggered job on [{}]", new DateTime()); latch.countDown(); @@ -142,7 +148,7 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { int hour = hourOfDay.value; logger.info("scheduling hourly job [{}:{}]", hour, minute); logger.info("current date [{}]", now); - scheduler.add(new SimpleJob(name, daily().at(hour, minute).build())); + engine.add(new SimpleJob(name, daily().at(hour, minute).build())); // 30 sec is the default idle time of quartz long secondsToWait = now.getSecondOfMinute() < 29 ? 62 - now.getSecondOfMinute() : 122 - now.getSecondOfMinute(); logger.info("waiting at least [{}] seconds for response", secondsToWait); @@ -155,10 +161,10 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { public void testAdd_Weekly() throws Exception { final String name = "job_name"; final CountDownLatch latch = new CountDownLatch(1); - scheduler.start(Collections.emptySet()); - scheduler.addListener(new Scheduler.Listener() { + engine.start(Collections.emptySet()); + engine.register(new TriggerEngine.Listener() { @Override - public void fire(String jobName, DateTime scheduledFireTime, DateTime fireTime) { + public void triggered(String jobName, TriggerEvent event) { assertThat(jobName, is(name)); logger.info("triggered job on [{}]", new DateTime()); latch.countDown(); @@ -177,7 +183,7 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { DayOfWeek day = dayOfWeek.day(); logger.info("scheduling hourly job [{} {}:{}]", day, hour, minute); logger.info("current date [{}]", now); - scheduler.add(new SimpleJob(name, weekly().time(WeekTimes.builder().on(day).at(hour, minute).build()).build())); + engine.add(new SimpleJob(name, weekly().time(WeekTimes.builder().on(day).at(hour, minute).build()).build())); // 30 sec is the default idle time of quartz long secondsToWait = now.getSecondOfMinute() < 29 ? 62 - now.getSecondOfMinute() : 122 - now.getSecondOfMinute(); logger.info("waiting at least [{}] seconds for response", secondsToWait); @@ -186,14 +192,14 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { } } - static class SimpleJob implements Scheduler.Job { + static class SimpleJob implements TriggerEngine.Job { private final String name; - private final Schedule schedule; + private final ScheduleTrigger trigger; public SimpleJob(String name, Schedule schedule) { this.name = name; - this.schedule = schedule; + this.trigger = new ScheduleTrigger(schedule); } @Override @@ -202,8 +208,8 @@ public class InternalSchedulerTests extends ElasticsearchTestCase { } @Override - public Schedule schedule() { - return schedule; + public Trigger trigger() { + return trigger; } } diff --git a/src/test/java/org/elasticsearch/watcher/watch/WatchServiceTests.java b/src/test/java/org/elasticsearch/watcher/watch/WatchServiceTests.java index 25c698353f9..22dac936368 100644 --- a/src/test/java/org/elasticsearch/watcher/watch/WatchServiceTests.java +++ b/src/test/java/org/elasticsearch/watcher/watch/WatchServiceTests.java @@ -7,14 +7,15 @@ package org.elasticsearch.watcher.watch; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.index.IndexResponse; -import org.elasticsearch.watcher.WatcherException; -import org.elasticsearch.watcher.history.HistoryService; -import org.elasticsearch.watcher.scheduler.Scheduler; -import org.elasticsearch.watcher.scheduler.schedule.Schedule; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.test.ElasticsearchTestCase; +import org.elasticsearch.watcher.WatcherException; +import org.elasticsearch.watcher.history.HistoryService; +import org.elasticsearch.watcher.trigger.Trigger; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.TriggerService; import org.junit.Before; import org.junit.Test; @@ -30,7 +31,7 @@ import static org.mockito.Mockito.*; */ public class WatchServiceTests extends ElasticsearchTestCase { - private Scheduler scheduler; + private TriggerService triggerService; private WatchStore watchStore; private WatchService watchService; private HistoryService historyService; @@ -38,11 +39,11 @@ public class WatchServiceTests extends ElasticsearchTestCase { @Before public void init() throws Exception { - scheduler = mock(Scheduler.class); + triggerService = mock(TriggerService.class); watchStore = mock(WatchStore.class); historyService = mock(HistoryService.class); watchLockService = mock(WatchLockService.class); - watchService = new WatchService(ImmutableSettings.EMPTY, scheduler, watchStore, historyService, watchLockService); + watchService = new WatchService(ImmutableSettings.EMPTY, triggerService, watchStore, historyService, watchLockService); Field field = WatchService.class.getDeclaredField("state"); field.setAccessible(true); AtomicReference state = (AtomicReference) field.get(watchService); @@ -63,21 +64,21 @@ public class WatchServiceTests extends ElasticsearchTestCase { IndexResponse response = watchService.putWatch("_name", new BytesArray("{}")); assertThat(response, sameInstance(indexResponse)); - verify(scheduler, times(1)).add(any(Scheduler.Job.class)); + verify(triggerService, times(1)).add(any(TriggerEngine.Job.class)); } @Test public void testPutWatch_NotSchedule() { - Schedule schedule = mock(Schedule.class); + Trigger trigger = mock(Trigger.class); IndexResponse indexResponse = mock(IndexResponse.class); Watch watch = mock(Watch.class); - when(watch.schedule()).thenReturn(schedule); + when(watch.trigger()).thenReturn(trigger); WatchStore.WatchPut watchPut = mock(WatchStore.WatchPut.class); when(watchPut.indexResponse()).thenReturn(indexResponse); when(watchPut.current()).thenReturn(watch); Watch previousWatch = mock(Watch.class); - when(previousWatch.schedule()).thenReturn(schedule); + when(previousWatch.trigger()).thenReturn(trigger); when(watchPut.previous()).thenReturn(previousWatch); WatchLockService.Lock lock = mock(WatchLockService.Lock.class); @@ -86,7 +87,7 @@ public class WatchServiceTests extends ElasticsearchTestCase { IndexResponse response = watchService.putWatch("_name", new BytesArray("{}")); assertThat(response, sameInstance(indexResponse)); - verifyZeroInteractions(scheduler); + verifyZeroInteractions(triggerService); } @Test @@ -102,7 +103,7 @@ public class WatchServiceTests extends ElasticsearchTestCase { WatchStore.WatchDelete watchDelete = watchService.deleteWatch("_name"); assertThat(watchDelete, sameInstance(expectedWatchDelete)); - verify(scheduler, times(1)).remove("_name"); + verify(triggerService, times(1)).remove("_name"); } @Test @@ -118,7 +119,7 @@ public class WatchServiceTests extends ElasticsearchTestCase { WatchStore.WatchDelete watchDelete = watchService.deleteWatch("_name"); assertThat(watchDelete, sameInstance(expectedWatchDelete)); - verifyZeroInteractions(scheduler); + verifyZeroInteractions(triggerService); } @Test diff --git a/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java b/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java index 35d54f69990..6b374138ba2 100644 --- a/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java +++ b/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java @@ -5,7 +5,20 @@ */ package org.elasticsearch.watcher.watch; +import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableSet; import com.carrotsearch.randomizedtesting.annotations.Repeat; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.collect.ImmutableList; +import org.elasticsearch.common.collect.ImmutableMap; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.common.netty.handler.codec.http.HttpMethod; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.ActionRegistry; import org.elasticsearch.watcher.actions.Actions; @@ -24,31 +37,25 @@ import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.InputRegistry; import org.elasticsearch.watcher.input.search.SearchInput; import org.elasticsearch.watcher.input.simple.SimpleInput; -import org.elasticsearch.watcher.scheduler.schedule.*; -import org.elasticsearch.watcher.scheduler.schedule.support.*; -import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.support.Script; +import org.elasticsearch.watcher.support.WatcherUtils; import org.elasticsearch.watcher.support.clock.SystemClock; import org.elasticsearch.watcher.support.init.proxy.ClientProxy; import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy; import org.elasticsearch.watcher.support.template.ScriptTemplate; import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.test.WatcherTestUtils; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.collect.ImmutableList; -import org.elasticsearch.common.collect.ImmutableMap; -import org.elasticsearch.common.logging.ESLogger; -import org.elasticsearch.common.logging.Loggers; -import org.elasticsearch.common.netty.handler.codec.http.HttpMethod; -import org.elasticsearch.common.settings.ImmutableSettings; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.watcher.transform.*; +import org.elasticsearch.watcher.trigger.Trigger; +import org.elasticsearch.watcher.trigger.TriggerEngine; +import org.elasticsearch.watcher.trigger.TriggerService; +import org.elasticsearch.watcher.trigger.schedule.*; +import org.elasticsearch.watcher.trigger.schedule.support.*; import org.junit.Before; import org.junit.Test; +import java.io.IOException; +import java.util.Collection; import java.util.Map; import static org.elasticsearch.watcher.test.WatcherTestUtils.matchAllRequest; @@ -81,7 +88,10 @@ public class WatchTests extends ElasticsearchTestCase { TransformRegistry transformRegistry = transformRegistry(); Schedule schedule = randomSchedule(); + Trigger trigger = new ScheduleTrigger(schedule); ScheduleRegistry scheduleRegistry = registry(schedule); + TriggerEngine triggerEngine = new ParseOnlyScheduleTriggerEngine(ImmutableSettings.EMPTY, scheduleRegistry); + TriggerService triggerService = new TriggerService(ImmutableSettings.EMPTY, ImmutableSet.of(triggerEngine)); Input input = randomInput(); InputRegistry inputRegistry = registry(input); @@ -100,11 +110,11 @@ public class WatchTests extends ElasticsearchTestCase { TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10)); - Watch watch = new Watch("_name", SystemClock.INSTANCE, schedule, input, condition, transform, actions, metadata, throttlePeriod, status); + Watch watch = new Watch("_name", SystemClock.INSTANCE, trigger, input, condition, transform, actions, metadata, throttlePeriod, status); BytesReference bytes = XContentFactory.jsonBuilder().value(watch).bytes(); logger.info(bytes.toUtf8()); - Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, scheduleRegistry, transformRegistry, actionRegistry, inputRegistry, SystemClock.INSTANCE); + Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, inputRegistry, SystemClock.INSTANCE); boolean includeStatus = randomBoolean(); Watch parsedWatch = watchParser.parse("_name", includeStatus, bytes); @@ -112,7 +122,7 @@ public class WatchTests extends ElasticsearchTestCase { if (includeStatus) { assertThat(parsedWatch.status(), equalTo(status)); } - assertThat(parsedWatch.schedule(), equalTo(schedule)); + assertThat(parsedWatch.trigger(), equalTo(trigger)); assertThat(parsedWatch.input(), equalTo(input)); assertThat(parsedWatch.condition(), equalTo(condition)); if (throttlePeriod != null) { @@ -273,4 +283,46 @@ public class WatchTests extends ElasticsearchTestCase { return new ActionRegistry(parsers.build()); } + + static class ParseOnlyScheduleTriggerEngine extends ScheduleTriggerEngine { + + private final ScheduleRegistry registry; + + public ParseOnlyScheduleTriggerEngine(Settings settings, ScheduleRegistry registry) { + super(settings); + this.registry = registry; + } + + @Override + public void start(Collection jobs) { + } + + @Override + public void stop() { + } + + @Override + public void register(Listener listener) { + } + + @Override + public void add(Job job) { + } + + @Override + public boolean remove(String jobName) { + return false; + } + + @Override + public ScheduleTrigger parseTrigger(String context, XContentParser parser) throws IOException { + Schedule schedule = registry.parse(context, parser); + return new ScheduleTrigger(schedule); + } + + @Override + public ScheduleTriggerEvent parseTriggerEvent(String context, XContentParser parser) throws IOException { + return null; + } + } }