/guiced-jsf/src/main/java/org/openlogics/guice/jsf/core/GuiceJSFConfigurer.java
Java | 513 lines | 283 code | 77 blank | 153 comment | 65 complexity | 1739f2181e04b983eea5873bbc33314d MD5 | raw file
- /**
- *
- */
- package org.openlogics.guice.jsf.core;
- import com.google.common.base.Strings;
- import com.google.inject.*;
- import com.google.inject.servlet.GuiceServletContextListener;
- import org.openlogics.guice.jsf.scope.JSFScopeBuilder;
- import org.openlogics.guice.jsf.scope.ScopeHandler;
- import org.openlogics.utils.reflect.Reflections;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import javax.faces.bean.*;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletContextEvent;
- import java.lang.annotation.Annotation;
- import java.net.JarURLConnection;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.Enumeration;
- import java.util.List;
- import java.util.Set;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
- /**
- * The Guice module context provider loads all the required modules for DI for
- * the entire application
- *
- * @author Miguel Vega
- */
- public class GuiceJSFConfigurer extends GuiceServletContextListener {
- /**
- * the context parameter for configuring the managed bean root package, all
- * the classes under this root pacakage will be scanned to match the managed
- * bean classes
- */
- public static final String GUICE_JSF_MB_ROOT_PACKAGE_CONTEXT_PARAMETER = "guice.jsf.MANAGED_BEAN_ROOT_PACKAGE";
- /**
- * the guice jsf modules that needs to be loaded, separated by ','
- */
- public static final String GUICE_JSF_MODULES_CONTEXT_PARAMETER = "guice.jsf.MODULES";
- /**
- * the guice jsf jars defines the name of jars that need to be scanned for
- * managed beans, separated by ','
- */
- public static final String GUICE_JSF_MB_JARS_CONTEXT_PARAMETER = "guice.jsf.MANAGED_BEAN_JAR_FILES";
- /**
- * the default WEB-INF classes folder
- */
- private static final String WEB_INF_CLASSES = "/WEB-INF/classes/";
- /**
- * the default WEB-INF lib folder
- */
- private static final String WEB_INF_LIB = "/WEB-INF/lib/";
- /*
- * the logger instance
- */
- private static Logger logger = LoggerFactory.getLogger(GuiceJSFConfigurer.class);
- /**
- * the instance of the servlet context
- */
- private ServletContext servletContext;
- /**
- * get the servlet context
- *
- * @return
- */
- final ServletContext getServletContext() {
- return this.servletContext;
- }
- /**
- * override the super class to get the servlet context reference
- */
- @Override
- public final void contextInitialized(ServletContextEvent servletContextEvent) {
- if (logger.isDebugEnabled()) {
- logger
- .debug("ServletContext initialized, set the servletContext referece.");
- }
- // store the servlet context reference as the local variable
- this.servletContext = servletContextEvent.getServletContext();
- // scan the managed bean
- this.scanManagedBeans();
- // invoke the base method to enable injector creation
- super.contextInitialized(servletContextEvent);
- }
- /*
- * @see com.google.inject.servlet.GuiceServletContextListener#getInjector()
- */
- @Override
- protected final Injector getInjector() {
- // load existing modules
- List<Module> modules = loadModules();
- final ManagedBeanConfig config = (ManagedBeanConfig) getServletContext()
- .getAttribute(ManagedBeanConfig.KEY);
- // create the scope builder
- final JSFScopeBuilder builder = new JSFScopeBuilder();
- // create the managed bean module
- Module managedBeanModule = new AbstractModule() {
- @Override
- protected void configure() {
- // create managed bean scope modules
- List<ManagedBeanMetadata> allBeans = config
- .getManagedBeanMetadata();
- // go through all the defined managed bean
- for (ManagedBeanMetadata each : allBeans) {
- // create the custom scope instance
- Scope customScope = builder.build(each.getBeanName(), each
- .getScope());
- // bind this bean class to the custom scope instance
- bind(each.getBeanClass()).in(customScope);
- if (logger.isDebugEnabled()) {
- logger.debug("Prepare Guice Injector->Bind JSF bean [name:'" + each.getBeanName() + "',scope:'" + each.getScope().getName() + "',class:'" + each.getBeanClass().getName() + "'] in Guice custom Scope '" + customScope.getClass().getName());
- }
- }
- }
- };
- // add the managed bean module
- modules.add(managedBeanModule);
- // create the injector
- Injector injector = Guice.createInjector(modules);
- //create the eager managed bean in application scope
- createEagerApplicationScopeManagedBean(config, injector);
- //return the injector
- return injector;
- }
- /**
- * create all the managed beans in application scope which
- * its eager attribute set to true
- *
- * @param config
- * @param injector
- */
- private void createEagerApplicationScopeManagedBean(
- final ManagedBeanConfig config, Injector injector) {
- List<ManagedBeanMetadata> applicationBeans = config
- .getManagedBeanMetadata(ApplicationScoped.class);
- for (ManagedBeanMetadata each : applicationBeans) {
- if (each.isEager() == true) {
- if (logger.isDebugEnabled()) {
- logger.debug("eagerly create the bean '" + each.getBeanName()
- + "' in application scope.");
- }
- //create the bean instance
- Object beanInstance = injector.getInstance(each.getBeanClass());
- //add it into the application scope
- getServletContext().setAttribute(each.getBeanName(),
- beanInstance);
- }
- }
- }
- /**
- * subclass can override this method to configure extra modules in code
- * rather than from the GUICE_JSF_MODULES_CONTEXT_PARAMETER context
- * parameter
- *
- * @return
- */
- protected List<Module> configureModules() {
- return new ArrayList<Module>();
- }
- /**
- * scan the managed beans
- */
- private void scanManagedBeans() {
- String contextScanPathValue = getServletContext().getInitParameter(
- GUICE_JSF_MB_ROOT_PACKAGE_CONTEXT_PARAMETER);
- String rootPackage = contextScanPathValue.replace(".", "/") + "/";
- // create the managed bean config to store all the managed beans
- ManagedBeanConfig config = new ManagedBeanConfig();
- // scan the web info classes to find managed beans
- scanClasses(getServletContext(), WEB_INF_CLASSES + rootPackage, config);
- // scan the web info libs to find managed beans
- scanJars(getServletContext(), rootPackage, config);
- // save the managed bean config into the servlet context
- getServletContext().setAttribute(ManagedBeanConfig.KEY, config);
- }
- /**
- * scan the web info jar
- *
- * @param servletContext
- * @param contextScanPackage
- */
- private void scanJars(ServletContext servletContext,
- String contextScanPackage, ManagedBeanConfig config) {
- List<JarFile> jars = findJars(servletContext, WEB_INF_LIB);
- if (!jars.isEmpty()) {
- for (JarFile jarFile : jars) {
- scanJarFile(jarFile, contextScanPackage, config);
- }
- }
- }
- /**
- * scan each jar file
- *
- * @param jarFile
- * @param beanPackage
- */
- private void scanJarFile(JarFile jarFile, String beanPackage,
- ManagedBeanConfig config) {
- Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- // go to the next jar entry
- JarEntry entry = entries.nextElement();
- // only check the jar matches the beanPackage value
- if (!entry.getName().startsWith(beanPackage)) {
- continue;
- }
- if (entry.getName().endsWith(".class")) {
- Class<?> clazz = extractClassFromPath(entry.getName());
- if (clazz != null) {
- loadManagedBean(config, clazz);
- }
- }
- }
- }
- /**
- * load a managed bean metadata and put it into the managed bean config
- *
- * @param config
- * @param clazz
- */
- private void loadManagedBean(ManagedBeanConfig config, Class<?> clazz) {
- if (logger.isDebugEnabled()) {
- logger.debug("loading managed bean from class " + clazz);
- }
- // get the @ManagedBean annotation from the bean class
- ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
- if (managedBean != null) {
- // get the scope annotation
- Class<? extends Annotation> scopeAnnotation = getScopeAnnotation(clazz);
- String beanName = managedBean.name();
- if (Strings.isNullOrEmpty(beanName) == true) {
- beanName = clazz.getSimpleName();
- beanName = formatBeanClass(beanName);
- }
- // add to the managed bean config
- config.addManagedBean(beanName, clazz, scopeAnnotation, managedBean
- .eager());
- }
- }
- /**
- * get the scope annotation class
- *
- * @param clazz
- * @return
- */
- private Class<? extends Annotation> getScopeAnnotation(Class<?> clazz) {
- Class<? extends Annotation> scope = null;
- if (clazz.getAnnotation(RequestScoped.class) != null) {
- scope = RequestScoped.class;
- } else if (clazz.getAnnotation(SessionScoped.class) != null) {
- scope = SessionScoped.class;
- } else if (clazz.getAnnotation(ApplicationScoped.class) != null) {
- scope = ApplicationScoped.class;
- } else if (clazz.getAnnotation(ViewScoped.class) != null) {
- scope = ViewScoped.class;
- } else {
- // find the annotation which has a meta annotation ScopeResolver
- scope = Reflections.findAnnotation(clazz, ScopeHandler.class);
- }
- // if non scope is provided, the scope should be request
- if (scope == null) {
- scope = RequestScoped.class;
- }
- return scope;
- }
- /**
- * format the bean name from the class name, make the first letter as lower
- * case
- *
- * @param beanName
- * @return
- */
- private String formatBeanClass(String beanName) {
- String firstChar = String.valueOf(beanName.charAt(0)).toLowerCase();
- return firstChar + beanName.substring(1);
- }
- /**
- * find a proper jar file
- *
- * @param servletContext
- * @param rootPath
- * @return
- */
- private List<JarFile> findJars(ServletContext servletContext,
- String rootPath) {
- // get the jars provided by the init parameter
- String jarsInitParameter = servletContext
- .getInitParameter(GUICE_JSF_MB_JARS_CONTEXT_PARAMETER);
- String[] jarNames = new String[]{};
- if (jarsInitParameter != null) {
- jarNames = jarsInitParameter.split(",");
- }
- Set<String> paths = servletContext.getResourcePaths(rootPath);
- List<JarFile> jars = new ArrayList<JarFile>();
- if (paths != null && !paths.isEmpty()) {
- for (String path : paths) {
- if (path.endsWith(".jar")) {
- boolean included = jarNames.length > 0 ? false : true;
- // search for the name match
- for (String jarName : jarNames) {
- if (path.toLowerCase().endsWith(jarName.toLowerCase())) {
- included = true;
- break;
- }
- }
- if (included) {
- if (logger.isDebugEnabled()) {
- logger.debug("Scan library '" + path
- + "' for managed beans");
- }
- try {
- String jarUrlPath = "jar:"
- + servletContext.getResource(path) + "!/";
- URL url = new URL(jarUrlPath);
- JarFile jarFile = ((JarURLConnection) url
- .openConnection()).getJarFile();
- jars.add(jarFile);
- } catch (Exception e) {
- }
- }
- }
- }
- }
- return jars;
- }
- /**
- * scan the web inf classes directory
- *
- * @param servletContext
- * @param rootPath
- */
- private void scanClasses(ServletContext servletContext, String rootPath,
- ManagedBeanConfig config) {
- Set<String> paths = servletContext.getResourcePaths(rootPath);
- for (String path : paths) {
- if (path.endsWith("/")) {
- scanClasses(servletContext, path, config);
- } else {
- if (path.endsWith(".class")) {
- Class<?> clazz = extractClassFromPath(path);
- if (clazz != null) {
- loadManagedBean(config, clazz);
- }
- }
- }
- }
- }
- /**
- * convert a package path to a class
- *
- * @param path
- * @return
- */
- private Class<?> extractClassFromPath(String path) {
- String classNamePath = null;
- if (path.indexOf(WEB_INF_CLASSES) != -1)
- classNamePath = path.substring(WEB_INF_CLASSES.length());
- else
- classNamePath = path;
- classNamePath = classNamePath
- .substring(0, (classNamePath.length() - 6));
- classNamePath = classNamePath.replaceAll("/", ".");
- try {
- return Class.forName(classNamePath);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
- /**
- * load the modules from the context parameter
- *
- * @return
- */
- private List<Module> loadModules() {
- // get the list of modules
- List<Module> modules = new ArrayList<Module>();
- // get the modules init parameter
- String modulesInitParameter = servletContext
- .getInitParameter(GUICE_JSF_MODULES_CONTEXT_PARAMETER);
- if (logger.isDebugEnabled()) {
- logger.debug("loading the guice modules from the "
- + GUICE_JSF_MODULES_CONTEXT_PARAMETER
- + " context parameter as '" + modulesInitParameter + "'");
- }
- if (modulesInitParameter != null) {
- String[] moduleNames = modulesInitParameter.split(",");
- for (String moduleName : moduleNames) {
- String trimmedModuleName = moduleName.trim();
- if (Strings.isNullOrEmpty(trimmedModuleName) == false) {
- if (logger.isDebugEnabled()) {
- logger.debug("parsing the guice modules for '"
- + trimmedModuleName + "'");
- }
- try {
- // get the module form the name
- Module module = (Module) Class.forName(
- trimmedModuleName).newInstance();
- // add the module
- modules.add(module);
- } catch (Exception e) {
- // error loading the modules
- if (logger.isDebugEnabled()) {
- logger.error("Skip module '" + trimmedModuleName
- + "', could not load it due to "
- + e.getMessage(), e);
- }
- throw new RuntimeException(e);
- }
- } else {
- if (logger.isDebugEnabled()) {
- logger.debug("skip the empty module entry.");
- }
- }
- }
- // load modules from the subclasses if possible
- modules.addAll(configureModules());
- // throw exception, no module has been provided
- if (modules.size() == 0) {
- throw new RuntimeException(
- "No guice module has been provided by context parameter '"
- + GUICE_JSF_MODULES_CONTEXT_PARAMETER
- + "', verify your settings in your application. If you want to disable Guice in JSF application, simply remove the GuiceServletContextListener in web.xml.");
- }
- } else {
- // throw exception, no module has been provided
- throw new RuntimeException(
- "No guice module has been provided by context parameter '"
- + GUICE_JSF_MODULES_CONTEXT_PARAMETER
- + "', verify your settings in your application. If you want to disable Guice in JSF application, simply remove the GuiceServletContextListener in web.xml.");
- }
- return modules;
- }
- }