org.hawk.http.HTTPManager.java Source code

Java tutorial

Introduction

Here is the source code for org.hawk.http.HTTPManager.java

Source

/*******************************************************************************
 * Copyright (c) 2011-2015 The 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
 ******************************************************************************/
package org.hawk.http;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Set;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.DateUtils;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.hawk.core.IConsole;
import org.hawk.core.ICredentialsStore;
import org.hawk.core.ICredentialsStore.Credentials;
import org.hawk.core.IModelIndexer;
import org.hawk.core.IVcsManager;
import org.hawk.core.VcsChangeType;
import org.hawk.core.VcsCommit;
import org.hawk.core.VcsCommitItem;
import org.hawk.core.VcsRepositoryDelta;

@SuppressWarnings("restriction")
public class HTTPManager implements IVcsManager {

    private static final String HEADER_CONTENT_LENGTH = "Content-Length";
    private static final String HEADER_LAST_MODIFIED = "Last-Modified";
    private static final String HEADER_NONE_MATCH = "If-None-Match";
    private static final String HEADER_ETAG = "ETag";
    private static final String FIRST_REV = "0";

    private boolean isActive;
    private IConsole console;
    private URI repositoryURL;

    private String username;
    private String password;
    private String lastETag;

    private String lastDelta;
    private IModelIndexer indexer;
    private boolean isFrozen = false;

    @Override
    public String getCurrentRevision() throws Exception {
        try (final CloseableHttpClient cl = createClient()) {
            /*
             * Since HTTP servers can be quite varied, we try several methods in
             * sequence:
             *
             * - ETag headers are preferred, since these explicitly check for
             * changes. - Otherwise, Last-Modified dates are used. - Otherwise,
             * Content-Length is used.
             *
             * We try first a HEAD request, and if that doesn't work a GET
             * request.
             */

            final HttpHead headRequest = new HttpHead(repositoryURL);
            decorateCurrentRevisionRequest(headRequest);
            try (CloseableHttpResponse response = cl.execute(headRequest)) {
                String headRevision = getRevision(response);
                if (headRevision != null) {
                    return headRevision;
                }
            }

            final HttpGet getRequest = new HttpGet(repositoryURL);
            decorateCurrentRevisionRequest(getRequest);
            try (CloseableHttpResponse response = cl.execute(getRequest)) {
                String getRev = getRevision(response);
                if (getRev != null) {
                    return getRev;
                }
            }
        }

        // No way to detect changes - just fetch the file once
        return "1";
    }

    protected void decorateCurrentRevisionRequest(final HttpRequestBase request) {
        if (lastETag != null) {
            request.setHeader(HEADER_ETAG, lastETag);
            request.setHeader(HEADER_NONE_MATCH, "*");
        }
    }

    protected String getRevision(CloseableHttpResponse response) {
        if (response.getStatusLine().getStatusCode() == 304) {
            // Not-Modified, as told by the server
            return lastETag;
        } else if (response.getStatusLine().getStatusCode() != 200) {
            // Request failed for some reason (4xx, 5xx: we already
            // handle 3xx redirects)
            return FIRST_REV;
        }

        final Header etagHeader = response.getFirstHeader(HEADER_ETAG);
        if (etagHeader != null) {
            lastETag = etagHeader.getValue();
            return lastETag;
        }

        final Header lmHeader = response.getFirstHeader(HEADER_LAST_MODIFIED);
        if (lmHeader != null) {
            final Date lmDate = DateUtils.parseDate(lmHeader.getValue());
            return lmDate.getTime() + "";
        }

        final Header clHeader = response.getFirstHeader(HEADER_CONTENT_LENGTH);
        if (clHeader != null) {
            return clHeader.getValue();
        }

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            final long cLength = entity.getContentLength();
            if (cLength >= 0) {
                return cLength + "";
            }
        }

        return null;
    }

    private CloseableHttpClient createClient() {
        final HttpClientBuilder builder = HttpClientBuilder.create();

        // Provide username and password if specified
        if (username != null) {
            final BasicCredentialsProvider credProvider = new BasicCredentialsProvider();
            credProvider.setCredentials(new AuthScope(new HttpHost(repositoryURL.getHost())),
                    new UsernamePasswordCredentials(username, password));
            builder.setDefaultCredentialsProvider(credProvider);
        }

        // Follow redirects
        builder.setRedirectStrategy(new LaxRedirectStrategy());

        return builder.build();
    }

    @Override
    public String getFirstRevision() throws Exception {
        return FIRST_REV;
    }

    @Override
    public Collection<VcsCommitItem> getDelta(String endRevision) throws Exception {
        return getDelta(FIRST_REV, endRevision).getCompactedCommitItems();
    }

    @Override
    public VcsRepositoryDelta getDelta(String startRevision, String endRevision) throws Exception {
        VcsRepositoryDelta delta = new VcsRepositoryDelta();
        delta.setManager(this);
        if (lastDelta == null || !lastDelta.equals(endRevision)) {
            VcsCommit c = new VcsCommit();
            c.setAuthor("Unknown");
            c.setJavaDate(new Date());
            c.setMessage("HTTP file changed: " + repositoryURL);
            c.setRevision(endRevision);
            c.setDelta(delta);
            delta.getCommits().add(c);

            VcsCommitItem ci = new VcsCommitItem();
            ci.setChangeType(VcsChangeType.UPDATED);
            ci.setPath(repositoryURL.getPath());
            ci.setCommit(c);
            c.getItems().add(ci);
        }
        delta.setLatestRevision(getCurrentRevision());

        return delta;
    }

    @Override
    public File importFiles(String path, File temp) {
        try (CloseableHttpClient cl = createClient()) {
            try (CloseableHttpResponse response = cl.execute(new HttpGet(repositoryURL))) {
                Files.copy(response.getEntity().getContent(), temp.toPath());
                return temp;
            }
        } catch (IOException e) {
            console.printerrln(e);
            return null;
        }
    }

    @Override
    public boolean isActive() {
        return isActive;
    }

    @Override
    public void init(String vcsloc, IModelIndexer indexer) throws URISyntaxException {
        console = indexer.getConsole();
        this.repositoryURL = new URI(vcsloc);
        this.indexer = indexer;
    }

    @Override
    public void run() throws Exception {
        try {
            final ICredentialsStore credStore = indexer.getCredentialsStore();
            if (username != null) {
                // The credentials were provided by a previous setCredentials
                // call: retry the change to the credentials store.
                setCredentials(username, password, credStore);
            } else {
                final Credentials credentials = credStore.get(repositoryURL.toString());
                if (credentials != null) {
                    this.username = credentials.getUsername();
                    this.password = credentials.getPassword();
                } else {
                    /*
                     * If we use null for the default username/password, SVNKit
                     * will try to use the GNOME keyring in Linux, and that will
                     * lock up our Eclipse instance in some cases.
                     */
                    console.printerrln("No username/password recorded for the repository " + repositoryURL);
                    this.username = "";
                    this.password = "";
                }
            }

            isActive = true;
        } catch (Exception e) {
            console.printerrln("exception in svnmanager run():");
            console.printerrln(e);
        }
    }

    @Override
    public void shutdown() {
        repositoryURL = null;
        console = null;
    }

    @Override
    public String getLocation() {
        return repositoryURL.toString();
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public void setCredentials(String username, String password, ICredentialsStore credStore) {
        if (username != null && password != null && repositoryURL != null
                && (!username.equals(this.username) || !password.equals(this.password))) {
            try {
                credStore.put(repositoryURL.toString(), new Credentials(username, password));
            } catch (Exception e) {
                console.printerrln("Could not save new username/password");
                console.printerrln(e);
            }
        }
        this.username = username;
        this.password = password;
    }

    @Override
    public String getType() {
        return getClass().getName();
    }

    @Override
    public String getHumanReadableName() {
        return "HTTP Monitor";
    }

    @Override
    public boolean isAuthSupported() {
        return true;
    }

    @Override
    public boolean isPathLocationAccepted() {
        return false;
    }

    @Override
    public boolean isURLLocationAccepted() {
        return true;
    }

    @Override
    public Set<String> getPrefixesToBeStripped() {
        return Collections.emptySet();
    }

    @Override
    public boolean isFrozen() {
        return isFrozen;
    }

    @Override
    public void setFrozen(boolean f) {
        isFrozen = f;
    }
}