1. 按照以下代码改写你自己的Activator (或者将代码中的"/pages"改成你的jsf网页路径):
注意加粗的那段代码(使用当前的class loader来加载jsf的FacesServlet)
package net.andyluo.singlife.jsf.demo;
import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;
import javax.faces.webapp.FacesServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.eclipse.equinox.http.helper.BundleEntryHttpContext;
import org.eclipse.equinox.http.helper.ContextPathServletAdaptor;
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.util.tracker.ServiceTracker;
import com.sun.faces.config.ConfigureListener;
public class Activator implements BundleActivator
{
private ServiceTracker httpServiceTracker;
public void start(BundleContext context) throws Exception
{
httpServiceTracker = new HttpServiceTracker(context);
httpServiceTracker.open();
}
public void stop(BundleContext context) throws Exception
{
httpServiceTracker.close();
}
private class HttpServiceTracker extends ServiceTracker
{
private static final String PATH = "/jsf";
public HttpServiceTracker(BundleContext context)
{
super(context, HttpService.class.getName(), null);
}
public Object addingService(ServiceReference reference)
{
final HttpService httpService = (HttpService) context
.getService(reference);
try
{
HttpContext commonContext = new BundleEntryHttpContext(context
.getBundle(), "/pages");
httpService.registerResources(PATH, "/", commonContext);
JspServlet jspServlet = new JspServlet(context.getBundle(),
"/pages");
Servlet adaptedJspServlet = new ContextPathServletAdaptor(
jspServlet, PATH);
httpService.registerServlet(PATH + "/*.jsp", adaptedJspServlet,
null, commonContext);
Dictionary initparams = new Hashtable();
initparams.put("servlet-name", "Faces Servlet");
Servlet adaptedFacesServlet = new ServletContextListenerServletAdaptor(
new ConfigureListener(), new FacesServlet(), jspServlet
.getJspLoader());
adaptedFacesServlet = new ContextPathServletAdaptor(
adaptedFacesServlet, PATH);
httpService.registerServlet(PATH + "/*.jsf",
adaptedFacesServlet, initparams, commonContext);
} catch (Exception e)
{
e.printStackTrace();
}
return httpService;
}
public void removedService(ServiceReference reference, Object service)
{
final HttpService httpService = (HttpService) service;
httpService.unregister(PATH); //$NON-NLS-1$
httpService.unregister(PATH + "/*.jsp"); //$NON-NLS-1$
httpService.unregister(PATH + "/*.jsf"); //$NON-NLS-1$
super.removedService(reference, service);
}
}
public class ServletContextListenerServletAdaptor implements Servlet
{
private ServletConfig config;
private ServletContextListener listener;
private Servlet delegate;
private ClassLoader jspLoader;
public ServletContextListenerServletAdaptor(
ServletContextListener listener, Servlet delegate,
ClassLoader jspLoader)
{
this.listener = listener;
this.delegate = delegate;
this.jspLoader = jspLoader;
}
public void init(ServletConfig config) throws ServletException
{
this.config = config;
ClassLoader original = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(jspLoader);
listener.contextInitialized(new ServletContextEvent(config
.getServletContext()));
delegate.init(config);
} finally
{
Thread.currentThread().setContextClassLoader(original);
}
}
public void service(ServletRequest req, ServletResponse resp)
throws ServletException, IOException
{
ClassLoader original = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(jspLoader);
delegate.service(req, resp);
} finally
{
Thread.currentThread().setContextClassLoader(original);
}
}
public void destroy()
{
ClassLoader original = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(jspLoader);
delegate.destroy();
listener.contextDestroyed(new ServletContextEvent(config
.getServletContext()));
config = null;
} finally
{
Thread.currentThread().setContextClassLoader(original);
}
}
public ServletConfig getServletConfig()
{
return config;
}
public String getServletInfo()
{
return "";
}
}
}
2. 因为JspServlet中没有返回class loader的方法,所以我们要更改一下JspServlet的实现代码(hack一下):更改equinox的org.eclipse.equinox.jsp.jasper_*.jar中的org.eclipse.equinox.jsp.jasper.JspServlet类:(可以下载JspServlet的源代码,在本地更改编译成功后将class文件覆盖到org.eclipse.equinox.jsp.jasper_*.jar中)
添加以下方法:
public ClassLoader getJspLoader()
{
return this.jspLoader;
}
如此即可^_^, 其实就是让FacesServlet使用JspServlet的ClassLoader,这样就不会出现"Can't find FacesContext"错误了。
参考: [news.eclipse.technology.equinox]
JSF, Equinox & FactoryFinder
版权所有 罗明