Package org.gudy.azureus2.update

Source Code of org.gudy.azureus2.update.CoreUpdateChecker

/*
* Created on 20-May-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package org.gudy.azureus2.update;

/**
* @author parg
*
*/

import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.net.*;
import java.io.*;

import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.html.*;
import org.gudy.azureus2.core3.internat.MessageText;

import org.gudy.azureus2.platform.win32.access.AEWin32Access;
import org.gudy.azureus2.platform.win32.access.AEWin32Manager;
import org.gudy.azureus2.plugins.*;
import org.gudy.azureus2.plugins.logging.LoggerChannel;
import org.gudy.azureus2.plugins.ui.UIManager;
import org.gudy.azureus2.plugins.ui.UIManagerEvent;
import org.gudy.azureus2.plugins.update.*;
import org.gudy.azureus2.plugins.utils.StaticUtilities;
import org.gudy.azureus2.plugins.utils.resourcedownloader.*;

import com.aelitis.azureus.core.util.GeneralUtils;
import com.aelitis.azureus.core.versioncheck.*;
import com.aelitis.azureus.ui.UIFunctions;
import com.aelitis.azureus.ui.UIFunctionsManager;


public class
CoreUpdateChecker
  implements Plugin, UpdatableComponent
{   
  public static final String  LATEST_VERSION_PROPERTY  = "latest_version";
  public static final String  MESSAGE_PROPERTY    = "message";
 
  public static final int  RD_GET_DETAILS_RETRIES  = 3;
  public static final int  RD_GET_MIRRORS_RETRIES  = 3;
 
  public static final int  RD_SIZE_RETRIES  = 3;
  public static final int  RD_SIZE_TIMEOUT  = 10000;

  protected static CoreUpdateChecker    singleton;
 
  protected PluginInterface        plugin_interface;
  protected ResourceDownloaderFactory   rdf;
  protected LoggerChannel          log;
  protected ResourceDownloaderListener  rd_logger;
 
  protected boolean            first_check    = true;
 
  public static void
  doUsageStats()
  {
    singleton.doUsageStatsSupport();
  }
 
  public
  CoreUpdateChecker()
  {
    singleton  = this;
  }
 
  protected void
  doUsageStatsSupport()
  {
    try{
      Map decoded = VersionCheckClient.getSingleton().getVersionCheckInfo(
              first_check?VersionCheckClient.REASON_UPDATE_CHECK_START:VersionCheckClient.REASON_UPDATE_CHECK_PERIODIC);
       
      displayUserMessage( decoded );
     
    }finally{
     
        first_check  = false;
    }
  }

 
  public void
  initialize(
    PluginInterface    _plugin_interface )
  {
    plugin_interface  = _plugin_interface;
   
    plugin_interface.getPluginProperties().setProperty( "plugin.name", "Core Updater" );
   
    log  = plugin_interface.getLogger().getChannel("CoreUpdater");
   
    rd_logger =
      new ResourceDownloaderAdapter()
      {
        public void
        reportActivity(
          ResourceDownloader  downloader,
          String        activity )
        {
          log.log( activity );
        }
      };
     
    Properties  props = plugin_interface.getPluginProperties();
             
    props.setProperty( "plugin.version", plugin_interface.getAzureusVersion());
   
    rdf = plugin_interface.getUtilities().getResourceDownloaderFactory();
 
    plugin_interface.getUpdateManager().registerUpdatableComponent( this, true );
  }
 
  public String
  getName()
  {
    return( "Azureus Core" );
  }
 
  public int
  getMaximumCheckTime()
  {
    return( ( RD_SIZE_RETRIES * RD_SIZE_TIMEOUT )/1000);
 

  public void
  checkForUpdate(
    final UpdateChecker  checker )
  {
    try{     
      String  current_version = plugin_interface.getAzureusVersion();
     
      log.log( "Update check starts: current = " + current_version );
                         
      Map  decoded = VersionCheckClient.getSingleton().getVersionCheckInfo(
            first_check?VersionCheckClient.REASON_UPDATE_CHECK_START:VersionCheckClient.REASON_UPDATE_CHECK_PERIODIC);

     
      displayUserMessage( decoded );
     
      // No point complaining later if we don't have any data in the map (which is
      // more likely due to network problems rather than the version check server
      // *actually* returning a map with nothing in it.
      if (decoded.isEmpty()) {return;}
     
      String latest_version;
      String latest_file_name;
     
      byte[] b_version = (byte[])decoded.get("version");
     
      if ( b_version != null ){
     
        latest_version = new String( b_version );
       
        plugin_interface.getPluginProperties().setProperty( LATEST_VERSION_PROPERTY, latest_version );
       
      }else{
       
        throw( new Exception( "No version found in reply" ));
      }
     
      byte[] b_filename = (byte[]) decoded.get("filename");
     
      if ( b_filename != null ){
     
        latest_file_name = new String( b_filename );
       
      }else{
       
        throw( new Exception( "No update file details in reply" ));
      }
     
      //latest_version     = "3.0.0.3";
      //latest_file_name  = "http://torrent.vuze.com:88/torrents/Azureus2.5.0.0.jar.torrent";
      //latest_file_name  = "Azureus2.5.0.0.jar.torrent";
     
      String  msg = "Core: latest_version = '" + latest_version + "', file = '" + latest_file_name + "'";
     
      URL    full_download_url;
     
        // since 2501 we support a full download URL, falling back to SF mirrors if this
        // fails.
         
      if ( latest_file_name.startsWith( "http" )){
       
        try{
          full_download_url  = new URL( latest_file_name );
         
        }catch( Throwable e ){
         
          full_download_url = null;
         
          log.log( e );
        }
       
        int  pos = latest_file_name.lastIndexOf( '/' );
       
        latest_file_name = latest_file_name.substring( pos+1 );
       
      }else{
       
        full_download_url  = null;
      }
     
      checker.reportProgress( msg );
     
      log.log( msg );
     
      if ( !shouldUpdate( current_version, latest_version )){
       
        return;
      }
       
      final String  f_latest_version  = latest_version;
      final String  f_latest_file_name  = latest_file_name;
     
      ResourceDownloader  top_downloader;
     
      if ( full_download_url == null ){
       
        ResourceDownloader[]  primary_mirrors;
                 
        primary_mirrors = getPrimaryDownloaders( latest_file_name );
 
          // the download hierarchy is primary mirrors first (randomised alternate)
          // then backup mirrors (randomised alternate)
       
          // we don't want to load the backup mirrors until the primary mirrors fail
       
        ResourceDownloader    random_primary_mirrors = rdf.getRandomDownloader( primary_mirrors );
       
        ResourceDownloader    backup_downloader =
          rdf.create(
            new ResourceDownloaderDelayedFactory()
            {
              public ResourceDownloader
              create()
              {
                ResourceDownloader[]  backup_mirrors = getBackupDownloaders( f_latest_file_name );
             
                return( rdf.getRandomDownloader( backup_mirrors ));
              }
            });
               
        top_downloader =
          rdf.getAlternateDownloader(
              new ResourceDownloader[]
                {
                  random_primary_mirrors,
                  backup_downloader,
                });

      }else{
       
        ResourceDownloader full_rd = rdf.create( full_download_url );
       
        full_rd = rdf.getSuffixBasedDownloader( full_rd );
       
        ResourceDownloader    primary_downloader =
          rdf.create(
            new ResourceDownloaderDelayedFactory()
            {
              public ResourceDownloader
              create()
              {
                ResourceDownloader[]  primary_mirrors = getPrimaryDownloaders( f_latest_file_name );
             
                return( rdf.getRandomDownloader( primary_mirrors ));
              }
            });
         
        ResourceDownloader    backup_downloader =
          rdf.create(
            new ResourceDownloaderDelayedFactory()
            {
              public ResourceDownloader
              create()
              {
                ResourceDownloader[]  backup_mirrors = getBackupDownloaders( f_latest_file_name );
             
                return( rdf.getRandomDownloader( backup_mirrors ));
              }
            });
       
       
        top_downloader =
          rdf.getAlternateDownloader(
              new ResourceDownloader[]
                {
                  full_rd,
                  primary_downloader,
                  backup_downloader,
                });
      }
     
      top_downloader.addListener( rd_logger );
     
        // get size so it is cached
     
      top_downloader.getSize();   
             

      byte[]  info_b = (byte[])decoded.get( "info" );
     
      String  info = null;
     
      if ( info_b != null ){
     
        try{
          info = new String( info_b, "UTF-8" );
       
        }catch( Throwable e ){
         
          Debug.printStackTrace( e );
        }
      }
     
      byte[] info_url_bytes = (byte[])decoded.get("info_url");
     
      String info_url = null;
     
      if ( info_url_bytes != null ){
       
        try{
          info_url = new String( info_url_bytes );
         
        }catch( Exception e ){
         
          Debug.out(e);
        }
      }
     
      if ( info != null || info_url != null ){
       
        String  check;
       
        if ( info == null ){
         
          check = info_url;
         
        }else if ( info_url == null ){
         
          check = info;
         
        }else{
         
          check = info + "|" + info_url;
        }
       
        byte[]  sig = (byte[])decoded.get( "info_sig" );

        boolean  ok = false;
       
        if ( sig == null ){
       
          Logger.log( new LogEvent( LogIDs.LOGGER, "info signature check failed - missing signature" ));

        }else{
         
          try{
            AEVerifier.verifyData( check, sig );

            ok = true;
           
          }catch( Throwable e ){

            Logger.log( new LogEvent( LogIDs.LOGGER, "info signature check failed", e  ));
          }     
        }
       
        if ( !ok ){
         
          info    = null;
          info_url  = null;
        }
      }
     
      String[]  desc;
     
      if ( info == null ){
       
        desc = new String[]{"Core Azureus Version" };
       
      }else{
       
        desc = new String[]{"Core Azureus Version", info };
      }
     


      final Update update =
        checker.addUpdate(
            "Core Azureus Version",
            desc,
            latest_version,
            top_downloader,
            Update.RESTART_REQUIRED_YES );
     
      if ( info_url != null ){
       
        update.setDescriptionURL(info_url);
      }
     
      top_downloader.addListener(
          new ResourceDownloaderAdapter()
          {
            public boolean
            completed(
              final ResourceDownloader  downloader,
              InputStream          data )
            { 
              installUpdate( checker, update, downloader, f_latest_file_name, f_latest_version, data );
                 
              return( true );
            }
           
            public void
            failed(
              ResourceDownloader      downloader,
              ResourceDownloaderException e )
            {
              Debug.out( downloader.getName() + " failed", e );
             
              update.complete( false );
            }
          });
    }catch( Throwable e ){
     
      log.log( e );
     
      Debug.printStackTrace( e );
     
      checker.reportProgress( "Failed to check for core update: " + Debug.getNestedExceptionMessage(e));
     
      checker.failed();
     
    }finally{
     
      checker.completed();
     
      first_check = false;
    }
  }
 
     
 
 
  /**
   * Log and display a user message if contained within reply.
   * @param reply from server
   */
  private void
  displayUserMessage(
  Map reply )
  {
    //  pick up any user message in the reply

    try{
      Iterator it = reply.keySet().iterator();
     
      while( it.hasNext()){
       
        String  key = (String)it.next();
     
          // support message + message_sig
          //    message_1 + message_sig_1   etc
       
        if ( key.startsWith( "message_sig" ) || !key.startsWith( "message" )){
         
          continue;
        }
       
        byte[]  message_bytes = (byte[])reply.get( key );
 
        if ( message_bytes != null && message_bytes.length > 0 ){
 
          String  message;
         
          try{
            message = new String(message_bytes, "UTF-8" );
           
          }catch( Throwable e ){
           
            message = new String( message_bytes );
          }
 
          String sig_key;
         
          int  pos = key.indexOf('_');
         
          if ( pos == -1 ){
           
            sig_key = "message_sig";
           
          }else{
           
            sig_key = "message_sig" + key.substring( pos );
          }
         
          String  last_message_key = "CoreUpdateChecker.last" + key;
         
          String  last = COConfigurationManager.getStringParameter( last_message_key, "" );
 
          if ( !message.equals( last )){
 
            boolean  repeatable = false;
           
            byte[]  signature = (byte[])reply.get( sig_key );
 
            if ( signature == null ){
 
              Logger.log( new LogEvent( LogIDs.LOGGER, "Signature missing from message" ));
 
              return;
            }
 
            try{
              AEVerifier.verifyData( message, signature );
 
            }catch( Throwable e ){
 
              Logger.log( new LogEvent( LogIDs.LOGGER, "Message signature check failed", e  ));
 
              return;
            }
 
            boolean  completed = false;
           
            if ( message.startsWith( "x:" ) || message.startsWith( "y:" )){
             
                // emergency patch application
             
              repeatable = message.startsWith( "y:" );
             
              try{
                URL jar_url = new URL( message.substring(2));
               
                if ( !repeatable ){
               
                  Logger.log( new LogEvent( LogIDs.LOGGER, "Patch application requsted: url=" + jar_url ));
                }

                File  temp_dir = AETemporaryFileHandler.createTempDir();
               
                File  jar_file = new File( temp_dir, "patch.jar" );
               
                InputStream is = rdf.create( jar_url ).download();
               
                try{
                  FileUtil.copyFile( is, jar_file );
                 
                  is = null;
                 
                  AEVerifier.verifyData( jar_file );
                 
                  ClassLoader cl = CoreUpdateChecker.class.getClassLoader();
                         
                  if ( cl instanceof URLClassLoader ){

                    URL[]  old = ((URLClassLoader)cl).getURLs();

                    URL[]  new_urls = new URL[old.length+1];

                    System.arraycopy( old, 0, new_urls, 1, old.length );

                    new_urls[0]= jar_file.toURL();

                    cl = new URLClassLoader( new_urls, cl );

                  }else{

                    cl = new URLClassLoader( new URL[]{jar_file.toURL()}, cl );
                  }
 
                  Class cla = cl.loadClass( "org.gudy.azureus2.update.version.Patch" );
                 
                  cla.newInstance();
                 
                  completed = true;
                 
                }finally{
                 
                  if ( is != null ){
                 
                    is.close();
                  }
                 
                  jar_file.delete();
                 
                  temp_dir.delete();
                }
              }catch( Throwable e ){
               
                if ( !repeatable ){
               
                  Logger.log( new LogEvent( LogIDs.LOGGER, "Patch application failed", e  ));
                }
              }
            } else if ( message.startsWith("u:") && message.length() > 4 ) {
              try {
                String type = message.substring(2, 3);
                String url = message.substring(4);
                UIFunctions uif = UIFunctionsManager.getUIFunctions();
                if (uif != null) {
                  uif.viewURL(url, null, 0.9, 0.9, true, type.equals("1"));
                }
              } catch (Throwable t) {
                Logger.log( new LogEvent( LogIDs.LOGGER, "URL message failed", t  ));
              }
              // mark as complete even if errored
              completed = true;
            }else{
             
              int   alert_type    = LogAlert.AT_WARNING;
             
              String  alert_text    = message;
   
              boolean  force = false;
             
              if ( alert_text.startsWith( "f:" )){
               
                force = true;
             
                alert_text = alert_text.substring( 2 );
              }
             
              if ( alert_text.startsWith("i:" )){
   
                alert_type = LogAlert.AT_INFORMATION;
   
                alert_text = alert_text.substring(2);
              }
   
              plugin_interface.getPluginProperties().setProperty( MESSAGE_PROPERTY, alert_text );
   
              if ( force ){
               
                UIFunctions uif = UIFunctionsManager.getUIFunctions();
               
                if ( uif != null ){
                 
                  try{
                    uif.forceNotify( UIFunctions.STATUSICON_NONE, null, alert_text, null, null, 0 );
                 
                    completed = true;
                   
                  }catch( Throwable e ){
                   
                  }
                }
              }
             
              if ( !completed ){
               
                Logger.log(new LogAlert(LogAlert.UNREPEATABLE, alert_type, alert_text, 0 ));
              }
             
              completed = true;
            }
           
            if ( completed ){
             
              if ( !repeatable ){
               
                COConfigurationManager.setParameter( last_message_key, message );
   
                COConfigurationManager.save();
              }
            }
          }
        }
      }
    }catch( Throwable e ){

      Debug.printStackTrace( e );
    }
  }
 
  protected ResourceDownloader[]
  getPrimaryDownloaders(
    String    latest_file_name )
  {
    log.log( "Downloading primary mirrors" );
   
    List  res = new ArrayList();

    try{
      if ( latest_file_name == null ){
   
          // very old method, non-mirror based
       
        res.add( new URL( Constants.SF_WEB_SITE + "Azureus2.jar" ));
               
      }else{
   
        URL mirrors_url = new URL("http://prdownloads.sourceforge.net/azureus/" + latest_file_name + "?download");
       
        ResourceDownloader  rd = rdf.create( mirrors_url );
       
        rd = rdf.getRetryDownloader( rd, RD_GET_MIRRORS_RETRIES );
       
        rd.addListener( rd_logger );
       
        String  page = HTMLPageFactory.loadPage( rd.download()).getContent();
       
        String pattern = "/azureus/" + latest_file_name + "?use_mirror=";
      
        int position = page.indexOf(pattern);
       
        while ( position > 0 ){
         
          int end = page.indexOf(">", position);
         
          if (end < 0) {
           
            position = -1;
           
          }else{
           
            String mirror = page.substring(position, end);
           
            if ( mirror.endsWith("\"")){
             
              mirror = mirror.substring(0,mirror.length()-1);
            }
           
            try{
              res.add( new URL( "http://prdownloads.sourceforge.net" + mirror ));
             
            }catch( Throwable e ){
             
              log.log( "Invalid URL read:" + mirror, e );
            }
           
            position = page.indexOf(pattern, position + 1);
          }
        }
      }
    }catch( Throwable e ){
     
      log.log( "Failed to read primary mirror list", e );
    }
   
    ResourceDownloader[]  dls = new ResourceDownloader[res.size()];
       
    for (int i=0;i<res.size();i++){
     
      URL  url =(URL)res.get(i);
     
      log.log( "    Primary mirror:" +url.toString());
     
      ResourceDownloader dl = rdf.create( url );
     
      dl = rdf.getMetaRefreshDownloader( dl );
     
        // add in a layer to do torrent based downloads if url ends with .torrent
     
      dl = rdf.getSuffixBasedDownloader( dl );
     
      dls[i] = dl;
    }
   
    return( dls );
  }
 
  protected ResourceDownloader[]
  getBackupDownloaders(
    String  latest_file_name )
  {
    List  res = new ArrayList();
 
    try{
      if ( latest_file_name != null ){
             
        log.log( "Downloading backup mirrors" );
       
        URL mirrors_url = new URL("http://plugins.vuze.com/mirrors.php");
       
        ResourceDownloader  rd = rdf.create( mirrors_url );
       
        rd = rdf.getRetryDownloader( rd, RD_GET_MIRRORS_RETRIES );
       
        rd.addListener( rd_logger );
       
        BufferedInputStream  data = new BufferedInputStream(rd.download());
       
        Map decoded = BDecoder.decode(data);
       
        data.close();
       
        List mirrors = (List)decoded.get("mirrors");
   
        for (int i=0;i<mirrors.size();i++){
         
          String mirror = new String( (byte[])mirrors.get(i));
         
          try{
           
            res.add( new URL( mirror + latest_file_name ));
            // res.add( new URL( "http://torrent.vuze.com:88/torrents/Azureus2.4.0.2_signed.jar.torrent" ));
           
          }catch(Throwable e){
           
            log.log( "Invalid URL read:" + mirror, e );
          }
        }
      }
    }catch( Throwable e ){
     
      log.log( "Failed to read backup mirror list", e );
    }
   
    ResourceDownloader[]  dls = new ResourceDownloader[res.size()];
   
    for (int i=0;i<res.size();i++){
     
      URL  url =(URL)res.get(i);
     
      log.log( "    Backup mirror:" +url.toString());
     
      ResourceDownloader dl = rdf.create( url );

        // add in .torrent decoder if appropriate
     
      dl = rdf.getSuffixBasedDownloader( dl );

      dls[i] = dl;
    }
   
    return( dls );
  }        

  protected void
  installUpdate(
    UpdateChecker    checker,
    Update        update,
    ResourceDownloader  rd,
    String        filename,
    String        version,
    InputStream      data )
  {
    try{
      data = update.verifyData( data, true );

      rd.reportActivity( "Data verified successfully" );
     
      if ( filename.toLowerCase().endsWith( ".zip.torrent" )){
       
        handleZIPUpdate( checker, data );
       
      }else{
       
        String  temp_jar_name   = "Azureus2_" + version + ".jar";
        String  target_jar_name  = "Azureus2.jar";
       
        UpdateInstaller  installer = checker.createInstaller();
       
        installer.addResource( temp_jar_name, data );
       
        if ( Constants.isOSX ){
         
          installer.addMoveAction(
            temp_jar_name,
            installer.getInstallDir() + "/" + SystemProperties.getApplicationName() + ".app/Contents/Resources/Java/" + target_jar_name );       
        }else{
         
          installer.addMoveAction(
            temp_jar_name,
            installer.getInstallDir() + File.separator + target_jar_name );
        }
      }
     
      update.complete( true );
     
    }catch( Throwable e ){
     
      update.complete( false );
     
      rd.reportActivity("Update install failed:" + e.getMessage());
    }
  }
 
  protected void
  handleZIPUpdate(
    UpdateChecker    checker,
    InputStream      data )
 
    throws Exception
  {
    ZipInputStream zip = null;
   
    Properties  update_properties = new Properties();
   
    File    temp_dir = AETemporaryFileHandler.createTempDir();
   
    File    update_file = null;
   
    try{
      zip = new ZipInputStream(data);

      ZipEntry entry = null;

      while((entry = zip.getNextEntry()) != null) {

        String name = entry.getName().trim();

        if ( name.equals( "azureus.sig" ) || name.endsWith( "/" ) || name.length() == 0 ){
         
          continue;
        }

        if ( name.equals( "update.properties" )){
         
          update_properties.load( zip );
         
        }else{
         
          if ( update_file != null ){
           
            throw( new Exception( "Multiple update files are not supported" ));
          }
         
          update_file = new File( temp_dir, name );
         
          FileUtil.copyFile( zip, update_file, false );
        }
      }
    }finally{
     
      if ( zip != null ){
       
        try{
          zip.close();
         
        }catch( Throwable e ){
         
        }
      }
    }
   
    if ( update_properties == null ){
     
      throw( new Exception( "Update properties missing" ));
    }
   
    if ( update_file == null ){
     
      throw( new Exception( "Update file missing" ));
    }
   
    String  info_url = update_properties.getProperty( "info.url" );
   
    if ( info_url == null ){
     
      throw( new Exception( "Update property 'info.url' missing" ));
    }
     
      // update_properties.setProperty( "launch.args" , "-silent" );
      // update_properties.setProperty( "launch.silent" , "true" );
   
    String  s_args = update_properties.getProperty( "launch.args", "" ).trim();
       
    final String[] args;
   
    if ( s_args.length() > 0 ){
     
      args = GeneralUtils.splitQuotedTokens( s_args );
     
    }else{
     
      args = new String[0];
    }
   
    UIFunctions uif = UIFunctionsManager.getUIFunctions();

    if ( uif == null ){
     
      throw( new Exception( "Update can't proceed - UI functions unavailable" ));
    }
   
    checker.getCheckInstance().setProperty( UpdateCheckInstance.PT_CLOSE_OR_RESTART_ALREADY_IN_PROGRESS, true );

    final File f_update_file = update_file;
     
    boolean  silent = update_properties.getProperty( "launch.silent", "false" ).equals( "true" );
   
    if ( silent ){
     
        // problem on OSX if they have renamed their app and we're running silently as it
        // installs to Vuze.app regardless
     
      if ( Constants.isOSX ){
       
        String app_name = SystemProperties.getApplicationName();
       
        if ( !( app_name.equals( "Vuze" ) || app_name.equals( "Azureus" ))){
         
          UIManager ui_manager = StaticUtilities.getUIManager( 120*1000 );
         
          String details = MessageText.getString(
              "update.fail.app.changed",
              new String[]{ app_name });
         
          ui_manager.showMessageBox(
              "update.fail.app.changed.title",
              "!" + details + "!",
              UIManagerEvent.MT_OK );
         
          return;
        }
      }
     
      uif.performAction(
          UIFunctions.ACTION_UPDATE_RESTART_REQUEST,
          !FileUtil.canReallyWriteToAppDirectory(),
          new UIFunctions.actionListener()
          {
            public void
            actionComplete(
              Object  result )
            {
              if ((Boolean)result){
               
                launchUpdate( f_update_file, args );
              }
            }
          });
    }else{
     
      uif.performAction(
        UIFunctions.ACTION_FULL_UPDATE,
        info_url,
        new UIFunctions.actionListener()
        {
          public void
          actionComplete(
            Object  result )
          {
            if ((Boolean)result){
             
              launchUpdate( f_update_file, args );
            }
          }
        });
    }
  }
 
  protected void
  launchUpdate(
    File    file,
    String[]  args )
  {
    try{
        // hack here to allow testing of osx on windows (parg) - should replace with
        // Constants.isWindows etc
     
      if ( file.getName().endsWith( ".exe" )){
       
        try{
          AEWin32Access accessor = AEWin32Manager.getAccessor(true);
         
          // accessor.createProcess( , false );
         
          String  s_args = null;
         
          if ( args.length > 0 ){
         
            s_args = "";
           
            for ( String s: args ){
             
              s_args += (s_args.length()==0?"":" ") + s;
            }
          }
         
          accessor.shellExecute(
            null,
            file.getAbsolutePath(),
            s_args,
            SystemProperties.getApplicationPath(),
            AEWin32Access.SW_NORMAL );
         
        }catch( Throwable e ){
         
          Logger.log( new LogEvent( LogIDs.LOGGER, "AEWin32Access failed", e  ));

          if ( args.length > 0 ){
         
            String[] s_args = new String[args.length+1];
           
            s_args[0] = file.getAbsolutePath();
           
            System.arraycopy( args, 0, s_args, 1, args.length );
           
            Runtime.getRuntime().exec( s_args );
           
          }else{
         
            Runtime.getRuntime().exec( file.getAbsolutePath() );
          }
        }
      }else{
          // osx, need to unzip .app and launch
       
        File  dir = file.getParentFile();
       
           ZipInputStream  zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( file )));
           
           Throwable unzip_error = null;
          
           String chmod_command = findCommand( "chmod" );
          
          try{
          while( true ){
                       
            ZipEntry  entry = zis.getNextEntry();
             
            if ( entry == null ){
             
              break;
            }
           
            if ( entry.isDirectory()){
             
              continue;
            }
           
            String  name = entry.getName();
           
            FileOutputStream  entry_os   = null;
            File        entry_file   = null;
           
            if ( !name.endsWith("/")){
                           
              entry_file = new File( dir, name.replace('/', File.separatorChar ));
                           
              entry_file.getParentFile().mkdirs();
             
              entry_os  = new FileOutputStream( entry_file );
            }
           
            try{
              byte[]  buffer = new byte[65536];
             
              while( true ){
             
                int  len = zis.read( buffer );
               
                if ( len <= 0 ){
                 
                  break;
                }
                                                 
                if ( entry_os != null ){
                 
                  entry_os.write( buffer, 0, len );
                }
              }
            }finally{
             
              if ( entry_os != null ){
               
                entry_os.close();
                                 
                if ( name.endsWith( ".jnilib" ) || name.endsWith( "JavaApplicationStub" )){
                   
                  try{
                    String[] to_run = { chmod_command, "a+x", entry_file.getAbsolutePath() };
                     
                    runCommand( to_run, true );
                       
                  }catch( Throwable e ){
                   
                    unzip_error = e;
                  }
                }
              }
            }
          }
          }finally{
           
            zis.close();
          }
       
          if ( unzip_error != null ){
           
            throw( unzip_error );
          }
         
          File[] files = dir.listFiles();
         
          boolean launched = false;
         
          for ( File f: files ){
           
            if ( f.getName().endsWith( ".app" )){
         
              String[] to_run;
             
                // can't pass args unless using 'open' on 10.6 or higher. Update process
                // has been changed to avoid arg passing on OSX anyway, but leaving this
                // in in case needed in the future
             
              if ( args.length == 0 || !Constants.isOSX_10_6_OrHigher){
               
                to_run = new String[]{ "/bin/sh", "-c", "open \"" + f.getAbsolutePath() + "\""};
               
              }else{
               
                to_run = new String[ 3 + args.length ];
               
                to_run[0] = findCommand( "open" );
                to_run[1] = f.getAbsolutePath();               
                to_run[2] = "--args";
               
                System.arraycopy( args, 0, to_run, 3, args.length );
              }
             
              runCommand( to_run, false );
             
              launched = true;
            }
          }
         
          if ( !launched ){
           
            throw( new Exception( "No .app files found in '" + dir + "'" ));
          }
      }
    }catch( Throwable e ){
     
      Logger.log( new LogEvent( LogIDs.LOGGER, "Failed to launch update '" + file + "'", e  ));
    }
  }
 
  private static String
  findCommand(
    String  name )
  {
    final String[]  locations = { "/bin", "/usr/bin" };

    for ( String s: locations ){

      File f = new File( s, name );

      if ( f.exists() && f.canRead()){

        return( f.getAbsolutePath());
      }
    }

    return( name );
  }
   
  private static void
  runCommand(
    String[]  command,
    boolean    wait )
 
    throws Throwable
  {
    try{
      String  str = "";
     
      for ( String s: command ){
       
        str += (str.length()==0?"":" ") + s;
      }
     
      System.out.println( "running " + str );
     
      Process proc = Runtime.getRuntime().exec( command );
     
      if ( wait ){
       
        proc.waitFor();
      }
    }catch( Throwable e ){
     
      System.err.println( e );
     
      throw( e );
    }
  }
 
  protected static boolean
  shouldUpdate(
    String  current_version,
    String  latest_version )
  {
    String  current_base  = Constants.getBaseVersion( current_version );
    int    current_inc    = Constants.getIncrementalBuild( current_version );

    String  latest_base  = Constants.getBaseVersion( latest_version );
    int    latest_inc  = Constants.getIncrementalBuild( latest_version );
     
      // currently we upgrade from, for example
      //  1) 2.4.0.0     -> 2.4.0.2
      //  2) 2.4.0.1_CVS -> 2.4.0.2
      //  3) 2.4.0.1_B12 -> 2.4.0.2  and 2.4.0.1_B14
   
      // but NOT
      //  1) 2.4.0.0      -> 2.4.0.1_CVS
      //  2) 2.4.0.1_CVS -> 2.4.0.1_B23
   
      // for inc values: 0 = not CVS, -1 = _CVS, > 0 = Bnn

    int  major_comp = Constants.compareVersions( current_base, latest_base );
   
    if ( major_comp < 0 && latest_inc >= 0 ){
           
      return( true );    // latest is higher version and not CVS     
    }
   
      // same version, both are B versions and latest B is more recent
   
    return( major_comp == 0 && current_inc > 0 && latest_inc > 0 && latest_inc > current_inc );
  }
 
  public static void
  main(
    String[]  args )
  {
    String[][]  tests = {
        { "2.4.0.0",     "2.4.0.2",     "true" },
        { "2.4.0.1_CVS",   "2.4.0.2",     "true" },
        { "2.4.0.1_B12""2.4.0.2",     "true" },
        { "2.4.0.1_B12",   "2.4.0.1_B34""true" },
        { "2.4.0.1_B12",   "2.4.0.1_B6""false" },
        { "2.4.0.0",     "2.4.0.1_CVS""false" },
        { "2.4.0.0",     "2.4.0.1_B12""true" },
        { "2.4.0.0",     "2.4.0.0"  "false" },
        { "2.4.0.1_CVS",   "2.4.0.1_CVS""false" },
        { "2.4.0.1_B2",   "2.4.0.1_B2""false" },
        { "2.4.0.1_CVS",   "2.4.0.1_B2""false" },
        { "2.4.0.1_B2",   "2.4.0.1_CVS""false" },

    };

    for (int i=0;i<tests.length;i++){
     
      System.out.println( shouldUpdate(tests[i][0],tests[i][1]) + " / " + tests[i][2] );
    }
   
    /*
    AEDiagnostics.startup();
   
    CoreUpdateChecker  checker = new CoreUpdateChecker();
   
    checker.log = new LoggerImpl(null).getTimeStampedChannel("");
    checker.rdf  = new ResourceDownloaderFactoryImpl();
    checker.rd_logger =
      new ResourceDownloaderAdapter()
      {
        public void
        reportActivity(
          ResourceDownloader  downloader,
          String        activity )
        {
          System.out.println( activity );
        }
       
        public void
        reportPercentComplete(
          ResourceDownloader  downloader,
          int          percentage )
        {
          System.out.println( "    % = " + percentage );
        }
      };
     
    ResourceDownloader[]  primaries = checker.getPrimaryDownloaders( "Azureus-2.0.3.0.jar" );
   
    for (int i=0;i<primaries.length;i++){
     
      System.out.println( "primary: " + primaries[i].getName());
    }
   
    try{
      ResourceDownloader  rd = primaries[0];
     
      rd.addListener( checker.rd_logger );
     
      rd.download();
     
      System.out.println( "done" );
     
    }catch( Throwable e ){
     
      e.printStackTrace();
    }
    */
  }
TOP

Related Classes of org.gudy.azureus2.update.CoreUpdateChecker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.