/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.guice.servlet; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.Stage; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; import org.everrest.core.DependencySupplier; import org.everrest.core.Filter; import org.everrest.core.FilterDescriptor; import org.everrest.core.ResourceBinder; import org.everrest.core.impl.ApplicationProviderBinder; import org.everrest.core.impl.EverrestApplication; import org.everrest.core.impl.EverrestConfiguration; import org.everrest.core.impl.EverrestProcessor; import org.everrest.core.impl.FileCollectorDestroyer; import org.everrest.core.impl.FilterDescriptorImpl; import org.everrest.core.impl.RequestDispatcher; import org.everrest.core.impl.RequestHandlerImpl; import org.everrest.core.impl.ResourceBinderImpl; import org.everrest.core.impl.async.AsynchronousJobPool; import org.everrest.core.impl.async.AsynchronousJobService; import org.everrest.core.impl.async.AsynchronousProcessListWriter; import org.everrest.core.impl.method.filter.SecurityConstraint; import org.everrest.core.impl.provider.ProviderDescriptorImpl; import org.everrest.core.impl.resource.AbstractResourceDescriptor; import org.everrest.core.provider.ProviderDescriptor; import org.everrest.core.resource.ResourceDescriptor; import org.everrest.core.servlet.EverrestServletContextInitializer; import org.everrest.guice.BindingPath; import org.everrest.guice.EverrestConfigurationModule; import org.everrest.guice.EverrestModule; import org.everrest.guice.GuiceDependencySupplier; import org.everrest.guice.GuiceObjectFactory; import org.everrest.guice.GuiceRuntimeDelegateImpl; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.ws.rs.Path; import javax.ws.rs.core.Application; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.RuntimeDelegate; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @author andrew00x */ public abstract class EverrestGuiceContextListener extends GuiceServletContextListener { /** * Default EverrestGuiceContextListener implementation. It gets application's FQN from context-param * <i>javax.ws.rs.Application</i> and instantiate it. If such parameter is not specified then scan (if scanning is * enabled) web application's folders WEB-INF/classes and WEB-INF/lib for classes which contains JAX-RS annotations. * Interesting for three annotations {@link Path}, {@link Provider} and {@link Filter}. Scanning of JAX-RS * components * is managed by contex-param <i>org.everrest.scan.components</i>. This parameter must be <i>true</i> to enable * scanning. */ public static class DefaultListener extends EverrestGuiceContextListener { @Override protected List<Module> getModules() { return Collections.emptyList(); } } @Override public void contextInitialized(ServletContextEvent sce) { super.contextInitialized(sce); ServletContext servletContext = sce.getServletContext(); ResourceBinderImpl resources = new ResourceBinderImpl(); ApplicationProviderBinder providers = new ApplicationProviderBinder(); Injector injector = getInjector(servletContext); DependencySupplier dependencySupplier = new GuiceDependencySupplier(injector); EverrestConfiguration config = injector.getInstance(EverrestConfiguration.class); EverrestServletContextInitializer everrestInitializer = new EverrestServletContextInitializer(servletContext); Application application = everrestInitializer.getApplication(); EverrestApplication everrest = new EverrestApplication(); if (config.isAsynchronousSupported()) { everrest.addResource(config.getAsynchronousServicePath(), AsynchronousJobService.class); everrest.addSingleton(new AsynchronousJobPool(config)); everrest.addSingleton(new AsynchronousProcessListWriter()); } if (config.isCheckSecurity()) { everrest.addSingleton(new SecurityConstraint()); } everrest.addApplication(application); processBindings(injector, everrest); RequestDispatcher requestDispatcher = new RequestDispatcher(resources); RequestHandlerImpl requestHandler = new RequestHandlerImpl(requestDispatcher, providers); EverrestProcessor processor = new EverrestProcessor(config, dependencySupplier, requestHandler, everrest); processor.start(); servletContext.setAttribute(EverrestConfiguration.class.getName(), config); servletContext.setAttribute(Application.class.getName(), everrest); servletContext.setAttribute(DependencySupplier.class.getName(), dependencySupplier); servletContext.setAttribute(ResourceBinder.class.getName(), resources); servletContext.setAttribute(ApplicationProviderBinder.class.getName(), providers); servletContext.setAttribute(EverrestProcessor.class.getName(), processor); // use specific RuntimeDelegate instance which is able to work with guice rest service proxies. // (need for interceptors functionality) RuntimeDelegate.setInstance(new GuiceRuntimeDelegateImpl()); } @Override public void contextDestroyed(ServletContextEvent sce) { makeFileCollectorDestroyer().stopFileCollector(); ServletContext sctx = sce.getServletContext(); EverrestProcessor processor = (EverrestProcessor)sctx.getAttribute(EverrestProcessor.class.getName()); if (processor != null) { processor.stop(); } } protected FileCollectorDestroyer makeFileCollectorDestroyer() { return new FileCollectorDestroyer(); } @Override protected final Injector getInjector() { return Guice.createInjector(Stage.PRODUCTION, createModules()); } private List<Module> createModules() { List<Module> all = new ArrayList<>(); ServletModule servletModule = getServletModule(); if (servletModule != null) { all.add(servletModule); } all.add(new EverrestModule()); all.add(new EverrestConfigurationModule()); List<Module> modules = getModules(); if (modules != null && modules.size() > 0) { all.addAll(modules); } return all; } /** * Implementation can provide set of own {@link Module} for JAX-RS components. * <p/> * <pre> * protected List<Module> getModules() * { * List<Module> modules = new ArrayList<Module>(1); * modules.add(new Module() * { * public void configure(Binder binder) * { * binder.bind(MyResource.class); * binder.bind(MyProvider.class); * } * }); * return modules; * } * </pre> * * @return JAX-RS modules */ protected abstract List<Module> getModules(); /** * Create servlet module. By default return module with one component GuiceEverrestServlet. * * @return ServletModule */ protected ServletModule getServletModule() { return new ServletModule() { @Override protected void configureServlets() { serve("/*").with(GuiceEverrestServlet.class); } }; } protected Injector getInjector(ServletContext servletContext) { return (Injector)servletContext.getAttribute(Injector.class.getName()); } @SuppressWarnings({"unchecked"}) protected void processBindings(Injector injector, EverrestApplication everrest) { for (Binding<?> binding : injector.getBindings().values()) { Key<?> bindingKey = binding.getKey(); Type type = bindingKey.getTypeLiteral().getType(); if (type instanceof Class) { Class clazz = (Class)type; if (clazz.getAnnotation(Provider.class) != null) { ProviderDescriptor providerDescriptor = new ProviderDescriptorImpl(clazz); everrest.addFactory(new GuiceObjectFactory<>(providerDescriptor, binding.getProvider())); } else if (clazz.getAnnotation(Filter.class) != null) { FilterDescriptor filterDescriptor = new FilterDescriptorImpl(clazz); everrest.addFactory(new GuiceObjectFactory<>(filterDescriptor, binding.getProvider())); } else if (clazz.getAnnotation(Path.class) != null) { ResourceDescriptor resourceDescriptor; if (bindingKey.getAnnotation() != null && bindingKey.getAnnotationType().isAssignableFrom(BindingPath.class)) { String path = ((BindingPath)bindingKey.getAnnotation()).value(); resourceDescriptor = new AbstractResourceDescriptor(path, clazz); } else { resourceDescriptor = new AbstractResourceDescriptor(clazz); } everrest.addFactory(new GuiceObjectFactory<>(resourceDescriptor, binding.getProvider())); } } } } }