20 package net.sf.gridarta.updater;
22 import java.awt.Component;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InterruptedIOException;
28 import java.io.OutputStream;
29 import java.net.Proxy;
31 import java.net.URLConnection;
32 import java.net.UnknownHostException;
33 import java.util.MissingResourceException;
34 import java.util.PropertyResourceBundle;
35 import java.util.ResourceBundle;
36 import java.util.prefs.Preferences;
37 import javax.swing.JOptionPane;
38 import javax.swing.ProgressMonitor;
39 import javax.swing.ProgressMonitorInputStream;
44 import net.
sf.japi.swing.action.ActionBuilder;
45 import net.
sf.japi.swing.action.ActionBuilderFactory;
46 import org.apache.log4j.Category;
47 import org.apache.log4j.Logger;
48 import org.jetbrains.annotations.NotNull;
49 import org.jetbrains.annotations.Nullable;
58 public class Updater implements Runnable {
64 private static final ActionBuilder
ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder(
"net.sf.gridarta");
70 private static final Category
LOG = Logger.getLogger(
Updater.class);
113 public Updater(@Nullable
final Component parentComponent, @NotNull
final Exiter exiter, @NotNull
final String updateFileName) {
117 if (parentComponent != null) {
118 parentComponent.setEnabled(
false);
125 final String propUrl = ACTION_BUILDER.getString(
"update.url");
126 if (propUrl == null) {
131 final ResourceBundle updateBundle =
new PropertyResourceBundle(pin);
132 final String downloadUrl = updateBundle.getString(
"update.url");
133 if (downloadUrl == null) {
134 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateError",
"invalid server response: update.url is missing");
140 active =
new VersionInfo(ResourceBundle.getBundle(
"build"),
"build");
141 }
catch (
final MissingResourceException e) {
142 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateActiveVersionUnavailable");
144 PREFERENCES.putLong(LAST_UPDATE_KEY, System.currentTimeMillis());
145 if (active == null || update.isNewerThan(active)) {
153 }
catch (
final UnknownHostException e) {
154 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateError", e.getLocalizedMessage());
155 }
catch (
final IOException e) {
156 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateError", e);
158 if (parentComponent != null) {
159 parentComponent.setEnabled(
true);
174 return ACTION_BUILDER.showConfirmDialog(parentComponent, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
"updateAvailable", updateFileName, active == null ?
"?" : active.version, update.version, active == null ?
"?" : active.developer, update.developer, active == null ?
"?" : active.timestamp, update.timestamp, propUrl, downloadUrl) == JOptionPane.YES_OPTION;
185 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateUnavailable", active == null ?
"?" : active.version, update.version, active == null ?
"?" : active.developer, update.developer, active == null ?
"?" : active.timestamp, update.timestamp, propUrl, downloadUrl);
193 final File download =
new File(updateFileName +
".tmp");
194 final File backup =
new File(updateFileName +
".bak");
195 final File orig =
new File(updateFileName);
198 try (OutputStream out =
new FileOutputStream(download)) {
199 final byte[] buf =
new byte[
BUF_SIZE];
201 final int bytesRead = in.read(buf);
202 if (bytesRead == -1) {
205 out.write(buf, 0, bytesRead);
208 if ( !orig.renameTo(backup)) {
209 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateFailedNoBackup", updateFileName);
210 }
else if (!download.renameTo(orig)) {
211 backup.renameTo(orig);
212 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateFailedNoDownload");
214 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateRestart", updateFileName);
219 }
catch (
final InterruptedIOException e) {
220 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateAborted");
221 }
catch (
final Exception e) {
222 LOG.warn(
"updateError", e);
223 ACTION_BUILDER.showMessageDialog(parentComponent,
"updateError", e);
235 private InputStream
openStream(@NotNull
final String url)
throws IOException {
237 final URLConnection con =
new URL(url).openConnection(proxy);
238 final ProgressMonitorInputStream stream =
new ProgressMonitorInputStream(parentComponent,
ActionBuilderUtils.
getString(ACTION_BUILDER,
"updateProgress.title"), con.getInputStream());
239 final ProgressMonitor monitor = stream.getProgressMonitor();
240 monitor.setMaximum(con.getContentLength());
242 monitor.setMillisToDecideToPopup(10);
243 monitor.setMillisToPopup(10);
281 this(
"unavailable",
"unavailable",
"unavailable");
290 private VersionInfo(@NotNull
final String version, @NotNull
final String timestamp, @NotNull
final String developer) {
304 private VersionInfo(@NotNull
final ResourceBundle bundle, @NotNull
final String prefix) {
305 this(bundle.getString(prefix +
".number"), bundle.getString(prefix +
".tstamp"), bundle.getString(prefix +
".developer"));
314 @SuppressWarnings(
"ObjectEquality")
315 boolean isNewerThan(@NotNull
final VersionInfo other) {
316 return this != UNAVAILABLE && (other == UNAVAILABLE || timestamp.compareTo(other.timestamp) > 0);
static Proxy getProxy()
Returns the currently preferred proxy.
static final int BUF_SIZE
Buffer size.
Graphical User Interface of Gridarta.
VersionInfo(@NotNull final String version, @NotNull final String timestamp, @NotNull final String developer)
Private constructor to map the strings.
final Component parentComponent
The parentComponent to show dialogs on.
static final String LAST_UPDATE_KEY
Preferences key for last update.
This class handles updating the map editor.
final String updateFileName
The file to update.
Class for holding version information and quickly comparing it.
static String getString(@NotNull final ActionBuilder actionBuilder, @NotNull final String key, @NotNull final String defaultValue)
Returns the value of a key.
Base package of all Gridarta classes.
void doExit(int returnCode)
Exits the application.
InputStream openStream(@NotNull final String url)
Opens an InputStream on a URL.
final String developer
Update information: Developer that created the update version.
Updater(@Nullable final Component parentComponent, @NotNull final Exiter exiter, @NotNull final String updateFileName)
Create a new instance.
This package contains the preferences ui modules.
void noNewUpdate(@Nullable final VersionInfo active, @NotNull final VersionInfo update, @NotNull final String propUrl, @NotNull final String downloadUrl)
Tell the user there is no update.
Interface used as preferences location.
static final Preferences PREFERENCES
Preferences.
static final VersionInfo UNAVAILABLE
Special Version "unavailable".
Preferences Module for networking preferences.
void downloadAndInstallUpdate(@NotNull final String url)
Download and install an update.
final Exiter exiter
The Exiter for terminating the application.
final String version
Update information: Version of update version, usually the build number.
VersionInfo(@NotNull final ResourceBundle bundle, @NotNull final String prefix)
Create update information from a ResourceBundle.
VersionInfo()
Private constructor used for unavailable versions.
Utility class for ActionBuilder related functions.
final String timestamp
Update information: Time stamp of update version.
boolean askIfUserWantsUpdate(@Nullable final VersionInfo active, @NotNull final VersionInfo update, @NotNull final String propUrl, @NotNull final String downloadUrl)
Ask the user whether he wants to update.
static final ActionBuilder ACTION_BUILDER
Action Builder to create Actions.
static final Category LOG
Logger.