private List<LazyHostPlugin> update(
      LogSource logger,
      final List<LazyHostPlugin> updateCache,
      final AtomicLong lastFolderModification)
      throws Exception {
    final List<LazyHostPlugin> retList = new ArrayList<LazyHostPlugin>();
    for (PluginInfo<PluginForHost> pluginInfo :
        scan(logger, "jd/plugins/hoster", updateCache, lastFolderModification)) {

      if (pluginInfo.getLazyPlugin() != null) {
        final LazyHostPlugin plugin = (LazyHostPlugin) pluginInfo.getLazyPlugin();
        retList.add(plugin);
        // logger.finer("@HostPlugin ok(cached):" + plugin.getClassName() + " " +
        // plugin.getDisplayName() + " " +
        // plugin.getVersion());
      } else {
        final String simpleName = new String(pluginInfo.getClazz().getSimpleName());
        final HostPlugin a = pluginInfo.getClazz().getAnnotation(HostPlugin.class);
        if (a != null) {
          try {
            final long revision = pluginInfo.getLazyPluginClass().getRevision();
            String[] names = a.names();
            String[] patterns = a.urls();
            int[] flags = a.flags();
            if (names.length == 0) {
              /* create multiple hoster plugins from one source */
              patterns =
                  (String[])
                      pluginInfo
                          .getClazz()
                          .getDeclaredMethod("getAnnotationUrls", new Class[] {})
                          .invoke(null, new Object[] {});
              names =
                  (String[])
                      pluginInfo
                          .getClazz()
                          .getDeclaredMethod("getAnnotationNames", new Class[] {})
                          .invoke(null, new Object[] {});
              flags =
                  (int[])
                      pluginInfo
                          .getClazz()
                          .getDeclaredMethod("getAnnotationFlags", new Class[] {})
                          .invoke(null, new Object[] {});
            }
            if (patterns.length != names.length) {
              //
              throw new WTFException("names.length != patterns.length");
            }
            if (flags.length != names.length && a.interfaceVersion() == 2) {
              /* interfaceVersion 2 is for Stable/Nightly */
              logger.log(
                  (new WTFException(
                      "PLUGIN STABLE ISSUE!! names.length("
                          + names.length
                          + ")!= flags.length("
                          + flags.length
                          + ")->"
                          + simpleName)));
            }
            if (names.length == 0) {
              //
              throw new WTFException("names.length=0");
            }
            final PluginClassLoaderChild classLoader =
                (PluginClassLoaderChild) pluginInfo.getClazz().getClassLoader();
            /* during init we dont want dummy libs being created */
            classLoader.setCreateDummyLibs(false);
            for (int i = 0; i < names.length; i++) {
              LazyHostPlugin lazyHostPlugin = null;
              try {
                lazyHostPlugin =
                    new LazyHostPlugin(
                        pluginInfo.getLazyPluginClass(),
                        new String(patterns[i]),
                        new String(names[i]),
                        pluginInfo.getClazz(),
                        classLoader);
                if (list != null) {
                  final LazyHostPlugin previousLazyHostPlugin =
                      list.get(lazyHostPlugin.getDisplayName());
                  if (previousLazyHostPlugin != null) {
                    lazyHostPlugin.setPluginUsage(previousLazyHostPlugin.getPluginUsage());
                  }
                }
                try {
                  /* check for stable compatibility */
                  classLoader.setPluginClass(pluginInfo.getClazz().getName());
                  classLoader.setCheckStableCompatibility(
                      pluginInfo.getLazyPluginClass().getInterfaceVersion() == 2);
                  final PluginForHost plg = lazyHostPlugin.newInstance(classLoader);
                  /* set configinterface */
                  final Class<? extends ConfigInterface> configInterface = plg.getConfigInterface();
                  if (configInterface != null) {
                    lazyHostPlugin.setConfigInterface(new String(configInterface.getName()));
                  } else {
                    lazyHostPlugin.setConfigInterface(null);
                  }
                  /* set premium */
                  if (plg.isPremiumEnabled()) {
                    lazyHostPlugin.setPremium(true);
                    /* set premiumUrl */
                    final String purl = plg.getBuyPremiumUrl();
                    if (purl != null) {
                      lazyHostPlugin.setPremiumUrl(new String(purl));
                    }
                  } else {
                    lazyHostPlugin.setPremium(false);
                  }
                  /* set hasConfig */
                  lazyHostPlugin.setHasConfig(plg.hasConfig());

                  try {
                    lazyHostPlugin.setHasAllowHandle(PluginForHost.implementsAllowHandle(plg));
                  } catch (Throwable e) {
                    logger.log(e);
                    lazyHostPlugin.setHasAllowHandle(false);
                  }

                  try {
                    lazyHostPlugin.setHasRewrite(PluginForHost.implementsRewriteHost(plg));
                  } catch (Throwable e) {
                    logger.log(e);
                    lazyHostPlugin.setHasRewrite(false);
                  }

                } catch (Throwable e) {
                  if (e instanceof UpdateRequiredClassNotFoundException) {
                    logger.log(e);
                    logger.finest(
                        "@HostPlugin incomplete:"
                            + simpleName
                            + " "
                            + new String(names[i])
                            + " "
                            + e.getMessage()
                            + " "
                            + revision);
                  } else {
                    throw e;
                  }
                }
                if (lazyHostPlugin != null) {
                  retList.add(lazyHostPlugin);
                  // logger.finer("@HostPlugin ok:" + simpleName + " " + new String(names[i]) + " "
                  // + revision);
                }
              } catch (Throwable e) {
                logger.log(e);
                logger.severe(
                    "@HostPlugin failed:"
                        + simpleName
                        + " "
                        + new String(names[i])
                        + " "
                        + revision);
              } finally {
                /* now the pluginClassLoad may create dummy libraries */
                if (lazyHostPlugin != null) {
                  lazyHostPlugin.setClassLoader(null);
                  lazyHostPlugin.setPluginClass(null);
                }
              }
            }
          } catch (final Throwable e) {
            logger.severe("@HostPlugin failed:" + simpleName);
            logger.log(e);
          }
        } else {
          logger.severe("@HostPlugin missing:" + simpleName);
        }
      }
    }
    return retList;
  }
Example #2
0
  protected List<PluginInfo<T>> scan(
      LogSource logger,
      String hosterpath,
      final List<? extends LazyPlugin<T>> pluginCache,
      final AtomicLong lastFolderModification)
      throws Exception {
    DirectoryStream<Path> stream = null;
    final ArrayList<PluginInfo<T>> ret = new ArrayList<PluginInfo<T>>();
    final long timeStamp = System.currentTimeMillis();
    try {
      long lastModified = lastFolderModification != null ? lastFolderModification.get() : -1;
      final Path folder =
          Application.getRootByClass(jd.SecondLevelLaunch.class, hosterpath).toPath();
      final long lastFolderModified =
          Files.readAttributes(folder, BasicFileAttributes.class).lastModifiedTime().toMillis();
      if (lastModified > 0
          && lastFolderModified == lastModified
          && pluginCache != null
          && pluginCache.size() > 0) {
        for (final LazyPlugin<T> lazyPlugin : pluginCache) {
          final PluginInfo<T> pluginInfo = new PluginInfo<T>(lazyPlugin.getLazyPluginClass(), null);
          pluginInfo.setLazyPlugin(lazyPlugin);
          ret.add(pluginInfo);
        }
        return ret;
      }
      PluginClassLoaderChild cl = null;
      MessageDigest md = null;
      final String pkg = hosterpath.replace("/", ".");
      final byte[] mdCache = new byte[32767];
      final HashMap<String, List<LazyPlugin<T>>> lazyPluginClassMap;
      if (pluginCache != null && pluginCache.size() > 0) {
        lazyPluginClassMap = new HashMap<String, List<LazyPlugin<T>>>();
        for (final LazyPlugin<T> lazyPlugin : pluginCache) {
          List<LazyPlugin<T>> list =
              lazyPluginClassMap.get(lazyPlugin.getLazyPluginClass().getClassName());
          if (list == null) {
            list = new ArrayList<LazyPlugin<T>>();
            lazyPluginClassMap.put(lazyPlugin.getLazyPluginClass().getClassName(), list);
          }
          list.add(lazyPlugin);
        }
      } else {
        lazyPluginClassMap = null;
      }
      if (lastFolderModification != null) {
        lastFolderModification.set(lastFolderModified);
      }
      stream = Files.newDirectoryStream(folder, "*.class");
      for (final Path path : stream) {
        try {
          final String pathFileName = path.getFileName().toString();
          final String className = pathFileName.substring(0, pathFileName.length() - 6);
          if (className.indexOf("$") < 0 && !PluginController.IGNORELIST.contains(className)) {
            byte[] sha256 = null;
            final BasicFileAttributes pathAttr =
                Files.readAttributes(path, BasicFileAttributes.class);
            if (lazyPluginClassMap != null) {
              final List<LazyPlugin<T>> lazyPlugins = lazyPluginClassMap.get(className);
              if (lazyPlugins != null && lazyPlugins.size() > 0) {
                final LazyPluginClass lazyPluginClass = lazyPlugins.get(0).getLazyPluginClass();
                if (lazyPluginClass != null
                    && (lazyPluginClass.getLastModified() == pathAttr.lastModifiedTime().toMillis()
                        || ((md = MessageDigest.getInstance("SHA-256")) != null
                            && (sha256 =
                                    PluginController.getFileHashBytes(path.toFile(), md, mdCache))
                                != null
                            && Arrays.equals(sha256, lazyPluginClass.getSha256())))) {
                  for (final LazyPlugin<T> lazyPlugin : lazyPlugins) {
                    // logger.finer("Cached: " + className + "|" + lazyPlugin.getDisplayName() + "|"
                    // +
                    // lazyPluginClass.getRevision());
                    final PluginInfo<T> pluginInfo = new PluginInfo<T>(lazyPluginClass, null);
                    pluginInfo.setLazyPlugin(lazyPlugin);
                    ret.add(pluginInfo);
                  }
                  continue;
                }
              }
            }
            Class<T> pluginClass = null;
            long[] infos = null;
            try {
              if (cl == null) {
                cl = PluginClassLoader.getInstance().getChild();
              }
              if (md == null) {
                md = MessageDigest.getInstance("SHA-256");
              }
              pluginClass = (Class<T>) cl.loadClass(pkg + "." + className);
              if (!Modifier.isAbstract(pluginClass.getModifiers())
                  && Plugin.class.isAssignableFrom(pluginClass)) {
                infos = getPluginController().getInfos(pluginClass);
                if (infos == null) {
                  continue;
                }
              } else {
                continue;
              }
            } catch (final Throwable e) {
              logger.finer("Failed: " + className);
              logger.log(e);
              continue;
            }
            if (sha256 == null) {
              sha256 = PluginController.getFileHashBytes(path.toFile(), md, mdCache);
            }
            //
            final LazyPluginClass lazyPluginClass =
                new LazyPluginClass(
                    className,
                    sha256,
                    pathAttr.lastModifiedTime().toMillis(),
                    (int) infos[0],
                    infos[1]);
            final PluginInfo<T> pluginInfo = new PluginInfo<T>(lazyPluginClass, pluginClass);
            // logger.finer("Scaned: " + className + "|" + lazyPluginClass.getRevision());
            ret.add(pluginInfo);
          }

        } catch (Throwable e) {
          logger.finer("Failed: " + path);
          logger.log(e);
        }
      }
      return ret;
    } finally {
      logger.info(
          "@PluginController(NIO): scan took "
              + (System.currentTimeMillis() - timeStamp)
              + "ms for "
              + ret.size());
      if (stream != null) {
        stream.close();
      }
    }
  }