2014-04-05 10:39:10 +02:00
package com.rarchives.ripme.ui ;
2014-04-09 08:33:26 +02:00
import java.awt.Desktop ;
2014-04-05 11:11:04 +02:00
import java.io.File ;
2014-04-05 10:39:10 +02:00
import java.io.FileOutputStream ;
import java.io.IOException ;
import javax.swing.JLabel ;
2014-04-06 01:57:54 +02:00
import javax.swing.JOptionPane ;
2014-04-05 10:39:10 +02:00
2014-04-09 08:33:26 +02:00
import org.apache.commons.io.FileUtils ;
2014-04-05 11:11:04 +02:00
import org.apache.log4j.Logger ;
2014-04-05 10:39:10 +02:00
import org.json.JSONArray ;
import org.json.JSONObject ;
import org.jsoup.Connection.Response ;
import org.jsoup.Jsoup ;
import org.jsoup.nodes.Document ;
public class UpdateUtils {
2014-04-05 11:11:04 +02:00
private static final Logger logger = Logger . getLogger ( UpdateUtils . class ) ;
2014-04-09 08:33:26 +02:00
private static final String DEFAULT_VERSION = " 1.0.13 " ;
2014-04-05 10:39:10 +02:00
private static final String updateJsonURL = " http://rarchives.com/ripme.json " ;
private static final String updateJarURL = " http://rarchives.com/ripme.jar " ;
2014-04-05 11:11:04 +02:00
private static final String mainFileName = " ripme.jar " ;
private static final String updateFileName = " ripme.jar.update " ;
2014-04-05 10:39:10 +02:00
2014-04-05 11:11:04 +02:00
public static String getThisJarVersion ( ) {
String thisVersion = UpdateUtils . class . getPackage ( ) . getImplementationVersion ( ) ;
if ( thisVersion = = null ) {
// Version is null if we're not running from the JAR
thisVersion = DEFAULT_VERSION ; ; // Super-high version number
}
return thisVersion ;
}
2014-04-05 10:39:10 +02:00
public static void updateProgram ( JLabel configUpdateLabel ) {
2014-04-06 01:57:54 +02:00
configUpdateLabel . setText ( " Checking for update... " ) ;
2014-04-05 10:39:10 +02:00
Document doc = null ;
try {
doc = Jsoup . connect ( UpdateUtils . updateJsonURL )
. ignoreContentType ( true )
. get ( ) ;
} catch ( IOException e ) {
2014-04-05 11:11:04 +02:00
logger . error ( " Error while fetching update: " , e ) ;
2014-04-06 01:57:54 +02:00
JOptionPane . showMessageDialog ( null ,
" <html><font color= \" red \" >Error while fetching update: " + e . getMessage ( ) + " </font></html> " ,
" RipMe Updater " ,
JOptionPane . ERROR_MESSAGE ) ;
2014-04-05 10:39:10 +02:00
return ;
2014-04-06 01:57:54 +02:00
} finally {
configUpdateLabel . setText ( " Current version: " + getThisJarVersion ( ) ) ;
2014-04-05 10:39:10 +02:00
}
String jsonString = doc . body ( ) . html ( ) . replaceAll ( " " " , " \" " ) ;
JSONObject json = new JSONObject ( jsonString ) ;
JSONArray jsonChangeList = json . getJSONArray ( " changeList " ) ;
2014-04-06 01:57:54 +02:00
StringBuilder changeList = new StringBuilder ( ) ;
2014-04-05 10:39:10 +02:00
for ( int i = 0 ; i < jsonChangeList . length ( ) ; i + + ) {
String change = jsonChangeList . getString ( i ) ;
2014-04-06 01:57:54 +02:00
changeList . append ( " <br> + " + change ) ;
2014-04-05 10:39:10 +02:00
}
String latestVersion = json . getString ( " latestVersion " ) ;
if ( UpdateUtils . isNewerVersion ( latestVersion ) ) {
2014-04-06 01:57:54 +02:00
int result = JOptionPane . showConfirmDialog (
null ,
" <html><font color= \" green \" >New version ( " + latestVersion + " ) is available!</font> "
+ " <br><br>Recent changes: " + changeList . toString ( )
+ " <br><br>Do you want to download and run the newest version?</html> " ,
" RipMe Updater " ,
JOptionPane . YES_NO_OPTION ) ;
if ( result ! = JOptionPane . YES_OPTION ) {
configUpdateLabel . setText ( " <html>Current Version: " + getThisJarVersion ( )
+ " <br><font color= \" green \" >Latest version: " + latestVersion + " </font></html> " ) ;
return ;
}
configUpdateLabel . setText ( " <html><font color= \" green \" >Downloading new version...</font></html> " ) ;
2014-04-05 11:11:04 +02:00
logger . info ( " New version found, downloading... " ) ;
2014-04-05 10:39:10 +02:00
try {
2014-04-09 08:33:26 +02:00
UpdateUtils . downloadJarAndLaunch ( updateJarURL ) ;
2014-04-05 10:39:10 +02:00
} catch ( IOException e ) {
2014-04-06 01:57:54 +02:00
JOptionPane . showMessageDialog ( null ,
" Error while updating: " + e . getMessage ( ) ,
" RipMe Updater " ,
JOptionPane . ERROR_MESSAGE ) ;
configUpdateLabel . setText ( " " ) ;
2014-04-05 11:11:04 +02:00
logger . error ( " Error while updating: " , e ) ;
2014-04-05 10:39:10 +02:00
return ;
}
} else {
2014-04-06 01:57:54 +02:00
configUpdateLabel . setText ( " <html><font color= \" green \" >v " + UpdateUtils . getThisJarVersion ( ) + " is the latest version</font></html> " ) ;
2014-04-05 11:11:04 +02:00
logger . info ( " Running latest version: " + UpdateUtils . getThisJarVersion ( ) ) ;
2014-04-05 10:39:10 +02:00
}
}
private static boolean isNewerVersion ( String latestVersion ) {
int [ ] oldVersions = versionStringToInt ( getThisJarVersion ( ) ) ;
int [ ] newVersions = versionStringToInt ( latestVersion ) ;
if ( oldVersions . length < newVersions . length ) {
System . err . println ( " Calculated: " + oldVersions + " < " + latestVersion ) ;
return true ;
}
for ( int i = 0 ; i < oldVersions . length ; i + + ) {
if ( newVersions [ i ] > oldVersions [ i ] ) {
2014-04-05 11:11:04 +02:00
logger . debug ( " oldVersion " + getThisJarVersion ( ) + " < latestVersion " + latestVersion ) ;
2014-04-05 10:39:10 +02:00
return true ;
}
else if ( newVersions [ i ] < oldVersions [ i ] ) {
2014-04-05 11:11:04 +02:00
logger . debug ( " oldVersion " + getThisJarVersion ( ) + " > latestVersion " + latestVersion ) ;
2014-04-05 10:39:10 +02:00
return false ;
}
else {
continue ;
}
}
// At this point, the version numbers are exactly the same.
// Assume any additional changes to the version text means a new version
return ! ( latestVersion . equals ( getThisJarVersion ( ) ) ) ;
}
private static int [ ] versionStringToInt ( String version ) {
String strippedVersion = version . split ( " - " ) [ 0 ] ;
String [ ] strVersions = strippedVersion . split ( " \\ . " ) ;
int [ ] intVersions = new int [ strVersions . length ] ;
for ( int i = 0 ; i < strVersions . length ; i + + ) {
intVersions [ i ] = Integer . parseInt ( strVersions [ i ] ) ;
}
return intVersions ;
}
2014-04-05 11:11:04 +02:00
2014-04-09 08:33:26 +02:00
private static void downloadJarAndLaunch ( String updateJarURL )
2014-04-05 11:11:04 +02:00
throws IOException {
Response response ;
response = Jsoup . connect ( updateJarURL )
. ignoreContentType ( true )
. timeout ( 60000 )
. maxBodySize ( 1024 * 1024 * 100 )
. execute ( ) ;
FileOutputStream out = new FileOutputStream ( updateFileName ) ;
out . write ( response . bodyAsBytes ( ) ) ;
out . close ( ) ;
2014-04-09 08:33:26 +02:00
logger . info ( " Download of new version complete; saved to " + updateFileName ) ;
Runtime . getRuntime ( ) . addShutdownHook ( new Thread ( ) {
@Override
public void run ( ) {
try {
logger . info ( " Executing: java -jar " + updateFileName ) ;
Runtime . getRuntime ( ) . exec ( new String [ ] { " java " , " -jar " , updateFileName } ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
}
} ) ;
logger . info ( " Exiting older version, should execute updated jar ( " + updateFileName + " ) during exit " ) ;
2014-04-05 11:11:04 +02:00
System . exit ( 0 ) ;
}
public static void moveUpdatedJar ( ) {
2014-04-09 08:33:26 +02:00
// Copy the new file (ripme.jar.update) to original location (ripme.jar)
// Delete new file (update) on exit
// Exit
File newFile = new File ( updateFileName ) ; // ripme.jar.update
File oldFile = new File ( mainFileName ) ; // ripme.jar
2014-04-05 11:11:04 +02:00
if ( ! newFile . exists ( ) ) {
// Can't update without .update file
return ;
}
2014-04-09 08:33:26 +02:00
// Attempt to copy new .jar file over old jar file.
int retries = 3 ;
while ( true ) {
retries - - ;
2014-04-05 11:11:04 +02:00
try {
2014-04-09 08:33:26 +02:00
logger . info ( " Updated .jar file ' " + newFile + " ' exists, overwriting older version at " + oldFile + " ... " ) ;
FileUtils . copyFile ( newFile , oldFile ) ;
break ; // Copy was successful; break.
}
catch ( IOException e ) {
logger . error ( " Failed to copy the updated jar over the original jar. \ nUpdated Jar: \ t " + newFile + " \ nOriginal Jar: " + oldFile ) ;
if ( retries < 0 ) {
// We failed!
// Show error messages, pop up message dialog, and open the directory containing jars
logger . error ( " Cannot ovewrite existing jar file " + oldFile + " with updated file " + newFile + " ... Please update by moving files manually " ) ;
try {
Desktop . getDesktop ( ) . open ( newFile . getParentFile ( ) ) ;
} catch ( IOException ioe ) {
logger . error ( " Error while opening directory " + newFile . getParentFile ( ) , ioe ) ;
}
JOptionPane . showMessageDialog ( null ,
" Failed to copy the updated .jar file over the original .jar file \ nUpdated Jar: \ t " + newFile + " \ nOriginal Jar: " + oldFile + " \ n \ nPlease update by moving files manually " ,
" RipMe Updater Error " ,
JOptionPane . ERROR_MESSAGE ) ;
System . exit ( 1 ) ;
return ;
}
e . printStackTrace ( ) ;
try {
logger . warn ( " Waiting 1 second, copy retries remaining: " + retries ) ;
Thread . sleep ( 1000 ) ;
} catch ( InterruptedException ie ) {
logger . error ( " Interrupted while waiting for original jar " + oldFile + " to be overwritten " , ie ) ;
return ;
}
2014-04-05 11:11:04 +02:00
}
}
2014-04-09 08:33:26 +02:00
// Delete the updated .jar on exit
if ( newFile . exists ( ) ) {
logger . info ( " Will delete ' " + newFile + " ' on exit " ) ;
try {
FileUtils . forceDeleteOnExit ( newFile ) ;
}
catch ( Exception e ) {
logger . error ( " Failed to schedule delete on file: " + newFile ) ;
return ;
}
2014-04-05 11:11:04 +02:00
}
2014-04-09 08:33:26 +02:00
// Execute the copied, updated .jar at ripme.jar
2014-04-05 11:11:04 +02:00
try {
2014-04-09 08:33:26 +02:00
String [ ] command = new String [ ] {
" java " ,
" -jar " ,
oldFile . getName ( ) } ;
logger . info ( " Executing: " + command [ 0 ] + " " + command [ 1 ] + " " + command [ 2 ] ) ;
Runtime . getRuntime ( ) . exec ( command ) ;
logger . info ( " Started new version at " + oldFile . getName ( ) + " , quitting current program... " ) ;
2014-04-05 11:11:04 +02:00
System . exit ( 0 ) ;
2014-04-09 08:33:26 +02:00
}
catch ( IOException e ) {
logger . error ( " Error while executing new jar ' " + oldFile . getName ( ) + " ' " , e ) ;
2014-04-05 11:11:04 +02:00
return ;
}
}
2014-04-05 10:39:10 +02:00
}