All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jwebmp.guicedinjection.GuiceContext Maven / Gradle / Ivy

Go to download

Guice Injection allows you to access multiple Guice Binders and Modules across separate archives. Allowing you to configure your applications with injection from multiple dependancies. Servlets, EJB's, and Stand-Alone is supported. Requires JDK 8 or 10.

There is a newer version: 0.66.0.1
Show newest version
/*
 * Copyright (C) 2017 Marc Magon
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package com.jwebmp.guicedinjection;

import com.google.common.base.Stopwatch;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.jwebmp.guicedinjection.interfaces.*;
import com.jwebmp.guicedinjection.threading.PostStartupRunnable;
import com.jwebmp.logger.LogFactory;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ResourceList;
import io.github.classgraph.ScanResult;

import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Provides an interface for reflection and injection in one.
 * 

* Use reflect() to access the class library, or inject() to get the injector for any instance * * @author GedMarc * @version 1.0 * @since Nov 14, 2016 */ @SuppressWarnings("MissingClassJavaDoc") public class GuiceContext implements Serializable { /** * Field log */ private static final Logger log = LogFactory.getLog("GuiceContext"); /** * Field serialVersionUID */ private static final long serialVersionUID = 1L; /** * This particular instance of the class */ private static final GuiceContext instance = new GuiceContext(); /** * The building injector */ private static boolean buildingInjector = false; /** * The number of threads */ private static int threadCount = Runtime.getRuntime() .availableProcessors(); /** * The time in units to wait */ private static long asyncTerminationWait = 60L; /** * The time in chrono to wait */ private static TimeUnit asyncTerminationTimeUnit = TimeUnit.SECONDS; /** * The configuration object */ private static GuiceConfig config; /** * The physical injector for the JVM container */ private transient Injector injector; /** * The actual scanner */ private transient ClassGraph scanner; /** * The scan result built from everything - the core scanner. */ private transient ScanResult scanResult; /** * Facade layer for backwards compatibility */ private transient Reflections reflections; /** * 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 @SuppressWarnings("unchecked") public static synchronized Injector inject() { if (GuiceContext.buildingInjector) { throw new RuntimeException( "The injector is being called recursively during build. Place such actions in a IGuicePostStartup or use the IGuicePreStartup Service Loader."); } if (GuiceContext.instance().injector == null) { try { GuiceContext.buildingInjector = true; GuiceContext.log.info("Starting up Guice Context"); GuiceContext.instance() .loadPreStartups(); GuiceContext.instance() .loadConfiguration(); if (GuiceContext.instance() .getConfig() .isWhiteList() || GuiceContext.instance() .getConfig() .isClasspathScanning()) { GuiceContext.instance() .loadScanner(); } List cModules = GuiceContext.instance() .loadDefaultBinders(); GuiceContext.instance().injector = Guice.createInjector(cModules); GuiceContext.buildingInjector = false; GuiceContext.instance() .loadPostStartups(); GuiceContext.log.config("Injection System Ready"); } catch (Throwable e) { GuiceContext.log.log(Level.SEVERE, "Exception creating Injector : " + e.getMessage(), e); } } GuiceContext.buildingInjector = false; return GuiceContext.instance().injector; } /** * Gets a new injected instance of a class * * @param * The type to retrieve * @param type * The physical class object * * @return The scoped object */ @NotNull public static T getInstance(@NotNull Class type) { return GuiceContext.inject() .getInstance(type); } /** * Gets a new injected instance of a class * * @param * The type to retrieve * @param type * The physical class object * * @return The scoped object */ @NotNull public static T get(@NotNull Class type) { return GuiceContext.inject() .getInstance(type); } /** * Gets a new injected instance of a class * * @param * The type to retrieve * @param type * The physical class object * @param annotation * The annotation to fetch * * @return The scoped object */ @NotNull public static T get(@NotNull Class type, Class annotation) { return GuiceContext.inject() .getInstance(Key.get(type, annotation)); } /** * Gets a new specified instance from a give key * * @param * The type to retrieve * @param type * The physical class object * * @return The scoped object */ @NotNull public static T getInstance(@NotNull Key type) { return GuiceContext.inject() .getInstance(type); } /** * Gets a new specified instance from a give key * * @param * The type to retrieve * @param type * The physical class object * * @return The scoped object */ @NotNull public static T get(@NotNull Key type) { return GuiceContext.inject() .getInstance(type); } /** * Returns the async termination wait period Default 60 * * @return The wait time for post startup operations to finish */ @SuppressWarnings("unused") public static long getAsyncTerminationWait() { return GuiceContext.asyncTerminationWait; } /** * Sets the termination asynchronous wait period (60) * * @param asyncTerminationWait * The wait time for post startup threads to finish */ @SuppressWarnings("unused") public static void setAsyncTerminationWait(long asyncTerminationWait) { GuiceContext.asyncTerminationWait = asyncTerminationWait; } /** * Gets the termination waiting period (Defualt sesonds) * * @return The wait time for post startup object wait time */ @SuppressWarnings("unused") public static TimeUnit getAsyncTerminationTimeUnit() { return GuiceContext.asyncTerminationTimeUnit; } /** * Sets the asynchronous termination waiting period * * @param asyncTerminationTimeUnit * The unit to apply for the waiting time */ @SuppressWarnings("unused") public static void setAsyncTerminationTimeUnit(TimeUnit asyncTerminationTimeUnit) { GuiceContext.asyncTerminationTimeUnit = asyncTerminationTimeUnit; } /** * Execute on Destroy */ @SuppressWarnings("unused") public static void destroy() { GuiceContext.instance().reflections = null; GuiceContext.instance().scanResult = null; GuiceContext.instance().scanner = null; GuiceContext.instance().injector = null; } /** * 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; } /** * Builds a reflection object if one does not exist * * @return A facade of the ReflectUtils on the scan result */ public static Reflections reflect() { if (GuiceContext.instance().reflections == null) { GuiceContext.instance().reflections = new Reflections(); } return GuiceContext.instance().reflections; } /** * Builds an asynchronous running pool to execute with a termination waiter * * @param st * A list of startup objects * @param runnables * A list of post startup threads */ private static void configureWorkStealingPool(List st, List runnables) { ExecutorService postLoaderExecutionService = Executors.newWorkStealingPool(GuiceContext.threadCount); for (IGuicePostStartup IGuicePostStartup : st) { runnables.add(new PostStartupRunnable(IGuicePostStartup)); } for (PostStartupRunnable a : runnables) { try { postLoaderExecutionService.submit((Runnable) a); } catch (Exception e) { GuiceContext.log.log(Level.SEVERE, "Unable to invoke Post Startups\n", e); } } postLoaderExecutionService.shutdownNow(); try { postLoaderExecutionService.awaitTermination(GuiceContext.asyncTerminationWait, GuiceContext.asyncTerminationTimeUnit); } catch (Exception e) { GuiceContext.log.log(Level.SEVERE, "Could not execute asynchronous post loads", e); } } /** * Method loadPreStartups gets the pre startups and loads them up */ private void loadPreStartups() { ServiceLoader preStartups = ServiceLoader.load(IGuicePreStartup.class); List startups = new ArrayList<>(); for (IGuicePreStartup preStartup : preStartups) { startups.add(preStartup); } startups.sort(Comparator.comparing(IGuicePreStartup::sortOrder)); for (IGuicePreStartup startup : startups) { GuiceContext.log.config("Loading IGuicePreStartup - " + startup.getClass() .getCanonicalName()); startup.onStartup(); } } /** * 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; } /** * Starts up Guice and the scanner */ private void loadScanner() { Stopwatch stopwatch = Stopwatch.createStarted(); GuiceContext.log.info("Loading Classpath Scanner - [" + GuiceContext.getThreadCount() + "] threads"); if (GuiceContext.config == null) { loadConfiguration(); } scanner = new ClassGraph(); if (GuiceContext.config.isWhiteList()) { String[] packages = getPackagesList(); if (packages.length != 0) { scanner.whitelistPackages(packages); } String[] paths = getPathsList(); if (paths.length != 0) { scanner.whitelistPaths(paths); } if (GuiceContext.config.isExcludeModulesAndJars()) { String[] blacklistList = getPathsBlacklistList(); if (blacklistList.length != 0) { scanner.blacklistPaths(blacklistList); scanner.blacklistPaths("META-INF/MANIFEST.MF"); } String[] jarBlacklist = getJarsBlacklistList(); if (jarBlacklist.length != 0) { scanner.blacklistJars(jarBlacklist); } String[] modulesBlacklist = getModulesBlacklistList(); if (modulesBlacklist.length != 0) { scanner.blacklistModules(modulesBlacklist); } } } if (GuiceContext.config.isFieldInfo()) { scanner.enableFieldInfo(); } if (GuiceContext.config.isAnnotationScanning()) { scanner.enableAnnotationInfo(); } if (GuiceContext.config.isMethodInfo()) { scanner.enableMethodInfo(); } if (GuiceContext.config.isIgnoreFieldVisibility()) { scanner.ignoreFieldVisibility(); } if (GuiceContext.config.isIgnoreMethodVisibility()) { scanner.ignoreMethodVisibility(); } if (GuiceContext.config.isVerbose()) { scanner.verbose(); } try { scanResult = scanner.scan(GuiceContext.getThreadCount()); Map fileScans = quickScanFiles(); fileScans.forEach((key, value) -> scanResult.getResourcesWithLeafName(key) .forEachByteArray(value)); } catch (Exception mpe) { GuiceContext.log.log(Level.SEVERE, "Unable to run scanner", mpe); } stopwatch.stop(); GuiceContext.log.fine("Loaded Classpath Scanner -Took [" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "] millis."); } /** * Gets the number of threads to use when processing * Default processors count * * @return Default processors count */ @SuppressWarnings("all") public static int getThreadCount() { return threadCount; } private void loadConfiguration() { ServiceLoader guiceConfigurators = ServiceLoader.load(IGuiceConfigurator.class); if (GuiceContext.config == null) { GuiceContext.config = new GuiceConfig<>(); } for (IGuiceConfigurator guiceConfigurator : guiceConfigurators) { GuiceContext.log.config("Loading IGuiceConfigurator - " + guiceConfigurator.getClass() .getCanonicalName()); guiceConfigurator.configure(GuiceContext.config); } GuiceContext.log.config("IGuiceConfigurator : " + GuiceContext.config.toString()); } /** * Returns a complete list of generic exclusions * * @return A string list of packages to be scanned */ private String[] getPackagesList() { Set strings = new LinkedHashSet<>(); ServiceLoader exclusions = 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[] getPathsList() { Set strings = new LinkedHashSet<>(); ServiceLoader exclusions = 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 LinkedHashSet<>(); ServiceLoader exclusions = ServiceLoader.load(IPathContentsBlacklistScanner.class); if (exclusions.iterator() .hasNext()) { for (IPathContentsBlacklistScanner exclusion : exclusions) { GuiceContext.log.log(Level.CONFIG, "Loading IPathContentsBlacklistScanner - " + exclusion.getClass() .getCanonicalName()); Set searches = exclusion.searchFor(); strings.addAll(searches); } GuiceContext.log.log(Level.FINE, "IPathContentsBlacklistScanner - " + 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[] getJarsBlacklistList() { Set strings = new LinkedHashSet<>(); ServiceLoader exclusions = ServiceLoader.load(IGuiceScanJarExclusions.class); 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 */ private String[] getModulesBlacklistList() { Set strings = new LinkedHashSet<>(); ServiceLoader exclusions = 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]); } /** * Registers the quick scan files */ @SuppressWarnings("unchecked") private Map quickScanFiles() { Map fileScans = new HashMap<>(); ServiceLoader fileScanners = ServiceLoader.load(IFileContentsScanner.class); for (IFileContentsScanner fileScanner : fileScanners) { GuiceContext.log.log(Level.CONFIG, "Loading IFileContentsScanner - " + fileScanner.getClass() .getCanonicalName()); fileScans.putAll(fileScanner.onMatch()); } return fileScans; } /** * Sets the thread count to use * * @param threadCount * The thread count to execute on */ @SuppressWarnings("unused") public static void setThreadCount(int threadCount) { GuiceContext.threadCount = threadCount; } /** * 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; } @SuppressWarnings("unchecked") private List loadDefaultBinders() { ServiceLoader preStartups = ServiceLoader.load(IGuiceModule.class); List startups = new ArrayList<>(); for (IGuiceModule preStartup : preStartups) { startups.add(preStartup); } startups.sort(Comparator.comparing(IGuiceModule::sortOrder)); List output = new ArrayList<>(); for (IGuiceModule startup : startups) { GuiceContext.log.config("Loading IGuiceModule - " + startup.getClass() .getCanonicalName()); output.add(startup); } return output; } /** * 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; } private void loadPostStartups() { ServiceLoader postStartups = ServiceLoader.load(IGuicePostStartup.class); Map> postStartupGroups = new TreeMap<>(); for (IGuicePostStartup postStartup : postStartups) { IGuicePostStartup injected = GuiceContext.getInstance(postStartup.getClass()); Integer sortOrder = injected.sortOrder(); postStartupGroups.computeIfAbsent(sortOrder, k -> new ArrayList<>()) .add(injected); } postStartupGroups.forEach((key, value) -> { value.sort(Comparator.comparing(IGuicePostStartup::sortOrder)); if (value.size() == 1) { GuiceContext.log.config("Loading IGuicePostStartup - " + value.get(0) .getClass() .getCanonicalName()); value.get(0) .postLoad(); } else { List runnables = new ArrayList<>(); GuiceContext.configureWorkStealingPool(value, runnables); } }); } /** * Returns the Guice Config Instance * * @return The singleton Guice Config instance. Also available with @Inject */ public GuiceConfig getConfig() { return GuiceContext.config; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy