[Schmitzm-commits] r2259 - in trunk: schmitzm-core/src/main/java/de/schmitzm/io schmitzm-core/src/main/java/de/schmitzm/lang schmitzm-core/src/main/java/de/schmitzm/swing schmitzm-core/src/main/java/de/schmitzm/versionnumber schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales schmitzm-regex
scm-commit at wald.intevation.org
scm-commit at wald.intevation.org
Wed Feb 27 01:03:18 CET 2013
Author: mojays
Date: 2013-02-27 01:03:18 +0100 (Wed, 27 Feb 2013)
New Revision: 2259
Added:
trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtilBasic.java
trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUpdater.java
Modified:
trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtil.java
trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LangUtil.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java
trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUtil.java
trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties
trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
trunk/schmitzm-regex/
Log:
IOUtil: download methods extended with http authentication
LangUtil: BugFix for formatFileSize(.)
SwingUtil: method for interactive release update process
ReleaseUtil: constants for property keys; new method to copy release properties to new file
IOUtilBasic: utility IO methods WITHOUT any dependency except standard JDK
ReleaseUpdater: utility to check for applications updates on a server
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtil.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtil.java 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtil.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -166,7 +166,26 @@
return file.getAbsolutePath().substring(extIdx);
}
- /**
+ /**
+ * Liefert die Dateinamen-Erweiterung (z.B. ".exe") einer Datei.
+ *
+ * @param fileName
+ * Datei
+ * @param withDot
+ * wenn {@code false} wird die Dateinamen-Erweiterung ohne den
+ * fuehrenden Punkt zurueckgegeben (z.B. "exe" statt ".exe")
+ * @return Leerstring, falls die Datei keine Erweiterung hat
+ */
+ public static String getFileExt(String fileName, boolean withDot) {
+ int extIdx = getFileExtIdx(fileName);
+ if (extIdx < 0)
+ return "";
+ if (!withDot)
+ extIdx++;
+ return fileName.substring(extIdx);
+ }
+
+ /**
* Haengt an einen Dateinamen-Erweiterung eine Erweiterung an, sofern diese
* noch nicht angehaengt ist.
*
@@ -297,7 +316,22 @@
return file.getAbsolutePath().substring(0, extIdx);
}
- /**
+ /**
+ * Liefert den Dateinamen ohne Erweiterung (z.B. ohne ".exe") einer Datei.
+ *
+ * @param file
+ * Datei
+ *
+ * @see #getBaseFilePath(File)
+ */
+ public static String getBaseFileName(String fileName) {
+ int extIdx = getFileExtIdx(fileName);
+ if (extIdx < 0)
+ return fileName;
+ return fileName.substring(0, extIdx);
+ }
+
+ /**
* Liefert den Dateinamen ohne Erweiterung (z.B. ohne ".exe") einer Datei.
*
* @param file
@@ -306,10 +340,7 @@
* @see #getBaseFilePath(File)
*/
public static String getBaseFileName(File file) {
- int extIdx = getFileExtIdx(file.getName());
- if (extIdx < 0)
- return file.getName();
- return file.getName().substring(0, extIdx);
+ return getBaseFileName(file.getName());
}
/**
@@ -632,12 +663,28 @@
* deleted after JVM exit!)
*/
public static File downloadUrlToFile(URL url, ConnectionSettings connSettings, File file) throws IOException {
+ return downloadUrlToFile(url,connSettings,file,null,null);
+ }
+
+ /**
+ * Downloads an {@link URL} to local file.
+ * @param url remote URL
+ * @param connSettings connection settings (proxy, timeouts, retries)
+ * @param file local file (if {@code null} a temporary file is created, which will be
+ * deleted after JVM exit!)
+ * @param user user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param password password for http authentication
+ */
+ public static File downloadUrlToFile(URL url, ConnectionSettings connSettings, File file, String user, String password) throws IOException {
return downloadUrlToFile(url,
connSettings.getProxyForConnection(),
file,
connSettings.getConnTimeout(),
connSettings.getConnReadTimeout(),
- connSettings.getConnRetries()
+ connSettings.getConnRetries(),
+ user,
+ password
);
}
@@ -654,28 +701,69 @@
* @param maxRetries number of download retries in case of any error
*/
public static File downloadUrlToFile(URL url, Proxy proxy, File file, int connTimeout, int readTimeout, int maxRetries) throws IOException {
+ return downloadUrlToFile(url, proxy, file, connTimeout, readTimeout, maxRetries, null, null);
+ }
+
+ /**
+ * Downloads an {@link URL} to local file.
+ * @param url remote URL
+ * @param proxy proxy server used for url connection (if {@code null} the
+ * {@linkplain #getGlobalConnectionSettings() global connection settings}
+ * are used)
+ * @param file local file (if {@code null} a temporary file is created, which will be
+ * deleted after JVM exit!)
+ * @param connTimeout connection timeout in ms
+ * @param readTimeout read timeout in ms
+ * @param maxRetries number of download retries in case of any error
+ * @param user user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param password password for http authentication
+ */
+ public static File downloadUrlToFile(URL url, Proxy proxy, File file, int connTimeout, int readTimeout, int maxRetries, String user, String password) throws IOException {
if ( file == null )
file = createTemporaryFile("java-schmitzm-",null,true);
if ( proxy == null )
proxy = getGlobalConnectionSettings().getProxyForConnection();
-
+
LOGGER.debug("Download: "+url+" to "+file);
+ // if user/password not explicitly given, but in URL, extract
+ // user/password from URL
+ if ( user == null ) {
+ String[] urlUserPW = determineAuthenticationFromURL(url);
+ if ( urlUserPW != null ) {
+ user = urlUserPW[0];
+ password = urlUserPW[1];
+ }
+ }
+
for (int retry=0;; retry++)
try {
// do like FileUtils.copyURLToFile(URL,File,int,int)
// from Apache Commons IO 2.0
// JUST HANDLE USING PROXY!!
// Note: Problem with read timeout exception remains! :-(
- URLConnection connection = url.openConnection(proxy);
- if ( connTimeout > 0 ) {
- connection.setConnectTimeout(connTimeout);
- LOGGER.debug("Connection timeout set: "+connTimeout+"ms");
- }
- if ( readTimeout > 0 ) {
- connection.setReadTimeout(readTimeout);
- LOGGER.debug("Read timeout set: "+readTimeout+"ms");
- }
+// URLConnection connection = url.openConnection(proxy);
+//
+// // Handle authentication
+// String userPassword = null;
+// if ( user != null ) {
+// userPassword = user;
+// if ( password != null )
+// userPassword += ":" + password;
+// String encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes());
+// connection.setRequestProperty("Authorization", "Basic " + encoding);
+// }
+//
+// if ( connTimeout > 0 ) {
+// connection.setConnectTimeout(connTimeout);
+// LOGGER.debug("Connection timeout set: "+connTimeout+"ms");
+// }
+// if ( readTimeout > 0 ) {
+// connection.setReadTimeout(readTimeout);
+// LOGGER.debug("Read timeout set: "+readTimeout+"ms");
+// }
+ URLConnection connection = openConnection(url, user, password, proxy, connTimeout, readTimeout);
LOGGER.debug("Download: "+url+" to "+file);
InputStream input = connection.getInputStream();
copyInputStreamToFile(input, file);
@@ -737,6 +825,182 @@
}
/**
+ * Opens a connection for an {@link URL} and initializes it according to
+ * given authentication, proxy and timeout settings.
+ * @param url remote URL
+ * @param authUser user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param authPassword password for http authentication
+ * @param connSettings connection settings (proxy, timeouts, retries)
+ */
+ public static URLConnection openConnection(URL url, String authUser, String authPassword, ConnectionSettings connSettings) throws IOException {
+ return openConnection(url,
+ authUser,
+ authPassword,
+ connSettings.getProxyForConnection(),
+ connSettings.getConnTimeout(),
+ connSettings.getConnReadTimeout()
+ );
+ }
+
+ /**
+ * Opens a connection for an {@link URL} and initializes it according to
+ * given authentication, proxy and timeout settings.
+ * @param url remote URL
+ * @param authUser user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param authPassword password for http authentication
+ * @param proxy proxy server used for url connection (if {@code null} the
+ * {@linkplain #getGlobalConnectionSettings() global connection settings}
+ * are used)
+ * @param connTimeout connection timeout in ms
+ * @param readTimeout read timeout in ms
+ */
+ public static URLConnection openConnection(URL url, String authUser, String authPassword, Proxy proxy, int connTimeout, int readTimeout) throws IOException {
+ if ( proxy == null )
+ proxy = getGlobalConnectionSettings().getProxyForConnection();
+ // if user/password not explicitly given, but in URL, extract
+ // user/password from URL
+ if ( authUser == null ) {
+ String[] urlUserPW = determineAuthenticationFromURL(url);
+ if ( urlUserPW != null ) {
+ authUser = urlUserPW[0];
+ authPassword = urlUserPW[1];
+ }
+ }
+
+ // Open connection
+ URLConnection connection = url.openConnection(proxy);
+ // Handle authentication
+ String userPassword = null;
+ if ( authUser != null ) {
+ userPassword = authUser;
+ if ( authPassword != null )
+ userPassword += ":" + authPassword;
+ String encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes());
+ connection.setRequestProperty("Authorization", "Basic " + encoding);
+ }
+ // Configure timeouts
+ if ( connTimeout > 0 ) {
+ connection.setConnectTimeout(connTimeout);
+ LOGGER.debug("Connection timeout set: "+connTimeout+"ms");
+ }
+ if ( readTimeout > 0 ) {
+ connection.setReadTimeout(readTimeout);
+ LOGGER.debug("Read timeout set: "+readTimeout+"ms");
+ }
+
+ return connection;
+ }
+
+ /**
+ * Determines user and password for http authentication from URL
+ * string (e.g. {@code http://user:password@mydomain.com/myfolder/mydoc.txt}).
+ * @param url a remote URL
+ * @return {@code null} if URL contains no user/password information; otherwise a
+ * string array, which contains the user in element 0 and the (optional)
+ * password in element 1.
+ */
+ public static String[] determineAuthenticationFromURL(URL url) {
+ String urlStr = url.toString();
+ // check whether URL contains authentication information
+ int idx = urlStr.indexOf('@');
+ if ( idx <= 0 )
+ return null;
+
+ // extract URL part "user:password" (everything before @ and after /)
+ String userPwStr = urlStr.substring(0, idx);
+ idx = userPwStr.lastIndexOf('/');
+ if ( idx >= 0 )
+ userPwStr = userPwStr.substring(idx+1);
+ // Split user and password
+ idx = userPwStr.indexOf(':');
+ String user = null;
+ String password = null;
+ if ( idx < 0 ) {
+ user = userPwStr;
+ password = null;
+ } else {
+ user = userPwStr.substring(0,idx);
+ password = userPwStr.substring(idx+1);
+ }
+
+ return new String[] {user,password};
+ }
+
+ /**
+ * Determines the size of an {@link URL} file.
+ * @param url remote URL
+ * @param connSettings connection settings (proxy, timeouts, retries)
+ * @param user user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param password password for http authentication
+ */
+ public static int determineUrlFileSize(URL url, ConnectionSettings connSettings, String user, String password) throws IOException {
+ return determineUrlFileSize(url,
+ connSettings.getProxyForConnection(),
+ connSettings.getConnTimeout(),
+ connSettings.getConnReadTimeout(),
+ connSettings.getConnRetries(),
+ user,
+ password
+ );
+ }
+
+ /**
+ * Determines the size of an {@link URL} file.
+ * @param url remote URL
+ * @param proxy proxy server used for url connection (if {@code null} the
+ * {@linkplain #getGlobalConnectionSettings() global connection settings}
+ * are used)
+ * @param connTimeout connection timeout in ms
+ * @param readTimeout read timeout in ms
+ * @param maxRetries number of download retries in case of any error
+ * @param authUser user for http authentication (if {@code null}, authentication is tried to determine from
+ * URL {@code user:password})
+ * @param authPassword password for http authentication
+ */
+ public static int determineUrlFileSize(URL url, Proxy proxy, int connTimeout, int readTimeout, int maxRetries, String authUser, String authPassword) throws IOException {
+ if ( proxy == null )
+ proxy = getGlobalConnectionSettings().getProxyForConnection();
+
+ // if user/password not explicitly given, but in URL, extract
+ // user/password from URL
+ // if user/password not explicitly given, but in URL, extract
+ // user/password from URL
+ if ( authUser == null ) {
+ String[] urlUserPW = determineAuthenticationFromURL(url);
+ if ( urlUserPW != null ) {
+ authUser = urlUserPW[0];
+ authPassword = urlUserPW[1];
+ }
+ }
+
+ int fileSize = -1;
+ for (int retry=0;; retry++)
+ try {
+ // do like FileUtils.copyURLToFile(URL,File,int,int)
+ // from Apache Commons IO 2.0
+ // JUST HANDLE USING PROXY!!
+ // Note: Problem with read timeout exception remains! :-(
+ URLConnection connection = openConnection(url, authUser, authPassword, proxy, connTimeout, readTimeout);
+ fileSize = connection.getContentLength();
+ break;
+ } catch ( IOException err ) {
+ if ( maxRetries > 0 ) {
+ LOGGER.warn("Error checking file size of "+url+": "+err.getMessage());
+ if ( retry < maxRetries ) {
+ LOGGER.warn("Starting retry "+(retry+1)+" of "+maxRetries);
+ continue;
+ }
+ }
+ throw err;
+ }
+
+ return fileSize;
+ }
+
+ /**
* Copies the content of an {@link InputStream} to local {@link File}.<br>
* Copied 1:1 from FileUtils (Apache Commons IO 2.0).
* @param source source stream
@@ -948,7 +1212,7 @@
*
* @param arg
*/
- public static void main(final String[] arg) {
+ public static void main(final String[] arg) throws Exception {
if (arg.length == 0) {
LOGGER.error("Missing arguments.");
return;
@@ -1133,7 +1397,20 @@
return url;
}
- /**
+ /**
+ * Calls {@code new URL(.)} without the need to handle {@link MalformedURLException}.
+ * In case of error a {@link RuntimeException} is thrown.
+ * @param urlStr url definition
+ */
+ public static URL createURL(String urlStr) {
+ try {
+ return new URL(urlStr);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Test whether it is possible to access the given URL. Times-out after 3s
*/
public static boolean urlExists(final URL url) {
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtilBasic.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtilBasic.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/io/IOUtilBasic.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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 Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.io;
+
+import java.io.File;
+
+/**
+ * This class contains IO utility methods which only depend on standard JDK
+ * and no other dependency, so that especially the {@link #main(String[])}-method
+ * can be executed without including additional libraries.
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class IOUtilBasic {
+
+ /**
+ * Executes one of the following commands:
+ * <ul>
+ * <li>{@code COPY source dest delayMillis}<br>
+ * Copy a file on the file system.</li>
+ * <li>{@code MOVE source dest delaMillis}<br>
+ * Moved a file on the file system.</li>
+ * <li>{@code EXEC delayMillies command}<br>
+ * Executes an OS command.</li>
+ * </ul>
+ */
+ public static void main(String[] arg) throws Exception {
+ if (arg.length == 0) {
+ System.err.println("Missing arguments.");
+ return;
+ }
+
+ String func = arg[0].toUpperCase();
+ if (func.equals("COPY") || func.equals("MOVE")) {
+ // ###### COPY / MOVE ######
+ if (arg.length < 3) {
+ System.err.println("Missing arguments for "+func+".");
+ return;
+ }
+ if (arg.length > 3) {
+ long delay = Integer.parseInt(arg[3]);
+ Thread.sleep(delay);
+ }
+ File source = new File(arg[1]);
+ File dest = new File(arg[2]);
+ source.renameTo(dest);
+ if ( func.equals("MOVE") )
+ source.delete();
+ } else if ( func.equals("EXEC") ) {
+ // ###### EXEC ######
+ if (arg.length < 3) {
+ System.err.println("Missing arguments for "+func+".");
+ return;
+ }
+ long delay = Integer.parseInt(arg[1]);
+ Thread.sleep(delay);
+ String command = "";
+ for (int i=2; i<arg.length; i++)
+ command += " " + arg[i];
+ Runtime.getRuntime().exec(command);
+ } else {
+ System.err.println("Unknown function: " + func);
+ }
+
+ }
+
+}
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LangUtil.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LangUtil.java 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LangUtil.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -2639,9 +2639,9 @@
return kBytes + " KB";
int mBytes = (int) Math.round(bytes * 1.0 / LangUtil.MB_BYTES);
if (bytes < LangUtil.GB_BYTES)
- return kBytes + " MB";
+ return mBytes + " MB";
int gBytes = (int) Math.round(bytes * 1.0 / LangUtil.GB_BYTES);
- return kBytes + " GB";
+ return gBytes + " GB";
}
/**
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -73,6 +73,7 @@
import java.util.Map;
import java.util.Random;
import java.util.StringTokenizer;
+import java.util.Timer;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.imageio.ImageIO;
@@ -135,6 +136,7 @@
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
+import org.apache.tools.ant.taskdefs.Sleep;
import com.toedter.calendar.JDateChooser;
@@ -147,6 +149,7 @@
import de.schmitzm.swing.input.MultipleOptionPane;
import de.schmitzm.swing.table.ComponentRenderer;
import de.schmitzm.swing.table.SelectionTableModel;
+import de.schmitzm.versionnumber.ReleaseUpdater;
/**
* Diese Klasse beinhaltet statische Hilfsfunktionen fuer das Arbeiten mit
@@ -2879,5 +2882,126 @@
}
}
+
+ /**
+ * Uses a {@link ReleaseUpdater} to check online for application update. If new release is available
+ * it is downloaded.
+ * @param parent parent frame used for status dialogs
+ * @param updater update used to check for application updated
+ * @param destFile local destination file for download (if {@code null} a temporary file in
+ * user temp folder is created, which will be deleted after application exit!)
+ * @param askForUpdate indicates whether user is asked before starting the download
+ * @param updaterFileName (base) name of the an updater program/jar which is additionally downloaded
+ * to the same directory as {@code destFile};
+ * it can be used to install/copy the downloaded application file to destination
+ * directory (if {@code null} the updater will be ignored)
+ * @return the downloaded file or {@code null} if the update check or download progress was canceled
+ */
+ public static File performReleaseUpdateWithProgressBar(Frame parent, final ReleaseUpdater updater, File destFile, boolean askForUpdate, boolean showNoUpdateMess, String updaterFilename) throws IOException {
+ // We want to do a new online check for update, so we clear
+ // any cached update information
+ updater.clearCache();
+
+ // Check for update
+ final SwingWorker.Work updateCheckWork = new SwingWorker.Work() {
+ @Override
+ public Object execute() throws Exception {
+ boolean updateAvailable = updater.checkReleaseUpdate();
+ if ( !updateAvailable )
+ return null;
+ return updater.getLastestBuild();
+ }
+ };
+ final SwingWorker updateCheckWorker = new SwingWorker(updateCheckWork,
+ parent,
+ R("SwingUtil.releaseUpdate.check.mess",updater.getReleaseBaseUrl()));
+ updateCheckWorker.start();
+ // Cancel if check was canceled or no update is available
+ if ( updateCheckWorker.isCanceled() )
+ return null;
+ if ( updateCheckWorker.getWorkResult() == null ) {
+ if ( showNoUpdateMess )
+ JOptionPane.showMessageDialog(parent,
+ R("SwingUtil.releaseUpdate.none.mess"),
+ R("SwingUtil.releaseUpdate.none.title"),
+ JOptionPane.INFORMATION_MESSAGE);
+ return null;
+ }
+ // Determine file size to download
+ final int downloadSize = IOUtil.determineUrlFileSize(updater.getLastestReleaseURL(),
+ IOUtil.getGlobalConnectionSettings(),
+ updater.getHttpAuthUser(),
+ updater.getHttpAuthPW());
+
+
+ // Ask for update
+ String latestBuild = (String)updateCheckWorker.getWorkResult();
+ if ( askForUpdate ) {
+ String downloadSizeStr = LangUtil.formatFileSize(downloadSize);
+ int ret = JOptionPane.showConfirmDialog(parent,
+ R("SwingUtil.releaseUpdate.available.mess",
+ latestBuild,
+ updater.getReleaseBaseUrl(),
+ downloadSizeStr),
+ "SwingUtil.releaseUpdate.available.title",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ if ( ret != JOptionPane.YES_OPTION ) {
+ return null;
+ }
+ }
+
+ // Download file(s)
+ final File downloadFile = (destFile != null) ? destFile : IOUtil.createTemporaryFile(updater.getLastestReleaseFileName(), null, true);
+ final File updaterFile = updaterFilename == null ? null : new File(downloadFile.getParent(),updaterFilename);
+ final URL updaterURL = updaterFilename == null ? null : IOUtil.extendURL(updater.getReleaseBaseUrl(),updaterFile.getName());
+ final int updaterSize = updaterFilename == null ? 0 : IOUtil.determineUrlFileSize(updaterURL,
+ IOUtil.getGlobalConnectionSettings(),
+ updater.getHttpAuthUser(),
+ updater.getHttpAuthPW());
+ final boolean updaterExists = updaterSize > 10000;
+ final SwingWorker.Work downloadWork = new SwingWorker.Work() {
+ @Override
+ public Object execute() throws Exception {
+ // Download updater
+ if ( updaterExists )
+ IOUtil.downloadUrlToFile(updaterURL,
+ IOUtil.getGlobalConnectionSettings(),
+ updaterFile,
+ updater.getHttpAuthUser(),
+ updater.getHttpAuthPW());
+ return updater.downloadLatestRelease(downloadFile, false);
+ }
+ };
+ final SwingWorker downloadWorker = new SwingWorker(downloadWork);
+ downloadWorker.start();
+
+ // Show Dialog which continuously checks the downloaded file size
+ // and shows the progress
+ final SwingWorker.Work progressWork = new SwingWorker.Work() {
+ @Override
+ public Object execute() throws Exception {
+ setProgressIndeterminate(false);
+ setProgressRange(0, downloadSize+updaterSize);
+ while (downloadWorker.isAlive()) {
+ setProgress((int)downloadFile.length() + (int)updaterFile.length());
+ Thread.sleep(100);
+ }
+ return null;
+ }
+ };
+ final SwingWorker progressWorker = new SwingWorker(progressWork, parent, R("SwingUtil.releaseUpdate.download.mess",latestBuild));
+ progressWorker.start();
+ if ( progressWorker.isCanceled() ) {
+ downloadWorker.terminate();
+ downloadFile.delete();
+ if ( updaterFile != null )
+ updaterFile.delete();
+ }
+
+ // return downloaded file
+ return (File)downloadWorker.getWorkResult();
+ }
+
}
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUpdater.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUpdater.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUpdater.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -0,0 +1,310 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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 Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.versionnumber;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.commons.lang.StringUtils;
+
+import de.schmitzm.io.IOUtil;
+
+/**
+ * This class can be used to check whether a new program version (for the running application)
+ * is available on a download server.
+ *
+ * @author Martin O.J. Schmitz
+ */
+public class ReleaseUpdater {
+
+ protected Class<?> releaseClass = null;
+ protected URL releaseBaseUrl = null;
+ protected String releaseInfoFileName = null;
+ protected String applFileName = null;
+ protected boolean applFileNameInclBuild = false;
+ protected String httpAuthUser = null;
+ protected String httpAuthPW = null;
+
+ protected String cachedLatestBuild = null;
+
+ /**
+ * Creates a new update checker.
+ * @param releaseClass application class (used to determine release.properties file)
+ * @param releaseBaseUrl base URL where the update files can be found
+ * @param releaseInfoFileName name of properties file which contains the release informations
+ * of the latest available build
+ * @param applFileName (base) name of the latest application file
+ * @param applFileNameInclBuild indicates whether the {@code applFileName} has to be extended
+ * by build number to create download URL
+ */
+ public ReleaseUpdater(Class<?> releaseClass, String releaseBaseUrl, String releaseInfoFileName, String applFileName, boolean applFileNameInclBuild) {
+ this(releaseClass, releaseBaseUrl, null, null, releaseInfoFileName, applFileName, applFileNameInclBuild);
+ }
+
+ /**
+ * Creates a new update checker.
+ * @param releaseClass application class (used to determine release.properties file)
+ * @param releaseBaseUrl base URL where the update files can be found
+ * @param httpAuthUser user for http authentication (can also be specified in {@code releaseBaseUrl})
+ * @param httpAuthPW password for http authentication
+ * @param releaseInfoFileName name of properties file which contains the release informations
+ * of the latest available build
+ * @param applFileName (base) name of the latest application file
+ * @param applFileNameInclBuild indicates whether the {@code applFileName} has to be extended
+ * by build number to create download URL
+ */
+ public ReleaseUpdater(Class<?> releaseClass, String releaseBaseUrl, String httpAuthUser, String httpAuthPW, String releaseInfoFileName, String applFileName, boolean applFileNameInclBuild) {
+ this(releaseClass, IOUtil.createURL(releaseBaseUrl), httpAuthUser, httpAuthPW, releaseInfoFileName, applFileName, applFileNameInclBuild);
+ }
+
+ /**
+ * Creates a new update checker.
+ * @param releaseClass application class (used to determine release.properties file)
+ * @param releaseBaseUrl base URL where the update files can be found
+ * @param releaseInfoFileName name of properties file which contains the release informations
+ * of the latest available build
+ * @param applFileName (base) name of the latest application file
+ * @param applFileNameInclBuild indicates whether the {@code applFileName} has to be extended
+ * by build number to create download URL
+ */
+ public ReleaseUpdater(Class<?> releaseClass, URL releaseBaseUrl, String releaseInfoFileName, String applFileName, boolean applFileNameInclBuild) {
+ this(releaseClass, releaseBaseUrl, null, null, releaseInfoFileName, applFileName, applFileNameInclBuild);
+ }
+
+ /**
+ * Creates a new update checker.
+ * @param releaseClass application class (used to determine release.properties file)
+ * @param releaseBaseUrl base URL where the update files can be found
+ * @param httpAuthUser user for http authentication (can also be specified in {@code releaseBaseUrl})
+ * @param httpAuthPW password for http authentication
+ * @param releaseInfoFileName name of properties file which contains the release informations
+ * of the latest available build
+ * @param applFileName (base) name of the latest application file
+ * @param applFileNameInclBuild indicates whether the {@code applFileName} has to be extended
+ * by build number to create download URL
+ */
+ public ReleaseUpdater(Class<?> releaseClass, URL releaseBaseUrl, String httpAuthUser, String httpAuthPW, String releaseInfoFileName, String applFileName, boolean applFileNameInclBuild) {
+ this.releaseClass = releaseClass;
+ this.releaseBaseUrl = releaseBaseUrl;
+ this.releaseInfoFileName = releaseInfoFileName;
+ this.applFileName = applFileName;
+ this.applFileNameInclBuild = applFileNameInclBuild;
+ this.httpAuthUser = httpAuthUser;
+ this.httpAuthPW = httpAuthPW;
+ }
+
+ /**
+ * Returns the application class the updater is configured for.
+ */
+ public Class<?> getApplicationClass() {
+ return releaseClass;
+ }
+
+ /**
+ * Returns the base URL the updater checks for updates.
+ */
+ public URL getReleaseBaseUrl() {
+ return releaseBaseUrl;
+ }
+
+ /**
+ * Returns the properties file underneath base URL the updater checks for
+ * latest build.
+ * @see ReleaseUtil
+ */
+ public String getReleaseInfoFileName() {
+ return releaseInfoFileName;
+ }
+
+ /**
+ * Returns the user name the updater uses to authenticate http connection.
+ */
+ public String getHttpAuthUser() {
+ return httpAuthUser;
+ }
+
+ /**
+ * Returns the password the updater uses to authenticate http connection.
+ */
+ public String getHttpAuthPW() {
+ return httpAuthPW;
+ }
+
+ /**
+ * Returns the full {@link URL} of the information file which contains
+ * the latest build number.
+ */
+ public URL getLatestReleaseInfoURL() throws MalformedURLException {
+ return IOUtil.extendURL(releaseBaseUrl, releaseInfoFileName);
+ }
+
+ /**
+ * Returns the application file name of the the latest build.
+ */
+ public String getLastestReleaseFileName() throws IOException {
+ String fileName = applFileName;
+ if ( applFileNameInclBuild ) {
+ // determine build of latest version
+ String latestApplBuildStr = getLastestBuild();
+ long latestApplBuild = parseLong(latestApplBuildStr);
+ if ( latestApplBuild <= 0 )
+ throw new IOException("No release build can be determined. Can not check for release update!");
+ String baseFileName = IOUtil.getBaseFileName(fileName);
+ String fileExt = IOUtil.getFileExt(fileName, true);
+ fileName = baseFileName + "-" + latestApplBuild + fileExt;
+ }
+ return fileName;
+ }
+
+ /**
+ * Returns the full {@link URL} of the application file of the the latest build.
+ */
+ public URL getLastestReleaseURL() throws IOException {
+ String fileName = getLastestReleaseFileName();
+ return IOUtil.extendURL(releaseBaseUrl, fileName);
+ }
+
+
+ /**
+ * Downloads the latest application file.
+ * @param file destination file (if {@code null} a temporary file is created)
+ * @param renew if {@code true}, the latest release is determined online (even if
+ * it was cached before)
+ */
+ public File downloadLatestRelease(File file, boolean renew) throws IOException {
+ if ( renew )
+ clearCache();
+ File applFile = IOUtil.downloadUrlToFile(getLastestReleaseURL(),
+ IOUtil.getGlobalConnectionSettings(),
+ file,
+ httpAuthUser,
+ httpAuthPW);
+ return applFile;
+ }
+
+ /**
+ * Parses a string to long. Generates no {@link Exception}, but
+ * returns 0 if string can not be parsed.
+ */
+ private long parseLong(String str) {
+ try {
+ return StringUtils.isBlank(str) ? 0: Long.parseLong(str);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * If not yet cached, the latest build number is determined by downloading the
+ * release info file from update URL.
+ */
+ public String getLastestBuild() throws IOException {
+ // To avoid unnecessary/multiple downloads the latest build number
+ // can be cached
+ if ( cachedLatestBuild != null )
+ return cachedLatestBuild;
+ return determineLastestBuild();
+ }
+
+ /**
+ * Resets a possible cached latest build, so it is determined online
+ * on the next {@link #getLastestBuild()} call.
+ */
+ public void clearCache() {
+ this.cachedLatestBuild = null;
+ }
+
+ /**
+ * Downloads the release info file from update URL and checks
+ * whether it is newer than the build of the running application.
+ */
+ public boolean checkReleaseUpdate() throws IOException {
+ // determine build of running application
+ String currApplBuildStr = ReleaseUtil.getVersionBuild(releaseClass);
+ long currApplBuild = parseLong(currApplBuildStr);
+// if ( currApplBuild <= 0 )
+// throw new IOException("No release build set for running application. Can not check for release update!");
+ // determine build of latest version
+ String latestApplBuildStr = determineLastestBuild();
+ long latestApplBuild = parseLong(latestApplBuildStr);
+ if ( latestApplBuild <= 0 )
+ throw new IOException("No release build can be determined. Can not check for release update!");
+ // check whether latest build is newer than build of running application
+ return latestApplBuild > currApplBuild;
+ }
+
+ /**
+ * Downloads the release info file from update URL and
+ * returns the containing build number.
+ */
+ public String determineLastestBuild() throws IOException {
+ // Download properties file of latest release
+ File propsFile = IOUtil.downloadUrlToFile(getLatestReleaseInfoURL(),
+ IOUtil.getGlobalConnectionSettings(),
+ null,
+ httpAuthUser,
+ httpAuthPW);
+ // Determine build number from properties
+ FileReader input = null;
+ try {
+ input = new FileReader(propsFile);
+ Properties props = new Properties();
+ props.load(input);
+ String latestBuild = props.getProperty(ReleaseUtil.PROP_BUILD);
+ // cache latest build number
+ cachedLatestBuild = latestBuild;
+ return latestBuild;
+ } finally {
+ IOUtil.closeReader(input);
+ }
+ }
+
+
+
+ /**
+ * Copies the {@code release.properties} file of the class path application
+ * to a new location.<br>
+ * Usage: {@code ReleaseUpdater <destination file> [comments]}
+ */
+ public static void main(String[] args) throws Exception {
+ if ( args.length < 1 )
+ throw new IllegalArgumentException("At least 1 parameter required\n\nUsage: ReleaseUpdater <destination file> [comments]");
+ int paramIdx = 0;
+ File dest = new File(args[paramIdx++]);
+ String comments = "";
+ if ( paramIdx < args.length )
+ comments = args[paramIdx++];
+ ReleaseUtil.createReleasePropertiesFile(null, dest, comments);
+ }
+}
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUtil.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUtil.java 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/versionnumber/ReleaseUtil.java 2013-02-27 00:03:18 UTC (rev 2259)
@@ -1,5 +1,7 @@
package de.schmitzm.versionnumber;
+import java.io.File;
+import java.io.FileWriter;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
@@ -9,8 +11,11 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
+import de.schmitzm.io.IOUtil;
+
/**
* This class provides static utility classes that help releasing and versioning applications. Especially usefull in
* combination with maven2's buildnumber-maven plugin.<br/>
@@ -72,7 +77,12 @@
</code> die Versionsnummer / Zeit ausgegeben werden.
*/
public class ReleaseUtil {
- private static Logger log = Logger.getLogger(ReleaseUtil.class);
+ /** Property which contains the version number */
+ public static final String PROP_VERSION = "version";
+ /** Property which contains the build number */
+ public static final String PROP_BUILD = "build";
+
+ private static Logger log = Logger.getLogger(ReleaseUtil.class);
/**
* Returns all (the most) information in one sting. This is a public method which never throws an Exception.
@@ -111,7 +121,7 @@
} finally {
openStream.close();
}
- final String str = releaseProps.getProperty("build", "0");
+ final String str = releaseProps.getProperty(PROP_BUILD, "0");
if (str.equals("${buildNumber}")) {
// We are in development or Maven didn't filter the properties
@@ -148,7 +158,7 @@
openStream.close();
}
- final String versionProperty = releaseProps.getProperty("version", defaultVer);
+ final String versionProperty = releaseProps.getProperty(PROP_VERSION, defaultVer);
if (versionProperty.equals("${project.version}"))
return defaultVer;
return versionProperty;
@@ -310,4 +320,38 @@
public boolean isProfileActived(Class clazz, String testProfileId) {
return getActiveProviles(clazz).contains(testProfileId);
}
+
+ /**
+ * Creates a new properties file, which contains the release properties of
+ * the running application.
+ * @param clazz
+ * Pass a class that resides in the same "project" or jar, where the /release.properties resides as well.
+ */
+ public static void createReleasePropertiesFile(Class<?> clazz, File dest, String comments) {
+ if ( clazz == null )
+ clazz = ReleaseUtil.class;
+ try {
+ final URL releasePropsURL = clazz.getResource("/release.properties");
+ final Properties releaseProps = new Properties();
+ InputStream openStream = releasePropsURL.openStream();
+ FileWriter storeStream = null;
+ try {
+ // Load existing properties
+ releaseProps.load(openStream);
+ // Store properties to new location
+ try {
+ storeStream = new FileWriter(dest);
+ releaseProps.store(storeStream, StringUtils.trimToNull(comments));
+ } catch (Exception err){
+ log.error(dest.getName()+" can not be created: "+err.getMessage(), err);
+ }
+ } finally {
+ IOUtil.closeInputStream(openStream);
+ IOUtil.closeWriter(storeStream);
+ }
+ } catch (final Exception e) {
+ log.error("/release.properties could not be read from " + clazz.getSimpleName(), e);
+ }
+ }
+
}
Modified: trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties
===================================================================
--- trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties 2013-02-27 00:03:18 UTC (rev 2259)
@@ -284,6 +284,13 @@
SwingUtil.openDesktopFile.file.not.found.general=The file can not be found.
SwingUtil.openDesktopFile.file.not.found=The file can not be found: ${0}
+SwingUtil.releaseUpdate.check.mess=Checking ${0} for update...
+SwingUtil.releaseUpdate.none.mess=Your application is up-to-date.
+SwingUtil.releaseUpdate.none.title=No update available
+SwingUtil.releaseUpdate.available.mess=A new release (v${0}) is available on ${1}.\nDo you want to download the update (${2})?
+SwingUtil.releaseUpdate.available.title=Update available
+SwingUtil.releaseUpdate.download.mess=Downloading release v${0}
+
InfoDialog.Title=Info...
InfoDialog.Header.Parameter=Parameter
InfoDialog.Header.Value=Value
@@ -338,3 +345,5 @@
ListMaintainancePanel.action.moveUp.desc=Move selected elements up in list
ListMaintainancePanel.action.moveDown=Dn
ListMaintainancePanel.action.moveDown.desc=Move selected elements down in list
+
+
Modified: trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
===================================================================
--- trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties 2013-02-25 11:47:58 UTC (rev 2258)
+++ trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties 2013-02-27 00:03:18 UTC (rev 2259)
@@ -256,6 +256,12 @@
SwingUtil.openDesktopFile.not.supported=Das \u00d6ffnen einer Datei wird von Ihrem Betriebssystem nicht unterst\u00fctzt.
SwingUtil.openDesktopFile.file.not.found.general=Die Datei ist nicht vorhanden.
SwingUtil.openDesktopFile.file.not.found=Die Datei ist nicht vorhanden: ${0}
+SwingUtil.releaseUpdate.check.mess=Pr\u00fcfe ${0} auf verf\u00fcgbare Aktualisierungen...
+SwingUtil.releaseUpdate.none.mess=Ihr Programm ist auf dem aktuellen Stand.
+SwingUtil.releaseUpdate.none.title=Keine Aktualisierung verf\u00fcgbar
+SwingUtil.releaseUpdate.available.mess=Eine neue Programmversion (v${0}) ist verf\u00fcgbar auf ${1}.\nM\u00f6chten Sie das Update (${2}) herunterladen?
+SwingUtil.releaseUpdate.available.title=Aktualisierung verf\u00fcgbar
+SwingUtil.releaseUpdate.download.mess=Download der Programmversion v${0}
InfoDialog.Title=Info...
InfoDialog.Header.Parameter=Parameter
Property changes on: trunk/schmitzm-regex
___________________________________________________________________
Modified: svn:ignore
- bin
.settings
.classpath
.project
+ bin
.settings
.classpath
.project
target
More information about the Schmitzm-commits
mailing list