blob: e0070c3e104e05c97564e811b4bcdb1e6ca7811f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.extension.scripting.weld.startup;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyFactory.ClassLoaderProvider;
import org.jboss.weld.bootstrap.api.Bootstrap;
import org.jboss.weld.bootstrap.api.Environments;
import org.jboss.weld.environment.Container;
import org.jboss.weld.environment.ContainerContext;
import org.jboss.weld.environment.gwtdev.GwtDevHostedModeContainer;
import org.jboss.weld.environment.jetty.Jetty6Container;
import org.jboss.weld.environment.jetty.Jetty7Container;
import org.jboss.weld.environment.jetty.JettyPost72Container;
import org.jboss.weld.environment.servlet.deployment.ServletDeployment;
import org.jboss.weld.environment.servlet.deployment.URLScanner;
import org.jboss.weld.environment.servlet.deployment.VFSURLScanner;
import org.jboss.weld.environment.servlet.services.ServletResourceInjectionServices;
import org.jboss.weld.environment.servlet.util.Reflections;
import org.jboss.weld.environment.servlet.util.ServiceLoader;
import org.jboss.weld.environment.tomcat.Tomcat6Container;
import org.jboss.weld.environment.tomcat7.Tomcat7Container;
import org.jboss.weld.injection.spi.ResourceInjectionServices;
import org.jboss.weld.manager.api.WeldManager;
import org.jboss.weld.servlet.api.ServletListener;
import org.jboss.weld.servlet.api.helpers.ForwardingServletListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.el.ELContextListener;
import javax.enterprise.inject.spi.BeanManager;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
import java.util.Arrays;
/**
* @author Pete Muir
* @author Ales Justin
*/
public class Listener extends ForwardingServletListener {
private static final Logger log = LoggerFactory.getLogger(Listener.class);
private static final String BOOTSTRAP_IMPL_CLASS_NAME = "org.jboss.weld.bootstrap.WeldBootstrap";
private static final String WELD_LISTENER_CLASS_NAME = "org.jboss.weld.servlet.WeldListener";
private static final String EXPRESSION_FACTORY_NAME = "org.jboss.weld.el.ExpressionFactory";
public static final String BEAN_MANAGER_ATTRIBUTE_NAME = Listener.class.getPackage().getName() + "." +
BeanManager.class.getName();
private final transient Bootstrap bootstrap;
private final transient ServletListener weldListener;
private Container container;
public Listener() {
try {
bootstrap = Reflections.newInstance(BOOTSTRAP_IMPL_CLASS_NAME);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Error loading Weld bootstrap, check that Weld is on the classpath", e);
}
try {
weldListener = Reflections.newInstance(WELD_LISTENER_CLASS_NAME);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Error loading Weld listener, check that Weld is on the classpath", e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
bootstrap.shutdown();
if (container != null)
container.destroy(new ContainerContext(sce, null));
super.contextDestroyed(sce);
}
/**
* Create server deployment.
* <p>&nbsp;</p>
* Can be overridden with custom servlet deployment.
* e.g. exact resources listing in ristricted wnv like GAE
*
* @param context the servlet context
* @param bootstrap the bootstrap
* @return new servlet deployment
*/
protected ServletDeployment createServletDeployment(ServletContext context, Bootstrap bootstrap) {
return new ServletDeployment(context, bootstrap);
}
/**
* Get appropriate scanner.
* Return null to leave it to defaults.
*
* @param classLoader the classloader
* @param context the servlet context
* @return custom url scanner or null if we should use default
*/
protected URLScanner createUrlScanner(ClassLoader classLoader, ServletContext context) {
try {
classLoader.loadClass("org.jboss.virtual.VFS"); // check if we can use JBoss VFS
return new VFSURLScanner(classLoader);
} catch (Throwable t) {
return null;
}
}
@Override
public void contextInitialized(ServletContextEvent sce) {
// Make Javassist always use the TCCL to load classes
ProxyFactory.classLoaderProvider = new ClassLoaderProvider() {
public ClassLoader get(ProxyFactory pf) {
return Thread.currentThread().getContextClassLoader();
}
};
ClassLoader classLoader = Reflections.getClassLoader();
ServletContext context = sce.getServletContext();
URLScanner scanner = createUrlScanner(classLoader, context);
if (scanner != null) {
context.setAttribute(URLScanner.class.getName(), scanner);
}
ServletDeployment deployment = createServletDeployment(context, bootstrap);
try {
deployment.getWebAppBeanDeploymentArchive().getServices().add(
ResourceInjectionServices.class, new ServletResourceInjectionServices() {
});
} catch (NoClassDefFoundError e) {
// Support GAE
log.warn("@Resource injection not available in simple beans");
}
bootstrap.startContainer(Environments.SERVLET, deployment).startInitialization();
WeldManager manager = bootstrap.getManager(deployment.getWebAppBeanDeploymentArchive());
ContainerContext cc = new ContainerContext(sce, manager);
StringBuilder dump = new StringBuilder();
Container container = findContainer(cc, dump);
if (container == null) {
log.info("No supported servlet container detected, CDI injection will NOT be available" +
" in Servlets, Filters or Listeners");
if (log.isDebugEnabled())
log.debug("Exception dump from Container lookup: " + dump);
} else {
container.initialize(cc);
this.container = container;
}
// Push the manager into the servlet context so we can access in JSF
context.setAttribute(BEAN_MANAGER_ATTRIBUTE_NAME, manager);
if (JspFactory.getDefaultFactory() != null) {
JspApplicationContext jspApplicationContext = JspFactory.getDefaultFactory().
getJspApplicationContext(context);
// Register the ELResolver with JSP
jspApplicationContext.addELResolver(manager.getELResolver());
// Register ELContextListener with JSP
jspApplicationContext.addELContextListener(
Reflections.<ELContextListener>newInstance("org.jboss.weld.el.WeldELContextListener"));
// Push the wrapped expression factory into the servlet context so that Tomcat or Jetty can hook it in using a container code
context.setAttribute(EXPRESSION_FACTORY_NAME, manager.wrapExpressionFactory(
jspApplicationContext.getExpressionFactory()));
}
bootstrap.deployBeans().validateBeans().endInitialization();
super.contextInitialized(sce);
}
@Override
protected ServletListener delegate() {
return weldListener;
}
/**
* Find container env.
*
* @param cc the container context
* @param dump the exception dump
* @return valid container or null
*/
protected Container findContainer(ContainerContext cc, StringBuilder dump) {
Iterable<Container> extContainers = ServiceLoader.load(Container.class, getClass().getClassLoader());
Container container = checkContainers(cc, dump, extContainers);
if (container == null)
container = checkContainers(cc, dump, Arrays.asList(
// Needs to be first: gwt-dev jar has tomcat classes but uses jetty
GwtDevHostedModeContainer.INSTANCE,
Tomcat7Container.INSTANCE,
Tomcat6Container.INSTANCE,
Jetty6Container.INSTANCE,
JettyPost72Container.INSTANCE,
Jetty7Container.INSTANCE)
);
return container;
}
protected Container checkContainers(ContainerContext cc, StringBuilder dump, Iterable<Container> containers) {
for (Container c : containers) {
try {
if (c.touch(cc))
return c;
} catch (Throwable t) {
dump.append(c).append("->").append(t.getMessage()).append("\n");
}
}
return null;
}
}