java.lang.Object
net.i2p.router.web.PluginStarter
All Implemented Interfaces:
Runnable
Direct Known Subclasses:
PluginStopper

public class PluginStarterextends Object implements Runnable
Start/stop/delete plugins that are already installed Get properties of installed plugins Get or change settings in plugins.config.
  • Field Details

    • _context

      protected RouterContext _context
      The router context the plugins are started in.
    • CONFIG_FILE

      private static final String CONFIG_FILE
      File listing the enabled plugins.
      See Also:
    • PREFIX

      public static final String PREFIX
      Prefix of every plugin property key.
      See Also:
    • ENABLED

      public static final String ENABLED
      Suffix of the property recording whether a plugin starts at load, false, true, or deleted.
      See Also:
    • DELETED

      public static final String DELETED
      Value of the enabled property marking a plugin as deleted.
      See Also:
    • PLUGIN_DIR

      public static final String PLUGIN_DIR
      Directory under the router base holding the installed plugins.
      See Also:
    • STANDARD_WEBAPPS

      private static final String[] STANDARD_WEBAPPS
      The webapps that ship with the router.
    • STANDARD_THEMES

      private static final String[] STANDARD_THEMES
      The themes that ship with the router.
    • pluginThreadGroups

      private static Map<String, ThreadGroup> pluginThreadGroups
      The thread groups, by plugin name.
    • _pendingPluginClients

      private static Map<String, Collection<SimpleTimer2.TimedEvent>> _pendingPluginClients
      Delayed clients waiting for their plugins.
    • _clCache

      private static Map<String, ClassLoader> _clCache
      The cached class loaders, by plugin name.
    • pluginWars

      private static Map<String, Collection<String>> pluginWars
      The webapps each plugin provides.
    • jetty9Blacklist

      public static final Map<String,String> jetty9Blacklist
      Plugin name to plugin version of plugins that do not work with Jetty 9, but do not have a max-jetty-version=8.9999 set. Unmodifiable.
    • java9Blacklist

      public static final Map<String,String> java9Blacklist
      Plugin name to plugin version of plugins that do not work with Java 9+ Unmodifiable.
  • Constructor Details

    • PluginStarter

      public PluginStarter(RouterContext ctx)
      Creates the runner for the deferred plugin startup thread.
      Parameters:
      ctx - router context supplying the config dir, logging and console server
  • Method Details

    • pluginsEnabled

      public static boolean pluginsEnabled(I2PAppContext ctx)
      Has the user allowed plugins to be started at all?
      Parameters:
      ctx - context to read router.enablePlugins from
      Returns:
      false only if the user has explicitly disabled plugins
    • run

      public void run()
      Startup pass: apply deferred deletions, optionally update plugins, then start every plugin marked enabled in plugins.config.
      Specified by:
      run in interface Runnable
    • updateAll

      public static void updateAll(RouterContext ctx)
      Starts the plugin update on a daemon thread, so the caller does not block.
      Parameters:
      ctx - router context to check and fetch the plugins with
    • updateAll

      private static void updateAll(RouterContext ctx, boolean delay)
      Fetches and restarts the installed plugins in the calling thread.
      Parameters:
      ctx - the router context, used for the update manager and router state
      delay - true to first wait for the router to be running, up to 30 minutes, and for the scheduled update delay
    • startPlugins

      static void startPlugins(RouterContext ctx)
      Start every plugin whose plugins.config entry is "true", skipping any that an update already started. Failures are logged, never thrown.
      Parameters:
      ctx - router context supplying the config dir, logging and console server
    • deferredDeletePlugins

      private static void deferredDeletePlugins(RouterContext ctx)
      Deferred deletion of plugins that we failed to delete before.
      Parameters:
      ctx - the router context, used for the log
    • pluginIncompatible

      private static void pluginIncompatible(Log log, RouterContext ctx, String appName, String detail, String userMessage) throws Exception
      Reject a plugin with incompatible requirements: log, disable, and throw.
      Parameters:
      log - the plugin's logger
      ctx - the router context
      appName - the plugin directory name
      detail - the technical reason for the log
      userMessage - the message for the thrown exception
      Throws:
      Exception - always, carrying the user message
    • startPlugin

      public static boolean startPlugin(RouterContext ctx, String appName) throws Exception
      Start a plugin: extract a pending update, enforce the min/max I2P, Java and Jetty version requirements, register its themes, client apps, console webapps, translation jars and summary bar link.
      Parameters:
      ctx - router context supplying the config dir, logging and console server
      appName - plugin directory name under $I2P/plugins
      Returns:
      true on success, or false if the plugin directory is missing
      Throws:
      Exception - just about anything, caller would be wise to catch Throwable
    • stopPlugin

      public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception
      Stop a plugin: shut down its client apps and console webapps, drop its summary bar link, and release its thread group, pending timers and ClassLoader cache.
      Parameters:
      ctx - router context supplying the config dir, logging and console server
      appName - plugin directory name under $I2P/plugins
      Returns:
      true on success
      Throws:
      Exception - just about anything, caller would be wise to catch Throwable
    • stopPlugin

      protected static boolean stopPlugin(RouterContext ctx, Server s, String appName) throws Exception
      Stop a plugin using an already-located console server, so this also works during shutdown after the server has been unregistered.
      Parameters:
      ctx - router context supplying the config dir, logging and the PortMapper
      s - the Jetty server holding the console contexts, null if not running
      appName - plugin directory name under $I2P/plugins
      Returns:
      true on success
      Throws:
      Exception - just about anything, caller would be wise to catch Throwable
    • deletePlugin

      public static boolean deletePlugin(RouterContext ctx, String appName) throws Exception
      Uninstall a plugin: run its client apps' uninstall commands, unregister its themes (falling back to the default theme if it is the current one), remove its directory and drop its plugins.config entries.
      Parameters:
      ctx - router context supplying the config dir and logging
      appName - plugin directory name under $I2P/plugins
      Returns:
      true on success - caller should call stopPlugin(RouterContext, String) first
      Throws:
      Exception - just about anything, caller would be wise to catch Throwable
    • pluginProperties

      public static Properties pluginProperties(I2PAppContext ctx, String appName)
      Read the plugin.config file for a single plugin.
      Parameters:
      ctx - context to resolve the config dir holding the plugin
      appName - plugin directory name under $I2P/plugins
      Returns:
      non-null, empty if plugin.config is missing or unreadable
    • pluginProperties

      public static Properties pluginProperties()
      Read the plugins.config file, this auto-adds a property for every dir in the plugin directory.
      Returns:
      non-null, empty if plugins.config is missing or unreadable
    • isPluginEnabled

      public static boolean isPluginEnabled(String appName)
      Is the plugin enabled in plugins.config? Default true.
      Parameters:
      appName - plugin directory name under $I2P/plugins
      Returns:
      whether plugin enabled
    • disablePlugin

      public static void disablePlugin(String appName)
      Disable in plugins.config.
      Parameters:
      appName - plugin directory name under $I2P/plugins
    • getPlugins

      public static List<String> getPlugins()
      All installed plugins whether enabled or not, but does NOT include plugins marked as deleted.
      Returns:
      non-null, sorted, modifiable
    • getAllPlugins

      private static List<String> getAllPlugins()
      All installed plugins whether enabled or not, DOES include plugins marked as deleted.
      Returns:
      non-null, unsorted, modifiable
    • getPluginKeys

      public static Map<String,String> getPluginKeys(I2PAppContext ctx)
      The signing keys from all the plugins.
      Parameters:
      ctx - context supplying the config dir holding each plugin.config
      Returns:
      Map of key to keyname Last one wins if a dup (installer should prevent dups)
    • storePluginProperties

      public static void storePluginProperties(Properties props)
      Write the plugins.config file.
      Parameters:
      props - written to plugins.config, converted to OrderedProperties if needed
    • runClientApps

      private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) throws Exception
      Start the client apps of a plugin.
      Parameters:
      ctx - the router context, used for the logs and client apps
      pluginDir - the plugin's installation directory, its name is the plugin name
      apps - the client app configs to run, in order
      action - "start" or "stop" or "uninstall"
      Throws:
      Exception - just about anything if an app has a delay less than zero, caller would be wise to catch Throwable If no apps have a delay less than zero, it shouldn't throw anything
    • isPluginRunning

      public static boolean isPluginRunning(String pluginName, RouterContext ctx)
      Is any part of the plugin still up? Client threads, console webapps, queued client apps and registered client apps all count.
      Parameters:
      pluginName - plugin directory name under $I2P/plugins
      ctx - router context supplying the client app manager and logging
      Returns:
      whether plugin running
    • isPluginRunning

      protected static boolean isPluginRunning(String pluginName, RouterContext ctx, Server s)
      Is any part of the plugin still up? Client threads, console webapps, queued client apps and registered client apps all count.
      Parameters:
      pluginName - plugin directory name under $I2P/plugins
      ctx - router context supplying the client app manager and logging
      s - the Jetty server holding the console contexts, null to skip the webapp check
      Returns:
      whether plugin running
    • isClientThreadRunning

      private static boolean isClientThreadRunning(String pluginName, RouterContext ctx)
      Returns true if one or more client threads are running in a given plugin.
      Parameters:
      pluginName - plugin directory name whose thread group is inspected
      ctx - router context, for the debug log of the threads found
      Returns:
      true if running
    • classpathToURLArray

      private static URL[] classpathToURLArray(String classpath, String clientName, Log log)
      Convert a plugin classpath to URL array, for the plugin's own classloader. Perhaps there's an easy way to use Thread.setContextClassLoader(ClassLoader), but I don't see how to make it magically get used for everything.
      Parameters:
      classpath - the plugin classpath, comma-separated absolute file paths
      clientName - the plugin client name, used in the log messages
      log - the log to report invalid classpath elements to
      Returns:
      null if no valid elements
    • addPath

      private static void addPath(URL u) throws Exception
      Append a URL to the system classpath at runtime, as described at http://jimlife.wordpress.com/2007/12/19/java-adding-new-classpath-at-runtime/
      Parameters:
      u - the URL to append to the system classloader's classpath
      Throws:
      ClassCastException - in Java 9
      Exception - if the reflective lookup or invocation of the classloader's addURL method fails
    • stripHTML

      public static String stripHTML(Properties props, String key)
      Like in DataHelper but doesn't convert null to "" There's a lot worse things a plugin could do but...
      Parameters:
      props - plugin properties to read from
      key - plugin.config key to look up
      Returns:
      the value with markup replaced by spaces, or null if not set
    • gettext

      private static String gettext(String s, Object o, I2PAppContext ctx)
      Translate a string.
      Parameters:
      s - the message key to translate
      o - optional argument for the message, null if none
      ctx - the app context supplying the locale
      Returns:
      the translated text for s
    • ngettext

      private static String ngettext(String s, String p, int n, I2PAppContext ctx)
      Translate a string.
      Parameters:
      s - the singular form of the message
      p - the plural form of the message
      n - the count selecting the singular or plural form
      ctx - the app context supplying the locale
      Returns:
      the translated form matching the count