/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package xplanetconfigurator.downloader;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import xplanetconfigurator.gui.LoggingBoard;
import xplanetconfigurator.util.TimeStamp;
import xplanetconfigurator.util.XPlanetRessourceFinder;
/**
*
* @author tom
*/
public class HttpDownloader {
private Logger logger;
public HttpDownloader() {
this.logger = Logger.getLogger(this.getClass().getName());
}
/**
*
* @param downloadFile
* @param isTestMode true if the user presses download button for single URL directly
* He wants to see more messages if something goes wrong.
*/
public void downloadFile(DownloadFile downloadFile, boolean isTestMode, DownloaderProxy proxy) {
String sUrl = downloadFile.getUrl();
this.logger.finer("Preparing to download the URL: " + sUrl);
if (sUrl == null) {
downloadFile.setDownloadStatus("<html>font color='green'>No URL selected</font></html>");
this.logger.fine("Nothing to download. URL not set.");
return;
}
URL url = null;
try {
url = new URL(sUrl);
} catch (MalformedURLException ex) {
this.logger.log(Level.SEVERE, null, ex);
downloadFile.setDownloadStatus("<html>font color='red'>Malformed URL</font></html>");
LoggingBoard.logDownloaderMessage("Malformed URL: '" + sUrl + "'. Exception: '" + ex.toString() + "'. Message of Exception is: '" + ex.getMessage() + "'.");
return;
}
String remoteFile = url.getFile();
this.logger.finer("Trying to find a file name in the URL: " + sUrl);
String[] splittees = remoteFile.split("/");
int length = splittees.length;
String filename = splittees[length - 1];
this.logger.finer("Found the file name: " + filename + " in the URL: " + sUrl);
String localDirectoryRelativ = downloadFile.getLocalDirectoryRelativ();
XPlanetRessourceFinder rf = new XPlanetRessourceFinder();
String downloaderRootDir = rf.getRootDirectoryForDownloads();
String localDirectoryAbsolute = downloaderRootDir + File.separator + localDirectoryRelativ;
File dir = new File(localDirectoryAbsolute);
if (!dir.exists()) {
this.logger.warning("Making a directory '" + localDirectoryAbsolute + "' to download because it does not exist...");
LoggingBoard.logDownloaderMessage("Making a directory '" + localDirectoryAbsolute + "' to download because it does not exist...");
boolean b = dir.mkdirs();
if (!b) {
this.logger.warning("Faild to make directory '" + dir + "' to download because it does not exist.");
LoggingBoard.logDownloaderMessage("Faild to make directory '" + dir + "' to download because it does not exist.");
}
}
// Define the local download file
String localFile = localDirectoryAbsolute + "/" + filename;
this.logger.finer("Trying to download the remote file '" + sUrl + "' to '" + localFile + "'...");
HttpURLConnection http = null;
long byteCount = 0;
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
// TODO: Error: Setting back the proxy does not work
// TODO: Test the proxy
// TODO: Test user authentication with proxy
// TODO: Implement setting back the proxy
// Check the proxy
String proxySet = proxy.getProxySet();
if (proxySet.equalsIgnoreCase("true")) {
Properties systemSettings = System.getProperties();
String proxyHost = proxy.getProxyHost();
String proxyPort = proxy.getProxyPort();
String proxyUser = proxy.getProxyUser();
String proxyPass = proxy.getProxyPass();
systemSettings.put("proxySet", "true");
systemSettings.put("http.proxyHost", proxyHost);
systemSettings.put("http.proxyPort", proxyPort);
// Solution 1) proxy user:pass
if (proxyUser != null && !proxyUser.equals("")) {
Authenticator.setDefault(new SimpleAuthenticator(proxyUser, proxyPass));
}
}
// else {
// // Set back in case the user is experimenting with the proxy
// // and does not restart the programm.
// Properties systemSettings = System.getProperties();
// systemSettings.put("proxySet", "false");
// }
// Open the connection
http = (HttpURLConnection) url.openConnection();
// Solution 2) proxy user:pass
// String proxyUser = proxy.getProxyUser();
// if (proxyUser != null && !proxyUser.equals("")) {
// String proxyPass = proxy.getProxyPass();
// sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
// // String userPwd = domain "\\" + proxyUser + "." + proxyPass;
// // What is domain?
// // In the example found in the web it was "mydomain" in "simple.mydomain.local"
// String userPwd = proxyUser + "." + proxyPass;
// String encodedUserPwd = encoder.encode(userPwd.getBytes());
// http.setRequestProperty("Proxy-Authorization", "Basic " + encodedUserPwd);
// }
// Set the request method
http.setRequestMethod("HEAD");
// Check if file does exist on the server
int responseCode = http.getResponseCode();
String responseMessage = http.getResponseMessage();
String longResponseMessage = responseCode + ", " + responseMessage;
if (responseCode == HttpURLConnection.HTTP_OK) {
this.logger.finer("File exists on server. URL: " + sUrl);
} else {
// File on server older than on local disc. Do not downlaod.
downloadFile.setDownloadStatus("<html><font color='red'>" + longResponseMessage + "</font></html>");
String message = "File not found on server or problems with proxy: '" + sUrl + "'. Server Response '" + longResponseMessage + "'.";
this.logger.info(message);
LoggingBoard.logDownloaderMessage(message);
return;
}
// Check last modified on server
long lastModifiedOnServer = http.getLastModified();
long lastModifiedOnDisk = downloadFile.getLastModified();
// The DownloadFile only gets to the downloader if it is out of
// date (on local disc) an needs to updated.
// Check wether the server has a newer date. The last modified time
// is allways set by the date on the server
String timeOnServer = TimeStamp.getFullTimstamp(new Date(lastModifiedOnServer));
String timeOnDisc = TimeStamp.getFullTimstamp(new Date(lastModifiedOnDisk));
if (lastModifiedOnServer > lastModifiedOnDisk) {
// Download
this.logger.finer("File on server is newer '" + timeOnServer + "' than on local disc '" + timeOnDisc + "'. Downloading url '" + sUrl + "'...");
} else if (lastModifiedOnServer == lastModifiedOnDisk) {
if (lastModifiedOnServer == 0) {
// Yes, this happened during testing. The server returned '0'.
// Example: http://laps.fsl.noaa.gov/albers/sos/saturn/rhea/rhea_rgb_cyl_www.jpg
// We can't decide if it was downloaded befor.
// What to do?
// It happened only for maps during testing. Maps are only
// downloaded by user interaction. So we are save to
// download it here.
this.logger.warning("The Server gave a lastModified() of '0'. It this happens for Maps it might be ok. Proceeding with download.");
LoggingBoard.logDownloaderMessage("WATCH THIS: Server responded with '0' for lastModified(). Proceed download of " + sUrl);
} else if (isTestMode) {
// Same date. The user presses a button. So download.
// It could by a map for example that has the same date time
// which is unlikly - but who knows.
// Report the user via the GUI. It might not be an error
// because the user tries and tries again.
// The status gets overwritten later after the download.
downloadFile.setDownloadStatus("<html><font color='green'>Download with same Date as on Server</font></html>");
this.logger.finer("File on server is as old '" + timeOnServer + "' as on local disc '" + timeOnDisc + "'. No need to download url '" + sUrl + "'.");
} else {
// Same date. No download. But the downloader wants to download
// it because the last modified is out of date.
// Report this to the GUI
downloadFile.setDownloadStatus("<html><font color='red'>File on Server was not updated</font></html>");
this.logger.finer("File on server is as old '" + timeOnServer + "' as on local disc '" + timeOnDisc + "'. No need to download url '" + sUrl + "'.");
return;
}
} else {
if (isTestMode) {
// File on server older than on local disc.
// But the user pressed a button. Its is likly that he changed
// a map for example. So download. The user wants it.
// The status gets overwritten later after the download.
downloadFile.setDownloadStatus("<html><font color='red'>Download, File on Server older than local copy</font></html>");
String message = "File on server '" + timeOnServer + "' is older than local disc '" + timeOnDisc + "'. Did you change the server or URL? URL: '" + sUrl + "'...";
this.logger.info(message);
LoggingBoard.logDownloaderMessage(message);
} else {
// File on server older than on local disc. Do not download.
downloadFile.setDownloadStatus("<html><font color='red'>File on Server older than local copy</font></html>");
String message = "File on server '" + timeOnServer + "' is older than local disc '" + timeOnDisc + "'. Did you change the server? How ever, no need to download '" + sUrl + "'...";
this.logger.info(message);
LoggingBoard.logDownloaderMessage(message);
return;
}
}
// download
this.logger.finer("Opening connection for url: " + sUrl);
in = new BufferedInputStream(new DataInputStream(url.openStream()));
out = new BufferedOutputStream(new DataOutputStream(new FileOutputStream(localFile)));
byte[] bbuf = new byte[4096];
length = -1;
while ((length = in.read(bbuf)) != -1) {
out.write(bbuf, 0, length);
byteCount = byteCount + length;
}
this.logger.finest("Wrote '" + byteCount + "' bytes into file '" + localFile + "'.");
in.close();
in = null;
out.close();
out = null;
http.disconnect();
http = null;
downloadFile.setLastModified(lastModifiedOnServer);
downloadFile.setDownloadStatus("<html><font color='green'>File up to date with Server</font></html>");
this.logger.info("Downloaded file '" + sUrl + "' to '" + localFile + "'.");
LoggingBoard.logDownloaderMessage("Downloaded: " + sUrl);
if (isTestMode) {
LoggingBoard.logDownloaderMessage("Copied to: " + localFile);
}
} catch (java.net.UnknownHostException ex) {
//this.logger.log(Level.SEVERE, null, ex);
downloadFile.setDownloadStatus("<html><font color='red'>Connection failed</font></html>");
this.logger.finer("Download failed, URL: " + sUrl + ". Exception: " + ex.toString() + ". Original messages: " + ex.getLocalizedMessage());
if (isTestMode) {
LoggingBoard.logDownloaderMessage("Connection failed: " + sUrl);
LoggingBoard.logDownloaderMessage("Connection Error: " + ex.toString());
}
} catch (Exception ex) {
//this.logger.log(Level.SEVERE, null, ex);
downloadFile.setDownloadStatus("<html><font color='red'>Download failed</font></html>");
this.logger.finer("Download failed, URL: " + sUrl + ". Exception: " + ex.toString() + ". Original messages: " + ex.getLocalizedMessage());
if (isTestMode) {
LoggingBoard.logDownloaderMessage("Download failed: " + sUrl);
LoggingBoard.logDownloaderMessage("Original Error: " + ex.toString());
}
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
}
}
if (out != null) {
try {
out.close();
} catch (Exception e) {
}
}
if (http != null) {
try {
http.disconnect();
} catch (Exception e) {
}
}
}
}
}