de.ecclesia.kipeto.RepositoryResolver.java Source code

Java tutorial

Introduction

Here is the source code for de.ecclesia.kipeto.RepositoryResolver.java

Source

/*
 * #%L
 * Kipeto
 * %%
 * Copyright (C) 2010 - 2011 Ecclesia Versicherungsdienst GmbH
 * %%
 * 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.
 * #L%
 */
package de.ecclesia.kipeto;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.FileSystemOptions;
import org.apache.commons.vfs.VFS;
import org.apache.commons.vfs.provider.sftp.SftpFileSystemConfigBuilder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ecclesia.kipeto.common.util.Assert;

public class RepositoryResolver {

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

    /** Name des Distribution-Verzeichnisses im Repository */
    private static final String DIST_DIR = "dist";

    private static final String RESOLVE_CONFIG_FILE = "repos_resolve.properties";

    private final String defaultRepositoryUrl;
    private File keyFile;

    public RepositoryResolver(String defaultRepositoryUrl) {
        this.defaultRepositoryUrl = defaultRepositoryUrl;
    }

    /**
     * Versucht, im bergebenen Repository die Konfigurations-Datei zu finden
     * und daraus ein passendes Repository abzuleiten. Schlgt dies fehlt oder
     * tritt ein Fehler auf, wird dieser Fehler gelogt, und das bergebene
     * Repository zurckgegeben.
     * 
     * @return
     * @throws IOException
     */
    public String resolveReposUrl() throws IOException {
        try {
            URL url;
            FileName filename;
            FileSystemManager fsm = VFS.getManager();
            filename = fsm.resolveURI(defaultRepositoryUrl);

            if (!filename.getScheme().equalsIgnoreCase("http") && !filename.getScheme().equalsIgnoreCase("sftp")) {
                log.info("Resolving repository-config not implemented for protocol {} yet", filename.getScheme());
                return defaultRepositoryUrl;
            }

            Properties config = loadVfsConfig();

            if (config == null) {
                return defaultRepositoryUrl;
            }

            String localIp = determinateLocalIP();

            return resolveRepos(localIp, config);
        } catch (Exception e) {
            log.error(e.getMessage(), e);

            return defaultRepositoryUrl;
        }
    }

    /**
     * Ermittelt anhand der Default-Repository-URL die IP-Adresse der
     * Netzwerkkarte, die Verbindung zum Repository hat.
     */
    private String determinateLocalIP() throws IOException {
        Socket socket = null;

        try {

            int port;
            String hostname;

            if (isSftp()) {
                port = 22;
                hostname = getHostname();
            } else {
                URL url = new URL(defaultRepositoryUrl);
                port = url.getPort() > -1 ? url.getPort() : url.getDefaultPort();
                hostname = url.getHost();
            }

            log.debug("Determinating local IP-Adress by connect to {}:{}", defaultRepositoryUrl, port);
            InetAddress address = Inet4Address.getByName(hostname);

            socket = new Socket();
            socket.connect(new InetSocketAddress(address, port), 3000);
            InputStream stream = socket.getInputStream();
            InetAddress localAddress = socket.getLocalAddress();
            stream.close();

            String localIp = localAddress.getHostAddress();

            log.info("Local IP-Adress is {}", localIp);

            return localIp;
        } finally {
            if (socket != null) {
                socket.close();
            }
        }
    }

    /**
     * Ld die Config vom Default-Repository herunter.
     */
    private Properties loadVfsConfig() throws IOException {
        String configUrl = String.format("%s/%s/%s", defaultRepositoryUrl, DIST_DIR, RESOLVE_CONFIG_FILE);
        log.info("Looking for repository-config at {}", configUrl);
        Properties properties = new Properties();
        FileSystemOptions fso = new FileSystemOptions();
        if (isSftp()) {
            Assert.isTrue(this.keyFile.isFile(), "Keyfile is not a file");
            File[] files = { this.keyFile };
            SftpFileSystemConfigBuilder.getInstance().setIdentities(fso, files);
            SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fso, "yes");
        }

        FileObject fo;
        try {
            fo = VFS.getManager().resolveFile(configUrl, fso);

            BufferedInputStream inputStream = new BufferedInputStream(fo.getContent().getInputStream());

            properties.load(inputStream);
        } catch (FileSystemException e) {
            log.info("No repository-config found at {}", configUrl);
            throw new RuntimeException(e);
        }

        return properties;
    }

    /**
     * Ermittelt anhand der lokalen IP-Adresse und der bergebenen
     * Konfiguration, welches Repository fr den Update-Vorgang verwendet werden
     * soll.
     */
    private String resolveRepos(String localIp, Properties config) {
        for (Object key : config.keySet()) {
            String ipPraefix = (String) key;
            String repos = config.getProperty(ipPraefix);

            if (localIp.startsWith(ipPraefix)) {
                log.info("Local IP " + localIp + " starts with '{}', selecting [{}]", ipPraefix, repos);
                return repos;
            } else {
                log.debug("Local IP " + localIp + " does not start with '{}' --> {}", ipPraefix, repos);
            }
        }

        log.warn("No matching config-entry found for {}, falling back to default-repository {}", localIp,
                defaultRepositoryUrl);

        return defaultRepositoryUrl;
    }

    public void setKeyFile(File keyFile) {
        this.keyFile = keyFile;
    }

    private boolean isSftp() throws FileSystemException {
        if (VFS.getManager().resolveURI(defaultRepositoryUrl).getScheme().equals("sftp")) {
            return true;
        }
        return false;
    }

    private String getHostname() throws FileSystemException {
        String hostname = VFS.getManager().resolveURI(defaultRepositoryUrl).getRootURI().replaceAll("sftp://", "");
        if (hostname.contains("@")) {
            int idx = hostname.indexOf("@");
            hostname = hostname.substring(idx + 1, hostname.length());
        }

        if (hostname.endsWith("/")) {
            hostname = hostname.substring(0, hostname.length() - 1);
        }
        return hostname;
    }
}