org.openiot.gsn.http.rest.RestRemoteWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.openiot.gsn.http.rest.RestRemoteWrapper.java

Source

/**
*    Copyright (c) 2011-2014, OpenIoT
*   
*    This file is part of OpenIoT.
*
*    OpenIoT is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Lesser General Public License as published by
*    the Free Software Foundation, version 3 of the License.
*
*    OpenIoT 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 Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public License
*    along with OpenIoT.  If not, see <http://www.gnu.org/licenses/>.
*
*     Contact: OpenIoT mailto: info@openiot.eu
 * @author Ali Salehi
 * @author Mehdi Riahi
 * @author Timotee Maret
*/

package org.openiot.gsn.http.rest;

import org.openiot.gsn.Main;
import org.openiot.gsn.beans.ContainerConfig;
import org.openiot.gsn.beans.DataField;
import org.openiot.gsn.beans.StreamElement;
import org.openiot.gsn.wrappers.AbstractWrapper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.security.KeyStore;
import java.sql.SQLException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.log4j.Logger;

import com.thoughtworks.xstream.XStream;

public class RestRemoteWrapper extends AbstractWrapper {

    private final XStream XSTREAM = StreamElement4Rest.getXstream();

    private final transient Logger logger = Logger.getLogger(RestRemoteWrapper.class);

    private DataField[] structure = null;

    private DefaultHttpClient httpclient;

    private long lastReceivedTimestamp = -1;

    private ObjectInputStream inputStream;

    private HttpResponse response;

    private HttpParams getHttpClientParams(int timeout) {
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);
        HttpConnectionParams.setTcpNoDelay(params, false);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
        HttpConnectionParams.setStaleCheckingEnabled(params, true);
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000); // Set the connection time to 30s
        HttpConnectionParams.setSoTimeout(params, timeout);
        HttpProtocolParams.setUserAgent(params, "GSN-HTTP-CLIENT");
        return params;
    }

    public DataField[] getOutputFormat() {
        return structure;
    }

    private RemoteWrapperParamParser initParams;

    public String getWrapperName() {
        return "Rest Remote Wrapper";
    }

    public boolean initialize() {
        try {
            initParams = new RemoteWrapperParamParser(getActiveAddressBean(), false);
            httpclient = new DefaultHttpClient(getHttpClientParams(initParams.getTimeout()));
            // Init the http client
            if (initParams.isSSLRequired()) {
                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(new FileInputStream(new File("conf/servertestkeystore")),
                        Main.getContainerConfig().getSSLKeyStorePassword().toCharArray());
                SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
                socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                int sslPort = Main.getContainerConfig().getSSLPort() > 0 ? Main.getContainerConfig().getSSLPort()
                        : ContainerConfig.DEFAULT_SSL_PORT;
                Scheme sch = new Scheme("https", socketFactory, sslPort);
                httpclient.getConnectionManager().getSchemeRegistry().register(sch);
            }
            Scheme plainsch = new Scheme("http", PlainSocketFactory.getSocketFactory(),
                    Main.getContainerConfig().getContainerPort());
            httpclient.getConnectionManager().getSchemeRegistry().register(plainsch);
            //
            lastReceivedTimestamp = initParams.getStartTime();
            structure = connectToRemote();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
        return true;
    }

    public DataField[] connectToRemote() throws IOException, ClassNotFoundException {
        // Create the GET request
        HttpGet httpget = new HttpGet(initParams.getRemoteContactPointEncoded(lastReceivedTimestamp));
        // Create local execution context
        HttpContext localContext = new BasicHttpContext();
        //
        structure = null;
        int tries = 0;
        AuthState authState = null;
        //
        if (inputStream != null) {
            try {
                if (response != null && response.getEntity() != null) {
                    response.getEntity().consumeContent();
                }
                inputStream.close();
                inputStream = null;
            } catch (Exception e) {
                logger.debug(e.getMessage(), e);
            }
        }
        //
        while (tries < 2) {
            tries++;
            try {
                // Execute the GET request
                response = httpclient.execute(httpget, localContext);
                //
                int sc = response.getStatusLine().getStatusCode();
                //
                if (sc == HttpStatus.SC_OK) {
                    logger.debug(new StringBuilder().append("Wants to consume the structure packet from ")
                            .append(initParams.getRemoteContactPoint()));
                    inputStream = XSTREAM.createObjectInputStream(response.getEntity().getContent());
                    structure = (DataField[]) inputStream.readObject();
                    logger.warn("Connection established for: " + initParams.getRemoteContactPoint());
                    break;
                } else {
                    if (sc == HttpStatus.SC_UNAUTHORIZED)
                        authState = (AuthState) localContext.getAttribute(ClientContext.TARGET_AUTH_STATE); // Target host authentication required
                    else if (sc == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED)
                        authState = (AuthState) localContext.getAttribute(ClientContext.PROXY_AUTH_STATE); // Proxy authentication required
                    else {
                        logger.error(new StringBuilder().append("Unexpected GET status code returned: ").append(sc)
                                .append("\nreason: ").append(response.getStatusLine().getReasonPhrase()));
                    }
                    if (authState != null) {
                        if (initParams.getUsername() == null || (tries > 1 && initParams.getUsername() != null)) {
                            logger.error("A valid username/password required to connect to the remote host: "
                                    + initParams.getRemoteContactPoint());
                        } else {

                            AuthScope authScope = authState.getAuthScope();
                            logger.warn(new StringBuilder().append("Setting Credentials for host: ")
                                    .append(authScope.getHost()).append(":").append(authScope.getPort()));
                            Credentials creds = new UsernamePasswordCredentials(initParams.getUsername(),
                                    initParams.getPassword());
                            httpclient.getCredentialsProvider().setCredentials(authScope, creds);
                        }
                    }
                }
            } catch (RuntimeException ex) {
                // In case of an unexpected exception you may want to abort
                // the HTTP request in order to shut down the underlying
                // connection and release it back to the connection manager.
                logger.warn("Aborting the HTTP GET request.");
                httpget.abort();
                throw ex;
            } finally {
                if (structure == null) {
                    if (response != null && response.getEntity() != null) {
                        response.getEntity().consumeContent();
                    }
                }
            }
        }

        if (structure == null)
            throw new RuntimeException("Cannot connect to the remote host: " + initParams.getRemoteContactPoint());

        return structure;
    }

    public void dispose() {
        try {
            httpclient.getConnectionManager().shutdown(); //This closes the connection already in use by the response
        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
        }
    }

    public void run() {
        StreamElement4Rest se = null;
        while (isActive()) {
            try {
                while (isActive() && (se = (StreamElement4Rest) inputStream.readObject()) != null) {
                    StreamElement streamElement = se.toStreamElement();
                    if (!(streamElement.getFieldNames().length == 1
                            && streamElement.getFieldNames()[0].equals("keepalive"))) {
                        boolean status = manualDataInsertion(streamElement);
                        if (!status && inputStream != null) {
                            response.getEntity().consumeContent();
                            inputStream.close();
                            inputStream = null;
                        }
                    } else
                        logger.debug("Received a keep alive message.");
                }
            } catch (Exception e) {
                logger.warn("Connection to the remote host: " + initParams.getRemoteContactPoint()
                        + " is lost, trying to reconnect in 3 seconds...");
                try {
                    if (isActive()) {
                        Thread.sleep(3000);
                        connectToRemote();
                    }
                } catch (Exception err) {
                    logger.debug(err.getMessage(), err);
                }
            }
        }
    }

    public boolean manualDataInsertion(StreamElement se) {
        try {
            // If the stream element is out of order, we accept the stream element and wait for the next (update the last received time and return true)
            if (isOutOfOrder(se)) {
                lastReceivedTimestamp = se.getTimeStamp();
                return true;
            }
            // Otherwise, we first try to insert the stream element.
            // If the stream element was inserted succesfully, we wait for the next,
            // otherwise, we return false.
            boolean status = postStreamElement(se);
            if (status)
                lastReceivedTimestamp = se.getTimeStamp();
            return status;
        } catch (SQLException e) {
            logger.warn(e.getMessage(), e);
            return false;
        }
    }
}