org.hawk.service.api.utils.APIUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.hawk.service.api.utils.APIUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2015 University of York.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Antonio Garcia-Dominguez - initial API and implementation
 *    Abel Gmez - Generic methods
 *******************************************************************************/
package org.hawk.service.api.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.thrift.TServiceClient;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.protocol.TTupleProtocol;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.TZlibTransport;
import org.hawk.service.api.File;
import org.hawk.service.api.Subscription;
import org.hawk.service.api.SubscriptionDurability;
import org.hawk.service.artemis.consumer.Consumer;
import org.hawk.service.artemis.consumer.Consumer.QueueType;

/**
 * Utility methods for connecting to the MONDO APIs. These use the optional
 * dependency on Apache HTTP Components.
 */
public class APIUtils {

    /*
     * Note: all values of this enum must have names in uppercase, so the
     * 'tprotocol' values of the <code>hawk+http(s)://</code> URLs will be case
     * insensitive.
     */
    public static enum ThriftProtocol {
        /**
         * Efficient, compatible with almost all languages in Thrift 0.9.2.
         * (including JavaScript, with an unofficial extension).
         */
        BINARY(new TBinaryProtocol.Factory()),
        /**
         * More space efficient than {@link #BINARY} at the expense of some
         * time, but not available for JavaScript.
         */
        COMPACT(new TCompactProtocol.Factory()),
        /**
         * More space efficient than {@link #COMPACT}, but only available
         * for Java in Thrift 0.9.2.
         */
        TUPLE(new TTupleProtocol.Factory()),
        /**
         * Compatible with all languages of interest (including JavaScript) out
         * of the box, but not very efficient.
         */
        JSON(new TJSONProtocol.Factory());

        private final TProtocolFactory protocolFactory;

        private ThriftProtocol(TProtocolFactory factory) {
            this.protocolFactory = factory;
        }

        public static String[] strings() {
            return toStringArray(values());
        }

        public static ThriftProtocol guessFromURL(String location) {
            ThriftProtocol proto = TUPLE;
            if (location.endsWith("compact")) {
                proto = COMPACT;
            } else if (location.endsWith("binary")) {
                proto = BINARY;
            } else if (location.endsWith("json")) {
                proto = JSON;
            }
            return proto;
        }

        public TProtocolFactory getProtocolFactory() {
            return protocolFactory;
        }
    }

    private APIUtils() {
    }

    public static Consumer connectToArtemis(Subscription s, SubscriptionDurability sd) throws Exception {
        return Consumer.connectRemote(s.host, s.port, s.queueAddress, s.queueName, toQueueType(sd), s.sslRequired);
    }

    public static <T extends TServiceClient> T connectTo(Class<T> clazz, String url)
            throws TTransportException, URISyntaxException {
        return connectTo(clazz, url, ThriftProtocol.TUPLE);
    }

    public static <T extends TServiceClient> T connectTo(Class<T> clazz, String url, ThriftProtocol thriftProtocol)
            throws TTransportException, URISyntaxException {
        return connectTo(clazz, url, thriftProtocol, null, null);
    }

    public static <T extends TServiceClient> T connectTo(Class<T> clazz, String url, ThriftProtocol thriftProtocol,
            String username, String password) throws TTransportException, URISyntaxException {
        final UsernamePasswordCredentials credentials = (username != null && password != null)
                ? new UsernamePasswordCredentials(username, password)
                : null;
        return connectTo(clazz, url, thriftProtocol, credentials);
    }

    @SuppressWarnings({ "deprecation", "restriction" })
    public static <T extends TServiceClient> T connectTo(Class<T> clazz, String url, ThriftProtocol thriftProtocol,
            final Credentials credentials) throws TTransportException, URISyntaxException {
        try {
            final URI parsed = new URI(url);

            TTransport transport;
            if (parsed.getScheme().startsWith("http")) {
                final DefaultHttpClient httpClient = APIUtils.createGZipAwareHttpClient();
                if (credentials != null) {
                    httpClient.getCredentialsProvider().setCredentials(new AuthScope(null, -1), credentials);
                }
                transport = new THttpClient(url, httpClient);
            } else {
                transport = new TZlibTransport(new TSocket(parsed.getHost(), parsed.getPort()));
                transport.open();
            }
            Constructor<T> constructor = clazz.getDeclaredConstructor(org.apache.thrift.protocol.TProtocol.class);
            return constructor.newInstance(thriftProtocol.getProtocolFactory().getProtocol(transport));
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            throw new TTransportException(e);
        }
    }

    public static File convertJavaFileToThriftFile(java.io.File rawFile) throws FileNotFoundException, IOException {
        try (FileInputStream fIS = new FileInputStream(rawFile)) {
            FileChannel chan = fIS.getChannel();

            /* Note: this cast limits us to 2GB files - this shouldn't
             be a problem, but if it were we could use FileChannel#map
             and call Hawk.Client#registerModels one file at a time. */
            ByteBuffer buf = ByteBuffer.allocate((int) chan.size());
            chan.read(buf);
            buf.flip();

            File mmFile = new File();
            mmFile.name = rawFile.getName();
            mmFile.contents = buf;
            return mmFile;
        }
    }

    @SuppressWarnings({ "restriction", "deprecation" })
    private static DefaultHttpClient createGZipAwareHttpClient() {
        /*
         * Apache HttpClient 4.3 and later deprecate DefaultHttpClient in favour
         * of HttpClientBuilder, but Hadoop 2.7.x (used by CloudATL) uses Apache
         * HttpClient 4.2.5. Until Hadoop upgrades to HttpClient 4.3+, we'll
         * have to keep using this deprecated API. After that, we'll be able to
         * replace this bit of code with something like:
         *
         * <pre>
         *  return HttpClientBuilder.create()
         *      .addInterceptorFirst(new GZipRequestInterceptor())
         *   .addInterceptorFirst(new GZipResponseInterceptor())
         *   .build();
         * </pre>
         */
        final DefaultHttpClient client = new DefaultHttpClient();
        client.addRequestInterceptor(new GZipRequestInterceptor());
        client.addResponseInterceptor(new GZipResponseInterceptor());
        return client;
    }

    private static QueueType toQueueType(SubscriptionDurability sd) {
        switch (sd) {
        case DEFAULT:
            return QueueType.DEFAULT;
        case DURABLE:
            return QueueType.DURABLE;
        case TEMPORARY:
            return QueueType.TEMPORARY;
        default:
            throw new IllegalArgumentException("Unknown subscription durability " + sd);
        }
    }

    private static <T> String[] toStringArray(Object[] c) {
        final String[] strings = new String[c.length];
        int i = 0;
        for (Object o : c) {
            strings[i++] = o + "";
        }
        return strings;
    }

}