org.zenoss.zep.rest.RestClient.java Source code

Java tutorial

Introduction

Here is the source code for org.zenoss.zep.rest.RestClient.java

Source

/*****************************************************************************
 *
 * Copyright (C) Zenoss, Inc. 2010, all rights reserved.
 *
 * This content is made available according to terms specified in
 * License.zenoss under the directory where your Zenoss product is installed.
 *
 ****************************************************************************/

package org.zenoss.zep.rest;

import com.google.protobuf.Message;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
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.entity.BasicHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zenoss.protobufs.JsonFormat;
import org.zenoss.protobufs.ProtobufConstants;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class RestClient implements Closeable {
    @SuppressWarnings("unused")
    private static final Logger logger = LoggerFactory.getLogger(RestClient.class);

    private HttpClient client = new DefaultHttpClient();
    private Map<String, Message> supportedMessages = new HashMap<String, Message>();
    private String host = System.getProperty("jetty.host", "localhost");
    private String port = System.getProperty("jetty.port", "8084");

    public static class RestResponse {
        private final HttpResponse response;
        private final int responseCode;
        private final Message message;
        private final Map<String, List<String>> headers;

        public RestResponse(final HttpResponse response, final Message message) {
            this.response = response;
            this.responseCode = response.getStatusLine().getStatusCode();
            this.message = message;
            Map<String, List<String>> headers = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
            HeaderIterator it = response.headerIterator();
            while (it.hasNext()) {
                Header header = it.nextHeader();
                List<String> l = headers.get(header.getName());
                if (l == null) {
                    l = new ArrayList<String>();
                    headers.put(header.getName(), l);
                }
                l.add(header.getValue());
            }
            this.headers = headers;
        }

        public HttpResponse getResponse() {
            return this.response;
        }

        public int getResponseCode() {
            return responseCode;
        }

        public Message getMessage() {
            return message;
        }

        public Map<String, List<String>> getHeaders() {
            return Collections.unmodifiableMap(this.headers);
        }

        @Override
        public String toString() {
            return "RestResponse{" + "responseCode=" + responseCode + ", message=" + message + ", headers="
                    + headers + '}';
        }
    }

    public RestClient(Message... msgs) {
        for (Message msg : msgs) {
            this.supportedMessages.put(msg.getDescriptorForType().getFullName(), msg);
        }
    }

    private URI createURI(String path) throws IOException {
        try {
            if (path.startsWith("/")) {
                return new URI("http", null, host, Integer.valueOf(port), path, null, null);
            }
            return new URI(path);
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }

    private HttpEntity createProtobufEntity(Message msg) {
        BasicHttpEntity entity = new BasicHttpEntity();
        entity.setContentType(ProtobufConstants.CONTENT_TYPE_PROTOBUF);
        entity.setContentLength(msg.getSerializedSize());
        entity.setContent(new ByteArrayInputStream(msg.toByteArray()));
        return entity;
    }

    private HttpEntity createJsonEntity(Message msg) throws IOException {
        BasicHttpEntity entity = new BasicHttpEntity();
        entity.setContentType(MediaType.APPLICATION_JSON);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JsonFormat.writeTo(msg, baos);
        entity.setContent(new ByteArrayInputStream(baos.toByteArray()));
        return entity;
    }

    private Message createProtobufFromResponse(HttpResponse response) throws IllegalStateException, IOException {
        HttpEntity entity = response.getEntity();
        Message msg = null;
        int responseCode = response.getStatusLine().getStatusCode();
        Header fullNameHeader = response.getFirstHeader(ProtobufConstants.HEADER_PROTOBUF_FULLNAME);
        if (fullNameHeader != null) {
            Message msgForBuild = this.supportedMessages.get(fullNameHeader.getValue());
            if (msgForBuild == null) {
                throw new IOException("Unsupported message type: " + fullNameHeader.getValue());
            }
            String contentType = response.getFirstHeader("Content-Type").getValue();
            if (MediaType.APPLICATION_JSON.equals(contentType)) {
                msg = JsonFormat.merge(response.getEntity().getContent(), msgForBuild.newBuilderForType());
            } else if (ProtobufConstants.CONTENT_TYPE_PROTOBUF.equals(contentType)) {
                msg = msgForBuild.newBuilderForType().mergeFrom(response.getEntity().getContent()).build();
            } else {
                throw new IOException("Unsupported content type: " + contentType);
            }
        } else if (responseCode != HttpStatus.SC_NO_CONTENT && responseCode != HttpStatus.SC_CREATED) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            entity.writeTo(baos);
            throw new IOException(
                    String.format("Status code: %d, Response: %s", responseCode, baos.toString("UTF-8")));
        }
        entity.consumeContent();
        return msg;

    }

    public RestResponse get(String path, String acceptContent) throws IOException {
        Message msg = null;
        HttpGet method = new HttpGet(createURI(path));
        method.addHeader("Accept", acceptContent);
        HttpResponse response = this.client.execute(method);
        int rc = response.getStatusLine().getStatusCode();
        if (rc == 200) {
            msg = createProtobufFromResponse(response);
        } else if (response.getStatusLine().getStatusCode() != 404) {
            throw new IOException("Unexpected RC: " + rc);
        }
        return new RestResponse(response, msg);
    }

    public RestResponse getJson(String path) throws IOException {
        return get(path, MediaType.APPLICATION_JSON);
    }

    public RestResponse getProtobuf(String path) throws IOException {
        return get(path, ProtobufConstants.CONTENT_TYPE_PROTOBUF);
    }

    public RestResponse post(String path, Message msg, String contentType) throws IOException {
        HttpPost post = new HttpPost(createURI(path));
        post.addHeader(ProtobufConstants.HEADER_PROTOBUF_FULLNAME, msg.getDescriptorForType().getFullName());
        final HttpEntity entity;
        if (MediaType.APPLICATION_JSON.equals(contentType)) {
            entity = createJsonEntity(msg);
        } else if (ProtobufConstants.CONTENT_TYPE_PROTOBUF.equals(contentType)) {
            entity = createProtobufEntity(msg);
        } else {
            throw new IllegalArgumentException("Unsupported content type");
        }
        post.setEntity(entity);
        HttpResponse response = client.execute(post);
        Message msgRsp = null;
        if (isNonNullProtoBuf(response)) {
            msgRsp = createProtobufFromResponse(response);
        }
        return new RestResponse(response, msgRsp);
    }

    private boolean isNonNullProtoBuf(final HttpResponse response) {
        if (response.getEntity() == null || response.getFirstHeader(HttpHeaders.CONTENT_TYPE) == null) {
            return false;
        }
        String contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
        List<String> protoBufTypes = Arrays.asList(MediaType.APPLICATION_JSON,
                ProtobufConstants.CONTENT_TYPE_PROTOBUF);
        return protoBufTypes.contains(contentType);
    }

    public RestResponse postJson(String path, Message msg) throws IOException {
        return post(path, msg, MediaType.APPLICATION_JSON);
    }

    public RestResponse postProtobuf(String path, Message msg) throws IOException {
        return post(path, msg, ProtobufConstants.CONTENT_TYPE_PROTOBUF);
    }

    public RestResponse put(String path, Message msg, String contentType) throws IOException {
        HttpPut put = new HttpPut(createURI(path));
        put.addHeader(ProtobufConstants.HEADER_PROTOBUF_FULLNAME, msg.getDescriptorForType().getFullName());
        final HttpEntity entity;
        if (MediaType.APPLICATION_JSON.equals(contentType)) {
            entity = createJsonEntity(msg);
        } else if (ProtobufConstants.CONTENT_TYPE_PROTOBUF.equals(contentType)) {
            entity = createProtobufEntity(msg);
        } else {
            throw new IllegalArgumentException("Unsupported content type");
        }
        put.setEntity(entity);
        HttpResponse response = client.execute(put);
        Message msgRsp = null;
        if (response.getEntity() != null) {
            msgRsp = createProtobufFromResponse(response);
        }
        return new RestResponse(response, msgRsp);
    }

    public RestResponse putJson(String path, Message msg) throws IOException {
        return put(path, msg, MediaType.APPLICATION_JSON);
    }

    public RestResponse putProtobuf(String path, Message msg) throws IOException {
        return put(path, msg, ProtobufConstants.CONTENT_TYPE_PROTOBUF);
    }

    public RestResponse delete(String path) throws IOException {
        HttpResponse response = this.client.execute(new HttpDelete(createURI(path)));
        if (response.getEntity() != null) {
            response.getEntity().consumeContent();
        }
        return new RestResponse(response, null);
    }

    @Override
    public void close() throws IOException {
        this.client.getConnectionManager().shutdown();
    }
}