Package org.gudy.azureus2.pluginsimpl.local

Source Code of org.gudy.azureus2.pluginsimpl.local.PluginInitializer$VerifiedPluginHolder

/*
* File    : PluginInitializer.java
* Created : 2 nov. 2003 18:59:17
* By      : Olivier
*
* Azureus - a Java Bittorrent client
*
* 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.
*
* 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 ( see the LICENSE file ).
*
* 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
*/
package org.gudy.azureus2.pluginsimpl.local;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.*;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.global.GlobalManagerListener;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.security.SESecurityManager;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.*;
import org.gudy.azureus2.pluginsimpl.local.launch.PluginLauncherImpl;
import org.gudy.azureus2.pluginsimpl.local.ui.UIManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.update.UpdateManagerImpl;
import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl;
import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl.runnableWithException;
import org.gudy.azureus2.update.UpdaterUpdateChecker;
import org.gudy.azureus2.update.UpdaterUtils;


import com.aelitis.azureus.core.*;
import com.aelitis.azureus.core.versioncheck.VersionCheckClient;



/**
* @author Olivier
*
*/
public class
PluginInitializer
  implements GlobalManagerListener, AEDiagnosticsEvidenceGenerator
{
  public static final boolean DISABLE_PLUGIN_VERIFICATION = false;
 
  private static final LogIDs LOGID = LogIDs.CORE;
  public static final String  INTERNAL_PLUGIN_ID = "<internal>";
 
  // class name, plugin id, plugin key (key used for config props so if you change
  // it you'll need to migrate the config)
  // "id" is used when checking for updates
 
  // IF YOU ADD TO THE BUILTIN PLUGINS, AMEND PluginManagerDefault appropriately!!!!

    // Plugin ID constant
    // class
    // plugin id
    // plugin key for prefixing config data
    // report if not present
  // force re-enable if disabled by config
 
  private String[][]  builtin_plugins = {
         {   PluginManagerDefaults.PID_START_STOP_RULES,
             "com.aelitis.azureus.plugins.startstoprules.defaultplugin.StartStopRulesDefaultPlugin",
             "azbpstartstoprules",
             "",
             "true",
             "true"},
         {   PluginManagerDefaults.PID_REMOVE_RULES,
             "com.aelitis.azureus.plugins.removerules.DownloadRemoveRulesPlugin",
             "azbpremovalrules",
             "",
          "true",
          "false"},
        {   PluginManagerDefaults.PID_SHARE_HOSTER,
             "com.aelitis.azureus.plugins.sharing.hoster.ShareHosterPlugin",
             "azbpsharehoster",
             "ShareHoster",
          "true",
          "false"},
         {   PluginManagerDefaults.PID_PLUGIN_UPDATE_CHECKER,
             "org.gudy.azureus2.pluginsimpl.update.PluginUpdatePlugin",
             "azbppluginupdate",
             "PluginUpdate",
          "true",
          "true"},
      {   PluginManagerDefaults.PID_UPNP,
            "com.aelitis.azureus.plugins.upnp.UPnPPlugin",
            "azbpupnp",
            "UPnP",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_DHT,
          "com.aelitis.azureus.plugins.dht.DHTPlugin",
          "azbpdht",
          "DHT",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_DHT_TRACKER,
          "com.aelitis.azureus.plugins.tracker.dht.DHTTrackerPlugin",
          "azbpdhdtracker",
          "DHT Tracker",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_MAGNET,
          "com.aelitis.azureus.plugins.magnet.MagnetPlugin",
          "azbpmagnet",
          "Magnet URI Handler",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_CORE_UPDATE_CHECKER,
             "org.gudy.azureus2.update.CoreUpdateChecker",
             "azbpcoreupdater",
             "CoreUpdater",
          "true",
          "true"},
      {   PluginManagerDefaults.PID_CORE_PATCH_CHECKER,
             "org.gudy.azureus2.update.CorePatchChecker",
             "azbpcorepatcher",
             "CorePatcher",
          "true",
          "true"},
         {   PluginManagerDefaults.PID_PLATFORM_CHECKER,
             "org.gudy.azureus2.platform.PlatformManagerPluginDelegate",
             "azplatform2",
             "azplatform2",
          "true",
          "false"},
         //{   PluginManagerDefaults.PID_JPC,
        //  "com.aelitis.azureus.plugins.jpc.JPCPlugin",
        //  "azjpc",
        //  "azjpc",
        //  "false" },
         {   PluginManagerDefaults.PID_EXTERNAL_SEED,
          "com.aelitis.azureus.plugins.extseed.ExternalSeedPlugin",
          "azextseed",
          "azextseed",
             "true",
             "false"},
         {   PluginManagerDefaults.PID_LOCAL_TRACKER,
             "com.aelitis.azureus.plugins.tracker.local.LocalTrackerPlugin",
             "azlocaltracker",
             "azlocaltracker",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_NET_STATUS,
             "com.aelitis.azureus.plugins.net.netstatus.NetStatusPlugin",
             "aznetstat",
             "aznetstat",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_BUDDY,
          "com.aelitis.azureus.plugins.net.buddy.BuddyPlugin",
          "azbuddy",
          "azbuddy",
          "true",
          "false"},
      {   PluginManagerDefaults.PID_RSS,
          "com.aelitis.azureus.core.rssgen.RSSGeneratorPlugin",
          "azintrss",
          "azintrss",
          "true",
          "false"},
      /* disable until we can get some tracker admins to work on this
         {   PluginManagerDefaults.PID_TRACKER_PEER_AUTH,
          "com.aelitis.azureus.plugins.tracker.peerauth.TrackerPeerAuthPlugin",
          "aztrackerpeerauth",
          "aztrackerpeerauth",
          "true",
          "false" },
      */
        };
 
  static VerifiedPluginHolder verified_plugin_holder;
 
  static{
    synchronized( PluginInitializer.class ){
     
      verified_plugin_holder = new VerifiedPluginHolder();
    }
  }
 
    // these can be removed one day
 
  private static String[][]default_version_details =
  {
    { "org.cneclipse.multiport.MultiPortPlugin",
          "multi-ports",     "Mutli-Port Trackers""1.0" },
  };
 
  private static PluginInitializer  singleton;
  private static AEMonitor      class_mon  = new AEMonitor( "PluginInitializer");

  private static List    registration_queue   = new ArrayList();
 
  private static List    initThreads = new ArrayList(1);
 
  private static AsyncDispatcher  async_dispatcher = new AsyncDispatcher();
  private static List<PluginEvent>  plugin_event_history = new ArrayList<PluginEvent>();
 
 
 
  private AzureusCoreOperation core_operation;
 
  private AzureusCore    azureus_core;
 
  private PluginInterfaceImpl  default_plugin;
  private PluginManager      plugin_manager;
 
  private ClassLoader      root_class_loader  = getClass().getClassLoader();
 
  private List    loaded_pi_list    = new ArrayList();
 
  private static boolean  loading_builtin;
 
  private List    s_plugins        = new ArrayList();
  private List    s_plugin_interfaces    = new ArrayList();
 
  private boolean  initialisation_complete;
 
  private volatile boolean  plugins_initialised;
 
  private Set<String>  vc_disabled_plugins = VersionCheckClient.getSingleton().getDisabledPluginIDs();
   
  public static PluginInitializer
  getSingleton(
    AzureusCore         azureus_core,
    AzureusCoreOperation   core_operation )
  {
    try{
      class_mon.enter();
   
      if ( singleton == null ){
       
        singleton = new PluginInitializer( azureus_core, core_operation );
      }
    
      return( singleton );
     
  }finally{
       
    class_mon.exit();
  }   
  }
 
  private static PluginInitializer
  peekSingleton()
  {
    try{
      class_mon.enter();
        
      return( singleton );
     
  }finally{
       
    class_mon.exit();
  }   
  }
 
  protected static void
  queueRegistration(
    Class  _class )
  {
    try{
      class_mon.enter();
     
       if ( singleton == null ){
       
        registration_queue.add( _class );
  
      }else{
       
        try{
          singleton.initializePluginFromClass( _class, INTERNAL_PLUGIN_ID, _class.getName(), false, false, true);
         
      }catch(PluginException e ){
           
        }
      }
  }finally{
     
    class_mon.exit();
  }   
  }
 
  protected static void
  queueRegistration(
    Plugin    plugin,
  String    id )
  {
    try{
      class_mon.enter();
     
       if ( singleton == null ){
       
        registration_queue.add( new Object[]{ plugin, id });
  
      }else{
       
        try{
          singleton.initializePluginFromInstance( plugin, id, plugin.getClass().getName());
         
      }catch( Throwable e ){
           
        Debug.out( e );
        }
      }
  }finally{
     
    class_mon.exit();
  }   
  }
 
  protected static boolean
  isLoadingBuiltin()
  {
    return( loading_builtin );
  }
 
  public static void
  checkAzureusVersion(
    String name,
    Properties props,
    boolean alert_on_fail
  ) throws PluginException {
   
    String required_version = (String)props.get("plugin.azureus.min_version");
    if (required_version == null) {return;}
    if (Constants.compareVersions(Constants.AZUREUS_VERSION, required_version) < 0) {
      String plugin_name_bit = name.length() > 0 ? (name+" "):"";
      String msg = "Plugin " + plugin_name_bit + "requires " + Constants.APP_NAME + " version " + required_version + " or higher";
      if (alert_on_fail) {
        Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, msg));
      }
      throw new PluginException(msg);
    }
  }
 
  public static void
  checkJDKVersion(
  String    name,
  Properties  props,
  boolean    alert_on_fail )
 
    throws PluginException
  {
      String  required_jdk = (String)props.get( "plugin.jdk.min_version" );

      if ( required_jdk != null ){
       
        String  actual_jdk = System.getProperty( "java.version" );
       
        required_jdk   = normaliseJDK( required_jdk );
        actual_jdk  = normaliseJDK( actual_jdk );
       
        if ( required_jdk.length() == 0 || actual_jdk.length() == 0 ){
         
          return;
        }
       
        if ( Constants.compareVersions( actual_jdk, required_jdk ) < 0 ){
         
            String  msg =  "Plugin " + (name.length()>0?(name+" "):"" ) + "requires Java version " + required_jdk + " or higher";
             
            if ( alert_on_fail ){
             
              Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, msg));
            }
           
              throw( new PluginException( msg ));
        }
      }
  }
 
  protected static String
  normaliseJDK(
  String  jdk )
  {
    try{
      String  str = "";

      // take leading digit+. portion only

      for (int i=0;i<jdk.length();i++){

        char c = jdk.charAt( i );

        if ( c == '.' || Character.isDigit( c )){

          str += c;

        }else{

          break;
        }
      }

        // convert 5|6|... to 1.5|1.6 etc

      if ( Integer.parseInt( "" + str.charAt(0)) > 1 ){
       
        str = "1." + str;
      }
     
      return( str );
     
    }catch( Throwable e ){
     
      return( "" );
    }
  }
 
  protected
  PluginInitializer(
    AzureusCore       _azureus_core,
    AzureusCoreOperation  _core_operation )
  {
    azureus_core  = _azureus_core;
   
    AEDiagnostics.addEvidenceGenerator( this );
   
    azureus_core.addLifecycleListener(
        new AzureusCoreLifecycleAdapter()
      {
          public void
        componentCreated(
          AzureusCore          core,
          AzureusCoreComponent    comp )
          {
            if ( comp instanceof GlobalManager ){
             
              GlobalManager  gm  = (GlobalManager)comp;
             
              gm.addListener( PluginInitializer.this );
            }
          }
      });
   
    core_operation   = _core_operation;
   
    UpdateManagerImpl.getSingleton( azureus_core )// initialise the update manager
      
    plugin_manager = PluginManagerImpl.getSingleton( this );
   
    String  dynamic_plugins = System.getProperty( "azureus.dynamic.plugins", null );
   
    if ( dynamic_plugins != null ){
     
      String[]  classes = dynamic_plugins.split( ";" );
     
      for ( String c: classes ){
       
        try{
          queueRegistration( Class.forName( c ));
         
        }catch( Throwable e ){
         
          Debug.out( "Registration of dynamic plugin '" + c + "' failed", e );
        }
      }
    }
   
    UpdaterUtils.checkBootstrapPlugins();
  }
 
  protected void
  fireCreated(
  PluginInterfaceImpl pi )
  {
    azureus_core.triggerLifeCycleComponentCreated( pi );
  }
 
  protected void
  fireOperational(
  PluginInterfaceImpl  pi,
  boolean        op )
  {
    fireEventSupport( op?PluginEvent.PEV_PLUGIN_OPERATIONAL:PluginEvent.PEV_PLUGIN_NOT_OPERATIONAL, pi );
  }
 
  public static void
  addInitThread()
  {
    synchronized( initThreads ){
     
      if ( initThreads.contains( Thread.currentThread())){
       
        Debug.out( "Already added" );
      }
     
      initThreads.add( Thread.currentThread());
    }
  }
 
  public static void
  removeInitThread()
  {
    synchronized( initThreads ){
     
      initThreads.remove( Thread.currentThread());
    }
  }
 
  protected boolean
  isInitialisationThread()
  {
    synchronized( initThreads ){

      return initThreads.contains(Thread.currentThread());
    }
  }
 
    public List
  loadPlugins(
    AzureusCore    core,
    boolean bSkipAlreadyLoaded,
    boolean load_external_plugins,
    boolean loading_for_startup,
    boolean initialise_plugins)
    {
      if ( bSkipAlreadyLoaded ){
     
          // discard any failed ones
       
        List pis;
       
        synchronized( s_plugin_interfaces ){
         
          pis = new ArrayList( s_plugin_interfaces );
        }
       
        for (int i=0;i<pis.size();i++){
           
          PluginInterfaceImpl pi = (PluginInterfaceImpl)pis.get(i);
         
            Plugin p = pi.getPlugin();
           
            if ( p instanceof FailedPlugin ){
             
              unloadPlugin( pi );
            }
          }
       
      }
     
      List pluginLoaded = new ArrayList();
     
      PluginManagerImpl.setStartDetails( core );
         
      getRootClassLoader();
     
        // first do explicit plugins
       
      File  user_dir = FileUtil.getUserFile("plugins");
     
      File  app_dir   = FileUtil.getApplicationFile("plugins");
     
      int  user_plugins  = 0;
      int app_plugins    = 0;
         
      if ( user_dir.exists() && user_dir.isDirectory()){
       
        user_plugins = user_dir.listFiles().length;
       
      }
     
      if ( app_dir.exists() && app_dir.isDirectory()){
       
        app_plugins = app_dir.listFiles().length;
       
      }
     
        // user ones first so they override app ones if present
     
      if (load_external_plugins) {
        pluginLoaded.addAll(loadPluginsFromDir(user_dir, 0, user_plugins
          + app_plugins, bSkipAlreadyLoaded, loading_for_startup, initialise_plugins));
       
        if ( !user_dir.equals( app_dir )){
         
          pluginLoaded.addAll(loadPluginsFromDir(app_dir, user_plugins,
            user_plugins + app_plugins, bSkipAlreadyLoaded, loading_for_startup, initialise_plugins));
        }
      }
      else {
        if (Logger.isEnabled()) {
          Logger.log(new LogEvent(LOGID, "Loading of external plugins skipped"));
        }
      }
     
      if (Logger.isEnabled())
        Logger.log(new LogEvent(LOGID, "Loading built-in plugins"));
     
      PluginManagerDefaults  def = PluginManager.getDefaults();
   
      for (int i=0;i<builtin_plugins.length;i++){
       
        if ( def.isDefaultPluginEnabled( builtin_plugins[i][0])){
       
            if (core_operation != null) {
              core_operation.reportCurrentTask(MessageText.getString("splash.plugin")
                  + builtin_plugins[i][0]);
            }

          try{
            loading_builtin  = true;
           
              // lazyness here, for builtin we use static load method with default plugin interface
              // if we need to improve on this then we'll have to move to a system more akin to
              // the dir-loaded plugins
           
            Class  cla = root_class_loader.loadClass( builtin_plugins[i][1]);
                   
                Method  load_method = cla.getMethod( "load", new Class[]{ PluginInterface.class });
               
                load_method.invoke( null, new Object[]{ getDefaultInterfaceSupport() });
               
          Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
              "Built-in plugin '" + builtin_plugins[i][0] + "' ok"));
              }catch( NoSuchMethodException e ){
               
              }catch( Throwable e ){
               
          if ( builtin_plugins[i][4].equalsIgnoreCase("true" )){
             
            Debug.printStackTrace( e );
         
            Logger.log(new LogAlert(LogAlert.UNREPEATABLE,
                "Load of built in plugin '" + builtin_plugins[i][2] + "' fails", e));
          }
          }finally{
           
            loading_builtin = false;
          }
        }else{
          if (Logger.isEnabled())
            Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
                "Built-in plugin '" + builtin_plugins[i][2] + "' is disabled"));
        }
      }
     
     if (Logger.isEnabled())
      Logger.log(new LogEvent(LOGID, "Loading dynamically registered plugins"));
    
    for (int i=0;i<registration_queue.size();i++){
     
      Object  entry = registration_queue.get(i);
       
      Class  cla;
      String  id;
     
      if ( entry instanceof Class ){
       
          cla = (Class)entry;
         
          id  = cla.getName();     
      }else{
       
        Object[]  x = (Object[])entry;
       
        Plugin  plugin = (Plugin)x[0];
       
        cla  = plugin.getClass();
       
        id  = (String)x[1];
      }
     
      try{
          // lazyness here, for dynamic we use static load method with default plugin interface
          // if we need to improve on this then we'll have to move to a system more akin to
          // the dir-loaded plugins
                         
        Method  load_method = cla.getMethod( "load", new Class[]{ PluginInterface.class });
           
            load_method.invoke( null, new Object[]{ getDefaultInterfaceSupport() });
           
        }catch( NoSuchMethodException e ){
           
        }catch( Throwable e ){
           
        Debug.printStackTrace( e );
   
        Logger.log(new LogAlert(LogAlert.UNREPEATABLE,
            "Load of dynamic plugin '" + id + "' fails", e));
      }
    }
   
    return pluginLoaded;
    }
    private void
  getRootClassLoader()
    { 
        // first do explicit plugins
 
      File  user_dir = FileUtil.getUserFile("shared");

      getRootClassLoader( user_dir );
     
      File  app_dir   = FileUtil.getApplicationFile("shared");
     
      if ( !user_dir.equals( app_dir )){
       
        getRootClassLoader( app_dir );
      }
    }

   private void
  getRootClassLoader(
    File    dir )
    {
     dir = new File( dir, "lib" );
    
     if ( dir.exists() && dir.isDirectory()){
      
       File[]  files = dir.listFiles();
      
       if ( files != null ){
        
         files = PluginLauncherImpl.getHighestJarVersions( files, new String[]{ null }, new String[]{ null }, false );
        
         for (int i=0;i<files.length;i++){
          
            if (Logger.isEnabled())
             Logger.log(new LogEvent(LOGID, "Share class loader extended by " + files[i].toString()));

            root_class_loader =
              PluginLauncherImpl.addFileToClassPath(
                  PluginInitializer.class.getClassLoader(),
                  root_class_loader, files[i] );
         }
       }
     }
    }
  
  private List
  loadPluginsFromDir(
    File  pluginDirectory,
  int    plugin_offset,
  int    plugin_total,
  boolean bSkipAlreadyLoaded,
  boolean loading_for_startup,
  boolean initialise)
  {
    List dirLoadedPIs = new ArrayList();
   
    if (Logger.isEnabled())
      Logger.log(new LogEvent(LOGID, "Plugin Directory is " + pluginDirectory));
   
    if ( !pluginDirectory.exists() ){
     
      FileUtil.mkdirs(pluginDirectory);
    }
   
    if( pluginDirectory.isDirectory()){
     
      File[] pluginsDirectory = pluginDirectory.listFiles();
     
      for(int i = 0 ; i < pluginsDirectory.length ; i++) {
       
        if( pluginsDirectory[i].getName().equals( "CVS" ) ) {
         
          if (Logger.isEnabled())
            Logger.log(new LogEvent(LOGID, "Skipping plugin "
                + pluginsDirectory[i].getName()));
         
          continue;
        }
       
       
      if (Logger.isEnabled())
        Logger.log(new LogEvent(LOGID, "Loading plugin "
            + pluginsDirectory[i].getName()));

      if(core_operation != null) {
           
        core_operation.reportCurrentTask(MessageText.getString("splash.plugin") + pluginsDirectory[i].getName());
      }
       
      try{
     
        List  loaded_pis = loadPluginFromDir(pluginsDirectory[i], bSkipAlreadyLoaded, loading_for_startup, initialise);
         
          // save details for later initialisation
       
        loaded_pi_list.add( loaded_pis );
        dirLoadedPIs.addAll( loaded_pis );
       
        }catch( PluginException e ){
         
            // already handled
        }
       
        if( core_operation != null ){
         
          core_operation.reportPercent( (100 * (i + plugin_offset)) / plugin_total );
        }
      }
    }
    return dirLoadedPIs;
  }
 
  private List
  loadPluginFromDir(
      File directory,
      boolean bSkipAlreadyLoaded,
      boolean loading_for_startup,
      boolean initialise) // initialise setting is used if loading_for_startup isnt

  throws PluginException
  {
    List  loaded_pis = new ArrayList();

    ClassLoader plugin_class_loader = root_class_loader;

    if( !directory.isDirectory()){

      return( loaded_pis );
    }

    String pluginName = directory.getName();

    File[] pluginContents = directory.listFiles();

    if ( pluginContents == null || pluginContents.length == 0){

      return( loaded_pis );
    }

    // first sanity check - dir must include either a plugin.properties or
    // at least one .jar file

    boolean  looks_like_plugin  = false;

    for (int i=0;i<pluginContents.length;i++){

      String  name = pluginContents[i].getName().toLowerCase();

      if ( name.endsWith( ".jar") || name.equals( "plugin.properties" )){

        looks_like_plugin = true;

        break;
      }
    }

    if ( !looks_like_plugin ){

      if (Logger.isEnabled())
        Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
            "Plugin directory '" + directory + "' has no plugin.properties "
            + "or .jar files, skipping"));

      return( loaded_pis );
    }

    // take only the highest version numbers of jars that look versioned

    String[]  plugin_version = {null};
    String[]  plugin_id = {null};

    pluginContents  = PluginLauncherImpl.getHighestJarVersions( pluginContents, plugin_version, plugin_id, true );

    for( int i = 0 ; i < pluginContents.length ; i++){

      File  jar_file = pluginContents[i];

      // migration hack for i18nAZ_1.0.jar

      if ( pluginContents.length > 1 ){

        String  name = jar_file.getName();

        if ( name.startsWith( "i18nPlugin_" )){

          // non-versioned version still there, rename it

          if (Logger.isEnabled())
            Logger.log(new LogEvent(LOGID, "renaming '" + name
                + "' to conform with versioning system"));

          jar_file.renameTo( new File( jar_file.getParent(), "i18nAZ_0.1.jar  " ));

          continue;
        }
      }

      plugin_class_loader = PluginLauncherImpl.addFileToClassPath( root_class_loader, plugin_class_loader, jar_file);
    }

    String plugin_class_string = null;

    try {
      Properties props = new Properties();

      File  properties_file = new File(directory.toString() + File.separator + "plugin.properties");

      try {

        // if properties file exists on its own then override any properties file
        // potentially held within a jar

        if ( properties_file.exists()){

          FileInputStream  fis = null;

          try{
            fis = new FileInputStream( properties_file );

            props.load( fis );

          }finally{

            if ( fis != null ){

              fis.close();
            }
          }

        }else{

          if ( plugin_class_loader instanceof URLClassLoader ){

            URLClassLoader  current = (URLClassLoader)plugin_class_loader;

            URL url = current.findResource("plugin.properties");

            if ( url != null ){
              URLConnection connection = url.openConnection();

              InputStream is = connection.getInputStream();

              props.load(is);

            }else{

              throw( new Exception( "failed to load plugin.properties from jars"));
            }
          }else{

            throw( new Exception( "failed to load plugin.properties from dir or jars"));

          }
        }
      }catch( Throwable e ){

        Debug.printStackTrace( e );

        String  msg =  "Can't read 'plugin.properties' for plugin '" + pluginName + "': file may be missing";

        Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, msg));

        System.out.println( msg );

        throw( new PluginException( msg, e ));
      }

      checkJDKVersion( pluginName, props, true );
      checkAzureusVersion(pluginName, props, true);

      plugin_class_string = (String)props.get( "plugin.class");

      if ( plugin_class_string == null ){

        plugin_class_string = (String)props.get( "plugin.classes");

        if ( plugin_class_string == null ){

          // set so we don't bork later will npe

          plugin_class_string = "";
        }
      }

      String  plugin_name_string = (String)props.get( "plugin.name");

      if ( plugin_name_string == null ){

        plugin_name_string = (String)props.get( "plugin.names");
      }

      int  pos1 = 0;
      int  pos2 = 0;

      while(true){
        int  p1 = plugin_class_string.indexOf( ";", pos1 );

        String  plugin_class;

        if ( p1 == -1 ){
          plugin_class = plugin_class_string.substring(pos1).trim();
        }else{
          plugin_class  = plugin_class_string.substring(pos1,p1).trim();
          pos1 = p1+1;
        }

        PluginInterfaceImpl existing_pi = getPluginFromClass( plugin_class );

        if ( existing_pi != null ){

          if (bSkipAlreadyLoaded) {
            break;
          }

          // allow user dir entries to override app dir entries without warning

          File  this_parent   = directory.getParentFile();
          File  existing_parent = null;

          if ( existing_pi.getInitializerKey() instanceof File ){

            existing_parent  = ((File)existing_pi.getInitializerKey()).getParentFile();
          }

          if (   this_parent.equals( FileUtil.getApplicationFile("plugins")) &&
              existing_parent  != null &&
              existing_parent.equals( FileUtil.getUserFile( "plugins" ))){

            // skip this overridden plugin

            if (Logger.isEnabled())
              Logger.log(new LogEvent(LOGID, "Plugin '" + plugin_name_string
                  + "/" + plugin_class
                  + ": shared version overridden by user-specific one"));

            return( new ArrayList());

          }else{
            Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
                "Error loading '" + plugin_name_string + "', plugin class '"
                + plugin_class + "' is already loaded"));
          }

        }else{

          String  plugin_name = null;

          if ( plugin_name_string != null ){

            int  p2 = plugin_name_string.indexOf( ";", pos2 );


            if ( p2 == -1 ){
              plugin_name = plugin_name_string.substring(pos2).trim();
            }else{
              plugin_name  = plugin_name_string.substring(pos2,p2).trim();
              pos2 = p2+1;
            }   
          }

          Properties new_props = (Properties)props.clone();

          for (int j=0;j<default_version_details.length;j++){

            if ( plugin_class.equals( default_version_details[j][0] )){

              if ( new_props.get( "plugin.id") == null ){

                new_props.put( "plugin.id", default_version_details[j][1])
              }

              if ( plugin_name == null ){

                plugin_name  = default_version_details[j][2];
              }

              if ( new_props.get( "plugin.version") == null ){

                // no explicit version. If we've derived one then use that, otherwise defaults

                if ( plugin_version[0] != null ){

                  new_props.put( "plugin.version", plugin_version[0]);

                }else{

                  new_props.put( "plugin.version", default_version_details[j][3]);
                }
              }
            }
          }

          new_props.put( "plugin.class", plugin_class );

          if ( plugin_name != null ){

            new_props.put( "plugin.name", plugin_name );
          }

          // System.out.println( "loading plugin '" + plugin_class + "' using cl " + classLoader);

          // if the plugin load fails we still need to generate a plugin entry
          // as this drives the upgrade process


          Throwable  load_failure  = null;

          String pid = plugin_id[0]==null?directory.getName():plugin_id[0];

          List<File>  verified_files = null;

          Plugin plugin = null;

          if ( vc_disabled_plugins.contains ( pid )){

            log( "Plugin '" + pid + "' has been administratively disabled" );

          }else{
            try{
              String cl_key = "plugin.cl.ext." + pid;
             
              String str = COConfigurationManager.getStringParameter( cl_key, null );

              if ( str != null && str.length() > 0 ){

                COConfigurationManager.removeParameter( cl_key );
               
                plugin_class_loader = PluginLauncherImpl.extendClassLoader( root_class_loader, plugin_class_loader, new URL( str ));
              }
            }catch( Throwable e ){ 
            }

            if ( pid.endsWith( "_v" )){

              verified_files = new ArrayList<File>();

              // re-verify jar files

              log( "Re-verifying " + pid );

              for( int i = 0 ; i < pluginContents.length ; i++){

                File  jar_file = pluginContents[i];

                if ( jar_file.getName().endsWith( ".jar" )){

                  try{
                    log( "    verifying " + jar_file );

                    AEVerifier.verifyData( jar_file );

                    verified_files.add( jar_file );

                    log( "    OK" );

                  }catch( Throwable e ){

                    String  msg = "Error loading plugin '" + pluginName + "' / '" + plugin_class_string + "'";

                    Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e));

                    plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath());
                  }
                }
              }
            }

            if ( plugin == null ){

              plugin = PluginLauncherImpl.getPreloadedPlugin( plugin_class );

              if ( plugin == null ){

                try{
                  Class c = plugin_class_loader.loadClass(plugin_class);

                  plugin  = (Plugin) c.newInstance();

                  try{
                    // kick off any pre-inits

                    if ( plugin_class_loader instanceof URLClassLoader ){

                      URL[] urls = ((URLClassLoader)plugin_class_loader).getURLs();

                      for ( URL u: urls ){

                        String path = u.getPath();

                        if ( path.endsWith( ".jar" )){

                          int  s1 = path.lastIndexOf( '/' );
                          int  s2 = path.lastIndexOf( '\\' );

                          path = path.substring( Math.max( s1, s2 )+1);

                          s2 = path.indexOf( '_' );

                          if ( s2 > 0 ){

                            path = path.substring( 0, s2 );

                            path = path.replaceAll( "-", "" );
                           
                            String cl = "plugin.preinit." + pid + ".PI" + path;
                           
                            try{
                              Class pic = plugin_class_loader.loadClass( cl );

                              if ( pic != null ){

                                pic.newInstance();
                              }
                            }catch( Throwable e ){                       
                            }
                          }
                        }
                      }
                    }
                  }catch( Throwable e ){
                  }
                }catch (java.lang.UnsupportedClassVersionError e) {
                  plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath());

                  // shorten stack trace
                  load_failure  = new UnsupportedClassVersionError(e.getMessage());

                }catch( Throwable e ){

                  if (   e instanceof ClassNotFoundException &&
                      props.getProperty( "plugin.install_if_missing", "no" ).equalsIgnoreCase( "yes" )){

                    // don't report the failure

                  }else{

                    load_failure  = e;
                  }

                  plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath());
                }
              }else{

                plugin_class_loader = plugin.getClass().getClassLoader();
              }
            }

            MessageText.integratePluginMessages((String)props.get("plugin.langfile"),plugin_class_loader);

            PluginInterfaceImpl plugin_interface =
              new PluginInterfaceImpl(
                  plugin,
                  this,
                  directory,
                  plugin_class_loader,
                  verified_files,
                  directory.getName()// key for config values
                  new_props,
                  directory.getAbsolutePath(),
                  pid,
                  plugin_version[0] );

            boolean bEnabled = (loading_for_startup) ? plugin_interface.getPluginState().isLoadedAtStartup() : initialise;
            plugin_interface.getPluginState().setDisabled(!bEnabled);

            try{

              Method  load_method = plugin.getClass().getMethod( "load", new Class[]{ PluginInterface.class });

              load_method.invoke( plugin, new Object[]{ plugin_interface });

            }catch( NoSuchMethodException e ){

            }catch( Throwable e ){

              load_failure  = e;
            }

            loaded_pis.add( plugin_interface );

            if ( load_failure != null ){
              plugin_interface.setAsFailed();

              // don't complain about our internal one
              if ( !pid.equals(UpdaterUpdateChecker.getPluginID())){

                String msg = "Error loading plugin '" + pluginName + "' / '" + plugin_class_string + "'";
                LogAlert la;
                if (load_failure instanceof UnsupportedClassVersionError) {
                  la = new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, msg + ". " + MessageText.getString("plugin.install.class_version_error"));
                }
                else {
                  la = new LogAlert(LogAlert.UNREPEATABLE, msg, load_failure);
                }
                Logger.log(la);

                System.out.println( msg + ": " + load_failure);
              }
            }
          }
        }
        if ( p1 == -1 ){
          break;

        }
      }

      return( loaded_pis );

    }catch(Throwable e) {

      if ( e instanceof PluginException ){

        throw((PluginException)e);
      }

      Debug.printStackTrace( e );

      String  msg = "Error loading plugin '" + pluginName + "' / '" + plugin_class_string + "'";

      Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e));

      System.out.println( msg + ": " + e);

      throw( new PluginException( msg, e ));
    }
  }
 
  private void
  log(
  String  str )
  {
  if (Logger.isEnabled()){
    Logger.log(new LogEvent(LOGID, str ));
  }
  }
 
  public void
  initialisePlugins()
  {
    try{
      addInitThread();
     
      final LinkedList initQueue = new LinkedList();
     
      for (int i = 0; i < loaded_pi_list.size(); i++) {
        final int idx = i;
        initQueue.add(new Runnable() {
          public void run() {
            try {
              List l = (List) loaded_pi_list.get(idx);
             
              if (l.size() > 0) {
                PluginInterfaceImpl plugin_interface = (PluginInterfaceImpl) l.get(0);
     
                if (Logger.isEnabled())
                  Logger.log(new LogEvent(LOGID, "Initializing plugin '"
                      + plugin_interface.getPluginName() + "'"));
     
                if (core_operation != null) {
                  core_operation.reportCurrentTask(MessageText
                      .getString("splash.plugin.init")
                      + " " + plugin_interface.getPluginName());
                }
     
                initialisePlugin(l);
               
                if (Logger.isEnabled())
                  Logger.log(new LogEvent(LOGID, "Initialization of plugin '"
                      + plugin_interface.getPluginName() + "' complete"));
     
              }
     
            } catch ( Throwable e ){
              // already handled
            } finally {
              if (core_operation != null) {
                core_operation.reportPercent((100 * (idx + 1)) / loaded_pi_list.size());
              }
            }
           
            // some plugins try and steal the logger stdout redirects.
            // re-establish them if needed
            Logger.doRedirects();
          }
        });
      }
 

 
      // now do built in ones
     
      initQueue.add(new Runnable() {
        public void run() {
          if (Logger.isEnabled())
            Logger.log(new LogEvent(LOGID, "Initializing built-in plugins"));
        }
      });
 

 
      final PluginManagerDefaults def = PluginManager.getDefaults();
 
      for (int i = 0; i < builtin_plugins.length; i++) {
       
        final int idx = i;
       
        initQueue.add(new Runnable() {
          public void run() {
            if (def.isDefaultPluginEnabled(builtin_plugins[idx][0])) {
              String id = builtin_plugins[idx][2];
              String key = builtin_plugins[idx][3];
     
              try {
                Class cla = root_class_loader.loadClass(
                    builtin_plugins[idx][1]);
     
                if (Logger.isEnabled())
                  Logger.log(new LogEvent(LOGID, "Initializing built-in plugin '"
                      + builtin_plugins[idx][2] + "'" ));
     
                initializePluginFromClass(cla, id, key, "true".equals(builtin_plugins[idx][5]), true, true);
     
                if (Logger.isEnabled())
                Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
                    "Initialization of built in plugin '" + builtin_plugins[idx][2] + "' complete"));
              } catch (Throwable e) {
                try {
                  // replace it with a "broken" plugin instance
                  initializePluginFromClass(FailedPlugin.class, id, key, false, false, true);
     
                } catch (Throwable f) {
                }
     
                if (builtin_plugins[idx][4].equalsIgnoreCase("true")) {
                  Debug.printStackTrace(e);
                  Logger.log(new LogAlert(LogAlert.UNREPEATABLE,
                      "Initialization of built in plugin '" + builtin_plugins[idx][2]
                          + "' fails", e));
                }
              }
            } else {
              if (Logger.isEnabled())
                Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
                    "Built-in plugin '" + builtin_plugins[idx][2] + "' is disabled"));
            }
       
          }
        });

      }
 
      initQueue.add(new Runnable() {
        public void run() {
          if (Logger.isEnabled())
            Logger.log(new LogEvent(LOGID,
                "Initializing dynamically registered plugins"));
        }
      });

      for (int i = 0; i < registration_queue.size(); i++) {
       
        final int idx = i;
       
        initQueue.add(new Runnable() {
          public void run() {
            try {
              Object entry = registration_queue.get(idx);
     
              if (entry instanceof Class) {
     
                Class cla = (Class) entry;
     
                singleton.initializePluginFromClass(cla, INTERNAL_PLUGIN_ID, cla
                    .getName(), false, true, true);
     
              } else {
                Object[] x = (Object[]) entry;
     
                Plugin plugin = (Plugin) x[0];
     
                singleton.initializePluginFromInstance(plugin, (String) x[1], plugin
                    .getClass().getName());
              }
            } catch (PluginException e) {
            }
          }
        });
      }
     
      AEThread2 secondaryInitializer =
        new AEThread2("2nd PluginInitializer Thread",true)
        {
          public void run()
          {
           
            try{
              addInitThread();
             
              while( true ){
             
                Runnable toRun;
               
                synchronized (initQueue){
                 
                  if (initQueue.isEmpty()){
                   
                    break;
                  }
                 
                  toRun = (Runnable)initQueue.remove(0);
                }
               
                try{
                  toRun.run();
                 
                }catch( Throwable e ){
                 
                  Debug.out(e);
                }
              }
            }finally{
             
              removeInitThread();
            }
          }
        };
      secondaryInitializer.start();
     
      while(true){
     
        Runnable toRun;
       
        synchronized( initQueue ){
         
          if( initQueue.isEmpty()){
           
            break;
          }
         
          toRun = (Runnable)initQueue.remove(0);
        }
       
        try{
          toRun.run();
         
        }catch( Throwable e ){
         
          Debug.out(e);
        }
      }
     
      secondaryInitializer.join();
     
      registration_queue.clear();
     
      plugins_initialised = true;
     
      fireEvent( PluginEvent.PEV_ALL_PLUGINS_INITIALISED );
     
    }finally{
     
      removeInitThread();
    }
  }
 
    protected void
    checkPluginsInitialised()
    {
      if ( !plugins_initialised ){
       
        Debug.out( "Wait until plugin initialisation is complete until doing this!" );
      }
    }
 
    private void
  initialisePlugin(
    List  l )
   
      throws PluginException
    {
      PluginException  last_load_failure = null;
     
      for (int i=0;i<l.size();i++){
   
        final PluginInterfaceImpl  plugin_interface = (PluginInterfaceImpl)l.get(i);
       
        if (plugin_interface.getPluginState().isDisabled()) {
         
          synchronized( s_plugin_interfaces ){
           
            s_plugin_interfaces.add( plugin_interface );
          }
         
          continue;
        }
           
        if ( plugin_interface.getPluginState().isOperational()){
         
          continue;
        }
       
        Throwable  load_failure = null;
   
       final Plugin  plugin = plugin_interface.getPlugin();

        try{
       
          UtilitiesImpl.callWithPluginThreadContext(
            plugin_interface,
            new runnableWithException<PluginException>()
            {
              public void
              run()
                throws PluginException
              {
                fireCreated( plugin_interface );
       
                plugin.initialize(plugin_interface);
                 
                if (!(plugin instanceof FailedPlugin)){
           
                  plugin_interface.getPluginStateImpl().setOperational( true, false );
                }
              }
            });
         
        }catch( Throwable e ){
       
          load_failure  = e;
        }
    
        synchronized( s_plugin_interfaces ){
         
          s_plugins.add( plugin );
       
          s_plugin_interfaces.add( plugin_interface );
        }
       
        if ( load_failure != null ){
         
          Debug.printStackTrace( load_failure );
         
          String  msg = "Error initializing plugin '" + plugin_interface.getPluginName() + "'";
       
          Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, load_failure));
 
          System.out.println( msg + " : " + load_failure);
         
          last_load_failure = new PluginException( msg, load_failure );
        }
      }
     
      if ( last_load_failure != null ){
       
        throw( last_load_failure );
      }
    }
 
  protected void
  initializePluginFromClass(
    final Class   plugin_class,
  final String  plugin_id,
  String      plugin_config_key,
  boolean     force_enabled,
  boolean     loading_for_startup,
  boolean     initialise)
 
    throws PluginException
  {
 
    if ( plugin_class != FailedPlugin.class && getPluginFromClass( plugin_class ) != null ){
   
     
      Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
          "Error loading '" + plugin_id + "', plugin class '"
              + plugin_class.getName() + "' is already loaded"));
     
      return;
    }
       
    try{
      final Plugin plugin = (Plugin) plugin_class.newInstance();
     
      String  plugin_name;

      if ( plugin_config_key.length() == 0 ){

        plugin_name = plugin_class.getName();

        int  pos = plugin_name.lastIndexOf(".");

        if ( pos != -1 ){

          plugin_name = plugin_name.substring( pos+1 );

        }
      }else{

        plugin_name = plugin_config_key;
      }

      Properties properties = new Properties();
     
        // default plugin name
     
      properties.put( "plugin.name", plugin_name );
     
      final PluginInterfaceImpl plugin_interface =
        new PluginInterfaceImpl(
              plugin,
            this,
            plugin_class,
            plugin_class.getClassLoader(),
            null,
            plugin_config_key,
            properties,
            "",
            plugin_id,
            null );

      boolean bEnabled = (loading_for_startup) ? plugin_interface.getPluginState().isLoadedAtStartup() : initialise;
       
        /**
         * For some plugins, override any config setting which disables the plugin.
         */
        if (force_enabled && !bEnabled) {
          plugin_interface.getPluginState().setLoadedAtStartup(true);
          bEnabled = true;
          Logger.log(new LogAlert(false, LogAlert.AT_WARNING, MessageText.getString(
              "plugins.init.force_enabled", new String[] {plugin_id}
          )));
        }
       
        plugin_interface.getPluginState().setDisabled(!bEnabled);
     
        final boolean f_enabled = bEnabled;
       
        UtilitiesImpl.callWithPluginThreadContext(
           plugin_interface,
           new runnableWithException<PluginException>()
           {
             public void
             run()
               throws PluginException
             {
               try{

                 Method  load_method = plugin_class.getMethod( "load", new Class[]{ PluginInterface.class });

                 load_method.invoke( plugin, new Object[]{ plugin_interface });

               }catch( NoSuchMethodException e ){

               }catch( Throwable e ){

                 Debug.printStackTrace( e );

                 Logger.log(new LogAlert(LogAlert.UNREPEATABLE,
                     "Load of built in plugin '" + plugin_id + "' fails", e));
               }

               if (f_enabled) {

                 if ( core_operation != null ){

                   core_operation.reportCurrentTask(MessageText.getString("splash.plugin.init") + " " + plugin_interface.getPluginName());
                 }

                 fireCreated( plugin_interface );

                 plugin.initialize(plugin_interface);

                 if (!(plugin instanceof FailedPlugin)){

                   plugin_interface.getPluginStateImpl().setOperational( true, false );
                 }
               }
             }
           });
     
     synchronized( s_plugin_interfaces ){
      
      s_plugins.add( plugin );
      
      s_plugin_interfaces.add( plugin_interface );
     }
    }catch(Throwable e){
     
      Debug.printStackTrace( e );
     
      String  msg = "Error loading internal plugin '" + plugin_class.getName() + "'";

      Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e));

      System.out.println(msg + " : " + e);
     
      throw( new PluginException( msg, e ));
    }
  }
 
  protected void
  initializePluginFromInstance(
    final Plugin    plugin,
  String        plugin_id,
  String        plugin_config_key )
 
    throws PluginException
  {
    try{   
      final PluginInterfaceImpl plugin_interface =
        new PluginInterfaceImpl(
              plugin,
            this,
            plugin.getClass(),
            plugin.getClass().getClassLoader(),
            null,
            plugin_config_key,
            new Properties(),
            "",
            plugin_id,
            null );
     
    UtilitiesImpl.callWithPluginThreadContext(
      plugin_interface,
      new UtilitiesImpl.runnableWithException<PluginException>()
      {
        public void
        run()
       
          throws PluginException
        {
          fireCreated( plugin_interface );
         
            plugin.initialize(plugin_interface);
           
            if (!(plugin instanceof FailedPlugin)){
             
              plugin_interface.getPluginStateImpl().setOperational( true, false );
            }
        }
      });
           
      synchronized( s_plugin_interfaces ){
      
        s_plugins.add( plugin );
      
        s_plugin_interfaces.add( plugin_interface );
      }
    }catch(Throwable e){
     
      Debug.printStackTrace( e );
     
      String  msg = "Error loading internal plugin '" + plugin.getClass().getName() + "'";
     
      Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e));

      System.out.println(msg + " : " + e);
     
      throw( new PluginException( msg, e ));
    }  
  }
 
  protected void
  unloadPlugin(
    PluginInterfaceImpl    pi )
  {
  synchronized( s_plugin_interfaces ){
 
    s_plugins.remove( pi.getPlugin());
   
    s_plugin_interfaces.remove( pi );
  }
 
    pi.unloadSupport();
   
    for (int i=0;i<loaded_pi_list.size();i++){
     
      List  l = (List)loaded_pi_list.get(i);
     
      if ( l.remove(pi)){
     
        if ( l.size() == 0 ){
         
          loaded_pi_list.remove(i);
        }
       
        return;
      }
    }
  }
 
  protected void reloadPlugin(PluginInterfaceImpl pi) throws PluginException {
    reloadPlugin(pi, false, true);
  }
 
  protected void reloadPlugin(
      PluginInterfaceImpl pi,
      boolean loading_for_startup,
      boolean initialise) throws PluginException {
   
    unloadPlugin( pi );
   
    Object key       = pi.getInitializerKey();
    String config_key  = pi.getPluginConfigKey();
   
    if ( key instanceof File ){
     
      List  pis = loadPluginFromDir( (File)key, false, loading_for_startup, initialise);
     
      initialisePlugin( pis );
     
    }else{
      initializePluginFromClass( (Class) key, pi.getPluginID(), config_key, false, loading_for_startup, initialise );
    }
  }
  protected AzureusCore
  getAzureusCore()
  {
    return( azureus_core );
  }
 
  protected GlobalManager
  getGlobalManager()
  {
    return( azureus_core.getGlobalManager() );
  }
 
  public static PluginInterface
  getDefaultInterface()
  {
    if (singleton == null) {
      throw new AzureusCoreException(
          "PluginInitializer not instantiated by AzureusCore.create yet");
    }
    return( singleton.getDefaultInterfaceSupport());
  }

  protected PluginInterface
  getDefaultInterfaceSupport()
  {
 
    if ( default_plugin == null ){
     
      try{
        default_plugin =
          new PluginInterfaceImpl(
              new Plugin()
            {
                public void
              initialize(
                PluginInterface pi)
                {
                }
            },
            this,
            getClass(),
            getClass().getClassLoader(),
            null,
            "default",
            new Properties(),
            null,
            INTERNAL_PLUGIN_ID,
            null );
       
      }catch( Throwable e ){
       
        Debug.out( e );
      }
    }
   
    return( default_plugin );
  }
 
  public void
  downloadManagerAdded(
    DownloadManager  dm )
  {
  }
 
  public void
  downloadManagerRemoved(
    DownloadManager  dm )
  {
  }
 
  public void
  destroyInitiated()
  { 
    List plugin_interfaces;

    synchronized( s_plugin_interfaces ){

      plugin_interfaces = new ArrayList( s_plugin_interfaces );
    }
   
    for (int i=0;i<plugin_interfaces.size();i++){

      ((PluginInterfaceImpl)plugin_interfaces.get(i)).closedownInitiated();
    }

    if ( default_plugin != null ){

      default_plugin.closedownInitiated();
    }
  }
 
  public void
  destroyed()
  {
    List plugin_interfaces;

    synchronized( s_plugin_interfaces ){

      plugin_interfaces = new ArrayList( s_plugin_interfaces );
    }

    for (int i=0;i<plugin_interfaces.size();i++){

      ((PluginInterfaceImpl)plugin_interfaces.get(i)).closedownComplete();
   

    if ( default_plugin != null ){

      default_plugin.closedownComplete();
    }
  }
 
 
  public void seedingStatusChanged( boolean seeding_only_mode, boolean b ){
    /*nothing*/
  }
 
  protected void
  runPEVTask(
    AERunnable  run )
  {
    async_dispatcher.dispatch( run );
  }
 
 
  protected List<PluginEvent>
  getPEVHistory()
  {
    return( plugin_event_history );
  }
 
  protected void
  fireEventSupport(
    final int    type,
    final Object  value )
  {
    async_dispatcher.dispatch(
     new AERunnable()
     {
       public void
       runSupport()
       {    
          PluginEvent  ev =
            new PluginEvent()
            {
              public int
              getType()
              {
                return( type );
              }
             
              public Object
              getValue()
              {
                return( value );
              }
            };
         
          if (   type == PluginEvent.PEV_CONFIGURATION_WIZARD_STARTS ||
              type == PluginEvent.PEV_CONFIGURATION_WIZARD_COMPLETES ||
              type == PluginEvent.PEV_INITIAL_SHARING_COMPLETE ||
              type == PluginEvent.PEV_INITIALISATION_UI_COMPLETES ||
              type == PluginEvent.PEV_ALL_PLUGINS_INITIALISED ){
           
            plugin_event_history.add( ev );
           
            if ( plugin_event_history.size() > 1024 ){
             
              Debug.out( "Plugin event history too large!!!!" );
             
              plugin_event_history.remove( 0 );
            }
          }
         
          List plugin_interfaces;
               
          synchronized( s_plugin_interfaces ){
             
            plugin_interfaces = new ArrayList( s_plugin_interfaces );
          }
         
          for (int i=0;i<plugin_interfaces.size();i++){
           
            try{
              ((PluginInterfaceImpl)plugin_interfaces.get(i)).firePluginEventSupport(ev);
             
            }catch(Throwable e ){
             
              Debug.printStackTrace(e);
            }
          }
         
         if ( default_plugin != null ){
           
            default_plugin.firePluginEventSupport(ev);
          }
        }
     });
  }
 
  private void
  waitForEvents()
  {
    if ( async_dispatcher.isDispatchThread()){
     
      Debug.out( "Deadlock - recode this monkey boy" );
     
    }else{
     
      final AESemaphore sem = new AESemaphore( "waiter" );
     
      async_dispatcher.dispatch(
        new AERunnable()
        {
          public void
          runSupport()
          {
            sem.release();
          }
        });
     
      if ( !sem.reserve( 10*1000 )){
       
        Debug.out( "Timeout waiting for event dispatch" );
      }
        
    }
  }
 
  public static void
  fireEvent(
    int    type )
  {
    singleton.fireEventSupport(type, null);
 
 
  public static void
  fireEvent(
  int    type,
  Object  value )
  {
    singleton.fireEventSupport(type, value);
  }
 
  public static void
  waitForPluginEvents()
  {
    singleton.waitForEvents();
  }
 
  public void
  initialisationComplete()
  {
    initialisation_complete  = true;
   
    UIManagerImpl.initialisationComplete();
   
  List plugin_interfaces;
 
  synchronized( s_plugin_interfaces ){
   
    plugin_interfaces = new ArrayList( s_plugin_interfaces );
  }
 
    for (int i=0;i<plugin_interfaces.size();i++){
     
      ((PluginInterfaceImpl)plugin_interfaces.get(i)).initialisationComplete();
    }
   
    if ( default_plugin != null ){
     
      default_plugin.initialisationComplete();
    }
  }
 
  protected boolean
  isInitialisationComplete()
  {
    return( initialisation_complete );
  }
 
 
  public static List getPluginInterfaces() {
    return singleton.getPluginInterfacesSupport();
  }

  protected List getPluginInterfacesSupport() {
   
  checkPluginsInitialised();
   
  synchronized( s_plugin_interfaces ){
   
    return( new ArrayList( s_plugin_interfaces ));
  }
  }
 
  public PluginInterface[]
  getPlugins()
  {
    List  pis = getPluginInterfacesSupport();
   
    PluginInterface[]  res = new   PluginInterface[pis.size()];
   
    pis.toArray(res);
   
    return( res );
  }
 
  protected PluginManager
  getPluginManager()
  {
    return( plugin_manager );
  }
 
  protected PluginInterfaceImpl
  getPluginFromClass(
    Class  cla )
  {
    return( getPluginFromClass( cla.getName()));
  }
 
  protected PluginInterfaceImpl
  getPluginFromClass(
    String  class_name )
  { 
  List plugin_interfaces;
 
  synchronized( s_plugin_interfaces ){
   
    plugin_interfaces = new ArrayList( s_plugin_interfaces );
  }
 
    for (int i=0;i<plugin_interfaces.size();i++){
     
      PluginInterfaceImpl  pi = (PluginInterfaceImpl)plugin_interfaces.get(i);
     
      if ( pi.getPlugin().getClass().getName().equals( class_name )){
     
        return( pi );
      }
    }
   
      // fall back to the loaded but not-yet-initialised list
   
    for (int i=0;i<loaded_pi_list.size();i++){
     
      List  l = (List)loaded_pi_list.get(i);
     
      for (int j=0;j<l.size();j++){
       
        PluginInterfaceImpl  pi = (PluginInterfaceImpl)l.get(j);
       
        if ( pi.getPlugin().getClass().getName().equals( class_name )){
           
            return( pi );
          }
      }
    }
   
    return( null );
  }
 
 
  public void
  generate(
    IndentWriter    writer )
  {
    writer.println( "Plugins" );
     
    try{
      writer.indent();

      List plugin_interfaces;
     
      synchronized( s_plugin_interfaces ){
       
        plugin_interfaces = new ArrayList( s_plugin_interfaces );
      }
     
       for (int i=0;i<plugin_interfaces.size();i++){
         
          PluginInterfaceImpl  pi = (PluginInterfaceImpl)plugin_interfaces.get(i);

          pi.generateEvidence( writer );
       }
      
    }finally{
     
      writer.exdent();
    }
  }
 
  protected static void
  setVerified(
    PluginInterfaceImpl    pi,
    Plugin          plugin,
    boolean          v,
    boolean          bad )
 
    throws PluginException
  {   
    Object[] existing = (Object[])verified_plugin_holder.setValue( pi, new Object[]{ plugin, v });
   
    if ( existing != null && ( existing[0] != plugin || (Boolean)existing[1] != v )){
     
      throw( new PluginException( "Verified status change not permitted" ));
    }
   
        if ( bad && !DISABLE_PLUGIN_VERIFICATION ){
     
      throw( new RuntimeException( "Plugin verification failed" ));
    }
  }
 
  public static boolean
  isVerified(
    PluginInterface    pi,
    Plugin        plugin )
  {
    if ( !( pi instanceof PluginInterfaceImpl )){
     
      return( false );
    }
   
    VerifiedPluginHolder holder = verified_plugin_holder;
   
    if ( holder.getClass() != VerifiedPluginHolder.class ){
   
      Debug.out( "class mismatch" );
     
      return( false );
    }
   
    if ( DISABLE_PLUGIN_VERIFICATION ){
     
      Debug.out( " **************************** VERIFICATION DISABLED ******************" );
     
      return( true );
    }
   
    Object[] ver = (Object[])verified_plugin_holder.getValue( pi );
   
    return( ver != null && ver[0] == plugin && (Boolean)ver[1] );
  }
 
  public static boolean
  isCoreOrVerifiedPlugin()
  {
    Class<?>[] stack = SESecurityManager.getClassContext();
   
    ClassLoader core = PluginInitializer.class.getClassLoader();
   
    PluginInitializer singleton = peekSingleton();
   
    PluginInterface[] pis = singleton==null?new PluginInterface[0]:singleton.getPlugins();

    Set<ClassLoader>  ok_loaders = new HashSet<ClassLoader>();
   
    ok_loaders.add( core );
   
    for ( Class<?> c: stack ){
     
      ClassLoader cl = c.getClassLoader();
     
      if ( cl != null && !ok_loaders.contains( cl )){
       
        boolean ok = false;
       
        for ( PluginInterface pi: pis ){
         
          Plugin plugin = pi.getPlugin();
         
          if ( plugin.getClass().getClassLoader() == cl ){
           
            if ( isVerified( pi, plugin )){
             
              ok_loaders.add( cl );
             
              ok = true;
             
              break;
            }
          }
        }
       
        if ( !ok ){
         
          Debug.out( "Class " + c.getCanonicalName() + " with loader " + cl + " isn't trusted" );
         
          return( false );
        }
      }
    }
   
    return( true );
  }
 
  private static final class
  VerifiedPluginHolder
 
    private volatile boolean initialised;
   
    private AESemaphore  request_sem = new AESemaphore( "ValueHolder" );
   
    private List<Object[]>  request_queue = new ArrayList<Object[]>();
       
    private
    VerifiedPluginHolder()
    {
      Class[] context = SESecurityManager.getClassContext();
     
      if ( context[2] != PluginInitializer.class ){
       
        Debug.out( "Illegal operation" );
       
        return;
      }
     
      AEThread2 t =
        new AEThread2( "PluginVerifier" )
        {
          public void
          run()
          {
            Map<Object,Object> values = new IdentityHashMap<Object,Object>();
                       
            while( true ){
                           
              request_sem.reserve();
             
              Object[] req;
             
              synchronized( request_queue ){
               
                req = request_queue.remove(0);
              }
             
              if ( req[1] == null ){
               
                req[1] = values.get( req[0] );
               
              }else{
               
                Object existing = values.get( req[0] );
               
                if ( existing != null){
                 
                  req[1] = existing;
                 
                }else{
                 
                  values.put( req[0], req[1] );
                }
              }
             
              ((AESemaphore)req[2]).release();
            }
          }
        };
     
      t.start()
     
      initialised = true;
    }
   
    public Object
    setValue(
      Object  key,
      Object  value )
    { 
      if ( !initialised ){
       
        return( null );
      }
     
      AESemaphore sem = new AESemaphore( "ValueHolder:set" );
     
      Object[] request = new Object[]{ key, value, sem };
     
      synchronized( request_queue ){
       
        request_queue.add( request );
      }
     
      request_sem.release();
     
      sem.reserve();
     
      return(request[1]);
    }
   
    public Object
    getValue(
      Object  key )
    { 
      if ( !initialised ){
       
        return( null );
      }
     
      AESemaphore sem = new AESemaphore( "ValueHolder:get" );
     
      Object[] request = new Object[]{ key, null, sem };

      synchronized( request_queue ){
       
        request_queue.add( request );
      }
     
      request_sem.release();
     
      sem.reserve();
     
      return( request[1] );
    }
  }
}
TOP

Related Classes of org.gudy.azureus2.pluginsimpl.local.PluginInitializer$VerifiedPluginHolder

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.