package de.eisfeldj.augendiagnosefx.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import de.eisfeldj.augendiagnosefx.Application;
import de.eisfeldj.augendiagnosefx.util.DialogUtil.ConfirmDialogListener;
import de.eisfeldj.augendiagnosefx.util.DialogUtil.ProgressDialog;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javafx.application.Platform;
import static de.eisfeldj.augendiagnosefx.util.PreferenceUtil.KEY_LAST_KNOWN_VERSION;
/**
* Utility class for handling the download of new application version.
*/
public final class VersioningUtil {
/**
* The current version of the application.
*/
public static final VersionInfo CURRENT_VERSION = new VersionInfo(13, "0.1.12");
/**
* Base URL for downloading the application.
*/
private static final String DOWNLOAD_BASE_URL = "http://augendiagnose.jeisfeld.de/bin/";
/**
* The URL where to get the info about the latest version.
*/
private static final String CURRENT_VERSION_URL = DOWNLOAD_BASE_URL + "currentVersion.txt";
/**
* Size of the buffer for downloading the jar file.
*/
private static final int DOWNLOAD_BUFFER = 4096;
/**
* Hide default constructor.
*/
private VersioningUtil() {
throw new UnsupportedOperationException();
}
/**
* Retrieve information about the latest available application version (from Internet).
*
* @return The latest version info.
*/
@SuppressFBWarnings(value = "NP_DEREFERENCE_OF_READLINE_VALUE",
justification = "Generically catching all exceptions")
public static VersionInfo getLatestVersionInfo() {
try {
URLConnection connection = new URL(CURRENT_VERSION_URL).openConnection();
InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String versionNumberString = reader.readLine();
String versionString = reader.readLine();
reader.close();
inputStream.close();
int versionNumber = Integer.parseInt(versionNumberString);
return new VersionInfo(versionNumber, versionString);
}
catch (Exception e) {
Logger.error("Error while determining latest application version.", e);
return null;
}
}
/**
* Download a version update.
*
* @param version
* The version to be downloaded.
*/
public static void downloadUpdate(final VersionInfo version) {
String url = version.getJarDownloadUrl();
final File currentJarFile = SystemUtil.getJarPath();
final File tempJarFile;
final ProgressDialog dialog =
DialogUtil
.displayProgressDialog(ResourceConstants.MESSAGE_PROGRESS_LOADING_UPDATE, version.mVersionString);
final URLConnection connection;
try {
connection = new URL(url).openConnection();
tempJarFile = new File(SystemUtil.getTempDir(), "temp.jar");
}
catch (IOException e) {
Logger.error("Could not open URL " + url, e);
return;
}
Thread downloadThread = new Thread() {
@Override
public void run() {
Logger.info("Downloading update to file " + tempJarFile.getAbsolutePath());
try (InputStream input = connection.getInputStream();
OutputStream output = new FileOutputStream(tempJarFile)) {
long totalSize = connection.getContentLengthLong();
long currentSize = 0;
byte[] buffer = new byte[DOWNLOAD_BUFFER];
int n = -1;
while ((n = input.read(buffer)) != -1) {
if (n > 0) {
output.write(buffer, 0, n);
currentSize += n;
dialog.setProgress(1.0 * currentSize / totalSize);
}
}
Platform.runLater(new Runnable() {
@Override
public void run() {
dialog.close();
SystemUtil.updateApplication(tempJarFile.getAbsolutePath(),
currentJarFile.getAbsolutePath());
Application.exitAfterConfirmation();
}
});
}
catch (IOException e) {
Logger.error("Exception while downloading from " + url, e);
Platform.runLater(new Runnable() {
@Override
public void run() {
dialog.close();
}
});
}
}
};
downloadThread.start();
}
/**
* Check if there is a newer version of the application.
*
* @param fromMenu
* give information if started from menu. If started from menu, than failure to find new version will be
* reported, and previous cancellation is ignored.
*/
public static void checkForNewerVersion(final boolean fromMenu) {
VersionInfo latestVersion = getLatestVersionInfo();
boolean updateAutomatically = PreferenceUtil.getPreferenceBoolean(PreferenceUtil.KEY_UPDATE_AUTOMATICALLY);
if (latestVersion == null) {
return;
}
// Prompt only if the same version has not yet been refused.
boolean requiresNewVersion =
latestVersion.getVersionNumber() > CURRENT_VERSION.getVersionNumber();
// In case of automatic updates, just do the update if existing.
if (requiresNewVersion && updateAutomatically) {
downloadUpdate(latestVersion);
return;
}
// Otherwise, differentiate between check on startup and check via menu.
if (fromMenu) {
PreferenceUtil.setPreference(PreferenceUtil.KEY_LAST_KNOWN_VERSION,
VersioningUtil.CURRENT_VERSION.getVersionNumber());
}
else {
requiresNewVersion = requiresNewVersion
&& latestVersion.getVersionNumber() > PreferenceUtil.getPreferenceInt(KEY_LAST_KNOWN_VERSION);
}
if (requiresNewVersion) {
ConfirmDialogListener listener = new ConfirmDialogListener() {
@Override
public void onDialogPositiveClick() {
downloadUpdate(latestVersion);
}
@Override
public void onDialogNegativeClick() {
PreferenceUtil.setPreference(KEY_LAST_KNOWN_VERSION, latestVersion.mVersionNumber);
}
};
DialogUtil.displayConfirmationMessage(listener, ResourceConstants.BUTTON_DOWNLOAD,
ResourceConstants.MESSAGE_CONFIRM_NEW_VERSION, latestVersion.getVersionString());
}
else {
if (fromMenu) {
DialogUtil.displayInfo(ResourceConstants.MESSAGE_INFO_NO_NEW_VERSION);
}
}
}
/**
* A class holding information about the version of the application.
*/
public static final class VersionInfo {
/**
* The version number (counting upwards from 1).
*/
private int mVersionNumber;
public int getVersionNumber() {
return mVersionNumber;
}
/**
* The version String (such as 1.2.3).
*/
private String mVersionString;
public String getVersionString() {
return mVersionString;
}
/**
* Constructor for a VersionInfo object.
*
* @param versionNumber
* The version number.
* @param versionString
* The version String.
*/
private VersionInfo(final int versionNumber, final String versionString) {
this.mVersionNumber = versionNumber;
this.mVersionString = versionString;
}
@Override
public String toString() {
return mVersionString + " (" + mVersionNumber + ")";
}
/**
* Retrieve the download URL for this version of the application (exe file).
*
* @return The download URL.
*/
public String getExeDownloadUrl() {
StringBuffer result = new StringBuffer(DOWNLOAD_BASE_URL);
result.append("Augendiagnose-");
if (SystemUtil.is64Bit()) {
result.append("x64");
}
else {
result.append("x86");
}
result.append("-").append(getVersionString()).append(".exe");
return result.toString();
}
/**
* Retrieve the download URL for this version of the application (jar file).
*
* @return The download URL.
*/
public String getJarDownloadUrl() {
StringBuffer result = new StringBuffer(DOWNLOAD_BASE_URL);
result.append("AugendiagnoseFX-");
result.append(getVersionString()).append(".jar");
return result.toString();
}
}
}