/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* Copyright (C) 2011 jweintraut
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.cismet.tools.gui.downloadmanager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import javax.swing.JPanel;
import de.cismet.commons.security.AccessHandler.ACCESS_METHODS;
import de.cismet.commons.security.exceptions.BadHttpStatusCodeException;
import de.cismet.security.WebAccessManager;
import de.cismet.security.exceptions.AccessMethodIsNotSupportedException;
import de.cismet.security.exceptions.MissingArgumentException;
import de.cismet.security.exceptions.NoHandlerForURLException;
import de.cismet.security.exceptions.RequestFailedException;
/**
* The objects of this class represent a HTTP download. The objects of this class are observed by the download manager.
*
* @author jweintraut
* @version $Revision$, $Date$
*/
public class HttpDownload extends AbstractCancellableDownload {
//~ Static fields/initializers ---------------------------------------------
private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(HttpDownload.class);
private static final int MAX_BUFFER_SIZE = 1024;
//~ Instance fields --------------------------------------------------------
private URL url;
private String request;
private HashMap<String, String> headers;
//~ Constructors -----------------------------------------------------------
/**
* StandardConstructor defined for usage by subclasse like the ButlerDownload. If used it must be garuanteed that
* the fields are set correctly before the Download starts running.
*/
public HttpDownload() {
}
/**
* Constructor for Download.
*
* @param url The URL of the server to download from.
* @param request The request to send.
* @param directory Specifies in which directory to save the file. This should be specified relative to the
* general download directory.
* @param title The title of the download.
* @param filename A String containing the filename.
* @param extension A String containing the file extension.
*/
public HttpDownload(final URL url,
final String request,
final String directory,
final String title,
final String filename,
final String extension) {
this(url, request, new HashMap<String, String>(), directory, title, filename, extension);
}
/**
* Constructor for Download.
*
* @param url The URL of the server to download from.
* @param request The request to send.
* @param headers A map containing key/value String pairs which are used as request headers.
* @param directory Specifies in which directory to save the file. This should be specified relative to the
* general download directory.
* @param title The title of the download.
* @param filename A String containing the filename.
* @param extension A String containing the file extension.
*/
public HttpDownload(final URL url,
final String request,
final HashMap<String, String> headers,
final String directory,
final String title,
String filename,
final String extension) {
this.url = url;
this.request = request;
this.directory = directory;
this.title = title;
this.headers = headers;
status = State.WAITING;
if (url != null) {
LOG.info("inited HttpDownload on: " + url.toString()
+ "<br>and request=" + request
+ "<br>and title=" + title
+ "<br>and filename=" + filename
+ "<br>and extension=" + extension
+ "<br>with these headers:" + headers);
}
try {
filename = URLDecoder.decode(filename, "utf8");
} catch (UnsupportedEncodingException ex) {
LOG.error(ex, ex);
}
determineDestinationFile(filename, extension);
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @param src DOCUMENT ME!
* @param dest DOCUMENT ME!
*
* @throws IOException DOCUMENT ME!
*/
protected void downloadStream(final InputStream src, final OutputStream dest) throws IOException {
boolean downloading = true;
while (downloading) {
if (Thread.interrupted()) {
log.info("Download was interuppted");
dest.close();
src.close();
deleteFile();
return;
}
// Size buffer according to how much of the file is left to download.
final byte[] buffer;
buffer = new byte[MAX_BUFFER_SIZE];
// Read from server into buffer.
final int read = src.read(buffer);
if (read == -1) {
downloading = false;
} else {
// Write buffer to file.
dest.write(buffer, 0, read);
}
}
}
/**
* DOCUMENT ME!
*
* @param url DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws URISyntaxException DOCUMENT ME!
* @throws FileNotFoundException DOCUMENT ME!
* @throws AccessMethodIsNotSupportedException DOCUMENT ME!
* @throws RequestFailedException DOCUMENT ME!
* @throws NoHandlerForURLException DOCUMENT ME!
* @throws Exception DOCUMENT ME!
*/
protected InputStream getUrlInputStreamWithWebAcessManager(final URL url) throws URISyntaxException,
FileNotFoundException,
AccessMethodIsNotSupportedException,
RequestFailedException,
NoHandlerForURLException,
Exception {
InputStream resp = null;
if ("file".equals(url.getProtocol())) {
resp = new FileInputStream(new File(url.toURI()));
} else {
if (log.isDebugEnabled()) {
log.debug("Sending request \n" + request + "\n to '" + url.toExternalForm() + "'.");
}
if ((request == null) || (request.trim().length() <= 0)) {
resp = WebAccessManager.getInstance().doRequest(url);
} else {
resp = WebAccessManager.getInstance()
.doRequest(
url,
new StringReader(request),
ACCESS_METHODS.POST_REQUEST,
headers);
}
}
return resp;
}
/**
* DOCUMENT ME!
*/
protected void downloadStream() {
FileOutputStream out = null;
InputStream resp = null;
try {
resp = getUrlInputStreamWithWebAcessManager(url);
if (Thread.interrupted()) {
log.info("Download was interuppted");
deleteFile();
return;
}
out = new FileOutputStream(fileToSaveTo);
downloadStream(resp, out);
} catch (MissingArgumentException ex) {
error(ex);
} catch (AccessMethodIsNotSupportedException ex) {
error(ex);
} catch (RequestFailedException ex) {
error(ex);
} catch (NoHandlerForURLException ex) {
error(ex);
} catch (Exception ex) {
error(ex);
} finally {
// Close file.
if (out != null) {
try {
out.close();
} catch (Exception e) {
log.warn("Exception occured while closing file.", e);
}
}
// Close connection to server.
if (resp != null) {
try {
resp.close();
} catch (Exception e) {
log.warn("Exception occured while closing response stream.", e);
}
}
}
}
@Override
public void run() {
if (status != State.WAITING) {
return;
}
status = State.RUNNING;
stateChanged();
downloadStream();
if (status == State.RUNNING) {
status = State.COMPLETED;
stateChanged();
}
}
@Override
public JPanel getExceptionPanel(final Exception exception) {
if (exception instanceof BadHttpStatusCodeException) {
return new BadHttpStatusCodeExceptionPanel((BadHttpStatusCodeException)exception);
}
return super.getExceptionPanel(exception);
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof HttpDownload)) {
return false;
}
final HttpDownload other = (HttpDownload)obj;
boolean result = true;
if ((this.url != other.url) && ((this.url == null) || !this.url.equals(other.url))) {
result &= false;
}
if ((this.request == null) ? (other.request != null) : (!this.request.equals(other.request))) {
result &= false;
}
if ((this.fileToSaveTo == null) ? (other.fileToSaveTo != null)
: (!this.fileToSaveTo.equals(other.fileToSaveTo))) {
result &= false;
}
return result;
}
@Override
public int hashCode() {
int hash = 7;
hash = (43 * hash) + ((this.url != null) ? this.url.hashCode() : 0);
hash = (43 * hash) + ((this.request != null) ? this.request.hashCode() : 0);
hash = (43 * hash) + ((this.fileToSaveTo != null) ? this.fileToSaveTo.hashCode() : 0);
return hash;
}
/**
* DOCUMENT ME!
*/
private void deleteFile() {
if (fileToSaveTo.exists() && fileToSaveTo.isFile()) {
fileToSaveTo.delete();
}
}
}