Example #1
0
  /**
   * @return true on success
   * @throws just about anything, caller would be wise to catch Throwable
   */
  public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
    Log log = ctx.logManager().getLog(PluginStarter.class);
    File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
      log.error("Cannot stop nonexistent plugin: " + appName);
      return false;
    }

    // stop things in clients.config
    File clientConfig = new File(pluginDir, "clients.config");
    if (clientConfig.exists()) {
      Properties props = new Properties();
      DataHelper.loadProps(props, clientConfig);
      List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
      runClientApps(ctx, pluginDir, clients, "stop");
    }

    // stop console webapps in console/webapps
    // ContextHandlerCollection server = WebAppStarter.getConsoleServer();
    // if (server != null) {
    /*
        File consoleDir = new File(pluginDir, "console");
        Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
        File webappDir = new File(consoleDir, "webapps");
        String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance());
        if (fileNames != null) {
            for (int i = 0; i < fileNames.length; i++) {
                String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
                if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) {
                    continue;
                }
                WebAppStarter.stopWebApp(server, warName);
            }
        }
    */
    if (pluginWars.containsKey(appName)) {
      Iterator<String> wars = pluginWars.get(appName).iterator();
      while (wars.hasNext()) {
        String warName = wars.next();
        WebAppStarter.stopWebApp(warName);
      }
      pluginWars.get(appName).clear();
    }
    // }

    // remove summary bar link
    Properties props = pluginProperties(ctx, appName);
    String name =
        ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
    if (name == null) name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
    if (name != null && name.length() > 0) NavHelper.unregisterApp(name);

    if (log.shouldLog(Log.WARN)) log.warn("Stopping plugin: " + appName);
    return true;
  }
Example #2
0
  /** @return true on success - caller should call stopPlugin() first */
  static boolean deletePlugin(RouterContext ctx, String appName) throws Exception {
    Log log = ctx.logManager().getLog(PluginStarter.class);
    File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
      log.error("Cannot delete nonexistent plugin: " + appName);
      return false;
    }
    // uninstall things in clients.config
    File clientConfig = new File(pluginDir, "clients.config");
    if (clientConfig.exists()) {
      Properties props = new Properties();
      DataHelper.loadProps(props, clientConfig);
      List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
      runClientApps(ctx, pluginDir, clients, "uninstall");
    }

    // unregister themes, and switch to default if we are unregistering the current theme
    File dir = new File(pluginDir, "console/themes");
    File[] tfiles = dir.listFiles();
    if (tfiles != null) {
      String current = ctx.getProperty(CSSHelper.PROP_THEME_NAME);
      Map<String, String> changes = new HashMap<String, String>();
      List<String> removes = new ArrayList<String>();
      for (int i = 0; i < tfiles.length; i++) {
        String name = tfiles[i].getName();
        if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i]))) {
          removes.add(ConfigUIHelper.PROP_THEME_PFX + name);
          if (name.equals(current)) changes.put(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME);
        }
      }
      ctx.router().saveConfig(changes, removes);
    }

    boolean deleted = FileUtil.rmdir(pluginDir, false);
    Properties props = pluginProperties();
    for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
      String name = (String) iter.next();
      if (name.startsWith(PREFIX + appName + '.')) iter.remove();
    }
    if (!deleted) {
      // This happens on Windows when there are plugin jars in classpath
      // Mark it as deleted, we will try again after restart
      log.logAlways(Log.WARN, "Deletion of " + pluginDir + " failed, will try again at restart");
      props.setProperty(PREFIX + appName + ENABLED, DELETED);
    }
    storePluginProperties(props);
    return true;
  }
Example #3
0
  /**
   * @return true on success
   * @throws just about anything, caller would be wise to catch Throwable
   */
  public static boolean startPlugin(RouterContext ctx, String appName) throws Exception {
    Log log = ctx.logManager().getLog(PluginStarter.class);
    File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    String iconfile = null;
    if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
      log.error("Cannot start nonexistent plugin: " + appName);
      disablePlugin(appName);
      return false;
    }

    // Do we need to extract an update?
    File pluginUpdate = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip");
    if (pluginUpdate.exists()) {
      // Compare the start time of the router with the plugin.
      if (ctx.router().getWhenStarted() > pluginUpdate.lastModified()) {
        if (!FileUtil.extractZip(pluginUpdate, pluginDir)) {
          pluginUpdate.delete();
          String foo =
              "Plugin '"
                  + appName
                  + "' failed to update! File '"
                  + pluginUpdate
                  + "' deleted. You may need to remove and install the plugin again.";
          log.error(foo);
          disablePlugin(appName);
          throw new Exception(foo);
        } else {
          pluginUpdate.delete();
          // Need to always log this, and  log.logAlways() did not work for me.
          System.err.println("INFO: Plugin updated: " + appName);
        }
      } // silently fail to update, because we have not restarted.
    }

    Properties props = pluginProperties(ctx, appName);

    String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
    if (minVersion != null && VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) {
      String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
    if (minVersion != null
        && VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) {
      String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    String jVersion = LogsHelper.jettyVersion();
    minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
    if (minVersion != null && VersionComparator.comp(minVersion, jVersion) > 0) {
      String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
    if (maxVersion != null && VersionComparator.comp(maxVersion, jVersion) < 0) {
      String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    if (log.shouldLog(Log.INFO)) log.info("Starting plugin: " + appName);

    // register themes
    File dir = new File(pluginDir, "console/themes");
    File[] tfiles = dir.listFiles();
    if (tfiles != null) {
      for (int i = 0; i < tfiles.length; i++) {
        String name = tfiles[i].getName();
        if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i])))
          ctx.router()
              .setConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name, tfiles[i].getAbsolutePath());
        // we don't need to save
      }
    }

    // load and start things in clients.config
    File clientConfig = new File(pluginDir, "clients.config");
    if (clientConfig.exists()) {
      Properties cprops = new Properties();
      DataHelper.loadProps(cprops, clientConfig);
      List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
      runClientApps(ctx, pluginDir, clients, "start");
    }

    // start console webapps in console/webapps
    ContextHandlerCollection server = WebAppStarter.getConsoleServer();
    if (server != null) {
      File consoleDir = new File(pluginDir, "console");
      Properties wprops = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
      File webappDir = new File(consoleDir, "webapps");
      String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance());
      if (fileNames != null) {
        if (!pluginWars.containsKey(appName))
          pluginWars.put(appName, new ConcurrentHashSet<String>());
        for (int i = 0; i < fileNames.length; i++) {
          try {
            String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
            // log.error("Found webapp: " + warName);
            // check for duplicates in $I2P
            if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) {
              log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
              continue;
            }
            String enabled = wprops.getProperty(RouterConsoleRunner.PREFIX + warName + ENABLED);
            if (!"false".equals(enabled)) {
              if (log.shouldLog(Log.INFO)) log.info("Starting webapp: " + warName);
              String path = new File(webappDir, fileNames[i]).getCanonicalPath();
              WebAppStarter.startWebApp(ctx, server, warName, path);
              pluginWars.get(appName).add(warName);
            }
          } catch (IOException ioe) {
            log.error("Error resolving '" + fileNames[i] + "' in '" + webappDir, ioe);
          }
        }
        // Check for iconfile in plugin.properties
        String icfile = ConfigClientsHelper.stripHTML(props, "console-icon");
        if (icfile != null && !icfile.contains("..")) {
          StringBuilder buf = new StringBuilder(32);
          buf.append('/').append(appName);
          if (!icfile.startsWith("/")) buf.append('/');
          buf.append(icfile);
          iconfile = buf.toString();
        }
      }
    } else {
      log.error("No console web server to start plugins?");
    }

    // add translation jars in console/locale
    // These will not override existing resource bundles since we are adding them
    // later in the classpath.
    File localeDir = new File(pluginDir, "console/locale");
    if (localeDir.exists() && localeDir.isDirectory()) {
      File[] files = localeDir.listFiles();
      if (files != null) {
        boolean added = false;
        for (int i = 0; i < files.length; i++) {
          File f = files[i];
          if (f.getName().endsWith(".jar")) {
            try {
              addPath(f.toURI().toURL());
              log.error("INFO: Adding translation plugin to classpath: " + f);
              added = true;
            } catch (Exception e) {
              log.error("Plugin " + appName + " bad classpath element: " + f, e);
            }
          }
        }
        if (added) Translate.clearCache();
      }
    }
    // add summary bar link
    String name =
        ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
    if (name == null) name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
    String url = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
    if (name != null && url != null && name.length() > 0 && url.length() > 0) {
      String tip =
          ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx));
      if (tip == null) tip = ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip");
      NavHelper.registerApp(name, url, tip, iconfile);
    }

    return true;
  }