diff --git a/pom.xml b/pom.xml index 3d5db6d..a2748ea 100644 --- a/pom.xml +++ b/pom.xml @@ -10,8 +10,8 @@ 4.0.0 com.guicedee - guice-injection + jar 2.0.0-SNAPSHOT Guiced Injector diff --git a/src/main/java/com/guicedee/guicedinjection/GuiceContext.java b/src/main/java/com/guicedee/guicedinjection/GuiceContext.java index 5fe5371..dbbc63b 100644 --- a/src/main/java/com/guicedee/guicedinjection/GuiceContext.java +++ b/src/main/java/com/guicedee/guicedinjection/GuiceContext.java @@ -44,965 +44,940 @@ @SuppressWarnings("MissingClassJavaDoc") public class GuiceContext> implements IGuiceContext { - /** - * This particular instance of the class - */ - private static final GuiceContext instance = new GuiceContext<>(); - - /** - * A list of all the loaded singleton sets - */ - //private static final Map allLoadedServices = new LinkedHashMap<>(); - /** - * The building injector - */ - public static boolean buildingInjector = false; - /** - * The configuration object - */ - private static final GuiceConfig config = new GuiceConfig<>(); - /** - * The physical injector for the JVM container - */ - private Injector injector; - /** - * The actual scanner - */ - private ClassGraph scanner; - /** - * The scan result built from everything - the core scanner. - */ - private ScanResult scanResult; - /** - * If the scan should run async - */ - private boolean async; - /** - * If this context is configured - */ - private static boolean configured; - - /** - * Creates a new Guice context. Not necessary - */ - private GuiceContext() - { - //No config required - } - - - /** - * Reference the Injector Directly - * - * @return The global Guice Injector Object, Never Null, Instantiates the Injector if not configured - */ - @NotNull - public synchronized Injector inject() - { - if (GuiceContext.buildingInjector) - { - log.log(Level.SEVERE, "The injector is being called recursively during build. Place such actions in a IGuicePostStartup or use the IGuicePreStartup Service Loader."); - System.exit(1); - } - if (GuiceContext.instance().injector == null) - { - try - { - GuiceContext.buildingInjector = true; - GuiceContext.log.info("Starting up Guice Context"); - GuiceContext - .instance() - .loadConfiguration(); - if (GuiceContext - .instance() - .getConfig() - .isPathScanning() || GuiceContext - .instance() - .getConfig() - .isClasspathScanning()) - { - GuiceContext - .instance() - .loadScanner(); - } - GuiceContext - .instance() - .loadPreStartups(); - - List cModules = new ArrayList<>(modules); - Set iGuiceModules = GuiceContext - .instance() - .loadIGuiceModules(); - cModules.addAll(iGuiceModules); - - //cModules.add(new GuiceInjectorModule()); - log.config("Modules - " + Arrays.toString(cModules.toArray())); - GuiceContext.instance().injector = Guice.createInjector(cModules); - GuiceContext.buildingInjector = false; - GuiceContext - .instance() - .loadPostStartups(); - - Runtime - .getRuntime() - .addShutdownHook(new Thread() - { - public void run() - { - IGuiceContext - .getContext() - .destroy(); - } - }); - - GuiceContext.log.config("Injection System Ready"); - } - catch (Throwable e) - { - GuiceContext.log.log(Level.SEVERE, "Exception creating Injector : " + e.getMessage(), e); - throw new RuntimeException("Unable to boot Guice Injector", e); - } - } - GuiceContext.buildingInjector = false; - return GuiceContext.instance().injector; - } - - private static Set destroyers = GuiceContext - .instance() - .getLoader(IGuicePreDestroy.class, false, ServiceLoader.load(IGuicePreDestroy.class)); - - /** - * Execute on Destroy - */ - @SuppressWarnings("unused") - public void destroy() - { - try - { - for (IGuicePreDestroy destroyer : destroyers) - { - try - { - destroyer.onDestroy(); - } - catch (Throwable T) - { - log.log(Level.SEVERE, - "Could not run destroyer [" + destroyer - .getClass() - .getCanonicalName() + "]"); - } - } - } - catch (Throwable T) - { - log.log(Level.SEVERE, "Could not run destroyers", T); - } - if (GuiceContext.instance().scanResult != null) - { - GuiceContext.instance().scanResult.close(); - } - if (GuiceContext.instance().scanResult != null) - { - GuiceContext.instance().scanResult.close(); - } - GuiceContext.instance().scanResult = null; - GuiceContext.instance().scanner = null; - GuiceContext.instance().injector = null; - } - - /** - * Returns the Java version as an int value. - * - * @return the Java version as an int value (8, 9, etc.) - * - * @since 12130 - */ - private static int getJavaVersion() - { - String version = getSystemPropertyOrEnvironment("java.version", "11"); - if (version.startsWith("1.")) - { - version = version.substring(2); - } - // Allow these formats: - // 1.8.0_72-ea - // 9-ea - // 9 - // 9.0.1 - int dotPos = version.indexOf('.'); - int dashPos = version.indexOf('-'); - String value = version.substring(0, dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : version.length()); - return Integer.parseInt(value); - } - - /** - * Returns the current scan result - * - * @return The physical Scan Result from the complete class scanner - */ - @NotNull - public ScanResult getScanResult() - { - if (scanResult == null) - { - loadScanner(); - } - return scanResult; - } - - /** - * Sets the current scan result - * - * @param scanResult The physical Scan Result from the complete class scanner - */ - @SuppressWarnings("unused") - public void setScanResult(ScanResult scanResult) - { - GuiceContext.instance().scanResult = scanResult; - } - - /** - * Returns the actual context instance, provides access to methods existing a bit deeper - * - * @return The singleton instance of this - */ - public static GuiceContext instance() - { - return GuiceContext.instance; - } - - /** - * Loads the IGuiceConfigurator - */ - private void loadConfiguration() - { - if (!configured) - { - Set guiceConfigurators = loadIGuiceConfigs(); - for (IGuiceConfigurator guiceConfigurator : guiceConfigurators) - { - GuiceContext.log.config("Loading IGuiceConfigurator - " + guiceConfigurator - .getClass() - .getCanonicalName()); - guiceConfigurator.configure(GuiceContext.config); - } - if (!GuiceContext.config.isIncludeModuleAndJars()) - { - log.warning("Scanning is not restricted to modules and may incur a performance impact. Consider registering your module with GuiceContext.registerModule() to auto enable, or SPI IGuiceConfiguration"); - } - GuiceContext.log.config("IGuiceConfigurator : " + GuiceContext.config.toString()); - configured = true; - } - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - @SuppressWarnings("unchecked") - private String[] getJarsExclusionList() - { - Set strings = new TreeSet<>(); - Set exclusions = loadJarRejectScanners(); - if (exclusions - .iterator() - .hasNext()) - { - for (IGuiceScanJarExclusions exclusion : exclusions) - { - Set searches = exclusion.excludeJars(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IGuiceScanJarExclusions - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - @SuppressWarnings("unchecked") - private String[] getJarsInclusionList() - { - Set strings = new TreeSet<>(); - Set exclusions = loadJarInclusionScanners(); - if (exclusions - .iterator() - .hasNext()) - { - for (IGuiceScanJarInclusions exclusion : exclusions) - { - Set searches = exclusion.includeJars(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IGuiceScanJarExclusions - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - - /** - * Starts up Guice and the scanner - */ - private synchronized void loadScanner() - { - if (scanner == null) - { - scanner = new ClassGraph(); - Stopwatch stopwatch = Stopwatch.createStarted(); - GuiceContext.log.info("Loading Classpath Scanner"); - loadConfiguration(); - scanner = configureScanner(scanner); - try - { - if (async) - { - scanResult = scanner.scan(Runtime - .getRuntime() - .availableProcessors()); - } - else - { - scanResult = scanner.scan(); - } - stopwatch.stop(); - Map fileScans = quickScanFiles(); - fileScans.forEach((key, value) -> scanResult - .getResourcesWithLeafName(key) - .forEachByteArrayIgnoringIOException(value)); - quickScanFilesPattern().forEach((key, value) -> scanResult - .getResourcesMatchingPattern(key) - .forEachByteArrayIgnoringIOException(value)); - - } - catch (Exception mpe) - { - GuiceContext.log.log(Level.SEVERE, "Unable to run scanner", mpe); - } - GuiceContext.log.fine("Loaded Classpath Scanner - Took [" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "] millis."); - } - } - - /** - * Configures the scanner from its setup - * - * @param graph The ClassGraph to apply the configuration to - */ - private ClassGraph configureScanner(ClassGraph graph) - { - if (config.isAllowPaths()) - { - String[] paths = getPathsList(); - if (paths.length != 0) - { - graph = graph.acceptPaths(paths); - } - } - if (GuiceContext.config.isExcludePaths()) - { - String[] blacklistList = getPathsBlacklistList(); - if (blacklistList.length != 0) - { - graph = graph.rejectPaths(blacklistList); - } - } - - if (GuiceContext.config.isExcludeModulesAndJars()) - { - if (getJavaVersion() < 9) - { - String[] jarRejections = getJarsExclusionList(); - if (jarRejections.length != 0) - { - graph = graph.rejectJars(jarRejections); - } - } - else - { - String[] modulesRejection = getModulesExclusionList(); - if (modulesRejection.length != 0) - { - graph = graph.rejectModules(modulesRejection); - } - else - { - graph = graph.ignoreParentModuleLayers(); - } - } - } - - if (GuiceContext.config.isIncludeModuleAndJars()) - { - if (getJavaVersion() < 9) - { - String[] jarRejections = getJarsInclusionList(); - log.config("Accepted Jars for Scanning : " + Arrays.toString(jarRejections)); - if (jarRejections.length != 0) - { - graph = graph.acceptJars(jarRejections); - } - } - else - { - String[] modulesRejection = getModulesInclusionsList(); - log.config("Accepted Modules for Scanning : " + Arrays.toString(modulesRejection)); - if (modulesRejection.length != 0) - { - graph = graph.acceptModules(modulesRejection); - } - else - { - graph = graph.ignoreParentModuleLayers(); - } - } - } - - if (GuiceContext.config.isIncludePackages()) - { - String[] packages = getPackagesList(); - if (packages.length != 0) - { - graph = graph.acceptPackages(packages); - } - } - if (GuiceContext.config.isRejectPackages()) - { - String[] packages = getBlacklistPackages(); - if (packages.length != 0) - { - graph = graph.rejectPackages(packages); - } - } - if (GuiceContext.config.isExcludeParentModules()) - { - graph = graph.ignoreParentModuleLayers(); - } - if (GuiceContext.config.isFieldInfo()) - { - graph = graph.enableClassInfo(); - graph = graph.enableFieldInfo(); - } - if (GuiceContext.config.isAnnotationScanning()) - { - graph = graph.enableClassInfo(); - graph = graph.enableAnnotationInfo(); - } - if (GuiceContext.config.isMethodInfo()) - { - graph = graph.enableClassInfo(); - graph = graph.enableMethodInfo(); - } - if (GuiceContext.config.isIgnoreFieldVisibility()) - { - graph = graph.enableClassInfo(); - graph = graph.ignoreFieldVisibility(); - } - if (GuiceContext.config.isIgnoreMethodVisibility()) - { - graph = graph.enableClassInfo(); - graph = graph.ignoreMethodVisibility(); - } - if (GuiceContext.config.isClasspathScanning()) - { - graph = graph.enableClassInfo(); - } - if (GuiceContext.config.isVerbose()) - { - graph = graph.verbose(); - } - if (GuiceContext.config.isIgnoreClassVisibility()) - { - graph = graph.ignoreClassVisibility(); - } - return graph; - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - private String[] getPackagesList() - { - Set strings = new LinkedHashSet<>(); - Set exclusions = getLoader(IPackageContentsScanner.class, true, ServiceLoader.load(IPackageContentsScanner.class)); - if (exclusions - .iterator() - .hasNext()) - { - for (IPackageContentsScanner exclusion : exclusions) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IPackageContentsScanner - " + exclusion - .getClass() - .getCanonicalName()); - Set searches = exclusion.searchFor(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IPackageScanningContentsScanner - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - private String[] getBlacklistPackages() - { - Set strings = new LinkedHashSet<>(); - Set exclusions = getLoader(IPackageRejectListScanner.class, true, ServiceLoader.load(IPackageRejectListScanner.class)); - if (exclusions - .iterator() - .hasNext()) - { - for (IPackageRejectListScanner exclusion : exclusions) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IPackageContentsScanner - " + exclusion - .getClass() - .getCanonicalName()); - Set searches = exclusion.exclude(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IPackageScanningContentsScanner - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /* - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - private String[] getPathsList() - { - Set strings = new TreeSet<>(); - Set exclusions = getLoader(IPathContentsScanner.class, true, ServiceLoader.load(IPathContentsScanner.class)); - if (exclusions - .iterator() - .hasNext()) - { - for (IPathContentsScanner exclusion : exclusions) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IPathScanningContentsScanner - " + exclusion - .getClass() - .getCanonicalName()); - Set searches = exclusion.searchFor(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IPathScanningContentsScanner - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - private String[] getPathsBlacklistList() - { - Set strings = new TreeSet<>(); - Set exclusions = loadPathRejectScanners(); - if (exclusions - .iterator() - .hasNext()) - { - for (IPathContentsRejectListScanner exclusion : exclusions) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IPathContentsRejectListScanner - " + exclusion - .getClass() - .getCanonicalName()); - Set searches = exclusion.searchFor(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IPathContentsRejectListScanner - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - @SuppressWarnings("unchecked") - private String[] getModulesExclusionList() - { - Set strings = new TreeSet<>(); - Set exclusions = getLoader(IGuiceScanModuleExclusions.class, true, ServiceLoader.load(IGuiceScanModuleExclusions.class)); - if (exclusions - .iterator() - .hasNext()) - { - for (IGuiceScanModuleExclusions exclusion : exclusions) - { - Set searches = exclusion.excludeModules(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IGuiceScanModuleExclusions - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Returns a complete list of generic exclusions - * - * @return A string list of packages to be scanned - */ - @SuppressWarnings("unchecked") - private String[] getModulesInclusionsList() - { - Set strings = new TreeSet<>(); - strings.addAll(registerModuleForScanning); - Set exclusions = getLoader(IGuiceScanModuleInclusions.class, true, ServiceLoader.load(IGuiceScanModuleInclusions.class)); - if (exclusions - .iterator() - .hasNext()) - { - for (IGuiceScanModuleInclusions exclusion : exclusions) - { - Set searches = exclusion.includeModules(); - strings.addAll(searches); - } - GuiceContext.log.log(Level.FINE, "IGuiceScanModuleInclusions - " + strings.toString()); - } - return strings.toArray(new String[0]); - } - - /** - * Registers the quick scan files - */ - private Map quickScanFiles() - { - Map fileScans = new HashMap<>(); - Set fileScanners = getLoader(IFileContentsScanner.class, true, ServiceLoader.load(IFileContentsScanner.class)); - for (IFileContentsScanner fileScanner : fileScanners) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IFileContentsScanner - " + fileScanner - .getClass() - .getCanonicalName()); - fileScans.putAll(fileScanner.onMatch()); - } - return fileScans; - } - - /** - * Registers the quick scan files - */ - private Map quickScanFilesPattern() - { - Map fileScans = new HashMap<>(); - Set fileScanners = getLoader(IFileContentsPatternScanner.class, true, ServiceLoader.load(IFileContentsPatternScanner.class)); - for (IFileContentsPatternScanner fileScanner : fileScanners) - { - GuiceContext.log.log(Level.CONFIG, - "Loading IFileContentsPatternScanner - " + fileScanner - .getClass() - .getCanonicalName()); - fileScans.putAll(fileScanner.onMatch()); - } - return fileScans; - } - - /** - * A set - * - * @param loaderType The service type - * @param The type - * @param dontInject Don't inject - * - * @return A set of them - */ - @SuppressWarnings("unchecked") - @NotNull - public Set getLoader(Class loaderType, @SuppressWarnings("unused") boolean dontInject, ServiceLoader serviceLoader) - { - if (!IGuiceContext - .getAllLoadedServices() - .containsKey(loaderType)) - { - Set loader = IGuiceContext.loaderToSetNoInjection(serviceLoader); - IGuiceContext - .getAllLoadedServices() - .put(loaderType, loader); - } - return IGuiceContext - .getAllLoadedServices() - .get(loaderType); - } - - @Override - public boolean isBuildingInjector() - { - return buildingInjector; - } - - /** - * Returns the current classpath scanner - * - * @return Default processors count - */ - @SuppressWarnings("unused") - public ClassGraph getScanner() - { - return scanner; - } - - /** - * Sets the classpath scanner - * - * @param scanner Sets the scanner to a specific instance - */ - @SuppressWarnings("unused") - public static void setScanner(ClassGraph scanner) - { - GuiceContext.instance().scanner = scanner; - } - - /** - * Method loadPostStartups ... - */ - private void loadPostStartups() - { - Set startupSet = loadPostStartupServices(); - - Map> postStartupGroups = new TreeMap<>(); - for (IGuicePostStartup postStartup : startupSet) - { - Integer sortOrder = postStartup.sortOrder(); - postStartupGroups - .computeIfAbsent(sortOrder, k -> new TreeSet<>()) - .add(postStartup); - } - - for (Map.Entry> entry : postStartupGroups.entrySet()) - { - Integer key = entry.getKey(); - Set value = entry.getValue(); - if (value.size() == 1) - { - //run in order - for (IGuicePostStartup iGuicePostStartup : value) - { - try - { - iGuicePostStartup.postLoad(); - } - catch (Throwable T) - { - log.log(Level.SEVERE, - "Cannot execute post startup - " + iGuicePostStartup - .getClass() - .getCanonicalName(), - T); - } - } - } - else - { - log.info("Starting Post Startup Group [" + key + "] in Parallel"); - ExecutorService postStartup = null; - value.stream().forEach(a->{ - try - { - a.postLoad(); - } - catch (Throwable T) - { - log.log(Level.SEVERE, "Cannot execute post startup - ", T); - } - }); - /*for (IGuicePostStartup iGuicePostStartup : value) - { - postStartup = JobService.INSTANCE.addJob("PostStartup", () -> { - try - { - iGuicePostStartup.postLoad(); - } - catch (Throwable T) - { - log.log(Level.SEVERE, "Cannot execute post startup - ", T); - } - }); - } - try - { - if (postStartup != null) - { - log.config("Waiting for post startup group to finish...."); - JobService.INSTANCE.removeJob("PostStartup"); - } - } - catch (Throwable e) - { - log.log(Level.SEVERE, "Cannot execute post startup - ", e); - }*/ - } - GuiceContext.log.fine("Completed with Post Startups Key [" + key + "]"); - } - } - - /** - * Returns the Guice Config Instance - * - * @return The singleton Guice Config instance. Also available with @Inject - */ - public GuiceConfig getConfig() - { - return GuiceContext.config; - } - - /** - * Loads the service lists of post startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadPostStartupServices() - { - return getLoader(IGuicePostStartup.class, ServiceLoader.load(IGuicePostStartup.class)); - } - - /** - * Loads the service lists of post startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadPathRejectScanners() - { - return getLoader(IPathContentsRejectListScanner.class, true, ServiceLoader.load(IPathContentsRejectListScanner.class)); - } - - - /** - * Loads the service lists of post startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadJarRejectScanners() - { - return getLoader(IGuiceScanJarExclusions.class, true, ServiceLoader.load(IGuiceScanJarExclusions.class)); - } - - - /** - * Loads the service lists of post startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadJarInclusionScanners() - { - return getLoader(IGuiceScanJarInclusions.class, true, ServiceLoader.load(IGuiceScanJarInclusions.class)); - } - - - /** - * Returns the set of service lists of pre startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadPreStartupServices() - { - return getLoader(IGuicePreStartup.class, true, ServiceLoader.load(IGuicePreStartup.class)); - } - - /** - * Loads the service lists of post startup's for manual additions - * - * @return The list of guice post startups - */ - public @NotNull Set loadIGuiceModules() - { - return getLoader(IGuiceModule.class, true, ServiceLoader.load(IGuiceModule.class)); - } - - /** - * Loads the service lists of guice configurators (before pre-startup) for manual additions - * - * @return The list of guice configs - */ - public @NotNull Set loadIGuiceConfigs() - { - return getLoader(IGuiceConfigurator.class, true, ServiceLoader.load(IGuiceConfigurator.class)); - } - - /** - * Method loadPreStartups gets the pre startups and loads them up - */ - private void loadPreStartups() - { - Set preStartups = loadPreStartupServices(); - List startups = new ArrayList<>(preStartups); - startups.sort(Comparator.comparing(IGuicePreStartup::sortOrder)); - for (IGuicePreStartup startup : startups) - { - GuiceContext.log.config("Loading IGuicePreStartup - " + startup - .getClass() - .getCanonicalName()); - startup.onStartup(); - } - } - - /** - * Returns the loader for anything that is located locally in guice context - * replacing with set load methods instead for each type - * - * @param loaderType The service type - * @param The type - * - * @return A set of them - */ - @SuppressWarnings("unchecked") - @NotNull - public > Set getLoader(Class loaderType, ServiceLoader serviceLoader) - { - if (!IGuiceContext - .getAllLoadedServices() - .containsKey(loaderType)) - { - Set loader; - if (GuiceContext.buildingInjector || injector == null) - { - loader = IGuiceContext.loaderToSetNoInjection(serviceLoader); - } - else - { - loader = IGuiceContext.loaderToSet(serviceLoader); - } - IGuiceContext - .getAllLoadedServices() - .put(loaderType, loader); - } - return IGuiceContext - .getAllLoadedServices() - .get(loaderType); - } - - /** - * If this scanner is registered to run asynchronously - * - * @return - */ public boolean isAsync() - { - return async; - } - - /** - * Sets if the scanner must run asynchronously - * - * @param async - */ - public void setAsync(boolean async) - { - this.async = async; - } + /** + * This particular instance of the class + */ + private static final GuiceContext instance = new GuiceContext<>(); + + /** + * A list of all the loaded singleton sets + */ + //private static final Map allLoadedServices = new LinkedHashMap<>(); + /** + * The building injector + */ + public static boolean buildingInjector = false; + /** + * The configuration object + */ + private static final GuiceConfig config = new GuiceConfig<>(); + /** + * The physical injector for the JVM container + */ + private Injector injector; + /** + * The actual scanner + */ + private ClassGraph scanner; + /** + * The scan result built from everything - the core scanner. + */ + private ScanResult scanResult; + /** + * If the scan should run async + */ + private boolean async = true; + /** + * If this context is configured + */ + private static boolean configured; + + /** + * Creates a new Guice context. Not necessary + */ + private GuiceContext() + { + //No config required + } + + + /** + * Reference the Injector Directly + * + * @return The global Guice Injector Object, Never Null, Instantiates the Injector if not configured + */ + @NotNull + public synchronized Injector inject() + { + if (GuiceContext.buildingInjector) + { + log.log(Level.SEVERE, "The injector is being called recursively during build. Place such actions in a IGuicePostStartup or use the IGuicePreStartup Service Loader."); + System.exit(1); + } + if (GuiceContext.instance().injector == null) + { + try + { + GuiceContext.buildingInjector = true; + GuiceContext.log.info("Starting up Guice Context"); + GuiceContext + .instance() + .loadConfiguration(); + if (GuiceContext + .instance() + .getConfig() + .isPathScanning() || GuiceContext + .instance() + .getConfig() + .isClasspathScanning()) + { + GuiceContext + .instance() + .loadScanner(); + } + GuiceContext + .instance() + .loadPreStartups(); + + List cModules = new ArrayList<>(modules); + Set iGuiceModules = GuiceContext + .instance() + .loadIGuiceModules(); + cModules.addAll(iGuiceModules); + + //cModules.add(new GuiceInjectorModule()); + log.config("Modules - " + Arrays.toString(cModules.toArray())); + GuiceContext.instance().injector = Guice.createInjector(cModules); + GuiceContext.buildingInjector = false; + GuiceContext + .instance() + .loadPostStartups(); + + Runtime + .getRuntime() + .addShutdownHook(new Thread() + { + public void run() + { + IGuiceContext + .getContext() + .destroy(); + } + }); + + GuiceContext.log.config("Injection System Ready"); + } + catch (Throwable e) + { + GuiceContext.log.log(Level.SEVERE, "Exception creating Injector : " + e.getMessage(), e); + throw new RuntimeException("Unable to boot Guice Injector", e); + } + } + GuiceContext.buildingInjector = false; + return GuiceContext.instance().injector; + } + + private static Set destroyers = GuiceContext + .instance() + .getLoader(IGuicePreDestroy.class, false, ServiceLoader.load(IGuicePreDestroy.class)); + + /** + * Execute on Destroy + */ + @SuppressWarnings("unused") + public void destroy() + { + try + { + for (IGuicePreDestroy destroyer : destroyers) + { + try + { + destroyer.onDestroy(); + } + catch (Throwable T) + { + log.log(Level.SEVERE, + "Could not run destroyer [" + destroyer + .getClass() + .getCanonicalName() + "]"); + } + } + } + catch (Throwable T) + { + log.log(Level.SEVERE, "Could not run destroyers", T); + } + if (GuiceContext.instance().scanResult != null) + { + GuiceContext.instance().scanResult.close(); + } + if (GuiceContext.instance().scanResult != null) + { + GuiceContext.instance().scanResult.close(); + } + GuiceContext.instance().scanResult = null; + GuiceContext.instance().scanner = null; + GuiceContext.instance().injector = null; + } + + /** + * Returns the Java version as an int value. + * + * @return the Java version as an int value (8, 9, etc.) + * @since 12130 + */ + private static int getJavaVersion() + { + String version = getSystemPropertyOrEnvironment("java.version", "11"); + if (version.startsWith("1.")) + { + version = version.substring(2); + } + // Allow these formats: + // 1.8.0_72-ea + // 9-ea + // 9 + // 9.0.1 + int dotPos = version.indexOf('.'); + int dashPos = version.indexOf('-'); + String value = version.substring(0, dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : version.length()); + return Integer.parseInt(value); + } + + /** + * Returns the current scan result + * + * @return The physical Scan Result from the complete class scanner + */ + @NotNull + public ScanResult getScanResult() + { + if (scanResult == null) + { + loadScanner(); + } + return scanResult; + } + + /** + * Sets the current scan result + * + * @param scanResult The physical Scan Result from the complete class scanner + */ + @SuppressWarnings("unused") + public void setScanResult(ScanResult scanResult) + { + GuiceContext.instance().scanResult = scanResult; + } + + /** + * Returns the actual context instance, provides access to methods existing a bit deeper + * + * @return The singleton instance of this + */ + public static GuiceContext instance() + { + return GuiceContext.instance; + } + + /** + * Loads the IGuiceConfigurator + */ + private void loadConfiguration() + { + if (!configured) + { + Set guiceConfigurators = loadIGuiceConfigs(); + for (IGuiceConfigurator guiceConfigurator : guiceConfigurators) + { + GuiceContext.log.config("Loading IGuiceConfigurator - " + guiceConfigurator + .getClass() + .getCanonicalName()); + guiceConfigurator.configure(GuiceContext.config); + } + if (!GuiceContext.config.isIncludeModuleAndJars()) + { + log.warning("Scanning is not restricted to modules and may incur a performance impact. Consider registering your module with GuiceContext.registerModule() to auto enable, or SPI IGuiceConfiguration"); + } + GuiceContext.log.config("IGuiceConfigurator : " + GuiceContext.config.toString()); + configured = true; + } + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + @SuppressWarnings("unchecked") + private String[] getJarsExclusionList() + { + Set strings = new TreeSet<>(); + Set exclusions = loadJarRejectScanners(); + if (exclusions + .iterator() + .hasNext()) + { + for (IGuiceScanJarExclusions exclusion : exclusions) + { + Set searches = exclusion.excludeJars(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IGuiceScanJarExclusions - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + @SuppressWarnings("unchecked") + private String[] getJarsInclusionList() + { + Set strings = new TreeSet<>(); + Set exclusions = loadJarInclusionScanners(); + if (exclusions + .iterator() + .hasNext()) + { + for (IGuiceScanJarInclusions exclusion : exclusions) + { + Set searches = exclusion.includeJars(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IGuiceScanJarExclusions - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + + /** + * Starts up Guice and the scanner + */ + private synchronized void loadScanner() + { + if (scanner == null) + { + scanner = new ClassGraph(); + Stopwatch stopwatch = Stopwatch.createStarted(); + GuiceContext.log.info("Loading Classpath Scanner"); + loadConfiguration(); + scanner = configureScanner(scanner); + try + { + if (async) + { + scanResult = scanner.scan(Runtime + .getRuntime() + .availableProcessors()); + } + else + { + scanResult = scanner.scan(); + } + stopwatch.stop(); + Map fileScans = quickScanFiles(); + fileScans.forEach((key, value) -> scanResult + .getResourcesWithLeafName(key) + .forEachByteArrayIgnoringIOException(value)); + quickScanFilesPattern().forEach((key, value) -> scanResult + .getResourcesMatchingPattern(key) + .forEachByteArrayIgnoringIOException(value)); + + } + catch (Exception mpe) + { + GuiceContext.log.log(Level.SEVERE, "Unable to run scanner", mpe); + } + GuiceContext.log.fine("Loaded Classpath Scanner - Took [" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "] millis."); + } + } + + /** + * Configures the scanner from its setup + * + * @param graph The ClassGraph to apply the configuration to + */ + private ClassGraph configureScanner(ClassGraph graph) + { + if (config.isAllowPaths()) + { + String[] paths = getPathsList(); + if (paths.length != 0) + { + graph = graph.acceptPaths(paths); + } + } + if (GuiceContext.config.isExcludePaths()) + { + String[] blacklistList = getPathsBlacklistList(); + if (blacklistList.length != 0) + { + graph = graph.rejectPaths(blacklistList); + } + } + + if (GuiceContext.config.isExcludeModulesAndJars()) + { + if (getJavaVersion() < 9) + { + String[] jarRejections = getJarsExclusionList(); + if (jarRejections.length != 0) + { + graph = graph.rejectJars(jarRejections); + } + } + else + { + String[] modulesRejection = getModulesExclusionList(); + if (modulesRejection.length != 0) + { + graph = graph.rejectModules(modulesRejection); + } + else + { + graph = graph.ignoreParentModuleLayers(); + } + } + } + + if (GuiceContext.config.isIncludeModuleAndJars()) + { + if (getJavaVersion() < 9) + { + String[] jarRejections = getJarsInclusionList(); + log.config("Accepted Jars for Scanning : " + Arrays.toString(jarRejections)); + if (jarRejections.length != 0) + { + graph = graph.acceptJars(jarRejections); + } + } + else + { + String[] modulesRejection = getModulesInclusionsList(); + log.config("Accepted Modules for Scanning : " + Arrays.toString(modulesRejection)); + if (modulesRejection.length != 0) + { + graph = graph.acceptModules(modulesRejection); + } + else + { + graph = graph.ignoreParentModuleLayers(); + } + } + } + + if (GuiceContext.config.isIncludePackages()) + { + String[] packages = getPackagesList(); + if (packages.length != 0) + { + graph = graph.acceptPackages(packages); + } + } + if (GuiceContext.config.isRejectPackages()) + { + String[] packages = getBlacklistPackages(); + if (packages.length != 0) + { + graph = graph.rejectPackages(packages); + } + } + if (GuiceContext.config.isExcludeParentModules()) + { + graph = graph.ignoreParentModuleLayers(); + } + if (GuiceContext.config.isFieldInfo()) + { + graph = graph.enableClassInfo(); + graph = graph.enableFieldInfo(); + } + if (GuiceContext.config.isAnnotationScanning()) + { + graph = graph.enableClassInfo(); + graph = graph.enableAnnotationInfo(); + } + if (GuiceContext.config.isMethodInfo()) + { + graph = graph.enableClassInfo(); + graph = graph.enableMethodInfo(); + } + if (GuiceContext.config.isIgnoreFieldVisibility()) + { + graph = graph.enableClassInfo(); + graph = graph.ignoreFieldVisibility(); + } + if (GuiceContext.config.isIgnoreMethodVisibility()) + { + graph = graph.enableClassInfo(); + graph = graph.ignoreMethodVisibility(); + } + if (GuiceContext.config.isClasspathScanning()) + { + graph = graph.enableClassInfo(); + } + if (GuiceContext.config.isVerbose()) + { + graph = graph.verbose(); + } + if (GuiceContext.config.isIgnoreClassVisibility()) + { + graph = graph.ignoreClassVisibility(); + } + return graph; + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + private String[] getPackagesList() + { + Set strings = new LinkedHashSet<>(); + Set exclusions = getLoader(IPackageContentsScanner.class, true, ServiceLoader.load(IPackageContentsScanner.class)); + if (exclusions + .iterator() + .hasNext()) + { + for (IPackageContentsScanner exclusion : exclusions) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IPackageContentsScanner - " + exclusion + .getClass() + .getCanonicalName()); + Set searches = exclusion.searchFor(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IPackageScanningContentsScanner - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + private String[] getBlacklistPackages() + { + Set strings = new LinkedHashSet<>(); + Set exclusions = getLoader(IPackageRejectListScanner.class, true, ServiceLoader.load(IPackageRejectListScanner.class)); + if (exclusions + .iterator() + .hasNext()) + { + for (IPackageRejectListScanner exclusion : exclusions) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IPackageContentsScanner - " + exclusion + .getClass() + .getCanonicalName()); + Set searches = exclusion.exclude(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IPackageScanningContentsScanner - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /* + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + private String[] getPathsList() + { + Set strings = new TreeSet<>(); + Set exclusions = getLoader(IPathContentsScanner.class, true, ServiceLoader.load(IPathContentsScanner.class)); + if (exclusions + .iterator() + .hasNext()) + { + for (IPathContentsScanner exclusion : exclusions) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IPathScanningContentsScanner - " + exclusion + .getClass() + .getCanonicalName()); + Set searches = exclusion.searchFor(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IPathScanningContentsScanner - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + private String[] getPathsBlacklistList() + { + Set strings = new TreeSet<>(); + Set exclusions = loadPathRejectScanners(); + if (exclusions + .iterator() + .hasNext()) + { + for (IPathContentsRejectListScanner exclusion : exclusions) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IPathContentsRejectListScanner - " + exclusion + .getClass() + .getCanonicalName()); + Set searches = exclusion.searchFor(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IPathContentsRejectListScanner - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + @SuppressWarnings("unchecked") + private String[] getModulesExclusionList() + { + Set strings = new TreeSet<>(); + Set exclusions = getLoader(IGuiceScanModuleExclusions.class, true, ServiceLoader.load(IGuiceScanModuleExclusions.class)); + if (exclusions + .iterator() + .hasNext()) + { + for (IGuiceScanModuleExclusions exclusion : exclusions) + { + Set searches = exclusion.excludeModules(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IGuiceScanModuleExclusions - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Returns a complete list of generic exclusions + * + * @return A string list of packages to be scanned + */ + @SuppressWarnings("unchecked") + private String[] getModulesInclusionsList() + { + Set strings = new TreeSet<>(); + strings.addAll(registerModuleForScanning); + Set exclusions = getLoader(IGuiceScanModuleInclusions.class, true, ServiceLoader.load(IGuiceScanModuleInclusions.class)); + if (exclusions + .iterator() + .hasNext()) + { + for (IGuiceScanModuleInclusions exclusion : exclusions) + { + Set searches = exclusion.includeModules(); + strings.addAll(searches); + } + GuiceContext.log.log(Level.FINE, "IGuiceScanModuleInclusions - " + strings.toString()); + } + return strings.toArray(new String[0]); + } + + /** + * Registers the quick scan files + */ + private Map quickScanFiles() + { + Map fileScans = new HashMap<>(); + Set fileScanners = getLoader(IFileContentsScanner.class, true, ServiceLoader.load(IFileContentsScanner.class)); + for (IFileContentsScanner fileScanner : fileScanners) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IFileContentsScanner - " + fileScanner + .getClass() + .getCanonicalName()); + fileScans.putAll(fileScanner.onMatch()); + } + return fileScans; + } + + /** + * Registers the quick scan files + */ + private Map quickScanFilesPattern() + { + Map fileScans = new HashMap<>(); + Set fileScanners = getLoader(IFileContentsPatternScanner.class, true, ServiceLoader.load(IFileContentsPatternScanner.class)); + for (IFileContentsPatternScanner fileScanner : fileScanners) + { + GuiceContext.log.log(Level.CONFIG, + "Loading IFileContentsPatternScanner - " + fileScanner + .getClass() + .getCanonicalName()); + fileScans.putAll(fileScanner.onMatch()); + } + return fileScans; + } + + /** + * A set + * + * @param loaderType The service type + * @param The type + * @param dontInject Don't inject + * @return A set of them + */ + @SuppressWarnings("unchecked") + @NotNull + public Set getLoader(Class loaderType, @SuppressWarnings("unused") boolean dontInject, ServiceLoader serviceLoader) + { + if (!IGuiceContext + .getAllLoadedServices() + .containsKey(loaderType)) + { + Set loader = IGuiceContext.loaderToSetNoInjection(serviceLoader); + IGuiceContext + .getAllLoadedServices() + .put(loaderType, loader); + } + return IGuiceContext + .getAllLoadedServices() + .get(loaderType); + } + + @Override + public boolean isBuildingInjector() + { + return buildingInjector; + } + + /** + * Returns the current classpath scanner + * + * @return Default processors count + */ + @SuppressWarnings("unused") + public ClassGraph getScanner() + { + return scanner; + } + + /** + * Sets the classpath scanner + * + * @param scanner Sets the scanner to a specific instance + */ + @SuppressWarnings("unused") + public static void setScanner(ClassGraph scanner) + { + GuiceContext.instance().scanner = scanner; + } + + /** + * Method loadPostStartups ... + */ + private void loadPostStartups() + { + Set startupSet = loadPostStartupServices(); + + Map>> postStartupGroups = new TreeMap<>(); + for (IGuicePostStartup postStartup : startupSet) + { + Integer sortOrder = postStartup.sortOrder(); + postStartupGroups + .computeIfAbsent(sortOrder, k -> new TreeSet<>()) + .add(postStartup); + } + + for (Map.Entry>> entry : postStartupGroups.entrySet()) + { + Integer key = entry.getKey(); + Set> value = entry.getValue(); + if (value.size() == 1) + { + //run in order + for (IGuicePostStartup iGuicePostStartup : value) + { + try + { + iGuicePostStartup.postLoad(); + } + catch (Throwable T) + { + log.log(Level.SEVERE, + "Cannot execute post startup - " + iGuicePostStartup + .getClass() + .getCanonicalName(), + T); + } + } + } + else + { + log.info("Starting Post Startup Group [" + key + "] in Parallel"); + List> futures = new ArrayList<>(); + for (IGuicePostStartup iGuicePostStartup : value) + { + futures.add(CompletableFuture.runAsync(iGuicePostStartup::postLoad)); + } + try + { + CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{})).join(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "Exception in completing post startups", e); + } + } + GuiceContext.log.fine("Completed with Post Startups Key [" + key + "]"); + } + } + + /** + * Returns the Guice Config Instance + * + * @return The singleton Guice Config instance. Also available with @Inject + */ + public GuiceConfig getConfig() + { + return GuiceContext.config; + } + + /** + * Loads the service lists of post startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadPostStartupServices() + { + return getLoader(IGuicePostStartup.class, ServiceLoader.load(IGuicePostStartup.class)); + } + + /** + * Loads the service lists of post startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadPathRejectScanners() + { + return getLoader(IPathContentsRejectListScanner.class, true, ServiceLoader.load(IPathContentsRejectListScanner.class)); + } + + + /** + * Loads the service lists of post startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadJarRejectScanners() + { + return getLoader(IGuiceScanJarExclusions.class, true, ServiceLoader.load(IGuiceScanJarExclusions.class)); + } + + + /** + * Loads the service lists of post startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadJarInclusionScanners() + { + return getLoader(IGuiceScanJarInclusions.class, true, ServiceLoader.load(IGuiceScanJarInclusions.class)); + } + + + /** + * Returns the set of service lists of pre startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadPreStartupServices() + { + return getLoader(IGuicePreStartup.class, true, ServiceLoader.load(IGuicePreStartup.class)); + } + + /** + * Loads the service lists of post startup's for manual additions + * + * @return The list of guice post startups + */ + public @NotNull Set loadIGuiceModules() + { + return getLoader(IGuiceModule.class, true, ServiceLoader.load(IGuiceModule.class)); + } + + /** + * Loads the service lists of guice configurators (before pre-startup) for manual additions + * + * @return The list of guice configs + */ + public @NotNull Set loadIGuiceConfigs() + { + return getLoader(IGuiceConfigurator.class, true, ServiceLoader.load(IGuiceConfigurator.class)); + } + + /** + * Method loadPreStartups gets the pre startups and loads them up + */ + private void loadPreStartups() + { + Set preStartups = loadPreStartupServices(); + List startups = new ArrayList<>(preStartups); + startups.sort(Comparator.comparing(IGuicePreStartup::sortOrder)); + for (IGuicePreStartup startup : startups) + { + GuiceContext.log.config("Loading IGuicePreStartup - " + startup + .getClass() + .getCanonicalName()); + startup.onStartup(); + } + } + + /** + * Returns the loader for anything that is located locally in guice context + * replacing with set load methods instead for each type + * + * @param loaderType The service type + * @param The type + * @return A set of them + */ + @SuppressWarnings("unchecked") + @NotNull + public > Set getLoader(Class loaderType, ServiceLoader serviceLoader) + { + if (!IGuiceContext + .getAllLoadedServices() + .containsKey(loaderType)) + { + Set loader; + if (GuiceContext.buildingInjector || injector == null) + { + loader = IGuiceContext.loaderToSetNoInjection(serviceLoader); + } + else + { + loader = IGuiceContext.loaderToSet(serviceLoader); + } + IGuiceContext + .getAllLoadedServices() + .put(loaderType, loader); + } + return IGuiceContext + .getAllLoadedServices() + .get(loaderType); + } + + /** + * If this scanner is registered to run asynchronously + * + * @return + */ + public boolean isAsync() + { + return async; + } + + /** + * Sets if the scanner must run asynchronously + * + * @param async + */ + public void setAsync(boolean async) + { + this.async = async; + } }