All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.algorithmia.client.HttpClientHelpers Maven / Gradle / Ivy

There is a newer version: 1.0.16
Show newest version
package com.algorithmia.client;

import java.io.IOException;
import java.io.InputStream;

import com.algorithmia.algo.AlgoAsyncResponse;
import com.algorithmia.algo.AlgoFailure;
import com.algorithmia.algo.AlgoResponse;
import com.algorithmia.algo.AlgoSuccess;
import com.algorithmia.algo.Metadata;
import org.apache.commons.io.IOUtils;
import org.apache.http.ContentTooLongException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.ContentDecoder;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.entity.ContentBufferEntity;
import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
import org.apache.http.nio.util.HeapByteBufferAllocator;
import org.apache.http.nio.util.SimpleInputBuffer;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Asserts;

import com.algorithmia.APIException;
import com.algorithmia.AlgorithmException;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import static com.algorithmia.algo.Algorithm.AlgorithmOutputType;

/**
 * Various HTTP actions, using our HttpClient class, and automatically adding authorization
 */
public class HttpClientHelpers {
    private HttpClientHelpers() {}  // non-instantiable

    static abstract public class AbstractBasicResponseConsumer extends AbstractAsyncResponseConsumer {
        protected volatile HttpResponse response;
        private volatile SimpleInputBuffer buf;

        @Override
        protected void onResponseReceived(final HttpResponse response) throws IOException {
            this.response = response;
        }

        @Override
        protected void onEntityEnclosed(final HttpEntity entity, final ContentType contentType) throws IOException {
            long len = entity.getContentLength();
            if (len > Integer.MAX_VALUE) {
                throw new ContentTooLongException("Entity content is too long: " + len);
            }
            if (len < 0) {
                len = 4096;
            }
            this.buf = new SimpleInputBuffer((int) len, new HeapByteBufferAllocator());
            this.response.setEntity(new ContentBufferEntity(entity, this.buf));
        }

        @Override
        protected void onContentReceived(final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
            Asserts.notNull(this.buf, "Content buffer");
            this.buf.consumeContent(decoder);
        }

        @Override
        protected void releaseResources() {
            this.response = null;
            this.buf = null;
        }
    }

    static public class JsonDeserializeResponseHandler extends AbstractBasicResponseConsumer {
        @SuppressWarnings("rawtypes")
        final private TypeToken typeToken;
        public JsonDeserializeResponseHandler(@SuppressWarnings("rawtypes") TypeToken typeToken) {
            this.typeToken = typeToken;
        }
        @Override
        protected T buildResult(HttpContext context) throws APIException {
            JsonElement json = parseResponseJson(response);
            throwIfJsonHasError(json);
            Gson gson = new Gson();
            return gson.fromJson(json, typeToken.getType());
        }
    }

    static public class AlgoResponseHandler extends AbstractBasicResponseConsumer {
        private AlgorithmOutputType outputType;
        public AlgoResponseHandler(AlgorithmOutputType outputType) {
            this.outputType = outputType;
        }
        @Override
        protected AlgoResponse buildResult(HttpContext context) throws APIException {
            if (outputType.equals(AlgorithmOutputType.RAW)) {
                return parseRawOutput(response);
            } else {
                JsonElement json = parseResponseJson(response);
                return jsonToAlgoResponse(json, outputType);
            }
        }
    }

    private static AlgoResponse parseRawOutput(HttpResponse response) throws APIException {
        throwIfNotOk(response);
        try {
            final HttpEntity entity = response.getEntity();
            final InputStream is = entity.getContent();
            String rawOutputString = IOUtils.toString(is, "UTF-8");
            return new AlgoSuccess(null, null, rawOutputString, null);
        } catch(IOException ex) {
            throw new APIException("IOException: " + ex.getMessage());
        }
    }

    public static AlgoResponse jsonToAlgoResponse(JsonElement json, AlgorithmOutputType outputType) throws APIException {
        if(json != null && json.isJsonObject()) {
            final JsonObject obj = json.getAsJsonObject();
            if(obj.has("error")) {
                final JsonObject error = obj.getAsJsonObject("error");
                final String msg = error.get("message").getAsString();
                String stacktrace = null;
                if (error.has("stacktrace")) {
                    stacktrace = error.get("stacktrace").getAsString();
                }
                return new AlgoFailure(new AlgorithmException(msg, null, stacktrace));
            } else if (AlgorithmOutputType.DEFAULT.equals(outputType)) {
                JsonObject metaJson = obj.getAsJsonObject("metadata");
                Double duration = metaJson.get("duration").getAsDouble();
                com.algorithmia.algo.ContentType contentType = com.algorithmia.algo.ContentType.fromString(metaJson.get("content_type").getAsString());
                JsonElement stdoutJson = metaJson.get("stdout");
                String stdout = (stdoutJson == null) ? null : stdoutJson.getAsString();
                Metadata meta = new Metadata(contentType, duration, stdout);
                return new AlgoSuccess(obj.get("result"), meta, null, null);
            } else if (AlgorithmOutputType.VOID.equals(outputType)) {
                AlgoAsyncResponse asyncResponse = new AlgoAsyncResponse(obj.get("async").getAsString(), obj.get("request_id").getAsString());
                return new AlgoSuccess(null, null, null, asyncResponse);
            } else {
                throw new APIException("Unexpected output type: " + outputType);
            }
        } else {
            throw new APIException("Unexpected API response: " + json);
        }
    }

    public static void throwIfNotOk(HttpResponse response) throws APIException {
        final int status = response.getStatusLine().getStatusCode();
        if(200 > status || status > 300) {
            throw APIException.fromHttpResponse(response);
        }
    }

    public static void throwIfJsonHasError(JsonElement json) throws APIException {
        if(json != null && json.isJsonObject()) {
            final JsonObject obj = json.getAsJsonObject();
            if(obj.has("error")) {
                final JsonObject error = obj.getAsJsonObject("error");
                final String msg = error.get("message").getAsString();
                throw new APIException(msg);
            }
        }
    }

    final static JsonParser parser = new JsonParser();
    public static JsonElement parseResponseJson(HttpResponse response) throws APIException {
        throwIfNotOk(response);

        try {
            final HttpEntity entity = response.getEntity();
            final InputStream is = entity.getContent();
            String jsonString = IOUtils.toString(is, "UTF-8");
            JsonElement json = parser.parse(jsonString);
            return json;
        } catch(IOException ex) {
            throw new APIException("IOException: " + ex.getMessage());
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy