de.pdark.dsmp.ProxyDownload.java Source code

Java tutorial

Introduction

Here is the source code for de.pdark.dsmp.ProxyDownload.java

Source

/*
 * Copyright 2002-2005 The Apache Software Foundation.
 * 
 * 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.
 */
package de.pdark.dsmp;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;

/**
 * Download a file via a proxy server and store it somewhere.
 * 
 * @author digulla
 *
 */
public class ProxyDownload {
    public static final Logger log = Logger.getLogger(ProxyDownload.class);
    private final URL url;
    private final File dest;
    private final Config config;

    /**
     * Download <code>url</code> to <code>dest</code>.
     * 
     * <p>If the directory to store <code>dest</code> doesn't exist,
     * it will be created.
     * 
     * @param url The resource to download
     * @param dest Where to store it.
     */
    public ProxyDownload(URL url, File dest, Config config) {
        this.url = url;
        this.dest = dest;
        this.config = config;
    }

    /**
     * Create the neccessary paths to store the destination file.
     * 
     * @throws IOException
     */
    public void mkdirs() throws IOException {
        File parent = dest.getParentFile();
        IOUtils.mkdirs(parent);
    }

    /**
     * Do the download.
     * 
     * @throws IOException
     * @throws DownloadFailed
     */
    public void download() throws IOException, DownloadFailed {
        if (!config.isAllowed(url)) {
            throw new DownloadFailed(
                    "HTTP/1.1 " + HttpStatus.SC_FORBIDDEN + " Download denied by rule in DSMP config");
        }

        // If there is a status file in the cache, return it instead of trying it again
        // As usual with caches, this one is a key area which will always cause
        // trouble.
        // TODO There should be a simple way to get rid of the cached statuses
        // TODO Maybe retry a download after a certain time?
        File statusFile = new File(dest.getAbsolutePath() + ".status");
        if (statusFile.exists()) {
            try {
                FileReader r = new FileReader(statusFile);
                char[] buffer = new char[(int) statusFile.length()];
                int len = r.read(buffer);
                r.close();
                String status = new String(buffer, 0, len);
                throw new DownloadFailed(status);
            } catch (IOException e) {
                log.warn("Error writing 'File not found'-Status to " + statusFile.getAbsolutePath(), e);
            }
        }

        mkdirs();

        HttpClient client = new HttpClient();

        String msg = "";
        if (config.useProxy(url)) {
            Credentials defaultcreds = new UsernamePasswordCredentials(config.getProxyUsername(),
                    config.getProxyPassword());
            AuthScope scope = new AuthScope(config.getProxyHost(), config.getProxyPort(), AuthScope.ANY_REALM);
            HostConfiguration hc = new HostConfiguration();
            hc.setProxy(config.getProxyHost(), config.getProxyPort());
            client.setHostConfiguration(hc);
            client.getState().setProxyCredentials(scope, defaultcreds);
            msg = "via proxy ";
        }
        log.info("Downloading " + msg + "to " + dest.getAbsolutePath());

        GetMethod get = new GetMethod(url.toString());
        get.setFollowRedirects(true);
        try {
            int status = client.executeMethod(get);

            log.info("Download status: " + status);
            if (0 == 1 && log.isDebugEnabled()) {
                Header[] header = get.getResponseHeaders();
                for (Header aHeader : header)
                    log.debug(aHeader.toString().trim());
            }

            log.info("Content: " + valueOf(get.getResponseHeader("Content-Length")) + " bytes; "
                    + valueOf(get.getResponseHeader("Content-Type")));

            if (status != HttpStatus.SC_OK) {
                // Remember "File not found"
                if (status == HttpStatus.SC_NOT_FOUND) {
                    try {
                        FileWriter w = new FileWriter(statusFile);
                        w.write(get.getStatusLine().toString());
                        w.close();
                    } catch (IOException e) {
                        log.warn("Error writing 'File not found'-Status to " + statusFile.getAbsolutePath(), e);
                    }
                }
                throw new DownloadFailed(get);
            }

            File dl = new File(dest.getAbsolutePath() + ".new");
            OutputStream out = new BufferedOutputStream(new FileOutputStream(dl));
            IOUtils.copy(get.getResponseBodyAsStream(), out);
            out.close();

            File bak = new File(dest.getAbsolutePath() + ".bak");
            if (bak.exists())
                bak.delete();
            if (dest.exists())
                dest.renameTo(bak);
            dl.renameTo(dest);
        } finally {
            get.releaseConnection();
        }
    }

    private String valueOf(Header responseHeader) {
        return responseHeader == null ? "unknown" : responseHeader.getValue();
    }
}