From 7657e6d274bc4ac48f439db82b1a1336651af7de Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Tue, 20 Nov 2018 08:15:21 -0600 Subject: [PATCH] HLRC ML Add Event To Calendar API (#35704) * HLRC: ML Adding Post event to calendar api * Fixing tests and serialization * removing unused import --- .../client/MLRequestConverters.java | 16 +++ .../client/MachineLearningClient.java | 43 +++++++ .../client/RequestConverters.java | 7 +- .../client/ml/PostCalendarEventRequest.java | 113 ++++++++++++++++++ .../client/ml/PostCalendarEventResponse.java | 93 ++++++++++++++ .../client/MLRequestConvertersTests.java | 21 ++++ .../client/MachineLearningIT.java | 22 ++++ .../MlClientDocumentationIT.java | 59 +++++++++ .../ml/PostCalendarEventRequestTests.java | 53 ++++++++ .../ml/PostCalendarEventResponseTests.java | 51 ++++++++ .../ml/calendars/ScheduledEventTests.java | 11 +- .../ml/post-calendar-event.asciidoc | 38 ++++++ .../high-level/supported-apis.asciidoc | 2 + 13 files changed, 525 insertions(+), 4 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventResponse.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventRequestTests.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventResponseTests.java create mode 100644 docs/java-rest/high-level/ml/post-calendar-event.asciidoc diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java index 6f2f40728592f..2b6571272f1eb 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java @@ -50,6 +50,7 @@ import org.elasticsearch.client.ml.GetOverallBucketsRequest; import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; +import org.elasticsearch.client.ml.PostCalendarEventRequest; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PreviewDatafeedRequest; import org.elasticsearch.client.ml.PutCalendarJobRequest; @@ -538,6 +539,21 @@ static Request deleteCalendar(DeleteCalendarRequest deleteCalendarRequest) { return request; } + static Request postCalendarEvents(PostCalendarEventRequest postCalendarEventRequest) throws IOException { + String endpoint = new EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("ml") + .addPathPartAsIs("calendars") + .addPathPart(postCalendarEventRequest.getCalendarId()) + .addPathPartAsIs("events") + .build(); + Request request = new Request(HttpPost.METHOD_NAME, endpoint); + request.setEntity(createEntity(postCalendarEventRequest, + REQUEST_BODY_CONTENT_TYPE, + PostCalendarEventRequest.EXCLUDE_CALENDAR_ID_PARAMS)); + return request; + } + static Request putFilter(PutFilterRequest putFilterRequest) throws IOException { String endpoint = new EndpointBuilder() .addPathPartAsIs("_xpack") diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java index bb526b810c4dd..817f22fb4ce3e 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java @@ -60,6 +60,8 @@ import org.elasticsearch.client.ml.GetRecordsResponse; import org.elasticsearch.client.ml.OpenJobRequest; import org.elasticsearch.client.ml.OpenJobResponse; +import org.elasticsearch.client.ml.PostCalendarEventRequest; +import org.elasticsearch.client.ml.PostCalendarEventResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; import org.elasticsearch.client.ml.PreviewDatafeedRequest; @@ -1384,6 +1386,47 @@ public void deleteCalendarAsync(DeleteCalendarRequest request, RequestOptions op Collections.emptySet()); } + /** + * Creates new events for a a machine learning calendar + *

+ * For additional info + * see + * Add Events to Calendar API + * + * @param request The request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return The {@link PostCalendarEventRequest} containing the scheduled events + * @throws IOException when there is a serialization issue sending the request or receiving the response + */ + public PostCalendarEventResponse postCalendarEvent(PostCalendarEventRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::postCalendarEvents, + options, + PostCalendarEventResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Creates new events for a a machine learning calendar asynchronously, notifies the listener on completion + *

+ * For additional info + * see + * Add Events to Calendar API + * + * @param request The request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener Listener to be notified upon request completion + */ + public void postCalendarEventAsync(PostCalendarEventRequest request, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::postCalendarEvents, + options, + PostCalendarEventResponse::fromXContent, + listener, + Collections.emptySet()); + } + /** * Creates a new Machine Learning Filter *

diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index 4381b9879d3a1..844a1d4e8296f 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -652,7 +652,12 @@ static Request deleteScript(DeleteStoredScriptRequest deleteStoredScriptRequest) } static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { - BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef(); + return createEntity(toXContent, xContentType, ToXContent.EMPTY_PARAMS); + } + + static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType, ToXContent.Params toXContentParams) + throws IOException { + BytesRef source = XContentHelper.toXContent(toXContent, xContentType, toXContentParams, false).toBytesRef(); return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType)); } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventRequest.java new file mode 100644 index 0000000000000..2c43ec9ab7769 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventRequest.java @@ -0,0 +1,113 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.elasticsearch.client.ml; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.client.ml.calendars.Calendar; +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Request to add a ScheduledEvent to a Machine Learning calendar + */ +public class PostCalendarEventRequest extends ActionRequest implements ToXContentObject { + + private final String calendarId; + private final List scheduledEvents; + + public static final String INCLUDE_CALENDAR_ID_KEY = "include_calendar_id"; + public static final ParseField EVENTS = new ParseField("events"); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("post_calendar_event_request", + a -> new PostCalendarEventRequest((String)a[0], (List)a[1])); + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), Calendar.ID); + PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), + (p, c) -> ScheduledEvent.PARSER.apply(p, null), EVENTS); + } + public static final MapParams EXCLUDE_CALENDAR_ID_PARAMS = + new MapParams(Collections.singletonMap(INCLUDE_CALENDAR_ID_KEY, Boolean.toString(false))); + + /** + * Create a new PostCalendarEventRequest with an existing non-null calendarId and a list of Scheduled events + * + * @param calendarId The ID of the calendar, must be non-null + * @param scheduledEvents The non-null, non-empty, list of {@link ScheduledEvent} objects to add to the calendar + */ + public PostCalendarEventRequest(String calendarId, List scheduledEvents) { + this.calendarId = Objects.requireNonNull(calendarId, "[calendar_id] must not be null."); + this.scheduledEvents = Objects.requireNonNull(scheduledEvents, "[events] must not be null."); + if (scheduledEvents.isEmpty()) { + throw new IllegalArgumentException("At least 1 event is required"); + } + } + + public String getCalendarId() { + return calendarId; + } + + public List getScheduledEvents() { + return scheduledEvents; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + if (params.paramAsBoolean(INCLUDE_CALENDAR_ID_KEY, true)) { + builder.field(Calendar.ID.getPreferredName(), calendarId); + } + builder.field(EVENTS.getPreferredName(), scheduledEvents); + builder.endObject(); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(calendarId, scheduledEvents); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + PostCalendarEventRequest other = (PostCalendarEventRequest) obj; + return Objects.equals(calendarId, other.calendarId) && Objects.equals(scheduledEvents, other.scheduledEvents); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventResponse.java new file mode 100644 index 0000000000000..56e3cdce24f1b --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostCalendarEventResponse.java @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.elasticsearch.client.ml; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +/** + * Response to adding ScheduledEvent(s) to a Machine Learning calendar + */ +public class PostCalendarEventResponse extends ActionResponse implements ToXContentObject { + + private final List scheduledEvents; + public static final ParseField EVENTS = new ParseField("events"); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("post_calendar_event_response", + true, + a -> new PostCalendarEventResponse((List)a[0])); + + static { + PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), + (p, c) -> ScheduledEvent.PARSER.apply(p, null), EVENTS); + } + + public static PostCalendarEventResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + /** + * Create a new PostCalendarEventResponse containing the scheduled Events + * + * @param scheduledEvents The list of {@link ScheduledEvent} objects + */ + public PostCalendarEventResponse(List scheduledEvents) { + this.scheduledEvents = scheduledEvents; + } + + public List getScheduledEvents() { + return scheduledEvents; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(EVENTS.getPreferredName(), scheduledEvents); + builder.endObject(); + return builder; + } + + @Override + public int hashCode(){ + return Objects.hash(scheduledEvents); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + PostCalendarEventResponse other = (PostCalendarEventResponse) obj; + return Objects.equals(scheduledEvents, other.scheduledEvents); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java index 7e47f8c1ea8d3..f741aef511f98 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java @@ -46,6 +46,7 @@ import org.elasticsearch.client.ml.GetOverallBucketsRequest; import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; +import org.elasticsearch.client.ml.PostCalendarEventRequest; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PreviewDatafeedRequest; import org.elasticsearch.client.ml.PutCalendarJobRequest; @@ -61,6 +62,8 @@ import org.elasticsearch.client.ml.UpdateModelSnapshotRequest; import org.elasticsearch.client.ml.calendars.Calendar; import org.elasticsearch.client.ml.calendars.CalendarTests; +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.client.ml.calendars.ScheduledEventTests; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.datafeed.DatafeedConfigTests; import org.elasticsearch.client.ml.job.config.AnalysisConfig; @@ -73,6 +76,7 @@ import org.elasticsearch.client.ml.job.util.PageParams; import org.elasticsearch.common.Strings; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -83,6 +87,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import static org.hamcrest.Matchers.equalTo; @@ -586,6 +591,22 @@ public void testDeleteCalendar() { assertEquals("/_xpack/ml/calendars/" + deleteCalendarRequest.getCalendarId(), request.getEndpoint()); } + public void testPostCalendarEvent() throws Exception { + String calendarId = randomAlphaOfLength(10); + List events = Arrays.asList(ScheduledEventTests.testInstance(), + ScheduledEventTests.testInstance(), + ScheduledEventTests.testInstance()); + PostCalendarEventRequest postCalendarEventRequest = new PostCalendarEventRequest(calendarId, events); + + Request request = MLRequestConverters.postCalendarEvents(postCalendarEventRequest); + assertEquals(HttpPost.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/ml/calendars/" + calendarId + "/events", request.getEndpoint()); + + XContentBuilder builder = JsonXContent.contentBuilder(); + builder = postCalendarEventRequest.toXContent(builder, PostCalendarEventRequest.EXCLUDE_CALENDAR_ID_PARAMS); + assertEquals(Strings.toString(builder), requestEntityToString(request)); + } + public void testPutFilter() throws IOException { MlFilter filter = MlFilterTests.createRandomBuilder("foo").build(); PutFilterRequest putFilterRequest = new PutFilterRequest(filter); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java index 7716d7c20bb03..d2def3ec68e31 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java @@ -57,6 +57,8 @@ import org.elasticsearch.client.ml.GetModelSnapshotsResponse; import org.elasticsearch.client.ml.OpenJobRequest; import org.elasticsearch.client.ml.OpenJobResponse; +import org.elasticsearch.client.ml.PostCalendarEventRequest; +import org.elasticsearch.client.ml.PostCalendarEventResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; import org.elasticsearch.client.ml.PreviewDatafeedRequest; @@ -81,6 +83,8 @@ import org.elasticsearch.client.ml.UpdateModelSnapshotResponse; import org.elasticsearch.client.ml.calendars.Calendar; import org.elasticsearch.client.ml.calendars.CalendarTests; +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.client.ml.calendars.ScheduledEventTests; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.datafeed.DatafeedState; import org.elasticsearch.client.ml.datafeed.DatafeedStats; @@ -917,6 +921,24 @@ public void testDeleteCalendar() throws IOException { assertThat(exception.status().getStatus(), equalTo(404)); } + public void testPostCalendarEvent() throws Exception { + Calendar calendar = CalendarTests.testInstance(); + MachineLearningClient machineLearningClient = highLevelClient().machineLearning(); + machineLearningClient.putCalendar(new PutCalendarRequest(calendar), RequestOptions.DEFAULT); + + List events = new ArrayList<>(3); + for (int i = 0; i < 3; i++) { + events.add(ScheduledEventTests.testInstance(calendar.getId(), null)); + } + + PostCalendarEventRequest postCalendarEventRequest = new PostCalendarEventRequest(calendar.getId(), events); + + PostCalendarEventResponse postCalendarEventResponse = execute(postCalendarEventRequest, + machineLearningClient::postCalendarEvent, + machineLearningClient::postCalendarEventAsync); + assertThat(postCalendarEventResponse.getScheduledEvents(), containsInAnyOrder(events.toArray())); + } + public void testPutFilter() throws Exception { String filterId = "filter-job-test"; MlFilter mlFilter = MlFilter.builder(filterId) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index 4886bce185338..82f1f6d176ac4 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -73,6 +73,8 @@ import org.elasticsearch.client.ml.GetRecordsResponse; import org.elasticsearch.client.ml.OpenJobRequest; import org.elasticsearch.client.ml.OpenJobResponse; +import org.elasticsearch.client.ml.PostCalendarEventRequest; +import org.elasticsearch.client.ml.PostCalendarEventResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; import org.elasticsearch.client.ml.PreviewDatafeedRequest; @@ -96,6 +98,8 @@ import org.elasticsearch.client.ml.UpdateModelSnapshotRequest; import org.elasticsearch.client.ml.UpdateModelSnapshotResponse; import org.elasticsearch.client.ml.calendars.Calendar; +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.client.ml.calendars.ScheduledEventTests; import org.elasticsearch.client.ml.datafeed.ChunkingConfig; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.datafeed.DatafeedStats; @@ -2377,6 +2381,61 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } + public void testPostCalendarEvent() throws IOException, InterruptedException { + RestHighLevelClient client = highLevelClient(); + + Calendar calendar = new Calendar("holidays", Collections.singletonList("job_1"), "A calendar for public holidays"); + PutCalendarRequest putRequest = new PutCalendarRequest(calendar); + client.machineLearning().putCalendar(putRequest, RequestOptions.DEFAULT); + { + List events = Collections.singletonList(ScheduledEventTests.testInstance(calendar.getId(), null)); + + // tag::post-calendar-event-request + PostCalendarEventRequest request = new PostCalendarEventRequest("holidays", // <1> + events); // <2> + // end::post-calendar-event-request + + // tag::post-calendar-event-execute + PostCalendarEventResponse response = client.machineLearning().postCalendarEvent(request, RequestOptions.DEFAULT); + // end::post-calendar-event-execute + + // tag::post-calendar-event-response + List scheduledEvents = response.getScheduledEvents(); // <1> + // end::post-calendar-event-response + + assertEquals(1, scheduledEvents.size()); + } + { + List events = Collections.singletonList(ScheduledEventTests.testInstance()); + PostCalendarEventRequest request = new PostCalendarEventRequest("holidays", events); // <1> + + // tag::post-calendar-event-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(PostCalendarEventResponse postCalendarsResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::post-calendar-event-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::post-calendar-event-execute-async + client.machineLearning().postCalendarEventAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::post-calendar-event-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + public void testCreateFilter() throws Exception { RestHighLevelClient client = highLevelClient(); { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventRequestTests.java new file mode 100644 index 0000000000000..c8f65bd9113fe --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventRequestTests.java @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.ml; + +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.client.ml.calendars.ScheduledEventTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PostCalendarEventRequestTests extends AbstractXContentTestCase { + + @Override + protected PostCalendarEventRequest createTestInstance() { + String calendarId = randomAlphaOfLength(10); + int numberOfEvents = randomIntBetween(1, 10); + List events = new ArrayList<>(numberOfEvents); + for (int i = 0; i < numberOfEvents; i++) { + events.add(ScheduledEventTests.testInstance()); + } + return new PostCalendarEventRequest(calendarId, events); + } + + @Override + protected PostCalendarEventRequest doParseInstance(XContentParser parser) throws IOException { + return PostCalendarEventRequest.PARSER.apply(parser, null); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventResponseTests.java new file mode 100644 index 0000000000000..8f8be0981c864 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PostCalendarEventResponseTests.java @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.ml; + +import org.elasticsearch.client.ml.calendars.ScheduledEvent; +import org.elasticsearch.client.ml.calendars.ScheduledEventTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PostCalendarEventResponseTests extends AbstractXContentTestCase { + @Override + protected PostCalendarEventResponse createTestInstance() { + int numberOfEvents = randomIntBetween(1, 10); + List events = new ArrayList<>(numberOfEvents); + for (int i = 0; i < numberOfEvents; i++) { + events.add(ScheduledEventTests.testInstance()); + } + return new PostCalendarEventResponse(events); + } + + @Override + protected PostCalendarEventResponse doParseInstance(XContentParser parser) throws IOException { + return PostCalendarEventResponse.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java index 0b7a293340245..77380c2bd35e6 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.client.ml.calendars; +import org.elasticsearch.common.Nullable; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.AbstractXContentTestCase; @@ -26,12 +27,16 @@ public class ScheduledEventTests extends AbstractXContentTestCase { - public static ScheduledEvent testInstance() { + public static ScheduledEvent testInstance(String calendarId, @Nullable String eventId) { Date start = new Date(randomNonNegativeLong()); Date end = new Date(start.getTime() + randomIntBetween(1, 10000) * 1000); - return new ScheduledEvent(randomAlphaOfLength(10), start, end, randomAlphaOfLengthBetween(1, 20), - randomBoolean() ? null : randomAlphaOfLength(7)); + return new ScheduledEvent(randomAlphaOfLength(10), start, end, calendarId, eventId); + } + + public static ScheduledEvent testInstance() { + return testInstance(randomAlphaOfLengthBetween(1, 20), + randomBoolean() ? null : randomAlphaOfLength(7)); } @Override diff --git a/docs/java-rest/high-level/ml/post-calendar-event.asciidoc b/docs/java-rest/high-level/ml/post-calendar-event.asciidoc new file mode 100644 index 0000000000000..ba7c69acf03d9 --- /dev/null +++ b/docs/java-rest/high-level/ml/post-calendar-event.asciidoc @@ -0,0 +1,38 @@ +-- +:api: post-calendar-event +:request: PostCalendarEventRequest +:response: PostCalendarEventResponse +-- +[id="{upid}-{api}"] +=== Post Calendar Event API +Adds new ScheduledEvents to an existing {ml} calendar. + +The API accepts a +{request}+ and responds +with a +{response}+ object. + +[id="{upid}-{api}-request"] +==== Post Calendar Event Request + +A +{request}+ is constructed with a calendar ID object +and a non-empty list of scheduled events. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-request] +-------------------------------------------------- +<1> Non-null existing calendar ID +<2> Non-null, non-empty collection of `ScheduledEvent` objects + + +[id="{upid}-{api}-response"] +==== Post Calendar Event Response + +The returned +{response}+ contains the added `ScheduledEvent` objects: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-response] +-------------------------------------------------- +<1> The `ScheduledEvent` objects that were added to the calendar + +include::../execution.asciidoc[] diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 3a1878ab78b2b..d724589871174 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -266,6 +266,7 @@ The Java High Level REST Client supports the following Machine Learning APIs: * <<{upid}-get-categories>> * <<{upid}-get-calendars>> * <<{upid}-put-calendar>> +* <<{upid}-post-calendar-event>> * <<{upid}-put-calendar-job>> * <<{upid}-delete-calendar-job>> * <<{upid}-delete-calendar>> @@ -303,6 +304,7 @@ include::ml/get-influencers.asciidoc[] include::ml/get-categories.asciidoc[] include::ml/get-calendars.asciidoc[] include::ml/put-calendar.asciidoc[] +include::ml/post-calendar-event.asciidoc[] include::ml/put-calendar-job.asciidoc[] include::ml/delete-calendar-job.asciidoc[] include::ml/delete-calendar.asciidoc[]