1 /* 2 * File : PluginInitializer.java 3 * Created : 2 nov. 2003 18:59:17 4 * By : Olivier 5 * 6 * Azureus - a Java Bittorrent client 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details ( see the LICENSE file ). 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 package org.gudy.azureus2.pluginsimpl.local; 24 25 import java.io.File; 26 import java.io.FileInputStream; 27 import java.io.InputStream; 28 import java.lang.reflect.Method; 29 import java.net.URL; 30 import java.net.URLClassLoader; 31 import java.net.URLConnection; 32 import java.util.*; 33 34 import org.gudy.azureus2.core3.config.COConfigurationManager; 35 import org.gudy.azureus2.core3.download.DownloadManager; 36 import org.gudy.azureus2.core3.global.GlobalManager; 37 import org.gudy.azureus2.core3.global.GlobalManagerListener; 38 import org.gudy.azureus2.core3.internat.MessageText; 39 import org.gudy.azureus2.core3.logging.*; 40 import org.gudy.azureus2.core3.security.SESecurityManager; 41 import org.gudy.azureus2.core3.util.*; 42 import org.gudy.azureus2.platform.PlatformManagerFactory; 43 import org.gudy.azureus2.plugins.*; 44 import org.gudy.azureus2.plugins.platform.PlatformManagerException; 45 import org.gudy.azureus2.pluginsimpl.local.launch.PluginLauncherImpl; 46 import org.gudy.azureus2.pluginsimpl.local.ui.UIManagerImpl; 47 import org.gudy.azureus2.pluginsimpl.local.update.UpdateManagerImpl; 48 import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl; 49 import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl.runnableWithException; 50 import org.gudy.azureus2.update.UpdaterUpdateChecker; 51 import org.gudy.azureus2.update.UpdaterUtils; 52 53 54 import com.aelitis.azureus.core.*; 55 import com.aelitis.azureus.core.versioncheck.VersionCheckClient; 56 57 58 59 /** 60 * @author Olivier 61 * 62 */ 63 public class 64 PluginInitializer 65 implements GlobalManagerListener, AEDiagnosticsEvidenceGenerator 66 { 67 public static final boolean DISABLE_PLUGIN_VERIFICATION = false; 68 69 private static final LogIDs LOGID = LogIDs.CORE; 70 public static final String INTERNAL_PLUGIN_ID = "<internal>"; 71 72 // class name, plugin id, plugin key (key used for config props so if you change 73 // it you'll need to migrate the config) 74 // "id" is used when checking for updates 75 76 // IF YOU ADD TO THE BUILTIN PLUGINS, AMEND PluginManagerDefault appropriately!!!! 77 78 // Plugin ID constant 79 // class 80 // plugin id 81 // plugin key for prefixing config data 82 // report if not present 83 // force re-enable if disabled by config 84 85 private String[][] builtin_plugins = { 86 { PluginManagerDefaults.PID_START_STOP_RULES, 87 "com.aelitis.azureus.plugins.startstoprules.defaultplugin.StartStopRulesDefaultPlugin", 88 "azbpstartstoprules", 89 "", 90 "true", 91 "true"}, 92 { PluginManagerDefaults.PID_REMOVE_RULES, 93 "com.aelitis.azureus.plugins.removerules.DownloadRemoveRulesPlugin", 94 "azbpremovalrules", 95 "", 96 "true", 97 "false"}, 98 { PluginManagerDefaults.PID_SHARE_HOSTER, 99 "com.aelitis.azureus.plugins.sharing.hoster.ShareHosterPlugin", 100 "azbpsharehoster", 101 "ShareHoster", 102 "true", 103 "false"}, 104 { PluginManagerDefaults.PID_PLUGIN_UPDATE_CHECKER, 105 "org.gudy.azureus2.pluginsimpl.update.PluginUpdatePlugin", 106 "azbppluginupdate", 107 "PluginUpdate", 108 "true", 109 "true"}, 110 { PluginManagerDefaults.PID_UPNP, 111 "com.aelitis.azureus.plugins.upnp.UPnPPlugin", 112 "azbpupnp", 113 "UPnP", 114 "true", 115 "false"}, 116 { PluginManagerDefaults.PID_DHT, 117 "com.aelitis.azureus.plugins.dht.DHTPlugin", 118 "azbpdht", 119 "DHT", 120 "true", 121 "false"}, 122 { PluginManagerDefaults.PID_DHT_TRACKER, 123 "com.aelitis.azureus.plugins.tracker.dht.DHTTrackerPlugin", 124 "azbpdhdtracker", 125 "DHT Tracker", 126 "true", 127 "false"}, 128 { PluginManagerDefaults.PID_MAGNET, 129 "com.aelitis.azureus.plugins.magnet.MagnetPlugin", 130 "azbpmagnet", 131 "Magnet URI Handler", 132 "true", 133 "false"}, 134 { PluginManagerDefaults.PID_CORE_UPDATE_CHECKER, 135 "org.gudy.azureus2.update.CoreUpdateChecker", 136 "azbpcoreupdater", 137 "CoreUpdater", 138 "true", 139 "true"}, 140 { PluginManagerDefaults.PID_CORE_PATCH_CHECKER, 141 "org.gudy.azureus2.update.CorePatchChecker", 142 "azbpcorepatcher", 143 "CorePatcher", 144 "true", 145 "true"}, 146 { PluginManagerDefaults.PID_PLATFORM_CHECKER, 147 "org.gudy.azureus2.platform.PlatformManagerPluginDelegate", 148 "azplatform2", 149 "azplatform2", 150 "true", 151 "false"}, 152 //{ PluginManagerDefaults.PID_JPC, 153 // "com.aelitis.azureus.plugins.jpc.JPCPlugin", 154 // "azjpc", 155 // "azjpc", 156 // "false" }, 157 { PluginManagerDefaults.PID_EXTERNAL_SEED, 158 "com.aelitis.azureus.plugins.extseed.ExternalSeedPlugin", 159 "azextseed", 160 "azextseed", 161 "true", 162 "false"}, 163 { PluginManagerDefaults.PID_LOCAL_TRACKER, 164 "com.aelitis.azureus.plugins.tracker.local.LocalTrackerPlugin", 165 "azlocaltracker", 166 "azlocaltracker", 167 "true", 168 "false"}, 169 { PluginManagerDefaults.PID_NET_STATUS, 170 "com.aelitis.azureus.plugins.net.netstatus.NetStatusPlugin", 171 "aznetstat", 172 "aznetstat", 173 "true", 174 "false"}, 175 { PluginManagerDefaults.PID_BUDDY, 176 "com.aelitis.azureus.plugins.net.buddy.BuddyPlugin", 177 "azbuddy", 178 "azbuddy", 179 "true", 180 "false"}, 181 { PluginManagerDefaults.PID_RSS, 182 "com.aelitis.azureus.core.rssgen.RSSGeneratorPlugin", 183 "azintrss", 184 "azintrss", 185 "true", 186 "false"}, 187 /* disable until we can get some tracker admins to work on this 188 { PluginManagerDefaults.PID_TRACKER_PEER_AUTH, 189 "com.aelitis.azureus.plugins.tracker.peerauth.TrackerPeerAuthPlugin", 190 "aztrackerpeerauth", 191 "aztrackerpeerauth", 192 "true", 193 "false" }, 194 */ 195 }; 196 197 static VerifiedPluginHolder verified_plugin_holder; 198 199 static{ 200 synchronized( PluginInitializer.class ){ 201 202 verified_plugin_holder = new VerifiedPluginHolder(); 203 } 204 } 205 206 // these can be removed one day 207 208 private static String[][]default_version_details = 209 { 210 { "org.cneclipse.multiport.MultiPortPlugin", 211 "multi-ports", "Mutli-Port Trackers", "1.0" }, 212 }; 213 214 private static PluginInitializer singleton; 215 private static AEMonitor class_mon = new AEMonitor( "PluginInitializer"); 216 217 private static List registration_queue = new ArrayList(); 218 219 private static List initThreads = new ArrayList(1); 220 221 private static AsyncDispatcher async_dispatcher = new AsyncDispatcher(); 222 private static List<PluginEvent> plugin_event_history = new ArrayList<PluginEvent>(); 223 224 225 226 private AzureusCoreOperation core_operation; 227 228 private AzureusCore azureus_core; 229 230 private PluginInterfaceImpl default_plugin; 231 private PluginManager plugin_manager; 232 233 private ClassLoader root_class_loader = getClass().getClassLoader(); 234 235 private List loaded_pi_list = new ArrayList(); 236 237 private static boolean loading_builtin; 238 239 private List<Plugin> s_plugins = new ArrayList<Plugin>(); 240 private List<PluginInterfaceImpl> s_plugin_interfaces = new ArrayList<PluginInterfaceImpl>(); 241 242 private boolean initialisation_complete; 243 244 private volatile boolean plugins_initialised; 245 246 private Set<String> vc_disabled_plugins = VersionCheckClient.getSingleton().getDisabledPluginIDs(); 247 248 public static PluginInitializer getSingleton( AzureusCore azureus_core, AzureusCoreOperation core_operation )249 getSingleton( 250 AzureusCore azureus_core, 251 AzureusCoreOperation core_operation ) 252 { 253 try{ 254 class_mon.enter(); 255 256 if ( singleton == null ){ 257 258 singleton = new PluginInitializer( azureus_core, core_operation ); 259 } 260 261 return( singleton ); 262 263 }finally{ 264 265 class_mon.exit(); 266 } 267 } 268 269 private static PluginInitializer peekSingleton()270 peekSingleton() 271 { 272 try{ 273 class_mon.enter(); 274 275 return( singleton ); 276 277 }finally{ 278 279 class_mon.exit(); 280 } 281 } 282 283 protected static void queueRegistration( Class _class )284 queueRegistration( 285 Class _class ) 286 { 287 try{ 288 class_mon.enter(); 289 290 if ( singleton == null ){ 291 292 registration_queue.add( _class ); 293 294 }else{ 295 296 try{ 297 singleton.initializePluginFromClass( _class, INTERNAL_PLUGIN_ID, _class.getName(), false, false, true); 298 299 }catch(PluginException e ){ 300 301 } 302 } 303 }finally{ 304 305 class_mon.exit(); 306 } 307 } 308 309 protected static void queueRegistration( Plugin plugin, String id, String config_key )310 queueRegistration( 311 Plugin plugin, 312 String id, 313 String config_key ) 314 { 315 try{ 316 class_mon.enter(); 317 318 if ( singleton == null ){ 319 320 registration_queue.add( new Object[]{ plugin, id, config_key }); 321 322 }else{ 323 324 try{ 325 singleton.initializePluginFromInstance( plugin, id, config_key ); 326 327 }catch( Throwable e ){ 328 329 Debug.out( e ); 330 } 331 } 332 }finally{ 333 334 class_mon.exit(); 335 } 336 } 337 338 protected static boolean isLoadingBuiltin()339 isLoadingBuiltin() 340 { 341 return( loading_builtin ); 342 } 343 344 public static void checkAzureusVersion( String name, Properties props, boolean alert_on_fail )345 checkAzureusVersion( 346 String name, 347 Properties props, 348 boolean alert_on_fail 349 ) throws PluginException { 350 351 String required_version = (String)props.get("plugin.azureus.min_version"); 352 if (required_version == null) {return;} 353 if (Constants.compareVersions(Constants.AZUREUS_VERSION, required_version) < 0) { 354 String plugin_name_bit = name.length() > 0 ? (name+" "):""; 355 String msg = "Plugin " + plugin_name_bit + "requires " + Constants.APP_NAME + " version " + required_version + " or higher"; 356 if (alert_on_fail) { 357 Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, msg)); 358 } 359 throw new PluginException(msg); 360 } 361 } 362 363 public static void checkJDKVersion( String name, Properties props, boolean alert_on_fail )364 checkJDKVersion( 365 String name, 366 Properties props, 367 boolean alert_on_fail ) 368 369 throws PluginException 370 { 371 String required_jdk = (String)props.get( "plugin.jdk.min_version" ); 372 373 if ( required_jdk != null ){ 374 375 String actual_jdk = Constants.JAVA_VERSION; 376 377 required_jdk = normaliseJDK( required_jdk ); 378 actual_jdk = normaliseJDK( actual_jdk ); 379 380 if ( required_jdk.length() == 0 || actual_jdk.length() == 0 ){ 381 382 return; 383 } 384 385 if ( Constants.compareVersions( actual_jdk, required_jdk ) < 0 ){ 386 387 String msg = "Plugin " + (name.length()>0?(name+" "):"" ) + "requires Java version " + required_jdk + " or higher"; 388 389 if ( alert_on_fail ){ 390 391 Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, msg)); 392 } 393 394 throw( new PluginException( msg )); 395 } 396 } 397 } 398 399 protected static String normaliseJDK( String jdk )400 normaliseJDK( 401 String jdk ) 402 { 403 try{ 404 String str = ""; 405 406 // take leading digit+. portion only 407 408 for (int i=0;i<jdk.length();i++){ 409 410 char c = jdk.charAt( i ); 411 412 if ( c == '.' || Character.isDigit( c )){ 413 414 str += c; 415 416 }else{ 417 418 break; 419 } 420 } 421 422 // convert 5|6|... to 1.5|1.6 etc 423 424 if ( Integer.parseInt( "" + str.charAt(0)) > 1 ){ 425 426 str = "1." + str; 427 } 428 429 return( str ); 430 431 }catch( Throwable e ){ 432 433 return( "" ); 434 } 435 } 436 437 protected PluginInitializer( AzureusCore _azureus_core, AzureusCoreOperation _core_operation )438 PluginInitializer( 439 AzureusCore _azureus_core, 440 AzureusCoreOperation _core_operation ) 441 { 442 azureus_core = _azureus_core; 443 444 AEDiagnostics.addEvidenceGenerator( this ); 445 446 azureus_core.addLifecycleListener( 447 new AzureusCoreLifecycleAdapter() 448 { 449 public void 450 componentCreated( 451 AzureusCore core, 452 AzureusCoreComponent comp ) 453 { 454 if ( comp instanceof GlobalManager ){ 455 456 GlobalManager gm = (GlobalManager)comp; 457 458 gm.addListener( PluginInitializer.this ); 459 } 460 } 461 }); 462 463 core_operation = _core_operation; 464 465 UpdateManagerImpl.getSingleton( azureus_core ); // initialise the update manager 466 467 plugin_manager = PluginManagerImpl.getSingleton( this ); 468 469 String dynamic_plugins = System.getProperty( "azureus.dynamic.plugins", null ); 470 471 if ( dynamic_plugins != null ){ 472 473 String[] classes = dynamic_plugins.split( ";" ); 474 475 for ( String c: classes ){ 476 477 try{ 478 queueRegistration( Class.forName( c )); 479 480 }catch( Throwable e ){ 481 482 Debug.out( "Registration of dynamic plugin '" + c + "' failed", e ); 483 } 484 } 485 } 486 487 UpdaterUtils.checkBootstrapPlugins(); 488 } 489 490 protected void fireCreated( PluginInterfaceImpl pi )491 fireCreated( 492 PluginInterfaceImpl pi ) 493 { 494 azureus_core.triggerLifeCycleComponentCreated( pi ); 495 } 496 497 protected void fireOperational( PluginInterfaceImpl pi, boolean op )498 fireOperational( 499 PluginInterfaceImpl pi, 500 boolean op ) 501 { 502 fireEventSupport( op?PluginEvent.PEV_PLUGIN_OPERATIONAL:PluginEvent.PEV_PLUGIN_NOT_OPERATIONAL, pi ); 503 } 504 505 public static void addInitThread()506 addInitThread() 507 { 508 synchronized( initThreads ){ 509 510 if ( initThreads.contains( Thread.currentThread())){ 511 512 Debug.out( "Already added" ); 513 } 514 515 initThreads.add( Thread.currentThread()); 516 } 517 } 518 519 public static void removeInitThread()520 removeInitThread() 521 { 522 synchronized( initThreads ){ 523 524 initThreads.remove( Thread.currentThread()); 525 } 526 } 527 528 public static boolean isInitThread()529 isInitThread() 530 { 531 synchronized( initThreads ){ 532 533 return initThreads.contains(Thread.currentThread()); 534 } 535 } 536 537 protected boolean isInitialisationThread()538 isInitialisationThread() 539 { 540 return( isInitThread()); 541 } 542 543 public List loadPlugins( AzureusCore core, boolean bSkipAlreadyLoaded, boolean load_external_plugins, boolean loading_for_startup, boolean initialise_plugins)544 loadPlugins( 545 AzureusCore core, 546 boolean bSkipAlreadyLoaded, 547 boolean load_external_plugins, 548 boolean loading_for_startup, 549 boolean initialise_plugins) 550 { 551 if ( bSkipAlreadyLoaded ){ 552 553 // discard any failed ones 554 555 List pis; 556 557 synchronized( s_plugin_interfaces ){ 558 559 pis = new ArrayList( s_plugin_interfaces ); 560 } 561 562 for (int i=0;i<pis.size();i++){ 563 564 PluginInterfaceImpl pi = (PluginInterfaceImpl)pis.get(i); 565 566 Plugin p = pi.getPlugin(); 567 568 if ( p instanceof FailedPlugin ){ 569 570 unloadPlugin( pi ); 571 } 572 } 573 574 } 575 576 List pluginLoaded = new ArrayList(); 577 578 PluginManagerImpl.setStartDetails( core ); 579 580 getRootClassLoader(); 581 582 // first do explicit plugins 583 584 File user_dir = FileUtil.getUserFile("plugins"); 585 586 File app_dir = FileUtil.getApplicationFile("plugins"); 587 588 int user_plugins = 0; 589 int app_plugins = 0; 590 591 if ( user_dir.exists() && user_dir.isDirectory()){ 592 593 user_plugins = user_dir.listFiles().length; 594 595 } 596 597 if ( app_dir.exists() && app_dir.isDirectory()){ 598 599 app_plugins = app_dir.listFiles().length; 600 601 } 602 603 // user ones first so they override app ones if present 604 605 if (load_external_plugins) { 606 pluginLoaded.addAll(loadPluginsFromDir(user_dir, 0, user_plugins 607 + app_plugins, bSkipAlreadyLoaded, loading_for_startup, initialise_plugins)); 608 609 if ( !user_dir.equals( app_dir )){ 610 611 pluginLoaded.addAll(loadPluginsFromDir(app_dir, user_plugins, 612 user_plugins + app_plugins, bSkipAlreadyLoaded, loading_for_startup, initialise_plugins)); 613 } 614 } 615 else { 616 if (Logger.isEnabled()) { 617 Logger.log(new LogEvent(LOGID, "Loading of external plugins skipped")); 618 } 619 } 620 621 if (Logger.isEnabled()) 622 Logger.log(new LogEvent(LOGID, "Loading built-in plugins")); 623 624 PluginManagerDefaults def = PluginManager.getDefaults(); 625 626 for (int i=0;i<builtin_plugins.length;i++){ 627 628 if ( def.isDefaultPluginEnabled( builtin_plugins[i][0])){ 629 630 if (core_operation != null) { 631 core_operation.reportCurrentTask(MessageText.getString("splash.plugin") 632 + builtin_plugins[i][0]); 633 } 634 635 try{ 636 loading_builtin = true; 637 638 // lazyness here, for builtin we use static load method with default plugin interface 639 // if we need to improve on this then we'll have to move to a system more akin to 640 // the dir-loaded plugins 641 642 Class cla = root_class_loader.loadClass( builtin_plugins[i][1]); 643 644 Method load_method = cla.getMethod( "load", new Class[]{ PluginInterface.class }); 645 646 load_method.invoke( null, new Object[]{ getDefaultInterfaceSupport() }); 647 648 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 649 "Built-in plugin '" + builtin_plugins[i][0] + "' ok")); 650 }catch( NoSuchMethodException e ){ 651 652 }catch( Throwable e ){ 653 654 if ( builtin_plugins[i][4].equalsIgnoreCase("true" )){ 655 656 Debug.printStackTrace( e ); 657 658 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, 659 "Load of built in plugin '" + builtin_plugins[i][2] + "' fails", e)); 660 } 661 }finally{ 662 663 loading_builtin = false; 664 } 665 }else{ 666 if (Logger.isEnabled()) 667 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 668 "Built-in plugin '" + builtin_plugins[i][2] + "' is disabled")); 669 } 670 } 671 672 if (Logger.isEnabled()) 673 Logger.log(new LogEvent(LOGID, "Loading dynamically registered plugins")); 674 675 for (int i=0;i<registration_queue.size();i++){ 676 677 Object entry = registration_queue.get(i); 678 679 Class cla; 680 String id; 681 682 if ( entry instanceof Class ){ 683 684 cla = (Class)entry; 685 686 id = cla.getName(); 687 }else{ 688 689 Object[] x = (Object[])entry; 690 691 Plugin plugin = (Plugin)x[0]; 692 693 cla = plugin.getClass(); 694 695 id = (String)x[1]; 696 } 697 698 try{ 699 // lazyness here, for dynamic we use static load method with default plugin interface 700 // if we need to improve on this then we'll have to move to a system more akin to 701 // the dir-loaded plugins 702 703 Method load_method = cla.getMethod( "load", new Class[]{ PluginInterface.class }); 704 705 load_method.invoke( null, new Object[]{ getDefaultInterfaceSupport() }); 706 707 }catch( NoSuchMethodException e ){ 708 709 }catch( Throwable e ){ 710 711 Debug.printStackTrace( e ); 712 713 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, 714 "Load of dynamic plugin '" + id + "' fails", e)); 715 } 716 } 717 718 return pluginLoaded; 719 } 720 721 private void getRootClassLoader()722 getRootClassLoader() 723 { 724 // first do explicit plugins 725 726 File user_dir = FileUtil.getUserFile("shared"); 727 728 getRootClassLoader( user_dir ); 729 730 File app_dir = FileUtil.getApplicationFile("shared"); 731 732 if ( !user_dir.equals( app_dir )){ 733 734 getRootClassLoader( app_dir ); 735 } 736 } 737 738 private void getRootClassLoader( File dir )739 getRootClassLoader( 740 File dir ) 741 { 742 dir = new File( dir, "lib" ); 743 744 if ( dir.exists() && dir.isDirectory()){ 745 746 File[] files = dir.listFiles(); 747 748 if ( files != null ){ 749 750 files = PluginLauncherImpl.getHighestJarVersions( files, new String[]{ null }, new String[]{ null }, false ); 751 752 for (int i=0;i<files.length;i++){ 753 754 if (Logger.isEnabled()) 755 Logger.log(new LogEvent(LOGID, "Share class loader extended by " + files[i].toString())); 756 757 root_class_loader = 758 PluginLauncherImpl.addFileToClassPath( 759 PluginInitializer.class.getClassLoader(), 760 root_class_loader, files[i] ); 761 } 762 } 763 } 764 } 765 766 private List loadPluginsFromDir( File pluginDirectory, int plugin_offset, int plugin_total, boolean bSkipAlreadyLoaded, boolean loading_for_startup, boolean initialise)767 loadPluginsFromDir( 768 File pluginDirectory, 769 int plugin_offset, 770 int plugin_total, 771 boolean bSkipAlreadyLoaded, 772 boolean loading_for_startup, 773 boolean initialise) 774 { 775 List dirLoadedPIs = new ArrayList(); 776 777 if (Logger.isEnabled()) 778 Logger.log(new LogEvent(LOGID, "Plugin Directory is " + pluginDirectory)); 779 780 if ( !pluginDirectory.exists() ){ 781 782 FileUtil.mkdirs(pluginDirectory); 783 } 784 785 if( pluginDirectory.isDirectory()){ 786 787 File[] pluginsDirectory = pluginDirectory.listFiles(); 788 789 for(int i = 0 ; i < pluginsDirectory.length ; i++) { 790 791 if( pluginsDirectory[i].getName().equals( "CVS" ) ) { 792 793 if (Logger.isEnabled()) 794 Logger.log(new LogEvent(LOGID, "Skipping plugin " 795 + pluginsDirectory[i].getName())); 796 797 continue; 798 } 799 800 801 if (Logger.isEnabled()) 802 Logger.log(new LogEvent(LOGID, "Loading plugin " 803 + pluginsDirectory[i].getName())); 804 805 if(core_operation != null) { 806 807 core_operation.reportCurrentTask(MessageText.getString("splash.plugin") + pluginsDirectory[i].getName()); 808 } 809 810 try{ 811 812 List loaded_pis = loadPluginFromDir(pluginsDirectory[i], bSkipAlreadyLoaded, loading_for_startup, initialise); 813 814 // save details for later initialisation 815 816 loaded_pi_list.add( loaded_pis ); 817 dirLoadedPIs.addAll( loaded_pis ); 818 819 }catch( PluginException e ){ 820 821 // already handled 822 } 823 824 if( core_operation != null ){ 825 826 core_operation.reportPercent( (100 * (i + plugin_offset)) / plugin_total ); 827 } 828 } 829 } 830 return dirLoadedPIs; 831 } 832 833 private List loadPluginFromDir( File directory, boolean bSkipAlreadyLoaded, boolean loading_for_startup, boolean initialise)834 loadPluginFromDir( 835 File directory, 836 boolean bSkipAlreadyLoaded, 837 boolean loading_for_startup, 838 boolean initialise) // initialise setting is used if loading_for_startup isnt 839 840 throws PluginException 841 { 842 List loaded_pis = new ArrayList(); 843 844 ClassLoader plugin_class_loader = root_class_loader; 845 846 if( !directory.isDirectory()){ 847 848 return( loaded_pis ); 849 } 850 851 String pluginName = directory.getName(); 852 853 File[] pluginContents = directory.listFiles(); 854 855 if ( pluginContents == null || pluginContents.length == 0){ 856 857 return( loaded_pis ); 858 } 859 860 // first sanity check - dir must include either a plugin.properties or 861 // at least one .jar file 862 863 boolean looks_like_plugin = false; 864 865 for (int i=0;i<pluginContents.length;i++){ 866 867 String name = pluginContents[i].getName().toLowerCase(); 868 869 if ( name.endsWith( ".jar") || name.equals( "plugin.properties" )){ 870 871 looks_like_plugin = true; 872 873 break; 874 } 875 } 876 877 if ( !looks_like_plugin ){ 878 879 if (Logger.isEnabled()) 880 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 881 "Plugin directory '" + directory + "' has no plugin.properties " 882 + "or .jar files, skipping")); 883 884 return( loaded_pis ); 885 } 886 887 // take only the highest version numbers of jars that look versioned 888 889 String[] plugin_version = {null}; 890 String[] plugin_id = {null}; 891 892 pluginContents = PluginLauncherImpl.getHighestJarVersions( pluginContents, plugin_version, plugin_id, true ); 893 894 for( int i = 0 ; i < pluginContents.length ; i++){ 895 896 File jar_file = pluginContents[i]; 897 898 // migration hack for i18nAZ_1.0.jar 899 900 if ( pluginContents.length > 1 ){ 901 902 String name = jar_file.getName(); 903 904 if ( name.startsWith( "i18nPlugin_" )){ 905 906 // non-versioned version still there, rename it 907 908 if (Logger.isEnabled()) 909 Logger.log(new LogEvent(LOGID, "renaming '" + name 910 + "' to conform with versioning system")); 911 912 jar_file.renameTo( new File( jar_file.getParent(), "i18nAZ_0.1.jar " )); 913 914 continue; 915 } 916 } 917 918 plugin_class_loader = PluginLauncherImpl.addFileToClassPath( root_class_loader, plugin_class_loader, jar_file); 919 } 920 921 String plugin_class_string = null; 922 923 try { 924 Properties props = new Properties(); 925 926 File properties_file = new File(directory.toString() + File.separator + "plugin.properties"); 927 928 try { 929 930 // if properties file exists on its own then override any properties file 931 // potentially held within a jar 932 933 if ( properties_file.exists()){ 934 935 FileInputStream fis = null; 936 937 try{ 938 fis = new FileInputStream( properties_file ); 939 940 props.load( fis ); 941 942 }finally{ 943 944 if ( fis != null ){ 945 946 fis.close(); 947 } 948 } 949 950 }else{ 951 952 if ( plugin_class_loader instanceof URLClassLoader ){ 953 954 URLClassLoader current = (URLClassLoader)plugin_class_loader; 955 956 URL url = current.findResource("plugin.properties"); 957 958 if ( url != null ){ 959 URLConnection connection = url.openConnection(); 960 961 InputStream is = connection.getInputStream(); 962 963 props.load(is); 964 965 }else{ 966 967 throw( new Exception( "failed to load plugin.properties from jars")); 968 } 969 }else{ 970 971 throw( new Exception( "failed to load plugin.properties from dir or jars")); 972 973 } 974 } 975 }catch( Throwable e ){ 976 977 Debug.printStackTrace( e ); 978 979 String msg = "Can't read 'plugin.properties' for plugin '" + pluginName + "': file may be missing"; 980 981 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, msg)); 982 983 System.out.println( msg ); 984 985 throw( new PluginException( msg, e )); 986 } 987 988 checkJDKVersion( pluginName, props, true ); 989 checkAzureusVersion(pluginName, props, true); 990 991 plugin_class_string = (String)props.get( "plugin.class"); 992 993 if ( plugin_class_string == null ){ 994 995 plugin_class_string = (String)props.get( "plugin.classes"); 996 997 if ( plugin_class_string == null ){ 998 999 // set so we don't bork later will npe 1000 1001 plugin_class_string = ""; 1002 } 1003 } 1004 1005 String plugin_name_string = (String)props.get( "plugin.name"); 1006 1007 if ( plugin_name_string == null ){ 1008 1009 plugin_name_string = (String)props.get( "plugin.names"); 1010 } 1011 1012 int pos1 = 0; 1013 int pos2 = 0; 1014 1015 while(true){ 1016 int p1 = plugin_class_string.indexOf( ";", pos1 ); 1017 1018 String plugin_class; 1019 1020 if ( p1 == -1 ){ 1021 plugin_class = plugin_class_string.substring(pos1).trim(); 1022 }else{ 1023 plugin_class = plugin_class_string.substring(pos1,p1).trim(); 1024 pos1 = p1+1; 1025 } 1026 1027 PluginInterfaceImpl existing_pi = getPluginFromClass( plugin_class ); 1028 1029 if ( existing_pi != null ){ 1030 1031 if (bSkipAlreadyLoaded) { 1032 break; 1033 } 1034 1035 // allow user dir entries to override app dir entries without warning 1036 1037 File this_parent = directory.getParentFile(); 1038 File existing_parent = null; 1039 1040 if ( existing_pi.getInitializerKey() instanceof File ){ 1041 1042 existing_parent = ((File)existing_pi.getInitializerKey()).getParentFile(); 1043 } 1044 1045 if ( this_parent.equals( FileUtil.getApplicationFile("plugins")) && 1046 existing_parent != null && 1047 existing_parent.equals( FileUtil.getUserFile( "plugins" ))){ 1048 1049 // skip this overridden plugin 1050 1051 if (Logger.isEnabled()) 1052 Logger.log(new LogEvent(LOGID, "Plugin '" + plugin_name_string 1053 + "/" + plugin_class 1054 + ": shared version overridden by user-specific one")); 1055 1056 return( new ArrayList()); 1057 1058 }else{ 1059 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING, 1060 "Error loading '" + plugin_name_string + "', plugin class '" 1061 + plugin_class + "' is already loaded")); 1062 } 1063 1064 }else{ 1065 1066 String plugin_name = null; 1067 1068 if ( plugin_name_string != null ){ 1069 1070 int p2 = plugin_name_string.indexOf( ";", pos2 ); 1071 1072 1073 if ( p2 == -1 ){ 1074 plugin_name = plugin_name_string.substring(pos2).trim(); 1075 }else{ 1076 plugin_name = plugin_name_string.substring(pos2,p2).trim(); 1077 pos2 = p2+1; 1078 } 1079 } 1080 1081 Properties new_props = (Properties)props.clone(); 1082 1083 for (int j=0;j<default_version_details.length;j++){ 1084 1085 if ( plugin_class.equals( default_version_details[j][0] )){ 1086 1087 if ( new_props.get( "plugin.id") == null ){ 1088 1089 new_props.put( "plugin.id", default_version_details[j][1]); 1090 } 1091 1092 if ( plugin_name == null ){ 1093 1094 plugin_name = default_version_details[j][2]; 1095 } 1096 1097 if ( new_props.get( "plugin.version") == null ){ 1098 1099 // no explicit version. If we've derived one then use that, otherwise defaults 1100 1101 if ( plugin_version[0] != null ){ 1102 1103 new_props.put( "plugin.version", plugin_version[0]); 1104 1105 }else{ 1106 1107 new_props.put( "plugin.version", default_version_details[j][3]); 1108 } 1109 } 1110 } 1111 } 1112 1113 new_props.put( "plugin.class", plugin_class ); 1114 1115 if ( plugin_name != null ){ 1116 1117 new_props.put( "plugin.name", plugin_name ); 1118 } 1119 1120 // System.out.println( "loading plugin '" + plugin_class + "' using cl " + classLoader); 1121 1122 // if the plugin load fails we still need to generate a plugin entry 1123 // as this drives the upgrade process 1124 1125 1126 Throwable load_failure = null; 1127 1128 String pid = plugin_id[0]==null?directory.getName():plugin_id[0]; 1129 1130 List<File> verified_files = null; 1131 1132 Plugin plugin = null; 1133 1134 if ( vc_disabled_plugins.contains ( pid )){ 1135 1136 log( "Plugin '" + pid + "' has been administratively disabled" ); 1137 1138 }else{ 1139 try{ 1140 String cl_key = "plugin.cl.ext." + pid; 1141 1142 String str = COConfigurationManager.getStringParameter( cl_key, null ); 1143 1144 if ( str != null && str.length() > 0 ){ 1145 1146 COConfigurationManager.removeParameter( cl_key ); 1147 1148 plugin_class_loader = PluginLauncherImpl.extendClassLoader( root_class_loader, plugin_class_loader, new URL( str )); 1149 } 1150 }catch( Throwable e ){ 1151 } 1152 1153 if ( pid.endsWith( "_v" )){ 1154 1155 verified_files = new ArrayList<File>(); 1156 1157 // re-verify jar files 1158 1159 log( "Re-verifying " + pid ); 1160 1161 for( int i = 0 ; i < pluginContents.length ; i++){ 1162 1163 File jar_file = pluginContents[i]; 1164 1165 if ( jar_file.getName().endsWith( ".jar" )){ 1166 1167 try{ 1168 log( " verifying " + jar_file ); 1169 1170 AEVerifier.verifyData( jar_file ); 1171 1172 verified_files.add( jar_file ); 1173 1174 log( " OK" ); 1175 1176 }catch( Throwable e ){ 1177 1178 String msg = "Error loading plugin '" + pluginName + "' / '" + plugin_class_string + "'"; 1179 1180 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e)); 1181 1182 plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath()); 1183 } 1184 } 1185 } 1186 } 1187 1188 if ( plugin == null ){ 1189 1190 plugin = PluginLauncherImpl.getPreloadedPlugin( plugin_class ); 1191 1192 if ( plugin == null ){ 1193 1194 try{ 1195 try{ 1196 Class<Plugin> c = (Class<Plugin>)PlatformManagerFactory.getPlatformManager().loadClass( plugin_class_loader, plugin_class ); 1197 1198 1199 //Class c = plugin_class_loader.loadClass(plugin_class); 1200 1201 plugin = c.newInstance(); 1202 1203 try{ 1204 // kick off any pre-inits 1205 1206 if ( plugin_class_loader instanceof URLClassLoader ){ 1207 1208 URL[] urls = ((URLClassLoader)plugin_class_loader).getURLs(); 1209 1210 for ( URL u: urls ){ 1211 1212 String path = u.getPath(); 1213 1214 if ( path.endsWith( ".jar" )){ 1215 1216 int s1 = path.lastIndexOf( '/' ); 1217 int s2 = path.lastIndexOf( '\\' ); 1218 1219 path = path.substring( Math.max( s1, s2 )+1); 1220 1221 s2 = path.indexOf( '_' ); 1222 1223 if ( s2 > 0 ){ 1224 1225 path = path.substring( 0, s2 ); 1226 1227 path = path.replaceAll( "-", "" ); 1228 1229 String cl = "plugin.preinit." + pid + ".PI" + path; 1230 1231 try{ 1232 Class pic = plugin_class_loader.loadClass( cl ); 1233 1234 if ( pic != null ){ 1235 1236 pic.newInstance(); 1237 } 1238 }catch( Throwable e ){ 1239 } 1240 } 1241 } 1242 } 1243 } 1244 }catch( Throwable e ){ 1245 } 1246 }catch( PlatformManagerException e ){ 1247 1248 throw( e.getCause()); 1249 } 1250 1251 }catch (java.lang.UnsupportedClassVersionError e) { 1252 plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath()); 1253 1254 // shorten stack trace 1255 load_failure = new UnsupportedClassVersionError(e.getMessage()); 1256 1257 }catch( Throwable e ){ 1258 1259 if ( e instanceof ClassNotFoundException && 1260 props.getProperty( "plugin.install_if_missing", "no" ).equalsIgnoreCase( "yes" )){ 1261 1262 // don't report the failure 1263 1264 }else{ 1265 1266 load_failure = e; 1267 } 1268 1269 plugin = new FailedPlugin(plugin_name,directory.getAbsolutePath()); 1270 } 1271 }else{ 1272 1273 plugin_class_loader = plugin.getClass().getClassLoader(); 1274 } 1275 } 1276 1277 MessageText.integratePluginMessages((String)props.get("plugin.langfile"),plugin_class_loader); 1278 1279 PluginInterfaceImpl plugin_interface = 1280 new PluginInterfaceImpl( 1281 plugin, 1282 this, 1283 directory, 1284 plugin_class_loader, 1285 verified_files, 1286 directory.getName(), // key for config values 1287 new_props, 1288 directory.getAbsolutePath(), 1289 pid, 1290 plugin_version[0] ); 1291 1292 boolean bEnabled = (loading_for_startup) ? plugin_interface.getPluginState().isLoadedAtStartup() : initialise; 1293 1294 plugin_interface.getPluginState().setDisabled(!bEnabled); 1295 1296 try{ 1297 1298 Method load_method = plugin.getClass().getMethod( "load", new Class[]{ PluginInterface.class }); 1299 1300 load_method.invoke( plugin, new Object[]{ plugin_interface }); 1301 1302 }catch( NoSuchMethodException e ){ 1303 1304 }catch( Throwable e ){ 1305 1306 load_failure = e; 1307 } 1308 1309 loaded_pis.add( plugin_interface ); 1310 1311 if ( load_failure != null ){ 1312 1313 plugin_interface.setAsFailed(); 1314 1315 // don't complain about our internal one 1316 1317 if ( !pid.equals(UpdaterUpdateChecker.getPluginID())){ 1318 1319 String msg = 1320 MessageText.getString("plugin.init.load.failed", 1321 new String[]{ 1322 plugin_name==null?pluginName:plugin_name, 1323 directory.getAbsolutePath() 1324 }); 1325 1326 LogAlert la; 1327 1328 if ( load_failure instanceof UnsupportedClassVersionError ){ 1329 1330 la = new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, msg + ".\n\n" + MessageText.getString("plugin.install.class_version_error")); 1331 1332 }else if ( load_failure instanceof ClassNotFoundException ){ 1333 1334 la = new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, msg + ".\n\n" + MessageText.getString("plugin.init.load.failed.classmissing") + "\n\n", load_failure ); 1335 1336 }else{ 1337 1338 la = new LogAlert(LogAlert.UNREPEATABLE, msg, load_failure); 1339 } 1340 1341 Logger.log( la ); 1342 1343 System.out.println( msg + ": " + load_failure); 1344 } 1345 } 1346 } 1347 } 1348 if ( p1 == -1 ){ 1349 break; 1350 1351 } 1352 } 1353 1354 return( loaded_pis ); 1355 1356 }catch(Throwable e) { 1357 1358 if ( e instanceof PluginException ){ 1359 1360 throw((PluginException)e); 1361 } 1362 1363 Debug.printStackTrace( e ); 1364 1365 String msg = "Error loading plugin '" + pluginName + "' / '" + plugin_class_string + "'"; 1366 1367 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e)); 1368 1369 System.out.println( msg + ": " + e); 1370 1371 throw( new PluginException( msg, e )); 1372 } 1373 } 1374 1375 private void log( String str )1376 log( 1377 String str ) 1378 { 1379 if (Logger.isEnabled()){ 1380 Logger.log(new LogEvent(LOGID, str )); 1381 } 1382 } 1383 1384 public void initialisePlugins()1385 initialisePlugins() 1386 { 1387 try{ 1388 addInitThread(); 1389 1390 final LinkedList<Runnable> initQueue = new LinkedList<Runnable>(); 1391 1392 for (int i = 0; i < loaded_pi_list.size(); i++) { 1393 final int idx = i; 1394 initQueue.add(new Runnable() { 1395 public void run() { 1396 try { 1397 List l = (List) loaded_pi_list.get(idx); 1398 1399 if (l.size() > 0) { 1400 PluginInterfaceImpl plugin_interface = (PluginInterfaceImpl) l.get(0); 1401 1402 if (Logger.isEnabled()) 1403 Logger.log(new LogEvent(LOGID, "Initializing plugin '" 1404 + plugin_interface.getPluginName() + "'")); 1405 1406 if (core_operation != null) { 1407 core_operation.reportCurrentTask(MessageText 1408 .getString("splash.plugin.init") 1409 + " " + plugin_interface.getPluginName()); 1410 } 1411 1412 initialisePlugin(l); 1413 1414 if (Logger.isEnabled()) 1415 Logger.log(new LogEvent(LOGID, "Initialization of plugin '" 1416 + plugin_interface.getPluginName() + "' complete")); 1417 1418 } 1419 1420 } catch ( Throwable e ){ 1421 // already handled 1422 } finally { 1423 if (core_operation != null) { 1424 core_operation.reportPercent((100 * (idx + 1)) / loaded_pi_list.size()); 1425 } 1426 } 1427 1428 // some plugins try and steal the logger stdout redirects. 1429 // re-establish them if needed 1430 Logger.doRedirects(); 1431 } 1432 }); 1433 } 1434 1435 1436 1437 // now do built in ones 1438 1439 initQueue.add(new Runnable() { 1440 public void run() { 1441 if (Logger.isEnabled()) 1442 Logger.log(new LogEvent(LOGID, "Initializing built-in plugins")); 1443 } 1444 }); 1445 1446 1447 1448 final PluginManagerDefaults def = PluginManager.getDefaults(); 1449 1450 for (int i = 0; i < builtin_plugins.length; i++) { 1451 1452 final int idx = i; 1453 1454 initQueue.add(new Runnable() { 1455 public void run() { 1456 if (def.isDefaultPluginEnabled(builtin_plugins[idx][0])) { 1457 String id = builtin_plugins[idx][2]; 1458 String key = builtin_plugins[idx][3]; 1459 1460 try { 1461 Class cla = root_class_loader.loadClass( 1462 builtin_plugins[idx][1]); 1463 1464 if (Logger.isEnabled()) 1465 Logger.log(new LogEvent(LOGID, "Initializing built-in plugin '" 1466 + builtin_plugins[idx][2] + "'" )); 1467 1468 initializePluginFromClass(cla, id, key, "true".equals(builtin_plugins[idx][5]), true, true); 1469 1470 if (Logger.isEnabled()) 1471 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 1472 "Initialization of built in plugin '" + builtin_plugins[idx][2] + "' complete")); 1473 } catch (Throwable e) { 1474 try { 1475 // replace it with a "broken" plugin instance 1476 initializePluginFromClass(FailedPlugin.class, id, key, false, false, true); 1477 1478 } catch (Throwable f) { 1479 } 1480 1481 if (builtin_plugins[idx][4].equalsIgnoreCase("true")) { 1482 Debug.printStackTrace(e); 1483 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, 1484 "Initialization of built in plugin '" + builtin_plugins[idx][2] 1485 + "' fails", e)); 1486 } 1487 } 1488 } else { 1489 if (Logger.isEnabled()) 1490 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 1491 "Built-in plugin '" + builtin_plugins[idx][2] + "' is disabled")); 1492 } 1493 1494 } 1495 }); 1496 1497 } 1498 1499 initQueue.add(new Runnable() { 1500 public void run() { 1501 if (Logger.isEnabled()) 1502 Logger.log(new LogEvent(LOGID, 1503 "Initializing dynamically registered plugins")); 1504 } 1505 }); 1506 1507 for (int i = 0; i < registration_queue.size(); i++) { 1508 1509 final int idx = i; 1510 1511 initQueue.add(new Runnable() { 1512 public void run() { 1513 try { 1514 Object entry = registration_queue.get(idx); 1515 1516 if (entry instanceof Class) { 1517 1518 Class cla = (Class) entry; 1519 1520 singleton.initializePluginFromClass(cla, INTERNAL_PLUGIN_ID, cla 1521 .getName(), false, true, true); 1522 1523 } else { 1524 Object[] x = (Object[]) entry; 1525 1526 Plugin plugin = (Plugin) x[0]; 1527 1528 singleton.initializePluginFromInstance(plugin, (String) x[1], (String)x[2]); 1529 } 1530 } catch (PluginException e) { 1531 } 1532 } 1533 }); 1534 } 1535 1536 AEThread2 secondaryInitializer = 1537 new AEThread2("2nd PluginInitializer Thread",true) 1538 { 1539 public void run() 1540 { 1541 1542 try{ 1543 addInitThread(); 1544 1545 while( true ){ 1546 1547 Runnable toRun; 1548 1549 synchronized (initQueue){ 1550 1551 if (initQueue.isEmpty()){ 1552 1553 break; 1554 } 1555 1556 toRun = (Runnable)initQueue.remove(0); 1557 } 1558 1559 try{ 1560 toRun.run(); 1561 1562 }catch( Throwable e ){ 1563 1564 Debug.out(e); 1565 } 1566 } 1567 }finally{ 1568 1569 removeInitThread(); 1570 } 1571 } 1572 }; 1573 secondaryInitializer.start(); 1574 1575 while(true){ 1576 1577 Runnable toRun; 1578 1579 synchronized( initQueue ){ 1580 1581 if( initQueue.isEmpty()){ 1582 1583 break; 1584 } 1585 1586 toRun = (Runnable)initQueue.remove(0); 1587 } 1588 1589 try{ 1590 toRun.run(); 1591 1592 }catch( Throwable e ){ 1593 1594 Debug.out(e); 1595 } 1596 } 1597 1598 secondaryInitializer.join(); 1599 1600 registration_queue.clear(); 1601 1602 plugins_initialised = true; 1603 1604 fireEvent( PluginEvent.PEV_ALL_PLUGINS_INITIALISED ); 1605 1606 }finally{ 1607 1608 removeInitThread(); 1609 } 1610 } 1611 1612 protected void checkPluginsInitialised()1613 checkPluginsInitialised() 1614 { 1615 if ( !plugins_initialised ){ 1616 1617 Debug.out( "Wait until plugin initialisation is complete until doing this!" ); 1618 } 1619 } 1620 1621 protected boolean isInitialized()1622 isInitialized() 1623 { 1624 return( plugins_initialised ); 1625 } 1626 1627 private void initialisePlugin( List l )1628 initialisePlugin( 1629 List l ) 1630 1631 throws PluginException 1632 { 1633 PluginException last_load_failure = null; 1634 1635 for (int i=0;i<l.size();i++){ 1636 1637 final PluginInterfaceImpl plugin_interface = (PluginInterfaceImpl)l.get(i); 1638 1639 if (plugin_interface.getPluginState().isDisabled()) { 1640 1641 synchronized( s_plugin_interfaces ){ 1642 1643 s_plugin_interfaces.add( plugin_interface ); 1644 } 1645 1646 continue; 1647 } 1648 1649 if ( plugin_interface.getPluginState().isOperational()){ 1650 1651 continue; 1652 } 1653 1654 Throwable load_failure = null; 1655 1656 final Plugin plugin = plugin_interface.getPlugin(); 1657 1658 try{ 1659 1660 UtilitiesImpl.callWithPluginThreadContext( 1661 plugin_interface, 1662 new runnableWithException<PluginException>() 1663 { 1664 public void 1665 run() 1666 throws PluginException 1667 { 1668 fireCreated( plugin_interface ); 1669 1670 plugin.initialize(plugin_interface); 1671 1672 if (!(plugin instanceof FailedPlugin)){ 1673 1674 plugin_interface.getPluginStateImpl().setOperational( true, false ); 1675 } 1676 } 1677 }); 1678 1679 }catch( Throwable e ){ 1680 1681 load_failure = e; 1682 } 1683 1684 synchronized( s_plugin_interfaces ){ 1685 1686 s_plugins.add( plugin ); 1687 1688 s_plugin_interfaces.add( plugin_interface ); 1689 } 1690 1691 if ( load_failure != null ){ 1692 1693 Debug.printStackTrace( load_failure ); 1694 1695 String msg = "Error initializing plugin '" + plugin_interface.getPluginName() + "'"; 1696 1697 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, load_failure)); 1698 1699 System.out.println( msg + " : " + load_failure); 1700 1701 last_load_failure = new PluginException( msg, load_failure ); 1702 } 1703 } 1704 1705 if ( last_load_failure != null ){ 1706 1707 throw( last_load_failure ); 1708 } 1709 } 1710 1711 protected void initializePluginFromClass( final Class plugin_class, final String plugin_id, String plugin_config_key, boolean force_enabled, boolean loading_for_startup, boolean initialise)1712 initializePluginFromClass( 1713 final Class plugin_class, 1714 final String plugin_id, 1715 String plugin_config_key, 1716 boolean force_enabled, 1717 boolean loading_for_startup, 1718 boolean initialise) 1719 1720 throws PluginException 1721 { 1722 1723 if ( plugin_class != FailedPlugin.class && getPluginFromClass( plugin_class ) != null ){ 1724 1725 1726 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING, 1727 "Error loading '" + plugin_id + "', plugin class '" 1728 + plugin_class.getName() + "' is already loaded")); 1729 1730 return; 1731 } 1732 1733 try{ 1734 final Plugin plugin = (Plugin) plugin_class.newInstance(); 1735 1736 String plugin_name; 1737 1738 if ( plugin_config_key.length() == 0 ){ 1739 1740 plugin_name = plugin_class.getName(); 1741 1742 int pos = plugin_name.lastIndexOf("."); 1743 1744 if ( pos != -1 ){ 1745 1746 plugin_name = plugin_name.substring( pos+1 ); 1747 1748 } 1749 }else{ 1750 1751 plugin_name = plugin_config_key; 1752 } 1753 1754 Properties properties = new Properties(); 1755 1756 // default plugin name 1757 1758 properties.put( "plugin.name", plugin_name ); 1759 1760 final PluginInterfaceImpl plugin_interface = 1761 new PluginInterfaceImpl( 1762 plugin, 1763 this, 1764 plugin_class, 1765 plugin_class.getClassLoader(), 1766 null, 1767 plugin_config_key, 1768 properties, 1769 "", 1770 plugin_id, 1771 null ); 1772 1773 boolean bEnabled = (loading_for_startup) ? plugin_interface.getPluginState().isLoadedAtStartup() : initialise; 1774 1775 /** 1776 * For some plugins, override any config setting which disables the plugin. 1777 */ 1778 if (force_enabled && !bEnabled) { 1779 plugin_interface.getPluginState().setLoadedAtStartup(true); 1780 bEnabled = true; 1781 Logger.log(new LogAlert(false, LogAlert.AT_WARNING, MessageText.getString( 1782 "plugins.init.force_enabled", new String[] {plugin_id} 1783 ))); 1784 } 1785 1786 plugin_interface.getPluginState().setDisabled(!bEnabled); 1787 1788 final boolean f_enabled = bEnabled; 1789 1790 UtilitiesImpl.callWithPluginThreadContext( 1791 plugin_interface, 1792 new runnableWithException<PluginException>() 1793 { 1794 public void 1795 run() 1796 throws PluginException 1797 { 1798 try{ 1799 1800 Method load_method = plugin_class.getMethod( "load", new Class[]{ PluginInterface.class }); 1801 1802 load_method.invoke( plugin, new Object[]{ plugin_interface }); 1803 1804 }catch( NoSuchMethodException e ){ 1805 1806 }catch( Throwable e ){ 1807 1808 Debug.printStackTrace( e ); 1809 1810 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, 1811 "Load of built in plugin '" + plugin_id + "' fails", e)); 1812 } 1813 1814 if (f_enabled) { 1815 1816 if ( core_operation != null ){ 1817 1818 core_operation.reportCurrentTask(MessageText.getString("splash.plugin.init") + " " + plugin_interface.getPluginName()); 1819 } 1820 1821 fireCreated( plugin_interface ); 1822 1823 plugin.initialize(plugin_interface); 1824 1825 if (!(plugin instanceof FailedPlugin)){ 1826 1827 plugin_interface.getPluginStateImpl().setOperational( true, false ); 1828 } 1829 } 1830 } 1831 }); 1832 1833 synchronized( s_plugin_interfaces ){ 1834 1835 s_plugins.add( plugin ); 1836 1837 s_plugin_interfaces.add( plugin_interface ); 1838 } 1839 }catch(Throwable e){ 1840 1841 Debug.printStackTrace( e ); 1842 1843 String msg = "Error loading internal plugin '" + plugin_class.getName() + "'"; 1844 1845 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e)); 1846 1847 System.out.println(msg + " : " + e); 1848 1849 throw( new PluginException( msg, e )); 1850 } 1851 } 1852 1853 protected void initializePluginFromInstance( final Plugin plugin, String plugin_id, String plugin_config_key )1854 initializePluginFromInstance( 1855 final Plugin plugin, 1856 String plugin_id, 1857 String plugin_config_key ) 1858 1859 throws PluginException 1860 { 1861 try{ 1862 final PluginInterfaceImpl plugin_interface = 1863 new PluginInterfaceImpl( 1864 plugin, 1865 this, 1866 plugin.getClass(), 1867 plugin.getClass().getClassLoader(), 1868 null, 1869 plugin_config_key, 1870 new Properties(), 1871 "", 1872 plugin_id, 1873 null ); 1874 1875 UtilitiesImpl.callWithPluginThreadContext( 1876 plugin_interface, 1877 new UtilitiesImpl.runnableWithException<PluginException>() 1878 { 1879 public void 1880 run() 1881 1882 throws PluginException 1883 { 1884 fireCreated( plugin_interface ); 1885 1886 plugin.initialize(plugin_interface); 1887 1888 if (!(plugin instanceof FailedPlugin)){ 1889 1890 plugin_interface.getPluginStateImpl().setOperational( true, false ); 1891 } 1892 } 1893 }); 1894 1895 synchronized( s_plugin_interfaces ){ 1896 1897 s_plugins.add( plugin ); 1898 1899 s_plugin_interfaces.add( plugin_interface ); 1900 } 1901 }catch(Throwable e){ 1902 1903 Debug.printStackTrace( e ); 1904 1905 String msg = "Error loading internal plugin '" + plugin.getClass().getName() + "'"; 1906 1907 Logger.log(new LogAlert(LogAlert.UNREPEATABLE, msg, e)); 1908 1909 System.out.println(msg + " : " + e); 1910 1911 throw( new PluginException( msg, e )); 1912 } 1913 } 1914 1915 protected void unloadPlugin( PluginInterfaceImpl pi )1916 unloadPlugin( 1917 PluginInterfaceImpl pi ) 1918 { 1919 synchronized( s_plugin_interfaces ){ 1920 1921 s_plugins.remove( pi.getPlugin()); 1922 1923 s_plugin_interfaces.remove( pi ); 1924 } 1925 1926 pi.unloadSupport(); 1927 1928 for (int i=0;i<loaded_pi_list.size();i++){ 1929 1930 List l = (List)loaded_pi_list.get(i); 1931 1932 if ( l.remove(pi)){ 1933 1934 if ( l.size() == 0 ){ 1935 1936 loaded_pi_list.remove(i); 1937 } 1938 1939 break; 1940 } 1941 } 1942 1943 verified_plugin_holder.removeValue( pi ); 1944 } 1945 reloadPlugin(PluginInterfaceImpl pi)1946 protected void reloadPlugin(PluginInterfaceImpl pi) throws PluginException { 1947 reloadPlugin(pi, false, true); 1948 } 1949 reloadPlugin( PluginInterfaceImpl pi, boolean loading_for_startup, boolean initialise)1950 protected void reloadPlugin( 1951 PluginInterfaceImpl pi, 1952 boolean loading_for_startup, 1953 boolean initialise) throws PluginException { 1954 1955 unloadPlugin( pi ); 1956 1957 Object key = pi.getInitializerKey(); 1958 String config_key = pi.getPluginConfigKey(); 1959 1960 if ( key instanceof File ){ 1961 1962 List pis = loadPluginFromDir( (File)key, false, loading_for_startup, initialise); 1963 1964 initialisePlugin( pis ); 1965 1966 }else{ 1967 initializePluginFromClass( (Class) key, pi.getPluginID(), config_key, false, loading_for_startup, initialise ); 1968 } 1969 } 1970 1971 protected AzureusCore getAzureusCore()1972 getAzureusCore() 1973 { 1974 return( azureus_core ); 1975 } 1976 1977 protected GlobalManager getGlobalManager()1978 getGlobalManager() 1979 { 1980 return( azureus_core.getGlobalManager() ); 1981 } 1982 1983 public static PluginInterface getDefaultInterface()1984 getDefaultInterface() 1985 { 1986 if (singleton == null) { 1987 throw new AzureusCoreException( 1988 "PluginInitializer not instantiated by AzureusCore.create yet"); 1989 } 1990 return( singleton.getDefaultInterfaceSupport()); 1991 } 1992 1993 protected PluginInterface getDefaultInterfaceSupport()1994 getDefaultInterfaceSupport() 1995 { 1996 synchronized( s_plugin_interfaces ){ 1997 1998 if ( default_plugin == null ){ 1999 2000 try{ 2001 default_plugin = 2002 new PluginInterfaceImpl( 2003 new Plugin() 2004 { 2005 public void 2006 initialize( 2007 PluginInterface pi) 2008 { 2009 } 2010 }, 2011 this, 2012 getClass(), 2013 getClass().getClassLoader(), 2014 null, 2015 "default", 2016 new Properties(), 2017 null, 2018 INTERNAL_PLUGIN_ID, 2019 null ); 2020 2021 }catch( Throwable e ){ 2022 2023 Debug.out( e ); 2024 } 2025 } 2026 } 2027 2028 return( default_plugin ); 2029 } 2030 2031 public void downloadManagerAdded( DownloadManager dm )2032 downloadManagerAdded( 2033 DownloadManager dm ) 2034 { 2035 } 2036 2037 public void downloadManagerRemoved( DownloadManager dm )2038 downloadManagerRemoved( 2039 DownloadManager dm ) 2040 { 2041 } 2042 2043 public void destroyInitiated()2044 destroyInitiated() 2045 { 2046 List plugin_interfaces; 2047 2048 synchronized( s_plugin_interfaces ){ 2049 2050 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2051 } 2052 2053 for (int i=0;i<plugin_interfaces.size();i++){ 2054 2055 ((PluginInterfaceImpl)plugin_interfaces.get(i)).closedownInitiated(); 2056 } 2057 2058 if ( default_plugin != null ){ 2059 2060 default_plugin.closedownInitiated(); 2061 } 2062 } 2063 2064 public void destroyed()2065 destroyed() 2066 { 2067 List plugin_interfaces; 2068 2069 synchronized( s_plugin_interfaces ){ 2070 2071 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2072 } 2073 2074 for (int i=0;i<plugin_interfaces.size();i++){ 2075 2076 ((PluginInterfaceImpl)plugin_interfaces.get(i)).closedownComplete(); 2077 } 2078 2079 if ( default_plugin != null ){ 2080 2081 default_plugin.closedownComplete(); 2082 } 2083 } 2084 2085 seedingStatusChanged( boolean seeding_only_mode, boolean b )2086 public void seedingStatusChanged( boolean seeding_only_mode, boolean b ){ 2087 /*nothing*/ 2088 } 2089 2090 protected void runPEVTask( AERunnable run )2091 runPEVTask( 2092 AERunnable run ) 2093 { 2094 async_dispatcher.dispatch( run ); 2095 } 2096 2097 2098 protected List<PluginEvent> getPEVHistory()2099 getPEVHistory() 2100 { 2101 return( plugin_event_history ); 2102 } 2103 2104 protected void fireEventSupport( final int type, final Object value )2105 fireEventSupport( 2106 final int type, 2107 final Object value ) 2108 { 2109 async_dispatcher.dispatch( 2110 new AERunnable() 2111 { 2112 public void 2113 runSupport() 2114 { 2115 PluginEvent ev = 2116 new PluginEvent() 2117 { 2118 public int 2119 getType() 2120 { 2121 return( type ); 2122 } 2123 2124 public Object 2125 getValue() 2126 { 2127 return( value ); 2128 } 2129 }; 2130 2131 if ( type == PluginEvent.PEV_CONFIGURATION_WIZARD_STARTS || 2132 type == PluginEvent.PEV_CONFIGURATION_WIZARD_COMPLETES || 2133 type == PluginEvent.PEV_INITIAL_SHARING_COMPLETE || 2134 type == PluginEvent.PEV_INITIALISATION_UI_COMPLETES || 2135 type == PluginEvent.PEV_ALL_PLUGINS_INITIALISED ){ 2136 2137 plugin_event_history.add( ev ); 2138 2139 if ( plugin_event_history.size() > 1024 ){ 2140 2141 Debug.out( "Plugin event history too large!!!!" ); 2142 2143 plugin_event_history.remove( 0 ); 2144 } 2145 } 2146 2147 List plugin_interfaces; 2148 2149 synchronized( s_plugin_interfaces ){ 2150 2151 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2152 } 2153 2154 for (int i=0;i<plugin_interfaces.size();i++){ 2155 2156 try{ 2157 ((PluginInterfaceImpl)plugin_interfaces.get(i)).firePluginEventSupport(ev); 2158 2159 }catch(Throwable e ){ 2160 2161 Debug.printStackTrace(e); 2162 } 2163 } 2164 2165 if ( default_plugin != null ){ 2166 2167 default_plugin.firePluginEventSupport(ev); 2168 } 2169 } 2170 }); 2171 } 2172 2173 private void waitForEvents()2174 waitForEvents() 2175 { 2176 if ( async_dispatcher.isDispatchThread()){ 2177 2178 Debug.out( "Deadlock - recode this monkey boy" ); 2179 2180 }else{ 2181 2182 final AESemaphore sem = new AESemaphore( "waiter" ); 2183 2184 async_dispatcher.dispatch( 2185 new AERunnable() 2186 { 2187 public void 2188 runSupport() 2189 { 2190 sem.release(); 2191 } 2192 }); 2193 2194 if ( !sem.reserve( 10*1000 )){ 2195 2196 Debug.out( "Timeout waiting for event dispatch" ); 2197 } 2198 2199 } 2200 } 2201 2202 public static void fireEvent( int type )2203 fireEvent( 2204 int type ) 2205 { 2206 singleton.fireEventSupport(type, null); 2207 } 2208 2209 public static void fireEvent( int type, Object value )2210 fireEvent( 2211 int type, 2212 Object value ) 2213 { 2214 singleton.fireEventSupport(type, value); 2215 } 2216 2217 public static void waitForPluginEvents()2218 waitForPluginEvents() 2219 { 2220 singleton.waitForEvents(); 2221 } 2222 2223 public void initialisationComplete()2224 initialisationComplete() 2225 { 2226 initialisation_complete = true; 2227 2228 UIManagerImpl.initialisationComplete(); 2229 2230 List plugin_interfaces; 2231 2232 synchronized( s_plugin_interfaces ){ 2233 2234 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2235 } 2236 2237 for (int i=0;i<plugin_interfaces.size();i++){ 2238 2239 ((PluginInterfaceImpl)plugin_interfaces.get(i)).initialisationComplete(); 2240 } 2241 2242 // keep this last as there are things out there that rely on the init complete of the 2243 // default interface meaning that everything else is complete and informed complete 2244 2245 if ( default_plugin != null ){ 2246 2247 default_plugin.initialisationComplete(); 2248 } 2249 } 2250 2251 protected boolean isInitialisationComplete()2252 isInitialisationComplete() 2253 { 2254 return( initialisation_complete ); 2255 } 2256 2257 getPluginInterfaces()2258 public static List<PluginInterfaceImpl> getPluginInterfaces() { 2259 return singleton.getPluginInterfacesSupport( false ); 2260 } 2261 getPluginInterfacesSupport( boolean expect_partial_result )2262 private List<PluginInterfaceImpl> getPluginInterfacesSupport( boolean expect_partial_result ) { 2263 2264 if ( !expect_partial_result ){ 2265 2266 checkPluginsInitialised(); 2267 } 2268 2269 synchronized( s_plugin_interfaces ){ 2270 2271 return( new ArrayList<PluginInterfaceImpl>( s_plugin_interfaces )); 2272 } 2273 } 2274 2275 public PluginInterface[] getPlugins()2276 getPlugins() 2277 { 2278 return( getPlugins( false )); 2279 } 2280 2281 public PluginInterface[] getPlugins( boolean expect_partial_result )2282 getPlugins( 2283 boolean expect_partial_result ) 2284 { 2285 List pis = getPluginInterfacesSupport( expect_partial_result ); 2286 2287 PluginInterface[] res = new PluginInterface[pis.size()]; 2288 2289 pis.toArray(res); 2290 2291 return( res ); 2292 } 2293 2294 protected PluginManager getPluginManager()2295 getPluginManager() 2296 { 2297 return( plugin_manager ); 2298 } 2299 2300 protected PluginInterfaceImpl getPluginFromClass( Class cla )2301 getPluginFromClass( 2302 Class cla ) 2303 { 2304 return( getPluginFromClass( cla.getName())); 2305 } 2306 2307 protected PluginInterfaceImpl getPluginFromClass( String class_name )2308 getPluginFromClass( 2309 String class_name ) 2310 { 2311 List plugin_interfaces; 2312 2313 synchronized( s_plugin_interfaces ){ 2314 2315 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2316 } 2317 2318 for (int i=0;i<plugin_interfaces.size();i++){ 2319 2320 PluginInterfaceImpl pi = (PluginInterfaceImpl)plugin_interfaces.get(i); 2321 2322 if ( pi.getPlugin().getClass().getName().equals( class_name )){ 2323 2324 return( pi ); 2325 } 2326 } 2327 2328 // fall back to the loaded but not-yet-initialised list 2329 2330 for (int i=0;i<loaded_pi_list.size();i++){ 2331 2332 List l = (List)loaded_pi_list.get(i); 2333 2334 for (int j=0;j<l.size();j++){ 2335 2336 PluginInterfaceImpl pi = (PluginInterfaceImpl)l.get(j); 2337 2338 if ( pi.getPlugin().getClass().getName().equals( class_name )){ 2339 2340 return( pi ); 2341 } 2342 } 2343 } 2344 2345 return( null ); 2346 } 2347 2348 2349 public void generate( IndentWriter writer )2350 generate( 2351 IndentWriter writer ) 2352 { 2353 writer.println( "Plugins" ); 2354 2355 try{ 2356 writer.indent(); 2357 2358 List plugin_interfaces; 2359 2360 synchronized( s_plugin_interfaces ){ 2361 2362 plugin_interfaces = new ArrayList( s_plugin_interfaces ); 2363 } 2364 2365 for (int i=0;i<plugin_interfaces.size();i++){ 2366 2367 PluginInterfaceImpl pi = (PluginInterfaceImpl)plugin_interfaces.get(i); 2368 2369 pi.generateEvidence( writer ); 2370 } 2371 2372 }finally{ 2373 2374 writer.exdent(); 2375 } 2376 } 2377 2378 protected static void setVerified( PluginInterfaceImpl pi, Plugin plugin, boolean v, boolean bad )2379 setVerified( 2380 PluginInterfaceImpl pi, 2381 Plugin plugin, 2382 boolean v, 2383 boolean bad ) 2384 2385 throws PluginException 2386 { 2387 Object[] existing = (Object[])verified_plugin_holder.setValue( pi, new Object[]{ plugin, v }); 2388 2389 if ( existing != null && ( existing[0] != plugin || (Boolean)existing[1] != v )){ 2390 2391 throw( new PluginException( "Verified status change not permitted" )); 2392 } 2393 2394 if ( bad && !DISABLE_PLUGIN_VERIFICATION ){ 2395 2396 throw( new RuntimeException( "Plugin verification failed" )); 2397 } 2398 } 2399 2400 public static boolean isVerified( PluginInterface pi, Plugin plugin )2401 isVerified( 2402 PluginInterface pi, 2403 Plugin plugin ) 2404 { 2405 if ( !( pi instanceof PluginInterfaceImpl )){ 2406 2407 return( false ); 2408 } 2409 2410 VerifiedPluginHolder holder = verified_plugin_holder; 2411 2412 if ( holder.getClass() != VerifiedPluginHolder.class ){ 2413 2414 Debug.out( "class mismatch" ); 2415 2416 return( false ); 2417 } 2418 2419 if ( DISABLE_PLUGIN_VERIFICATION ){ 2420 2421 Debug.out( " **************************** VERIFICATION DISABLED ******************" ); 2422 2423 return( true ); 2424 } 2425 2426 Object[] ver = (Object[])verified_plugin_holder.getValue( pi ); 2427 2428 return( ver != null && ver[0] == plugin && (Boolean)ver[1] ); 2429 } 2430 2431 public static boolean isCoreOrVerifiedPlugin()2432 isCoreOrVerifiedPlugin() 2433 { 2434 Class<?>[] stack = SESecurityManager.getClassContext(); 2435 2436 ClassLoader core = PluginInitializer.class.getClassLoader(); 2437 2438 PluginInitializer singleton = peekSingleton(); 2439 2440 PluginInterface[] pis = singleton==null?new PluginInterface[0]:singleton.getPlugins(); 2441 2442 Set<ClassLoader> ok_loaders = new HashSet<ClassLoader>(); 2443 2444 ok_loaders.add( core ); 2445 2446 for ( Class<?> c: stack ){ 2447 2448 ClassLoader cl = c.getClassLoader(); 2449 2450 if ( cl != null && !ok_loaders.contains( cl )){ 2451 2452 boolean ok = false; 2453 2454 for ( PluginInterface pi: pis ){ 2455 2456 Plugin plugin = pi.getPlugin(); 2457 2458 if ( plugin.getClass().getClassLoader() == cl ){ 2459 2460 if ( isVerified( pi, plugin )){ 2461 2462 ok_loaders.add( cl ); 2463 2464 ok = true; 2465 2466 break; 2467 } 2468 } 2469 } 2470 2471 if ( !ok ){ 2472 2473 Debug.out( "Class " + c.getCanonicalName() + " with loader " + cl + " isn't trusted" ); 2474 2475 return( false ); 2476 } 2477 } 2478 } 2479 2480 return( true ); 2481 } 2482 2483 private static final class 2484 VerifiedPluginHolder 2485 { 2486 private static final Object NULL_VALUE = new Object(); 2487 2488 private volatile boolean initialised; 2489 2490 private AESemaphore request_sem = new AESemaphore( "ValueHolder" ); 2491 2492 private List<Object[]> request_queue = new ArrayList<Object[]>(); 2493 2494 private VerifiedPluginHolder()2495 VerifiedPluginHolder() 2496 { 2497 Class[] context = SESecurityManager.getClassContext(); 2498 2499 if ( context.length == 0 ){ 2500 2501 return; 2502 } 2503 2504 if ( context[2] != PluginInitializer.class ){ 2505 2506 Debug.out( "Illegal operation" ); 2507 2508 return; 2509 } 2510 2511 AEThread2 t = 2512 new AEThread2( "PluginVerifier" ) 2513 { 2514 public void 2515 run() 2516 { 2517 Map<Object,Object> values = new IdentityHashMap<Object,Object>(); 2518 2519 while( true ){ 2520 2521 request_sem.reserve(); 2522 2523 Object[] req; 2524 2525 synchronized( request_queue ){ 2526 2527 req = request_queue.remove(0); 2528 } 2529 2530 if ( req[1] == null ){ 2531 2532 req[1] = values.get( req[0] ); 2533 2534 }else{ 2535 2536 Object existing = values.get( req[0] ); 2537 2538 if ( req[1] == NULL_VALUE ){ 2539 2540 req[1] = existing; 2541 2542 values.remove( req[0] ); 2543 2544 }else{ 2545 if ( existing != null){ 2546 2547 req[1] = existing; 2548 2549 }else{ 2550 2551 values.put( req[0], req[1] ); 2552 } 2553 } 2554 } 2555 2556 ((AESemaphore)req[2]).release(); 2557 } 2558 } 2559 }; 2560 2561 t.start(); 2562 2563 initialised = true; 2564 } 2565 2566 public Object removeValue( Object key )2567 removeValue( 2568 Object key ) 2569 { 2570 if ( !initialised ){ 2571 2572 return( null ); 2573 } 2574 2575 AESemaphore sem = new AESemaphore( "ValueHolder:remove" ); 2576 2577 Object[] request = new Object[]{ key, NULL_VALUE, sem }; 2578 2579 synchronized( request_queue ){ 2580 2581 request_queue.add( request ); 2582 } 2583 2584 request_sem.release(); 2585 2586 sem.reserve(); 2587 2588 return(request[1]); 2589 } 2590 2591 public Object setValue( Object key, Object value )2592 setValue( 2593 Object key, 2594 Object value ) 2595 { 2596 if ( !initialised ){ 2597 2598 return( null ); 2599 } 2600 2601 AESemaphore sem = new AESemaphore( "ValueHolder:set" ); 2602 2603 Object[] request = new Object[]{ key, value, sem }; 2604 2605 synchronized( request_queue ){ 2606 2607 request_queue.add( request ); 2608 } 2609 2610 request_sem.release(); 2611 2612 sem.reserve(); 2613 2614 return(request[1]); 2615 } 2616 2617 public Object getValue( Object key )2618 getValue( 2619 Object key ) 2620 { 2621 if ( !initialised ){ 2622 2623 return( null ); 2624 } 2625 2626 AESemaphore sem = new AESemaphore( "ValueHolder:get" ); 2627 2628 Object[] request = new Object[]{ key, null, sem }; 2629 2630 synchronized( request_queue ){ 2631 2632 request_queue.add( request ); 2633 } 2634 2635 request_sem.release(); 2636 2637 sem.reserve(); 2638 2639 return( request[1] ); 2640 } 2641 } 2642 } 2643