Coverage Report - us.daveread.basicquery.util.CheckLatestVersion
 
Classes in this File Line Coverage Branch Coverage Complexity
CheckLatestVersion
0%
0/79
0%
0/11
0
 
 1  
 package us.daveread.basicquery.util;
 2  
 
 3  
 import java.io.BufferedReader;
 4  
 import java.io.InputStreamReader;
 5  
 import java.io.Reader;
 6  
 import java.io.StringReader;
 7  
 import java.net.URL;
 8  
 import java.net.URLConnection;
 9  
 import java.util.Observable;
 10  
 import java.util.regex.Matcher;
 11  
 import java.util.regex.Pattern;
 12  
 
 13  
 import org.apache.log4j.Logger;
 14  
 
 15  
 /**
 16  
  * Checks for the latest version information. Version identifier string must be
 17  
  * in the form of MAJOR#.MINOR#.PATCH# with 1 or 2 digits for each part.
 18  
  * 
 19  
  * e.g. 1.8.3
 20  
  * 
 21  
  * @author David Read
 22  
  * 
 23  
  */
 24  
 public class CheckLatestVersion extends Observable implements Runnable {
 25  
   /**
 26  
    * URL to version information
 27  
    */
 28  
   private static final String VERSION_INFO_URL = "http://monead.com/basicquery/basicquery_version.txt";
 29  
 
 30  
   /**
 31  
    * Logger Instance
 32  
    */
 33  0
   private static final Logger LOGGER = Logger.getLogger(CheckLatestVersion.class);
 34  
 
 35  
   /**
 36  
    * Maximum number of lines in the upgrade message
 37  
    */
 38  
   private static final int MAX_NEW_FEATURES_MESSAGE_LINES = 10;
 39  
 
 40  
   /**
 41  
    * The current version of the application
 42  
    */
 43  
   private String currentVersion;
 44  
 
 45  
   /**
 46  
    * The calculated value of the latest version. Used in order to identify
 47  
    * keep track of the most recent version identified from the list of newer
 48  
    * versions.
 49  
    */
 50  
   private int latestVersionValue;
 51  
 
 52  
   /**
 53  
    * Information regarding the newest version. This is only created if there is
 54  
    * a newer version than the currently running version.
 55  
    */
 56  
   private NewVersionInformation newVersionInformation;
 57  
 
 58  
   /**
 59  
    * Create an instance that will identify if a version newer than the supplied
 60  
    * one exists.
 61  
    * 
 62  
    * @param pCurrentVersion
 63  
    *          The current version (#.#.# format)
 64  
    */
 65  0
   public CheckLatestVersion(String pCurrentVersion) {
 66  0
     currentVersion = pCurrentVersion;
 67  0
   }
 68  
 
 69  
   @Override
 70  
   public void run() {
 71  0
     setupVersionInfo();
 72  
 
 73  0
     if (newVersionInformation != null) {
 74  0
       setChanged();
 75  0
       notifyObservers(newVersionInformation);
 76  
     }
 77  0
   }
 78  
 
 79  
   /**
 80  
    * Get version information from the website and check if any listed versions
 81  
    * are newer than the current version.
 82  
    */
 83  
   private void setupVersionInfo() {
 84  0
     final String latestVersionDetails = getVersionInfoFromWebsite();
 85  
 
 86  0
     if (latestVersionDetails != null) {
 87  0
       setupVersionMessage(latestVersionDetails);
 88  
     }
 89  0
   }
 90  
 
 91  
   /**
 92  
    * Download the version history information from the website.
 93  
    * 
 94  
    * @return The version history information
 95  
    */
 96  
   private String getVersionInfoFromWebsite() {
 97  0
     String informationFromWebsite = null;
 98  
 
 99  
     try {
 100  0
       final URL url = new URL(VERSION_INFO_URL);
 101  0
       final URLConnection con = url.openConnection();
 102  0
       final Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
 103  0
       final Matcher m = p.matcher(con.getContentType());
 104  
 
 105  
       /*
 106  
        * If Content-Type doesn't match this pre-conception, choose default and
 107  
        * hope for the best.
 108  
        */
 109  0
       final String charset = m.matches() ? m.group(1) : "UTF-8";
 110  
 
 111  0
       final Reader r = new InputStreamReader(con.getInputStream(), charset);
 112  0
       final StringBuilder buf = new StringBuilder();
 113  
       while (true) {
 114  0
         final int ch = r.read();
 115  0
         if (ch < 0) {
 116  0
           break;
 117  
         }
 118  0
         buf.append((char) ch);
 119  0
       }
 120  0
       informationFromWebsite = buf.toString();
 121  
 
 122  0
       LOGGER.debug("Got version information from website: "
 123  
           + informationFromWebsite);
 124  
 
 125  0
     } catch (Throwable throwable) {
 126  0
       LOGGER.warn("Unable to get version information from website", throwable);
 127  0
     }
 128  
 
 129  0
     return informationFromWebsite;
 130  
   }
 131  
 
 132  
   /**
 133  
    * Determine if a newer version of the application exists and if so setup the
 134  
    * newVersionInformation instance with information regarding the newest
 135  
    * version.
 136  
    * 
 137  
    * @param informationFromWebsite
 138  
    *          Downloadeed version information
 139  
    */
 140  
   private void setupVersionMessage(String informationFromWebsite) {
 141  0
     final int myVersion = versionParser(currentVersion);
 142  0
     String line = null;
 143  0
     int lineNumber = 0;
 144  
     int version;
 145  0
     boolean newFeatures = false;
 146  0
     int linesOfMessage = 0;
 147  
 
 148  
     try {
 149  0
       if (informationFromWebsite != null) {
 150  0
         final BufferedReader in = new BufferedReader(new StringReader(
 151  
             informationFromWebsite));
 152  
 
 153  0
         while ((line = in.readLine()) != null) {
 154  0
           line = line.trim();
 155  0
           ++lineNumber;
 156  0
           LOGGER.debug("Version file line: " + line);
 157  0
           if (line.startsWith("VERSION:")) {
 158  0
             version = versionParser(line.split(":")[1].trim());
 159  0
             if (version > myVersion) {
 160  0
               LOGGER.debug("Newer version found: " + version);
 161  0
               newFeatures = true;
 162  0
               if (newVersionInformation == null) {
 163  0
                 newVersionInformation = new NewVersionInformation();
 164  
                 // TODO encode download locations into website info file
 165  
                 try {
 166  0
                   newVersionInformation.setUrlToDownloadPage(new URL(
 167  
                       "http://monead.com/basicquery"));
 168  0
                   newVersionInformation.setUrlToSourceCode(new URL(
 169  
                       "https://github.com/DaveRead/BasicQuery"));
 170  0
                 } catch (Throwable throwable) {
 171  0
                   LOGGER.warn("Error configuring program download URLs",
 172  
                       throwable);
 173  0
                 }
 174  
               }
 175  0
               if (version > latestVersionValue) {
 176  0
                 latestVersionValue = version;
 177  0
                 newVersionInformation.setLatestVersion(line.split(":")[1]
 178  
                     .trim());
 179  0
                 LOGGER.debug("Latest version found: "
 180  
                     + newVersionInformation.getLatestVersion());
 181  
               }
 182  
             } else {
 183  0
               newFeatures = false;
 184  
             }
 185  0
           } else if (newFeatures && line.length() > 0
 186  
               && linesOfMessage < MAX_NEW_FEATURES_MESSAGE_LINES) {
 187  0
             LOGGER.debug("Adding a new feature message: " + line);
 188  0
             newVersionInformation.addNewFeatureMessage(line);
 189  0
             ++linesOfMessage;
 190  
           }
 191  
         }
 192  
 
 193  
       }
 194  0
     } catch (Throwable throwable) {
 195  0
       LOGGER.warn("Error parsing information from version file at line "
 196  
           + lineNumber + ": " + line, throwable);
 197  0
     }
 198  
 
 199  0
   }
 200  
 
 201  
   /**
 202  
    * Converts a version string MAJOR#.MINOR#.PATCH# into an integer so that
 203  
    * versions can be compared numerically. There can only be 1 or 2 digits for
 204  
    * each value for this to work properly.
 205  
    * 
 206  
    * @param version
 207  
    *          The version string (#.#.#)
 208  
    * 
 209  
    * @return An integer value suitable for comparing versions numerically
 210  
    */
 211  
   private int versionParser(String version) {
 212  0
     int versionValue = -1;
 213  
 
 214  0
     LOGGER.debug("Calculate version number for version: " + version);
 215  
     try {
 216  0
       final String[] parsed = version.split("\\.");
 217  0
       versionValue = Integer.parseInt(parsed[0]) * 10000;
 218  0
       versionValue += Integer.parseInt(parsed[1]) * 100;
 219  0
       versionValue += Integer.parseInt(parsed[2]);
 220  0
     } catch (Throwable throwable) {
 221  0
       LOGGER.warn("Unable to parse version number: " + version, throwable);
 222  0
     }
 223  
 
 224  0
     LOGGER.debug("Version calculation result for version: " + version
 225  
         + "  Value:" + versionValue);
 226  
 
 227  0
     return versionValue;
 228  
   }
 229  
 }