com.collective.celos.CelosClient.java Source code

Java tutorial

Introduction

Here is the source code for com.collective.celos.CelosClient.java

Source

/*
 * 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);
    }

}