Java tutorial
/* * Copyright 2015 Collective, Inc. * * 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 com.collective.celos; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; 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.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.Lists; /** * Utility class to talk to the Celos server HTTP API. */ public class CelosClient { private static final String LIST_REGISTER_KEYS_PATH = "/list-register-keys"; private static final String SCHEDULER_PATH = "/scheduler"; private static final String RERUN_PATH = "/rerun"; private static final String KILL_PATH = "/kill"; private static final String PAUSE_PATH = "/pause"; private static final String SLOT_STATE_PATH = "/slot-state"; private static final String CLEAR_CACHE_PATH = "/clear-cache"; private static final String WORKFLOW_LIST_PATH = "/workflow-list"; private static final String WORKFLOW_SLOTS_PATH = "/workflow-slots"; private static final String REGISTER_PATH = "/register"; public static final String START_TIME_PARAM = "start"; public static final String END_TIME_PARAM = "end"; public static final String TIME_PARAM = "time"; public static final String ID_PARAM = "id"; public static final String IDS_PARAM = "ids"; public static final String KEY_PARAM = "key"; public static final String BUCKET_PARAM = "bucket"; public static final String PREFIX_PARAM = "prefix"; public static final String KEYS_NODE = "keys"; public static final String PAUSE_NODE = "paused"; public static final String INFO_NODE = "info"; public static final String SLOTS_NODE = "slots"; private final HttpClient client; private final ScheduledTimeFormatter timeFormatter; private final URI address; public CelosClient(URI address) { this.address = Util.requireNonNull(address); this.client = new DefaultHttpClient(); this.timeFormatter = new ScheduledTimeFormatter(); } public URI getAddress() { return address; } public void checkStatus() throws Exception { getWorkflowList(); } public Set<WorkflowID> getWorkflowList() throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + WORKFLOW_LIST_PATH); HttpGet workflowListGet = new HttpGet(uriBuilder.build()); HttpResponse getResponse = execute(workflowListGet); InputStream content = getResponse.getEntity().getContent(); return parseWorkflowIdsList(content); } public WorkflowStatus getWorkflowStatus(WorkflowID workflowID, ScheduledTime startTime, ScheduledTime endTime) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + WORKFLOW_SLOTS_PATH); if (endTime != null) { uriBuilder.addParameter(END_TIME_PARAM, timeFormatter.formatPretty(endTime)); } if (startTime != null) { uriBuilder.addParameter(START_TIME_PARAM, timeFormatter.formatPretty(startTime)); } uriBuilder.addParameter(ID_PARAM, workflowID.toString()); URI uri = uriBuilder.build(); HttpGet workflowListGet = new HttpGet(uri); HttpResponse getResponse = execute(workflowListGet); InputStream content = getResponse.getEntity().getContent(); return parseWorkflowStatus(workflowID, content); } public WorkflowStatus getWorkflowStatus(WorkflowID workflowID, ScheduledTime endTime) throws Exception { return getWorkflowStatus(workflowID, null, endTime); } public WorkflowStatus getWorkflowStatus(WorkflowID workflowID) throws Exception { return getWorkflowStatus(workflowID, null, null); } public void iterateScheduler() throws Exception { iterateScheduler(ScheduledTime.now()); } public void iterateScheduler(ScheduledTime scheduledTime) throws Exception { iterateScheduler(scheduledTime, Collections.<WorkflowID>emptySet()); } public void iterateScheduler(ScheduledTime scheduledTime, Set<WorkflowID> workflowIDs) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + SCHEDULER_PATH); if (!workflowIDs.isEmpty()) { uriBuilder.addParameter(IDS_PARAM, StringUtils.join(workflowIDs, ",")); } uriBuilder.addParameter(TIME_PARAM, timeFormatter.formatPretty(scheduledTime)); executePost(uriBuilder.build()); } public void clearCache() throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + CLEAR_CACHE_PATH); executePost(uriBuilder.build()); } public SlotState getSlotState(WorkflowID workflowID, ScheduledTime scheduledTime) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + SLOT_STATE_PATH); uriBuilder.addParameter(ID_PARAM, workflowID.toString()); uriBuilder.addParameter(TIME_PARAM, scheduledTime.toString()); HttpGet workflowListGet = new HttpGet(uriBuilder.build()); HttpResponse getResponse = execute(workflowListGet); InputStream content = getResponse.getEntity().getContent(); return SlotState.fromJSONNode(workflowID, Util.JSON_READER.withType(ObjectNode.class).readValue(content)); } public void rerunSlot(SlotID slotID) throws Exception { rerunSlot(slotID.getWorkflowID(), slotID.getScheduledTime()); } public void rerunSlot(WorkflowID workflowID, ScheduledTime scheduledTime) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + RERUN_PATH); uriBuilder.addParameter(ID_PARAM, workflowID.toString()); uriBuilder.addParameter(TIME_PARAM, scheduledTime.toString()); executePost(uriBuilder.build()); } public void setWorkflowPaused(WorkflowID workflowID, Boolean paused) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + PAUSE_PATH); uriBuilder.addParameter(ID_PARAM, workflowID.toString()); uriBuilder.addParameter(PAUSE_NODE, paused.toString()); executePost(uriBuilder.build()); } public void kill(WorkflowID workflowID, ScheduledTime scheduledTime) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + KILL_PATH); uriBuilder.addParameter(ID_PARAM, workflowID.toString()); uriBuilder.addParameter(TIME_PARAM, scheduledTime.toString()); executePost(uriBuilder.build()); } //// Registers /** * Returns the specified register value, or null if not found. */ public JsonNode getRegister(BucketID bucket, RegisterKey key) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + REGISTER_PATH); uriBuilder.addParameter(BUCKET_PARAM, bucket.toString()); uriBuilder.addParameter(KEY_PARAM, key.toString()); HttpResponse res = client.execute(new HttpGet(uriBuilder.build())); try { switch (res.getStatusLine().getStatusCode()) { case HttpServletResponse.SC_NOT_FOUND: return null; case HttpServletResponse.SC_OK: return Util.JSON_READER.readTree(res.getEntity().getContent()); default: throw new Exception(res.getStatusLine().toString()); } } finally { EntityUtils.consume(res.getEntity()); } } /** * Sets the specified register value. */ public void putRegister(BucketID bucket, RegisterKey key, JsonNode value) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + REGISTER_PATH); uriBuilder.addParameter(BUCKET_PARAM, bucket.toString()); uriBuilder.addParameter(KEY_PARAM, key.toString()); executePut(uriBuilder.build(), new StringEntity(Util.JSON_WRITER.writeValueAsString(value), StandardCharsets.UTF_8)); } /** * Deletes the specified register value. */ public void deleteRegister(BucketID bucket, RegisterKey key) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + REGISTER_PATH); uriBuilder.addParameter(BUCKET_PARAM, bucket.toString()); uriBuilder.addParameter(KEY_PARAM, key.toString()); executeDelete(uriBuilder.build()); } public void deleteRegistersWithPrefix(BucketID bucket, String prefix) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + REGISTER_PATH); uriBuilder.addParameter(BUCKET_PARAM, bucket.toString()); uriBuilder.addParameter(PREFIX_PARAM, prefix); executeDelete(uriBuilder.build()); } public List<RegisterKey> getRegisterKeys(BucketID bucket) throws Exception { return getRegisterKeys(bucket, null); } public List<RegisterKey> getRegisterKeys(BucketID bucket, String prefix) throws Exception { URIBuilder uriBuilder = new URIBuilder(address); uriBuilder.setPath(uriBuilder.getPath() + LIST_REGISTER_KEYS_PATH); uriBuilder.addParameter(BUCKET_PARAM, bucket.toString()); if (!StringUtils.isEmpty(prefix)) { uriBuilder.addParameter(PREFIX_PARAM, prefix); } InputStream contentStream = execute(new HttpGet(uriBuilder.build())).getEntity().getContent(); return parseKeyList(contentStream); } private void executePost(URI request) throws IOException { executeAndConsume(new HttpPost(request)); } private void executePut(URI request, HttpEntity entity) throws IOException { HttpPut put = new HttpPut(request); put.setEntity(entity); executeAndConsume(put); } private void executeDelete(URI request) throws IOException { executeAndConsume(new HttpDelete(request)); } private void executeAndConsume(HttpUriRequest msg) throws IOException { HttpResponse postResponse = execute(msg); EntityUtils.consume(postResponse.getEntity()); } private HttpResponse execute(HttpUriRequest request) throws IOException { HttpResponse getResponse = client.execute(request); if (errorResponse(getResponse)) { EntityUtils.consume(getResponse.getEntity()); throw new IOException(getResponse.getStatusLine().toString()); } return getResponse; } private boolean errorResponse(HttpResponse getResponse) { return getResponse.getStatusLine() != null && getResponse.getStatusLine().getStatusCode() != 200; } private static class WorkflowList { private Set<WorkflowID> ids; public Set<WorkflowID> getIds() { return ids; } } private static class KeyList { private List<RegisterKey> keys; public List<RegisterKey> getKeys() { return keys; } } List<RegisterKey> parseKeyList(InputStream content) throws IOException { return Util.JSON_READER.withType(KeyList.class).<KeyList>readValue(content).getKeys(); } Set<WorkflowID> parseWorkflowIdsList(InputStream content) throws IOException { return Util.JSON_READER.withType(WorkflowList.class).<WorkflowList>readValue(content).getIds(); } WorkflowStatus parseWorkflowStatus(WorkflowID workflowID, InputStream content) throws IOException { JsonNode node = Util.JSON_READER.withType(JsonNode.class).readValue(content); WorkflowInfo info = Util.JSON_READER.treeToValue(node.get(INFO_NODE), WorkflowInfo.class); Boolean paused = node.get(PAUSE_NODE).asBoolean(); Iterator<JsonNode> elems = node.get(SLOTS_NODE).elements(); List<SlotState> result = Lists.newArrayList(); while (elems.hasNext()) { result.add(SlotState.fromJSONNode(workflowID, elems.next())); } return new WorkflowStatus(info, result, paused); } }