org.pepstock.jem.commands.util.HttpUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.commands.util.HttpUtil.java

Source

/**
JEM, the BEE - Job Entry Manager, the Batch Execution Environment
Copyright (C) 2012-2015   Andrea "Stock" Stocchero
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.pepstock.jem.commands.util;

import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Properties;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.pepstock.jem.PreJob;
import org.pepstock.jem.commands.SubmitException;
import org.pepstock.jem.commands.SubmitMessage;
import org.pepstock.jem.log.LogAppl;
import org.pepstock.jem.node.resources.impl.http.HttpResourceKeys;
import org.pepstock.jem.util.CharSet;

import com.thoughtworks.xstream.XStream;

/**
 * Utility class to call JEM by HTTP to extract group name and members list and
 * to submit a job by http.
 * 
 * @author Andrea "Stock" Stocchero
 * 
 */
public final class HttpUtil {

    /**
     * Key used to store user id
     */
    public static final String USER_PROPERTY_KEY = "jem.command.user";

    /**
     * Key used to store user password
     */
    public static final String PASSWORD_PROPERTY_KEY = "jem.command.password";
    /**
     * Query string to get cluster group name of Hazelcast
     */
    private static final String NAME_QUERY_STRING = "/servlet/getClusterGroupName";

    /**
     * Query string to get all member of group name of Hazelcast
     */
    private static final String MEMBERS_QUERY_STRING = "/servlet/getClusterMembers";

    /**
     * Query string to log in
     */
    private static final String LOGIN_QUERY_STRING = "/servlet/login";

    /**
     * Query string to log out
     */
    private static final String LOGOUT_QUERY_STRING = "/servlet/logout";

    /**
     * Query string to submit a job
     */
    private static final String SUBMIT_QUERY_STRING = "/servlet/submit";

    /**
     * Query string to get a ended job by id
     */
    private static final String ENDE_JOBID_QUERY_STRING = "/servlet/getEndedJobById";

    /**
     * Private constructor to avoid any instantiations
     */
    private HttpUtil() {
    }

    /**
     * Calls a http node of JEM to get all members of group, necessary to client
     * to connect to JEM.
     * 
     * @param url http URL to call
     * @return Arrays with all members of Hazelcast cluster
     * @throws SubmitException if errors occur
     */
    public static String[] getMembers(String url) throws SubmitException {
        // creates a HTTP client
        CloseableHttpClient httpclient = null;
        try {
            httpclient = createHttpClient(url);
            // concats URL with query string
            String completeUrl = url + HttpUtil.MEMBERS_QUERY_STRING;
            // prepares GET request and basic response handler
            HttpGet httpget = new HttpGet(completeUrl);
            CloseableHttpResponse response = httpclient.execute(httpget);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                long len = entity.getContentLength();
                if (len != -1 && len < 2048) {
                    // executes and parse the results
                    // result must be
                    // [ipaddress:port],[ipaddress:port],[ipaddress:port],....[ipaddress:port]
                    return EntityUtils.toString(entity).trim().split(",");
                } else {
                    throw new IOException("HTTP Entity content length wrong: " + len);
                }
            }
            throw new IOException("HTTP Entity is null");
        } catch (KeyManagementException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (UnrecoverableKeyException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (NoSuchAlgorithmException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (KeyStoreException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (URISyntaxException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (ClientProtocolException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } catch (IOException e) {
            throw new SubmitException(SubmitMessage.JEMW001E, e);
        } finally {
            // close http client
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    LogAppl.getInstance().ignore(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Calls a http node of JEM to get group anme of Hazelcast cluster,
     * necessary to client to connect to JEM.
     * 
     * @param url http URL to call
     * @return group name of Hazelcast cluster
     * @throws SubmitException if errors occur
     */
    public static String getGroupName(String url) throws SubmitException {
        // creates a HTTP client
        CloseableHttpClient httpclient = null;
        try {
            httpclient = createHttpClient(url);
            // concats URL with query string
            String completeUrl = url + HttpUtil.NAME_QUERY_STRING;
            // prepares GET request and basic response handler
            HttpGet httpget = new HttpGet(completeUrl);
            ResponseHandler<String> responseHandler = new BasicResponseHandler();

            // executes and no parsing
            // result must be only a string
            String responseBody = httpclient.execute(httpget, responseHandler);
            return responseBody.trim();
        } catch (KeyManagementException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (UnrecoverableKeyException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (NoSuchAlgorithmException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (KeyStoreException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (URISyntaxException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (ClientProtocolException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } catch (IOException e) {
            throw new SubmitException(SubmitMessage.JEMW002E, e);
        } finally {
            // close http client
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    LogAppl.getInstance().ignore(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Calls a http node of JEM to submit a job.
     * 
     * @param user user to authenticate
     * @param password password to authenticate
     * @param url http URL to call
     * @param prejob job instance to submit
     * @return job id
     * @throws SubmitException if errors occur
     */
    public static String submit(String user, String password, String url, PreJob prejob) throws SubmitException {
        // creates a HTTP client
        CloseableHttpClient httpclient = null;
        boolean loggedIn = false;
        try {
            httpclient = createHttpClient(url);
            // prepares the entity to send via HTTP
            XStream streamer = new XStream();
            String content = streamer.toXML(prejob);

            login(user, password, url, httpclient);
            loggedIn = true;
            // concats URL with query string
            String completeUrl = url + HttpUtil.SUBMIT_QUERY_STRING;
            StringEntity entity = new StringEntity(content,
                    ContentType.create("text/xml", CharSet.DEFAULT_CHARSET_NAME));

            // prepares POST request and basic response handler
            HttpPost httppost = new HttpPost(completeUrl);
            httppost.setEntity(entity);
            ResponseHandler<String> responseHandler = new BasicResponseHandler();

            // executes and no parsing
            // result must be only a string
            String responseBody = httpclient.execute(httppost, responseHandler);
            return responseBody.trim();
        } catch (KeyManagementException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (UnrecoverableKeyException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (NoSuchAlgorithmException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (KeyStoreException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (URISyntaxException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (ClientProtocolException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } catch (IOException e) {
            throw new SubmitException(SubmitMessage.JEMW003E, e);
        } finally {
            if (loggedIn) {
                try {
                    logout(url, httpclient);
                } catch (Exception e) {
                    // debug
                    LogAppl.getInstance().debug(e.getMessage(), e);
                }
            }
            // close http client
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    LogAppl.getInstance().ignore(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Returns the job by its ID. If is not in output queue, normal <code>Object</code> is returned.
     * @param user user to authenticate
     * @param password password to authenticate
     * @param url http URL to call
     * @param jobId jobId
     * @return Object Job instance of a normal <code>Object</code> is not ended
     * @throws SubmitException if errors occur
     */
    public static Object getEndedJobByID(String user, String password, String url, String jobId)
            throws SubmitException {
        // creates a HTTP client
        CloseableHttpClient httpclient = null;
        boolean loggedIn = false;
        try {
            httpclient = createHttpClient(url);
            // prepares the entity to send via HTTP
            XStream streamer = new XStream();

            login(user, password, url, httpclient);
            loggedIn = true;
            // concats URL with query string
            String completeUrl = url + HttpUtil.ENDE_JOBID_QUERY_STRING + "?jobId=" + jobId;
            // prepares POST request and basic response handler
            HttpGet httpget = new HttpGet(completeUrl);
            ResponseHandler<String> responseHandler = new BasicResponseHandler();

            // executes and no parsing
            // result must be only a string
            String responseBody = httpclient.execute(httpget, responseHandler);
            return streamer.fromXML(responseBody.trim());
        } catch (KeyManagementException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (UnrecoverableKeyException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (NoSuchAlgorithmException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (KeyStoreException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (URISyntaxException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (ClientProtocolException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } catch (IOException e) {
            throw new SubmitException(SubmitMessage.JEMW004E, e);
        } finally {
            if (loggedIn) {
                try {
                    logout(url, httpclient);
                } catch (Exception e) {
                    // debug
                    LogAppl.getInstance().debug(e.getMessage(), e);
                }
            }
            // close http client
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    LogAppl.getInstance().ignore(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Performs the login using user and password
     * 
     * @param user user to authenticate
     * @param password password to authenticate
     * @param url http URL to call
     * @param httpclient hhtp client already created
     * @throws ClientProtocolException if any errors occurs on calling the
     *             servlet
     * @throws IOException if I/O error occurs
     */
    private static void login(String user, String password, String url, HttpClient httpclient)
            throws ClientProtocolException, IOException {
        // account info in a properties
        Properties properties = new Properties();
        properties.setProperty(USER_PROPERTY_KEY, user);
        properties.setProperty(PASSWORD_PROPERTY_KEY, password);
        StringWriter writer = new StringWriter();
        properties.store(writer, "Account info");
        // login

        // concats URL with query string
        String completeUrl = url + HttpUtil.LOGIN_QUERY_STRING;
        StringEntity entity = new StringEntity(writer.toString(), ContentType.create("text/plain", "UTF-8"));

        // prepares POST request and basic response handler
        HttpPost httppost = new HttpPost(completeUrl);
        httppost.setEntity(entity);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();

        // executes and no parsing
        // result must be only a string
        httpclient.execute(httppost, responseHandler);
    }

    /**
     * Logs out from HTTP server.
     * 
     * @param url http URL to call
     * @param httpclient http client already created
     * @throws ClientProtocolException if any errors occurs on calling the
     *             servlet
     * @throws IOException if I/O error occurs
     */
    private static void logout(String url, HttpClient httpclient) throws ClientProtocolException, IOException {
        String completeUrl = url + HttpUtil.LOGOUT_QUERY_STRING;
        // prepares POST request and basic response handler
        HttpPost httppost = new HttpPost(completeUrl);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        // executes and no parsing
        httpclient.execute(httppost, responseHandler);
    }

    /**
     * Configures SSL HTTP client, if necessary
     * 
     * @param uri http URI to call
     * @return HTTP client
     * @throws URISyntaxException
     * @throws KeyManagementException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     */
    public static final CloseableHttpClient createHttpClient(String uri) throws URISyntaxException,
            KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
        URI uriObject = URI.create(uri);
        return HttpUtil.createHttpClient(uriObject);
    }

    /**
     * Configures SSL HTTP client, if necessary
     * 
     * @param uri http URI to call
     * @return HTTP client
     * @throws KeyManagementException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     */
    public static final CloseableHttpClient createHttpClient(URI uri)
            throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
        // sets SSL ONLY if the scheme is HTTPS
        return createHttpClientByScheme(uri.getScheme()).build();
    }

    /**
     * Configures SSL HTTP client, if necessary
     * @param scheme scheme of URI
     * @return HTTP client
     * @throws KeyManagementException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     */
    public static final HttpClientBuilder createHttpClientByScheme(String scheme)
            throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        if (scheme != null) {
            configureSSL(httpClientBuilder, scheme);
        }
        return httpClientBuilder;
    }

    /**
     * Configures SSL in the parameter <code>httpClientBuilder</code>, if
     * necessary, that is if the <code>protocolType</code> is
     * {@link HttpResource#HTTPS_PROTOCOL}. <br>
     * If <code>port</code> is <code>null</code>, {@link #DEFAULT_HTTPS_PORT} is
     * used.
     * 
     * @param httpClientBuilder http client builder already created in which to
     *            set SSL property.
     * @param protocolType the protocol type: <li>
     *            {@link HttpResource#HTTP_PROTOCOL} <li>
     *            {@link HttpResource#HTTPS_PROTOCOL}
     * @throws KeyStoreException if an error occurs
     * @throws NoSuchAlgorithmException if an error occurs
     * @throws UnrecoverableKeyException if an error occurs
     * @throws KeyManagementException if an error occurs
     */
    private static void configureSSL(HttpClientBuilder httpClientBuilder, String protocolType)
            throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
        // sets SSL ONLY if the scheme is HTTPS
        if (HttpResourceKeys.HTTPS_PROTOCOL.equalsIgnoreCase(protocolType)) {
            SSLConnectionSocketFactory sf = buildSSLConnectionSocketFactory();
            httpClientBuilder.setSSLSocketFactory(sf);
        }
    }

    /**
     * It builds a {@link SSLConnectionSocketFactory} if SSL is needed.
     * 
     * @return the {@link SSLConnectionSocketFactory} for SSL purposes.
     * @throws KeyManagementException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @see SSLConnectionSocketFactory
     */
    private static SSLConnectionSocketFactory buildSSLConnectionSocketFactory()
            throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
        TrustStrategy ts = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // always true to avoid certificate unknown exception
                return true;
            }
        };
        SSLContextBuilder builder = SSLContexts.custom();
        builder.loadTrustMaterial(null, ts);
        SSLContext sslContext = builder.build();
        return new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    }
}