FileDocCategorySizeDatePackage
AzureusRestarterImpl.javaAPI DocAzureus 3.0.3.419523Mon Jul 30 14:13:28 BST 2007com.aelitis.azureus.core.update.impl

AzureusRestarterImpl

public class AzureusRestarterImpl extends Object implements com.aelitis.azureus.core.update.AzureusRestarter

Fields Summary
private static final LogIDs
LOGID
private static final String
MAIN_CLASS
private static final String
UPDATER_JAR
private static final String
EXE_UPDATER
public static final String
UPDATE_PROPERTIES
protected static boolean
restarted
private static String
JAVA_EXEC_DIR
protected com.aelitis.azureus.core.AzureusCore
azureus_core
protected String
classpath_prefix
Constructors Summary
public AzureusRestarterImpl(com.aelitis.azureus.core.AzureusCore _azureus_core)

	
	
	
				 
	
		azureus_core	= _azureus_core;
	
Methods Summary
private java.lang.StringgetClassPath()

		String classPath = System.getProperty("java.class.path");
	    	
    	classPath = classpath_prefix + System.getProperty("path.separator") + classPath;
	    
	    return( "-classpath \"" + classPath + "\" " );
	
private java.lang.StringgetExeUpdater(java.io.PrintWriter log)

		try {
			boolean isVistaOrHigher = false;
			if (Constants.isWindows) {
				Float ver = null;
				try {
					ver = new Float(System.getProperty("os.version"));
				} catch (Exception e) {
				}
				isVistaOrHigher = ver != null && ver.floatValue() >= 6;
			}

			// Vista test: We will need to run an elevated EXE updater if we can't
			//             write to the program dir.
			
			if (isVistaOrHigher) {
				if (AzureusCoreFactory.getSingleton().getPluginManager().getDefaultPluginInterface().getUpdateManager().getInstallers().length > 0) {
					log.println("Vista restart w/Updates.. checking if EXE needed");
					try {
						final File writeFile = FileUtil.getApplicationFile("write.dll");
						// should fail if no perms, but sometimes it's created in
						// virtualstore (if ran from java(w).exe for example)
						FileOutputStream fos = new FileOutputStream(writeFile);
						fos.write(32);
						fos.close();

						writeFile.delete();

						File renameFile = FileUtil.getApplicationFile("License.txt");
						if (renameFile != null && renameFile.exists()) {
							File oldFile = FileUtil.getApplicationFile("License.txt");
							String oldName = renameFile.getName();
							File newFile = new File(renameFile.getParentFile(), oldName
									+ ".bak");
							renameFile.renameTo(newFile);

							if (oldFile.exists()) {
								log.println("Requiring EXE because rename test failed");
								return EXE_UPDATER; 
							}

							newFile.renameTo(oldFile);
						} else {
							log.println("Could not try Permission Test 2. File " + renameFile
									+ " not found");
						}

					} catch (Exception e) {
						log.println("Permission Test Failed. " + e.getMessage() + ";"
								+ Debug.getCompressedStackTrace());
						return EXE_UPDATER; 
					}
				}
			}
		} catch (Throwable t) {
			// ignore vista test
		}

		return null;
	
private java.lang.StringgetLibraryPath()

    String libraryPath = System.getProperty("java.library.path");
    
    if ( libraryPath == null ){
    	
      libraryPath = "";
      
    }else{
    	
    		// remove any quotes from the damn thing
    	
    	String	temp = "";
    	
    	for (int i=0;i<libraryPath.length();i++){
    		
    		char	c = libraryPath.charAt(i);
    		
    		if ( c != '"" ){
    			
    			temp += c;
    		}
    	}
    	
    	libraryPath	= temp;
    	
    		// remove trailing separator chars if they exist as they stuff up
    		// the following "
    	
    	while( libraryPath.endsWith(File.separator)){
    	
    		libraryPath = libraryPath.substring( 0, libraryPath.length()-1 );
    	}
    	
    	if ( libraryPath.length() > 0 ){
  
    		libraryPath = "-Djava.library.path=\"" + libraryPath + "\" ";
    	}
    }
    
    return( libraryPath );
  
private intgetUnixScriptVersion()

		String sVersion = System.getProperty("azureus.script.version", "0");
		int version = 0;
		try {
			version = Integer.parseInt(sVersion);
		} catch (Throwable t) {
		}
		return version;
  
private booleanjavaSpawn(java.io.PrintWriter log, java.lang.String execString)

		try {
			// hmm, try java method - this WILL inherit handles but might work :)

			log.println("Using java spawn");

			//NOTE: no logging done here, as we need the method to return right away, before the external process completes
			Process p = Runtime.getRuntime().exec(execString);

			log.println("    -> " + p);

			return true;
		} catch (Throwable g) {

			g.printStackTrace();
			return false;
		}
	
public voidrestart(boolean update_only)

		if ( restarted ){
			
			Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
					"AzureusRestarter: already restarted!!!!"));
			
			return;
		}
		
		restarted	= true;
		
		PluginInterface pi = azureus_core.getPluginManager().getPluginInterfaceByID( "azupdater" );
		
		if ( pi == null ){
			Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR,
					"Can't restart, mandatory plugin 'azupdater' not found"));
			
			return;
		}
		
		String	updater_dir = pi.getPluginDirectoryName();
		
		classpath_prefix = updater_dir + File.separator + UPDATER_JAR;
		
 	 	String	app_path = SystemProperties.getApplicationPath();
	  	
	  	while( app_path.endsWith(File.separator)){
	  		
	  		app_path = app_path.substring(0,app_path.length()-1);
	  	}
	  	
	 	String	user_path = SystemProperties.getUserPath();
	  	
	  	while( user_path.endsWith(File.separator)){
	  		
	  		user_path = user_path.substring(0,user_path.length()-1);
	  	}
	  	
	  	String config_override = System.getProperty( SystemProperties.SYS_PROP_CONFIG_OVERRIDE );
	  	
	  	if ( config_override == null ){
	  		
	  		config_override = "";
	  	}
	  	
	  	String[]	parameters = {
	  			update_only?"updateonly":"restart",
	  			app_path,
	  			user_path,
				config_override,
	  	};
	  	
	  	FileOutputStream	fos	= null;
	  	
	  	try{
	  		Properties	restart_properties = new Properties();
	  	
	  		long	max_mem = Runtime.getRuntime().maxMemory();
	  			  			  			
	  		restart_properties.put( "max_mem", ""+max_mem );
	  		restart_properties.put( "app_name", SystemProperties.getApplicationName());
	  		restart_properties.put( "app_entry", SystemProperties.getApplicationEntryPoint());
	  		
	  		if ( System.getProperty( "azureus.nativelauncher" ) != null || Constants.isOSX ){
	  			//NOTE: new 2306 osx bundle now sets azureus.nativelauncher=1, but older bundles dont
	  			
	  			try{
		  			String	cmd = PlatformManagerFactory.getPlatformManager().getApplicationCommandLine();
		  			
		  			if ( cmd != null ){
		  				
		  				restart_properties.put( "app_cmd", cmd );
		  			}
	  			}catch( Throwable e ){
	  				
	  				Debug.printStackTrace(e);
	  			}
	  		}	  		
	  		
	  		
	  		fos	= new FileOutputStream( new File( user_path, UPDATE_PROPERTIES ));
	  		
	  			// this handles unicode chars by writing \\u escapes
	  		
	  		restart_properties.store(fos, "Azureus restart properties" );
	  		
	  	}catch( Throwable e ){
	  		
	  		Debug.printStackTrace( e );
	  		
	  	}finally{
	  		
	  		if ( fos != null ){
	  			
	  			try{
	  				
	  				fos.close();
	  				
	  			}catch( Throwable e ){
	  				
	  				Debug.printStackTrace(e);
	  			}
	  		}
	  	}
	  	
	  	String[]	properties = { "-Duser.dir=\"" + app_path + "\"" };
	  	
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		
		restartAzureus(new PrintWriter(os) {
			public void println(String str) {
				// we intercept these logs and log immediately
				Logger.log(new LogEvent(LOGID, str));
			}

		}, MAIN_CLASS, properties, parameters, update_only);
		
			// just check if any non-logged data exists
		
		byte[]	bytes = os.toByteArray();
		
		if ( bytes.length > 0 ){
			
			Logger.log(new LogEvent(LOGID, "AzureusRestarter: extra log - "
					+ new String(bytes)));
		}
	
public voidrestartAzureus(java.io.PrintWriter log, java.lang.String mainClass, java.lang.String[] properties, java.lang.String[] parameters, boolean update_only)

    if(Constants.isOSX){
    	
    	restartAzureus_OSX(log,mainClass,properties,parameters);
    	
    }else if( Constants.isUnix ){
    	
    	restartAzureus_Unix(log,mainClass,properties,parameters);
      
    }else{
    	
    	restartAzureus_win32(log,mainClass,properties,parameters,update_only);
    }
  
private voidrestartAzureus_OSX(java.io.PrintWriter log, java.lang.String mainClass, java.lang.String[] properties, java.lang.String[] parameters)


     String exec = "\"" + JAVA_EXEC_DIR + "java\" " + getClassPath() + getLibraryPath();
  	 
     for (int i=0;i<properties.length;i++){
    	 exec += properties[i] + " ";
     }
    
     exec += mainClass ;
    
     for(int i = 0 ; i < parameters.length ; i++) {
    	 exec += " \"" + parameters[i] + "\"";
     }

     runExternalCommandViaUnixShell( log, exec );
  
private voidrestartAzureus_Unix(java.io.PrintWriter log, java.lang.String mainClass, java.lang.String[] properties, java.lang.String[] parameters)

    
    String exec = "\"" + JAVA_EXEC_DIR + "java\" " + getClassPath() +	getLibraryPath();
    
    for (int i=0;i<properties.length;i++){
      exec += properties[i] + " ";
    }
    
    int scriptVersion = getUnixScriptVersion();
    boolean restartByScript = Constants.compareVersions(
				UpdaterUtils.getUpdaterPluginVersion(), "1.8.5") >= 0
				&& scriptVersion > 0; 
    if (restartByScript) {
    	exec += "-Dazureus.script.version=\"" + scriptVersion + "\" ";
    }
    
    exec += mainClass ;
    
    for(int i = 0 ; i < parameters.length ; i++) {
      exec += " \"" + parameters[i] + "\"";
    }
    
  	if (restartByScript) {
  		// run script after az shutdown to launch updater and then re-run az
  		ScriptAfterShutdown.addExtraCommand("echo \"Applying (possible) patches before restarting..\"\n"
  				+ exec + "\n"
					+ "echo \"Restarting Azureus..\"\n"
					+ "$0\n");
			ScriptAfterShutdown.setRequiresExit(true);
  	} else {
  		runExternalCommandViaUnixShell( log, exec );
  	}
  
private voidrestartAzureus_win32(java.io.PrintWriter log, java.lang.String mainClass, java.lang.String[] properties, java.lang.String[] parameters, boolean update_only)

  	String exeUpdater = getExeUpdater(log);  // Not for Updater.java

  	String exec;

		//Classic restart way using Runtime.exec directly on java(w)
		exec = "\"" + JAVA_EXEC_DIR + "javaw\" " + getClassPath() + getLibraryPath();

		for (int i = 0; i < properties.length; i++) {
			exec += properties[i] + " ";
		}

		exec += mainClass;

		for (int i = 0; i < parameters.length; i++) {
			exec += " \"" + parameters[i] + "\"";
		}

		if (exeUpdater != null) {
			restartViaEXE(log, exeUpdater, properties, parameters, exec, update_only);
		} else {
			if (log != null) {
				log.println("  " + exec);
			}

			if (!win32NativeRestart(log, exec)) {
				javaSpawn(log, exec);
			}
		}
	
private booleanrestartViaEXE(java.io.PrintWriter log, java.lang.String exeUpdater, java.lang.String[] properties, java.lang.String[] parameters, java.lang.String backupJavaRunString, boolean update_only)

		String azRunner = null;
		File fileRestart = null;
		if (!update_only) {
  		try {
  			azRunner = PlatformManagerFactory.getPlatformManager().getApplicationCommandLine();
  		} catch (PlatformManagerException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		}
		}

		try {
			int result;
			AEWin32Access accessor = AEWin32Manager.getAccessor(true);
			if (accessor == null) {
				result = -123;
			} else {
				if (azRunner != null) {
					// create a batch file to run the updater, then to restart azureus
					// bceause the updater would restart azureus as administrator user
					// and confuse the user
					fileRestart = FileUtil.getUserFile("restart.bat");
					String s = "title Azureus Updater Runner\r\n";
					s += exeUpdater + " \"updateonly\"";
					for (int i = 1; i < parameters.length; i++) {
						s += " \"" + parameters[i].replaceAll("\\\"", "") + "\"";
					}
					s += "\r\n";
					s += "start \"\" \"" + azRunner + "\"";
					FileUtil.writeBytesAsFile(fileRestart.getAbsolutePath(), s.getBytes());

					result = accessor.shellExecute(null, fileRestart.getAbsolutePath(),
							null, SystemProperties.getApplicationPath(),
							AEWin32Access.SW_SHOWMINIMIZED);
				} else {
					String execEXE = "\"-J" + getClassPath().replaceAll("\\\"", "")
							+ "\" ";

					for (int i = 0; i < properties.length; i++) {
						execEXE += "\"-J" + properties[i].replaceAll("\\\"", "") + "\" ";
					}

					for (int i = 0; i < parameters.length; i++) {
						execEXE += " \"" + parameters[i].replaceAll("\\\"", "") + "\"";
					}

					log.println("Launch via " + exeUpdater + " params " + execEXE);
					result = accessor.shellExecute(null, exeUpdater, execEXE,
							SystemProperties.getApplicationPath(), AEWin32Access.SW_NORMAL);
				}
			}

			/*
			 * Some results:
			 * 0: OOM
			 * 2: FNF
			 * 3: Path Not Foud
			 * 5: Access Denied (User clicked cancel on admin access dialog)
			 * 8: OOM
			 * 11: Bad Format
			 * 26: Sharing Violation
			 * 27: Association incomplete
			 * 28: DDE Timeout
			 * 29: DDE Fail
			 * 30: DDE Busy
			 * 31: No Association
			 * 32: DLL Not found
			 * >32: OK!
			 */
			log.println("   -> " + result);

			if (result <= 32) {
				String sErrorReason = "";
				String key = null;

				switch (result) {
					case 0:
					case 8:
						key = "oom";
						break;

					case 2:
						key = "fnf";
						break;

					case 3:
						key = "pnf";
						break;

					case 5:
						key = "denied";
						break;

					case 11:
						key = "bad";
						break;

					case -123:
						key = "nowin32";
						break;

					default:
						sErrorReason = "" + result;
						break;
				}
				if (key != null) {
					sErrorReason = MessageText.getString("restart.error." + key,
							new String[] {
								exeUpdater,
								SystemProperties.getApplicationPath(),
							});
				}
				Logger.log(new LogAlert(false, LogAlert.AT_ERROR,
						MessageText.getString("restart.error", new String[] {
							sErrorReason
						})));
				return false;
			}
		} catch (Throwable f) {

			f.printStackTrace(log);

			return javaSpawn(log, backupJavaRunString);
		}

		return true;
	
private voidrunExternalCommandViaUnixShell(java.io.PrintWriter log, java.lang.String command)

  	String[] to_run = new String[3];
  	to_run[0] = "/bin/sh";
  	to_run[1] = "-c";
  	to_run[2] = command;
   	 
  	if( log != null )  log.println("Executing: R:[" +to_run[0]+ " " +to_run[1]+ " " +to_run[2]+ "]" );

  	try {
  		//NOTE: no logging done here, as we need the method to return right away, before the external process completes
  		Runtime.getRuntime().exec( to_run );	
  	}
  	catch(Throwable t) {
  		if( log != null )  {
  			log.println( t.getMessage() != null ? t.getMessage() : "<null>" );
  			log.println( t );
  			t.printStackTrace( log );
  		}
  		else {
  			t.printStackTrace();
  		}
  	}
  
private booleanwin32NativeRestart(java.io.PrintWriter log, java.lang.String exec)

	    try{
	    		// we need to spawn without inheriting handles
	    	
	    	PlatformManager pm = PlatformManagerFactory.getPlatformManager();
	    	
	    	pm.createProcess( exec, false );
	    
	    	return( true );
	    	
	    }catch(Throwable e) {
	        e.printStackTrace(log);
	        
	        return( false );
	    }