internal refactoring : use an apiPath builder

This commit is contained in:
Vincent Behar 2011-07-06 16:43:55 +02:00
parent 852fab0407
commit 59748a2481
3 changed files with 155 additions and 48 deletions

View file

@ -104,13 +104,13 @@ class ApiCall {
* Execute an HTTP GET request to the RunDeck instance, on the given path. We will login first, and then execute the * Execute an HTTP GET request to the RunDeck instance, on the given path. We will login first, and then execute the
* API call. At the end, the given parser will be used to convert the response to a more useful result object. * API call. At the end, the given parser will be used to convert the response to a more useful result object.
* *
* @param apiPath on which we will make the HTTP request * @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
* @param parser used to parse the response * @param parser used to parse the response
* @return the result of the call, as formatted by the parser * @return the result of the call, as formatted by the parser
* @throws RundeckApiException in case of error when calling the API * @throws RundeckApiException in case of error when calling the API
* @throws RundeckApiLoginException if the login fails * @throws RundeckApiLoginException if the login fails
*/ */
public <T> T get(String apiPath, NodeParser<T> parser) throws RundeckApiException, RundeckApiLoginException { public <T> T get(ApiPathBuilder apiPath, NodeParser<T> parser) throws RundeckApiException, RundeckApiLoginException {
String apiUrl = client.getUrl() + RundeckClient.API_ENDPOINT + apiPath; String apiUrl = client.getUrl() + RundeckClient.API_ENDPOINT + apiPath;
HttpClient httpClient = instantiateHttpClient(); HttpClient httpClient = instantiateHttpClient();

View file

@ -0,0 +1,128 @@
/*
* Copyright 2011 Vincent Behar
*
* Licensed 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.rundeck.api;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.rundeck.api.util.ParametersUtil;
/**
* Builder for API paths
*
* @author Vincent Behar
*/
class ApiPathBuilder {
/** Internally, we store everything in a {@link StringBuilder} */
private final StringBuilder apiPath;
/** Maker for using the right separator between parameters ("?" or "&") */
private boolean firstParamDone = false;
/**
* Build a new instance, for the given "path" (the "path" is the part before the parameters. The path and the
* parameters are separated by a "?")
*
* @param paths elements of the path
*/
public ApiPathBuilder(String... paths) {
apiPath = new StringBuilder();
if (paths != null) {
for (String path : paths) {
if (StringUtils.isNotBlank(path)) {
append(path);
}
}
}
}
/**
* Append the given parameter (key and value). This will only append the parameter if it is not blank (null, empty
* or whitespace), and make sure to add the right separator ("?" or "&") before. The key and value will be separated
* by the "=" character. Also, the value will be url-encoded.
*
* @param key of the parameter. Must not be null or empty
* @param value of the parameter. May be null/empty/blank. Will be url-encoded.
* @return this, for method chaining
*/
public ApiPathBuilder param(String key, String value) {
if (StringUtils.isNotBlank(value)) {
appendSeparator();
append(key);
append("=");
append(ParametersUtil.urlEncode(value));
}
return this;
}
/**
* Append the given parameter (key and value). This will only append the parameter if it is not null, and make sure
* to add the right separator ("?" or "&") before. The key and value will be separated by the "=" character.
*
* @param key of the parameter. Must not be null or empty
* @param value of the parameter. May be null
* @return this, for method chaining
*/
public ApiPathBuilder param(String key, Long value) {
if (value != null) {
param(key, value.toString());
}
return this;
}
/**
* Append the given node filters, only if it is not null/empty
*
* @param nodeFilters may be null/empty
* @return this, for method chaining
* @see ParametersUtil#generateNodeFiltersString(Properties)
*/
public ApiPathBuilder nodeFilters(Properties nodeFilters) {
String filters = ParametersUtil.generateNodeFiltersString(nodeFilters);
if (StringUtils.isNotBlank(filters)) {
appendSeparator();
append(filters);
}
return this;
}
@Override
public String toString() {
return apiPath.toString();
}
/**
* Append the given string
*
* @param str to append
*/
private void append(String str) {
apiPath.append(str);
}
/**
* Append the right separator "?" or "&" between 2 parameters
*/
private void appendSeparator() {
if (firstParamDone) {
append("&");
} else {
append("?");
firstParamDone = true;
}
}
}

View file

@ -115,7 +115,7 @@ public class RundeckClient implements Serializable {
* @throws RundeckApiLoginException if the login failed * @throws RundeckApiLoginException if the login failed
*/ */
public List<RundeckProject> getProjects() throws RundeckApiException, RundeckApiLoginException { public List<RundeckProject> getProjects() throws RundeckApiException, RundeckApiLoginException {
return new ApiCall(this).get("/projects", new ProjectsParser("result/projects/project")); return new ApiCall(this).get(new ApiPathBuilder("/projects"), new ProjectsParser("result/projects/project"));
} }
/** /**
@ -130,7 +130,8 @@ public class RundeckClient implements Serializable {
public RundeckProject getProject(String projectName) throws RundeckApiException, RundeckApiLoginException, public RundeckProject getProject(String projectName) throws RundeckApiException, RundeckApiLoginException,
IllegalArgumentException { IllegalArgumentException {
AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !"); AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
return new ApiCall(this).get("/project/" + projectName, new ProjectParser("result/projects/project")); return new ApiCall(this).get(new ApiPathBuilder("/project/", projectName),
new ProjectParser("result/projects/project"));
} }
/* /*
@ -183,18 +184,11 @@ public class RundeckClient implements Serializable {
public List<RundeckJob> getJobs(String project, String jobFilter, String groupPath, String... jobIds) public List<RundeckJob> getJobs(String project, String jobFilter, String groupPath, String... jobIds)
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException { throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
AssertUtil.notBlank(project, "project is mandatory to get all jobs !"); AssertUtil.notBlank(project, "project is mandatory to get all jobs !");
StringBuilder apiPath = new StringBuilder("/jobs"); return new ApiCall(this).get(new ApiPathBuilder("/jobs").param("project", project)
apiPath.append("?project=").append(project); .param("jobFilter", jobFilter)
if (StringUtils.isNotBlank(jobFilter)) { .param("groupPath", groupPath)
apiPath.append("&jobFilter=").append(jobFilter); .param("idlist", StringUtils.join(jobIds, ",")),
} new JobsParser("result/jobs/job"));
if (StringUtils.isNotBlank(groupPath)) {
apiPath.append("&groupPath=").append(groupPath);
}
if (jobIds != null && jobIds.length > 0) {
apiPath.append("&idlist=").append(StringUtils.join(jobIds, ","));
}
return new ApiCall(this).get(apiPath.toString(), new JobsParser("result/jobs/job"));
} }
/** /**
@ -229,7 +223,7 @@ public class RundeckClient implements Serializable {
public RundeckJob getJob(String jobId) throws RundeckApiException, RundeckApiLoginException, public RundeckJob getJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
IllegalArgumentException { IllegalArgumentException {
AssertUtil.notBlank(jobId, "jobId is mandatory to get the details of a job !"); AssertUtil.notBlank(jobId, "jobId is mandatory to get the details of a job !");
return new ApiCall(this).get("/job/" + jobId, new JobParser("joblist/job")); return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId), new JobParser("joblist/job"));
} }
/** /**
@ -285,16 +279,10 @@ public class RundeckClient implements Serializable {
public RundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters) public RundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters)
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException { throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
AssertUtil.notBlank(jobId, "jobId is mandatory to trigger a job !"); AssertUtil.notBlank(jobId, "jobId is mandatory to trigger a job !");
StringBuilder apiPath = new StringBuilder("/job/").append(jobId).append("/run?"); return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/run").param("argString",
String argString = ParametersUtil.generateArgString(options); ParametersUtil.generateArgString(options))
if (StringUtils.isNotBlank(argString)) { .nodeFilters(nodeFilters),
apiPath.append("argString=").append(ParametersUtil.urlEncode(argString)).append("&"); new ExecutionParser("result/executions/execution"));
}
String filters = ParametersUtil.generateNodeFiltersString(nodeFilters);
if (StringUtils.isNotBlank(filters)) {
apiPath.append(filters);
}
return new ApiCall(this).get(apiPath.toString(), new ExecutionParser("result/executions/execution"));
} }
/** /**
@ -456,14 +444,10 @@ public class RundeckClient implements Serializable {
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException { throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !"); AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !");
AssertUtil.notBlank(command, "command is mandatory to trigger an ad-hoc command !"); AssertUtil.notBlank(command, "command is mandatory to trigger an ad-hoc command !");
StringBuilder apiPath = new StringBuilder("/run/command"); RundeckExecution execution = new ApiCall(this).get(new ApiPathBuilder("/run/command").param("project", project)
apiPath.append("?project=").append(project); .param("exec", command)
apiPath.append("&exec=").append(ParametersUtil.urlEncode(command)); .nodeFilters(nodeFilters),
String filters = ParametersUtil.generateNodeFiltersString(nodeFilters); new ExecutionParser("result/execution"));
if (StringUtils.isNotBlank(filters)) {
apiPath.append("&").append(filters);
}
RundeckExecution execution = new ApiCall(this).get(apiPath.toString(), new ExecutionParser("result/execution"));
// the first call just returns the ID of the execution, so we need another call to get a "real" execution // the first call just returns the ID of the execution, so we need another call to get a "real" execution
return getExecution(execution.getId()); return getExecution(execution.getId());
} }
@ -600,7 +584,7 @@ public class RundeckClient implements Serializable {
public List<RundeckExecution> getRunningExecutions(String project) throws RundeckApiException, public List<RundeckExecution> getRunningExecutions(String project) throws RundeckApiException,
RundeckApiLoginException, IllegalArgumentException { RundeckApiLoginException, IllegalArgumentException {
AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !"); AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !");
return new ApiCall(this).get("/executions/running?project=" + project, return new ApiCall(this).get(new ApiPathBuilder("/executions/running").param("project", project),
new ExecutionsParser("result/executions/execution")); new ExecutionsParser("result/executions/execution"));
} }
@ -648,17 +632,11 @@ public class RundeckClient implements Serializable {
public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset) public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset)
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException { throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !"); AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !");
StringBuilder apiPath = new StringBuilder("/job/").append(jobId).append("/executions?"); return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/executions").param("status",
if (status != null) { status != null ? StringUtils.lowerCase(status.toString()) : null)
apiPath.append("status=").append(StringUtils.lowerCase(status.toString())).append("&"); .param("max", max)
} .param("offset", offset),
if (max != null && max >= 0) { new ExecutionsParser("result/executions/execution"));
apiPath.append("max=").append(max).append("&");
}
if (offset != null && offset >= 0) {
apiPath.append("offset=").append(offset);
}
return new ApiCall(this).get(apiPath.toString(), new ExecutionsParser("result/executions/execution"));
} }
/** /**
@ -673,7 +651,8 @@ public class RundeckClient implements Serializable {
public RundeckExecution getExecution(Long executionId) throws RundeckApiException, RundeckApiLoginException, public RundeckExecution getExecution(Long executionId) throws RundeckApiException, RundeckApiLoginException,
IllegalArgumentException { IllegalArgumentException {
AssertUtil.notNull(executionId, "executionId is mandatory to get the details of an execution !"); AssertUtil.notNull(executionId, "executionId is mandatory to get the details of an execution !");
return new ApiCall(this).get("/execution/" + executionId, new ExecutionParser("result/executions/execution")); return new ApiCall(this).get(new ApiPathBuilder("/execution/", executionId.toString()),
new ExecutionParser("result/executions/execution"));
} }
public String getUrl() { public String getUrl() {