org.geomajas.layer.common.proxy.LayerHttpServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.geomajas.layer.common.proxy.LayerHttpServiceImpl.java

Source

/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2013 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the GNU Affero
 * General Public License. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */

package org.geomajas.layer.common.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map.Entry;

import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.SystemDefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Implementation of {@link LayerHttpService}.
 *
 * @author Joachim Van der Auwera
 * @author Kristof Heirwegh
 */
@Component
public class LayerHttpServiceImpl implements LayerHttpService {

    private final Logger log = LoggerFactory.getLogger(LayerHttpServiceImpl.class);

    private static final String URL_PARAM_START = "?";
    private static final String URL_PARAM_SEPARATOR = "&";
    private static final String URL_PARAM_IS = "=";
    private static final String URL_PROTOCOL_SEPARATOR = "://";
    private static final int TIMEOUT = 5000;
    private static final int URL_DEFAULT_PORT = 80;
    private static final int URL_DEFAULT_SECURE_PORT = 443;

    @Autowired(required = false)
    private LayerHttpServiceInterceptors interceptors;

    public String addCredentialsToUrl(final String url, final LayerAuthentication authentication) {
        if (null != authentication
                && LayerAuthenticationMethod.URL.equals(authentication.getAuthenticationMethod())) {
            StringBuilder res = new StringBuilder(url);
            if (res.indexOf(URL_PARAM_START) >= 0) {
                res.append(URL_PARAM_SEPARATOR);
            } else {
                res.append(URL_PARAM_START);
            }
            res.append(authentication.getUserKey());
            res.append(URL_PARAM_IS);
            res.append(authentication.getUser());
            res.append(URL_PARAM_SEPARATOR);
            res.append(authentication.getPasswordKey());
            res.append(URL_PARAM_IS);
            res.append(authentication.getPassword());
            return res.toString();
        }
        return url;
    }

    public InputStream getStream(final String baseUrl, final LayerAuthentication authentication,
            final String layerId) throws IOException {
        // Create a HTTP client object, which will initiate the connection:
        final HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT);
        SystemDefaultHttpClient client = new SystemDefaultHttpClient(httpParams);

        String url = addCredentialsToUrl(baseUrl, authentication);

        // -- add basic authentication
        if (null != authentication
                && (LayerAuthenticationMethod.BASIC.equals(authentication.getAuthenticationMethod())
                        || LayerAuthenticationMethod.DIGEST.equals(authentication.getAuthenticationMethod()))) {
            // Set up the credentials:
            Credentials creds = new UsernamePasswordCredentials(authentication.getUser(),
                    authentication.getPassword());
            AuthScope scope = new AuthScope(parseDomain(url), parsePort(url), authentication.getRealm());
            client.getCredentialsProvider().setCredentials(scope, creds);
        }

        // -- add interceptors if any --
        addInterceptors(client, baseUrl, layerId);

        // Create the GET method with the correct URL:
        HttpGet get = new HttpGet(url);

        // Execute the GET:
        HttpResponse response = client.execute(get);
        log.debug("Response: {} - {}", response.getStatusLine().getStatusCode(),
                response.getStatusLine().getReasonPhrase());

        return new LayerHttpServiceStream(response, client);
    }

    /**
     * Check if there are interceptors & add to client if any.
     * 
     * @param client
     * @param baseUrl
     */
    private void addInterceptors(DefaultHttpClient client, String baseUrl, String layerId) {
        try {
            if (interceptors != null && baseUrl != null) {
                for (Entry<String, List<HttpRequestInterceptor>> entry : interceptors.getMap().entrySet()) {
                    String key = entry.getKey();
                    if ("".equals(key) || layerId.equals(key) || baseUrl.startsWith(key)) {
                        for (HttpRequestInterceptor inter : entry.getValue()) {
                            client.addRequestInterceptor(inter);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("Error adding interceptors: " + e.getMessage());
        }
    }

    /**
     * Get the domain out of a full URL.
     *
     * @param url base url
     * @return domain name
     */
    private String parseDomain(String url) {
        int index = url.indexOf(URL_PROTOCOL_SEPARATOR);
        String domain = url.substring(index + URL_PROTOCOL_SEPARATOR.length());
        domain = domain.substring(0, domain.indexOf('/'));
        int colonPos = domain.indexOf(':');
        if (colonPos >= 0) {
            domain = domain.substring(0, colonPos);
        }
        return domain;
    }

    /**
     * Get the port out of a full URL.
     * <p>
     * Note that we only take https & http into account if you are using a non-default port/protocol you will need to
     * add the port to your baseUrl.
     * 
     * @param url base url
     * @return domain name
     */
    private int parsePort(String url) {
        try {
            URL u = new URL(url);
            int defaultport = "https".equalsIgnoreCase(u.getProtocol()) ? URL_DEFAULT_SECURE_PORT
                    : URL_DEFAULT_PORT;
            return (u.getPort() == -1 ? defaultport : u.getPort());
        } catch (MalformedURLException e) {
            return URL_DEFAULT_SECURE_PORT;
        }
    }

    /**
     * Delegating input stream which also closes the HTTP connection when closing the stream.
     *
     * @author Joachim Van der Auwera
     */
    private static class LayerHttpServiceStream extends InputStream {

        private final HttpClient client;
        private final InputStream inputStream;

        public LayerHttpServiceStream(HttpResponse response, HttpClient client) throws IOException {
            super();
            this.client = client;
            this.inputStream = response.getEntity().getContent();
        }

        @Override
        public int read() throws IOException {
            return inputStream.read();
        }

        @Override
        public int read(byte[] bytes) throws IOException {
            return inputStream.read(bytes);
        }

        @Override
        public int read(byte[] bytes, int i, int i1) throws IOException {
            return inputStream.read(bytes, i, i1);
        }

        @Override
        public long skip(long l) throws IOException {
            return inputStream.skip(l);
        }

        @Override
        public int available() throws IOException {
            return inputStream.available();
        }

        @Override
        public void close() throws IOException {
            inputStream.close();
            client.getConnectionManager().shutdown(); // reuse would be better
        }

        @Override
        public void mark(int i) {
            inputStream.mark(i);
        }

        @Override
        public void reset() throws IOException {
            inputStream.reset();
        }

        @Override
        public boolean markSupported() {
            return inputStream.markSupported();
        }
    }
}