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; }
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(); } } }