org.nuxeo.connect.connector.http.ConnectHttpConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.connect.connector.http.ConnectHttpConnector.java

Source

/*
 * (C) Copyright 2006-2017 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Nuxeo - initial API and implementation
 *     Yannis JULIENNE
 *
 */

package org.nuxeo.connect.connector.http;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.nuxeo.connect.NuxeoConnectClient;
import org.nuxeo.connect.connector.AbstractConnectConnector;
import org.nuxeo.connect.connector.CanNotReachConnectServer;
import org.nuxeo.connect.connector.ConnectClientVersionMismatchError;
import org.nuxeo.connect.connector.ConnectConnector;
import org.nuxeo.connect.connector.ConnectSecurityError;
import org.nuxeo.connect.connector.ConnectServerError;
import org.nuxeo.connect.connector.ConnectServerResponse;
import org.nuxeo.connect.data.SubscriptionStatus;

/**
 * Real HTTP based {@link ConnectConnector} implementation. Manages communication with the Nuxeo Connect Server via
 * JAX-RS
 *
 * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a>
 */
public class ConnectHttpConnector extends AbstractConnectConnector {

    public String overrideUrl = null;

    protected SubscriptionStatus cachedStatus = null;

    protected boolean connectServerNotReachable;

    public static final String CONNECT_HTTP_CACHE_MINUTES_PROPERTY = "org.nuxeo.connect.http.cache.duration";

    public static final String CONNECT_HTTP_TIMEOUT = "org.nuxeo.connect.http.timeout";

    protected int connectHttpTimeout = Integer
            .parseInt(NuxeoConnectClient.getProperty(CONNECT_HTTP_TIMEOUT, "10000"));

    protected long lastStatusFetchTime;

    @Override
    protected String getBaseUrl() {
        if (overrideUrl != null) {
            return overrideUrl;
        }
        return super.getBaseUrl();
    }

    @Override
    protected ConnectServerResponse execServerCall(String url, Map<String, String> headers)
            throws ConnectServerError {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        ProxyHelper.configureProxyIfNeeded(httpClientBuilder, url);
        httpClientBuilder.setConnectionTimeToLive(connectHttpTimeout, TimeUnit.MILLISECONDS);
        HttpGet method = new HttpGet(url);

        for (String name : headers.keySet()) {
            method.addHeader(name, headers.get(name));
        }

        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        try {
            // We do not use autoclose on the httpClient nor on the httpResponse since we may return them yet
            // not consumed in the ConnectHttpResponse
            httpClient = httpClientBuilder.build();
            httpResponse = httpClient.execute(method);
            int rc = httpResponse.getStatusLine().getStatusCode();
            switch (rc) {
            case HttpStatus.SC_OK:
            case HttpStatus.SC_NO_CONTENT:
            case HttpStatus.SC_NOT_FOUND:
                return new ConnectHttpResponse(httpClient, httpResponse);
            case HttpStatus.SC_UNAUTHORIZED:
                httpResponse.close();
                httpClient.close();
                throw new ConnectSecurityError("Connect server refused authentication (returned 401)");
            case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
                httpResponse.close();
                httpClient.close();
                throw new ConnectSecurityError("Proxy server require authentication (returned 407)");
            case HttpStatus.SC_GATEWAY_TIMEOUT:
            case HttpStatus.SC_REQUEST_TIMEOUT:
                httpResponse.close();
                httpClient.close();
                throw new ConnectServerError("Timeout " + rc);
            default:
                try {
                    String body = EntityUtils.toString(httpResponse.getEntity());
                    JSONObject obj = new JSONObject(body);
                    String message = obj.getString("message");
                    String errorClass = obj.getString("errorClass");
                    ConnectServerError error;
                    if (ConnectSecurityError.class.getSimpleName().equals(errorClass)) {
                        error = new ConnectSecurityError(message);
                    } else if (ConnectClientVersionMismatchError.class.getSimpleName().equals(errorClass)) {
                        error = new ConnectClientVersionMismatchError(message);
                    } else {
                        error = new ConnectServerError(message);
                    }
                    throw error;
                } catch (JSONException e) {
                    log.debug("Can't parse server error " + rc, e);
                    throw new ConnectServerError("Server returned a code " + rc);
                } finally {
                    httpResponse.close();
                    httpClient.close();
                }
            }
        } catch (ConnectServerError cse) {
            throw cse;
        } catch (IOException e) {
            IOUtils.closeQuietly(httpResponse);
            IOUtils.closeQuietly(httpClient);
            throw new ConnectServerError("Error during communication with the Nuxeo Connect Server", e);
        }
    }

    protected int httpCacheDurationInMinutes() {
        String cacheInMinutes = NuxeoConnectClient.getProperty(CONNECT_HTTP_CACHE_MINUTES_PROPERTY, "0");
        try {
            return Integer.parseInt(cacheInMinutes);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    protected boolean useHttpCache() {
        return httpCacheDurationInMinutes() > 0;
    }

    @Override
    public SubscriptionStatus getConnectStatus() throws ConnectServerError {
        if (!isConnectServerReachable()) {
            throw new CanNotReachConnectServer("Connect server set as not reachable");
        }

        if (useHttpCache() && cachedStatus != null) {
            if ((System.currentTimeMillis() - lastStatusFetchTime) < httpCacheDurationInMinutes() * 60 * 1000) {
                return cachedStatus;
            }
        }

        try {
            SubscriptionStatus status = super.getConnectStatus();
            if (!NuxeoConnectClient.isTestModeSet() && useHttpCache()) {
                // no cache for testing
                cachedStatus = status;
            }
            lastStatusFetchTime = System.currentTimeMillis();
            return status;
        } catch (CanNotReachConnectServer e) {
            if (cachedStatus != null) {
                return cachedStatus;
            } else {
                throw e;
            }
        }
    }

}