[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