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 7178a9c7fc3e7..9a4e825be7c66 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
@@ -20,12 +20,14 @@
package org.elasticsearch.client;
import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.elasticsearch.client.RequestConverters.EndpointBuilder;
import org.elasticsearch.common.Strings;
import org.elasticsearch.protocol.xpack.ml.CloseJobRequest;
import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.GetJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -50,6 +52,23 @@ static Request putJob(PutJobRequest putJobRequest) throws IOException {
return request;
}
+ static Request getJob(GetJobRequest getJobRequest) {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("anomaly_detectors")
+ .addPathPart(Strings.collectionToCommaDelimitedString(getJobRequest.getJobIds()))
+ .build();
+ Request request = new Request(HttpGet.METHOD_NAME, endpoint);
+
+ RequestConverters.Params params = new RequestConverters.Params(request);
+ if (getJobRequest.isAllowNoJobs() != null) {
+ params.putParam("allow_no_jobs", Boolean.toString(getJobRequest.isAllowNoJobs()));
+ }
+
+ return request;
+ }
+
static Request openJob(OpenJobRequest openJobRequest) 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 2073d613ac660..90acabfbdd8a4 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
@@ -23,6 +23,8 @@
import org.elasticsearch.protocol.xpack.ml.CloseJobResponse;
import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
+import org.elasticsearch.protocol.xpack.ml.GetJobRequest;
+import org.elasticsearch.protocol.xpack.ml.GetJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -84,6 +86,47 @@ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionLis
Collections.emptySet());
}
+ /**
+ * Gets one or more Machine Learning job configuration info.
+ *
+ *
listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ MLRequestConverters::getJob,
+ options,
+ GetJobResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
+
/**
* Deletes the given Machine Learning Job
*
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 a313b99a54f52..9ed09d06b72f1 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
@@ -20,12 +20,14 @@
package org.elasticsearch.client;
import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.protocol.xpack.ml.CloseJobRequest;
import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.GetJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig;
@@ -54,6 +56,23 @@ public void testPutJob() throws IOException {
}
}
+ public void testGetJob() {
+ GetJobRequest getJobRequest = new GetJobRequest();
+
+ Request request = MLRequestConverters.getJob(getJobRequest);
+
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/ml/anomaly_detectors", request.getEndpoint());
+ assertFalse(request.getParameters().containsKey("allow_no_jobs"));
+
+ getJobRequest = new GetJobRequest("job1", "jobs*");
+ getJobRequest.setAllowNoJobs(true);
+ request = MLRequestConverters.getJob(getJobRequest);
+
+ assertEquals("/_xpack/ml/anomaly_detectors/job1,jobs*", request.getEndpoint());
+ assertEquals(Boolean.toString(true), request.getParameters().get("allow_no_jobs"));
+ }
+
public void testOpenJob() throws Exception {
String jobId = "some-job-id";
OpenJobRequest openJobRequest = new OpenJobRequest(jobId);
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 2c0fc70b8486d..cec5dd7ccf8ff 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
@@ -24,6 +24,8 @@
import org.elasticsearch.protocol.xpack.ml.CloseJobResponse;
import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
+import org.elasticsearch.protocol.xpack.ml.GetJobRequest;
+import org.elasticsearch.protocol.xpack.ml.GetJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -37,7 +39,11 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
public class MachineLearningIT extends ESRestHighLevelClientTestCase {
@@ -59,6 +65,41 @@ public void testPutJob() throws Exception {
assertThat(createdJob.getJobType(), is(Job.ANOMALY_DETECTOR_JOB_TYPE));
}
+ public void testGetJob() throws Exception {
+ String jobId1 = randomValidJobId();
+ String jobId2 = randomValidJobId();
+
+ Job job1 = buildJob(jobId1);
+ Job job2 = buildJob(jobId2);
+ MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+ machineLearningClient.putJob(new PutJobRequest(job1), RequestOptions.DEFAULT);
+ machineLearningClient.putJob(new PutJobRequest(job2), RequestOptions.DEFAULT);
+
+ GetJobRequest request = new GetJobRequest(jobId1, jobId2);
+
+ // Test getting specific jobs
+ GetJobResponse response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync);
+
+ assertEquals(2, response.count());
+ assertThat(response.jobs(), hasSize(2));
+ assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), containsInAnyOrder(jobId1, jobId2));
+
+ // Test getting all jobs explicitly
+ request = GetJobRequest.getAllJobsRequest();
+ response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync);
+
+ assertTrue(response.count() >= 2L);
+ assertTrue(response.jobs().size() >= 2L);
+ assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2));
+
+ // Test getting all jobs implicitly
+ response = execute(new GetJobRequest(), machineLearningClient::getJob, machineLearningClient::getJobAsync);
+
+ assertTrue(response.count() >= 2L);
+ assertTrue(response.jobs().size() >= 2L);
+ assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2));
+ }
+
public void testDeleteJob() throws Exception {
String jobId = randomValidJobId();
Job job = buildJob(jobId);
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 6e48036419b79..73531bae5532f 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
@@ -30,6 +30,8 @@
import org.elasticsearch.protocol.xpack.ml.CloseJobResponse;
import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
+import org.elasticsearch.protocol.xpack.ml.GetJobRequest;
+import org.elasticsearch.protocol.xpack.ml.GetJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -46,8 +48,11 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.hasSize;
public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase {
@@ -134,6 +139,63 @@ public void onFailure(Exception e) {
}
}
+ public void testGetJob() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ String jobId = "get-machine-learning-job1";
+
+ Job job = MachineLearningIT.buildJob("get-machine-learning-job1");
+ client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ Job secondJob = MachineLearningIT.buildJob("get-machine-learning-job2");
+ client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT);
+
+ {
+ //tag::x-pack-ml-get-job-request
+ GetJobRequest request = new GetJobRequest("get-machine-learning-job1", "get-machine-learning-job*"); //<1>
+ request.setAllowNoJobs(true); //<2>
+ //end::x-pack-ml-get-job-request
+
+ //tag::x-pack-ml-get-job-execute
+ GetJobResponse response = client.machineLearning().getJob(request, RequestOptions.DEFAULT);
+ long numberOfJobs = response.count(); //<1>
+ List jobs = response.jobs(); //<2>
+ //end::x-pack-ml-get-job-execute
+
+ assertEquals(2, response.count());
+ assertThat(response.jobs(), hasSize(2));
+ assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()),
+ containsInAnyOrder(job.getId(), secondJob.getId()));
+ }
+ {
+ GetJobRequest request = new GetJobRequest("get-machine-learning-job1", "get-machine-learning-job*");
+
+ // tag::x-pack-ml-get-job-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(GetJobResponse response) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::x-pack-ml-get-job-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::x-pack-ml-get-job-execute-async
+ client.machineLearning().getJobAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ // end::x-pack-ml-get-job-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
public void testDeleteJob() throws Exception {
RestHighLevelClient client = highLevelClient();
diff --git a/docs/java-rest/high-level/ml/get-job.asciidoc b/docs/java-rest/high-level/ml/get-job.asciidoc
new file mode 100644
index 0000000000000..4ecf70e8e6538
--- /dev/null
+++ b/docs/java-rest/high-level/ml/get-job.asciidoc
@@ -0,0 +1,57 @@
+[[java-rest-high-x-pack-ml-get-job]]
+=== Get Job API
+
+The Get Job API provides the ability to get {ml} jobs in the cluster.
+It accepts a `GetJobRequest` object and responds
+with a `GetJobResponse` object.
+
+[[java-rest-high-x-pack-ml-get-job-request]]
+==== Get Job Request
+
+A `GetJobRequest` object gets can have any number of `jobId` or `groupName`
+entries. However, they all must be non-null. An empty list is the same as
+requesting for all jobs.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-request]
+--------------------------------------------------
+<1> Constructing a new request referencing existing `jobIds`, can contain wildcards
+<2> Whether to ignore if a wildcard expression matches no jobs.
+ (This includes `_all` string or when no jobs have been specified)
+
+[[java-rest-high-x-pack-ml-get-job-execution]]
+==== Execution
+
+The request can be executed through the `MachineLearningClient` contained
+in the `RestHighLevelClient` object, accessed via the `machineLearningClient()` method.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-execute]
+--------------------------------------------------
+<1> `getCount()` from the `GetJobResponse` indicates the number of jobs found
+<2> `getJobs()` is the collection of {ml} `Job` objects found
+
+[[java-rest-high-x-pack-ml-get-job-execution-async]]
+==== Asynchronous Execution
+
+The request can also be executed asynchronously:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-execute-async]
+--------------------------------------------------
+<1> The `GetJobRequest` to execute and the `ActionListener` to use when
+the execution completes
+
+The method does not block and returns immediately. The passed `ActionListener` is used
+to notify the caller of completion. A typical `ActionListener` for `GetJobResponse` may
+look like
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-listener]
+--------------------------------------------------
+<1> `onResponse` is called back when the action is completed successfully
+<2> `onFailure` is called back when some unexpected error occurs
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index b3de26e56bd0e..c7b46b399622f 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -205,11 +205,13 @@ include::licensing/delete-license.asciidoc[]
The Java High Level REST Client supports the following Machine Learning APIs:
* <>
+* <>
* <>
* <>
* <>
include::ml/put-job.asciidoc[]
+include::ml/get-job.asciidoc[]
include::ml/delete-job.asciidoc[]
include::ml/open-job.asciidoc[]
include::ml/close-job.asciidoc[]
diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java
new file mode 100644
index 0000000000000..64f350933c9c4
--- /dev/null
+++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java
@@ -0,0 +1,62 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ToXContent;
+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;
+
+/**
+ * Abstract class that provides a list of results and their count.
+ */
+public abstract class AbstractResultResponse extends ActionResponse implements ToXContentObject {
+
+ public static final ParseField COUNT = new ParseField("count");
+
+ private final ParseField resultsField;
+ protected final List results;
+ protected final long count;
+
+ AbstractResultResponse(ParseField resultsField, List results, long count) {
+ this.resultsField = Objects.requireNonNull(resultsField,
+ "[results_field] must not be null");
+ this.results = Collections.unmodifiableList(results);
+ this.count = count;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ builder.field(COUNT.getPreferredName(), count);
+ builder.field(resultsField.getPreferredName(), results);
+ builder.endObject();
+ return builder;
+ }
+
+ public long count() {
+ return count;
+ }
+}
diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java
new file mode 100644
index 0000000000000..b0377c86fdc78
--- /dev/null
+++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.ActionRequestValidationException;
+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.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Request object to get {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} objects with the matching `jobId`s or
+ * `groupName`s.
+ *
+ * `_all` explicitly gets all the jobs in the cluster
+ * An empty request (no `jobId`s) implicitly gets all the jobs in the cluster
+ */
+public class GetJobRequest extends ActionRequest implements ToXContentObject {
+
+ public static final ParseField JOB_IDS = new ParseField("job_ids");
+ public static final ParseField ALLOW_NO_JOBS = new ParseField("allow_no_jobs");
+
+ private static final String ALL_JOBS = "_all";
+ private final List jobIds;
+ private Boolean allowNoJobs;
+
+ @SuppressWarnings("unchecked")
+ public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "get_job_request",
+ true, a -> new GetJobRequest(a[0] == null ? new ArrayList<>() : (List) a[0]));
+
+ static {
+ PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), JOB_IDS);
+ PARSER.declareBoolean(GetJobRequest::setAllowNoJobs, ALLOW_NO_JOBS);
+ }
+
+ /**
+ * Helper method to create a query that will get ALL jobs
+ * @return new {@link GetJobRequest} object searching for the jobId "_all"
+ */
+ public static GetJobRequest getAllJobsRequest() {
+ return new GetJobRequest(ALL_JOBS);
+ }
+
+ /**
+ * Get the specified {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} configurations via their unique jobIds
+ * @param jobIds must not contain any null values
+ */
+ public GetJobRequest(String... jobIds) {
+ this(Arrays.asList(jobIds));
+ }
+
+ GetJobRequest(List jobIds) {
+ if (jobIds.stream().anyMatch(Objects::isNull)) {
+ throw new NullPointerException("jobIds must not contain null values");
+ }
+ this.jobIds = new ArrayList<>(jobIds);
+ }
+
+ /**
+ * All the jobIds for which to get configuration information
+ */
+ public List getJobIds() {
+ return jobIds;
+ }
+
+
+ /**
+ * See {@link GetJobRequest#isAllowNoJobs()}
+ * @param allowNoJobs
+ */
+ public void setAllowNoJobs(boolean allowNoJobs) {
+ this.allowNoJobs = allowNoJobs;
+ }
+
+ /**
+ * Whether to ignore if a wildcard expression matches no jobs.
+ *
+ * If this is `false`, then an error is returned when a wildcard (or `_all`) does not match any jobs
+ */
+ public Boolean isAllowNoJobs() {
+ return allowNoJobs;
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(jobIds, allowNoJobs);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other == null || other.getClass() != getClass()) {
+ return false;
+ }
+
+ GetJobRequest that = (GetJobRequest) other;
+ return Objects.equals(jobIds, that.jobIds) &&
+ Objects.equals(allowNoJobs, that.allowNoJobs);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+
+ if (jobIds.isEmpty() == false) {
+ builder.field(JOB_IDS.getPreferredName(), jobIds);
+ }
+
+ if (allowNoJobs != null) {
+ builder.field(ALLOW_NO_JOBS.getPreferredName(), allowNoJobs);
+ }
+
+ builder.endObject();
+ return builder;
+ }
+}
diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java
new file mode 100644
index 0000000000000..4db542dc1526d
--- /dev/null
+++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java
@@ -0,0 +1,89 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.xpack.ml.job.config.Job;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+
+/**
+ * Contains a {@link List} of the found {@link Job} objects and the total count found
+ */
+public class GetJobResponse extends AbstractResultResponse {
+
+ public static final ParseField RESULTS_FIELD = new ParseField("jobs");
+
+ @SuppressWarnings("unchecked")
+ public static final ConstructingObjectParser PARSER =
+ new ConstructingObjectParser<>("jobs_response", true,
+ a -> new GetJobResponse((List) a[0], (long) a[1]));
+
+ static {
+ PARSER.declareObjectArray(constructorArg(), Job.PARSER, RESULTS_FIELD);
+ PARSER.declareLong(constructorArg(), AbstractResultResponse.COUNT);
+ }
+
+ GetJobResponse(List jobBuilders, long count) {
+ super(RESULTS_FIELD, jobBuilders.stream().map(Job.Builder::build).collect(Collectors.toList()), count);
+ }
+
+ /**
+ * The collection of {@link Job} objects found in the query
+ */
+ public List jobs() {
+ return results;
+ }
+
+ public static GetJobResponse fromXContent(XContentParser parser) throws IOException {
+ return PARSER.parse(parser, null);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(results, count);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+
+ GetJobResponse other = (GetJobResponse) obj;
+ return Objects.equals(results, other.results) && count == other.count;
+ }
+
+ @Override
+ public final String toString() {
+ return Strings.toString(this);
+ }
+}
diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java
new file mode 100644
index 0000000000000..b94b704fbf6e8
--- /dev/null
+++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java
@@ -0,0 +1,69 @@
+/*
+ * 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.protocol.xpack.ml;
+
+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 GetJobRequestTests extends AbstractXContentTestCase {
+
+ public void testAllJobsRequest() {
+ GetJobRequest request = GetJobRequest.getAllJobsRequest();
+
+ assertEquals(request.getJobIds().size(), 1);
+ assertEquals(request.getJobIds().get(0), "_all");
+ }
+
+ public void testNewWithJobId() {
+ Exception exception = expectThrows(NullPointerException.class, () -> new GetJobRequest("job",null));
+ assertEquals(exception.getMessage(), "jobIds must not contain null values");
+ }
+
+ @Override
+ protected GetJobRequest createTestInstance() {
+ int jobCount = randomIntBetween(0, 10);
+ List jobIds = new ArrayList<>(jobCount);
+
+ for (int i = 0; i < jobCount; i++) {
+ jobIds.add(randomAlphaOfLength(10));
+ }
+
+ GetJobRequest request = new GetJobRequest(jobIds);
+
+ if (randomBoolean()) {
+ request.setAllowNoJobs(randomBoolean());
+ }
+
+ return request;
+ }
+
+ @Override
+ protected GetJobRequest doParseInstance(XContentParser parser) throws IOException {
+ return GetJobRequest.PARSER.parse(parser, null);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return true;
+ }
+}
diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java
new file mode 100644
index 0000000000000..79d4d678b9295
--- /dev/null
+++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.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.protocol.xpack.ml;
+
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.xpack.ml.job.config.Job;
+import org.elasticsearch.protocol.xpack.ml.job.config.JobTests;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GetJobResponseTests extends AbstractXContentTestCase {
+
+ @Override
+ protected GetJobResponse createTestInstance() {
+
+ int count = randomIntBetween(1, 5);
+ List results = new ArrayList<>(count);
+ for(int i = 0; i < count; i++) {
+ results.add(JobTests.createRandomizedJobBuilder());
+ }
+
+ return new GetJobResponse(results, count);
+ }
+
+ @Override
+ protected GetJobResponse doParseInstance(XContentParser parser) throws IOException {
+ return GetJobResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}
diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java
index 7ba4946efa753..61931743403e0 100644
--- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java
+++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java
@@ -210,7 +210,7 @@ public static AnalysisConfig.Builder createAnalysisConfig() {
return new AnalysisConfig.Builder(Arrays.asList(d1.build(), d2.build()));
}
- public static Job createRandomizedJob() {
+ public static Job.Builder createRandomizedJobBuilder() {
String jobId = randomValidJobId();
Job.Builder builder = new Job.Builder(jobId);
if (randomBoolean()) {
@@ -265,7 +265,11 @@ public static Job createRandomizedJob() {
if (randomBoolean()) {
builder.setResultsIndexName(randomValidJobId());
}
- return builder.build();
+ return builder;
+ }
+
+ public static Job createRandomizedJob() {
+ return createRandomizedJobBuilder().build();
}
@Override