Home » Eclipse Projects » Equinox » MyFaces & Equinox - Issue with FactoryFinder
MyFaces & Equinox - Issue with FactoryFinder [message #84841] |
Thu, 22 March 2007 16:46  |
Eclipse User |
|
|
|
Originally posted by: the.dev.ich-will-net.de
Hi all,
I want to use MyFaces within the Equinox Http Service and just ran into a problem with MyFaces' FactoryFinder.
The FactoryFinder is used to set up the JSF factories (normally within the StartupServletContextListener, a MyFaces specific ServletContextListener) and provide them to the framework in later phases, e.g. when the JSF tags are rendered. The factories are stored in a hash map, with the (current) classloader as key.
I'm using the recommended approach to wrap the StartupServletContextListener together with the FacesServlet within a ContextListenerServletAdaptor. So the factories are stored with the current classloader as key. Later on, when the jsp is rendered a different class loader is used -> the according JspClassLoader. Therefore the appropriate factories can not be found in the HashMap and the request fails.
The MyFaces approach to use the classloader as key seems to collide with the Eclipse/Equinox way of classloading. When I think of more complex applications with jsp's distributed over serveral bundles, ...
Just verified the problem by changing the FactoryFinder to use a static key instead of the classloader. The Factory was found.
Did anybody else encounter the same problem? How did you solve it? Maybe i can't see the forest for the trees :-)
Thanks,
Jörg
|
|
| |
Re: MyFaces & Equinox - Issue with FactoryFinder [message #85288 is a reply to message #84868] |
Tue, 27 March 2007 05:02   |
Eclipse User |
|
|
|
Originally posted by: the.dev.ich-will-net.de
Hi Simon,
I had to modify the MyFaces code. Nothing to spectacular. Simply defined a static String to act as key (instead of the class loader) and used it for the storage of the factories . I just wanted to verify my theory in the first place. I can send you the source if you want to take a look.
Currently I don't see a alternative (proper) solution, since FactoryFinder is declared as final and has about 50 references in MyFaces code to it.
Your wording "how far we could get with MyFaces" is a little thought-provoking to me. What is your opinion on the feasibility of using MyFaces (or alternative JSF libraries / implementations) with the OSGi http service? I found some footprints of trials to get JSF running, but (sad enough) no confirmations about successful implementations.
I'm advancing step by step, but still a little bit wondering about a big / final obstacle that prevents the usage of JSF.
The only true obstacles i found (until now) is the class loader topic currently discussed and the fact that the web.xml deployment descriptor is loaded / parsed / used from within the MyFaces implementation. I worked around this one by simply adding the web.xml to my MyFaces bundle for now. Clearly not the desired way to work, but I have not yet looked into a proper solution for this.
Current state is that a got a simple JSF app running which uses some basic extended components (input/outputText, command, validator) and now am trying to get some MyFaces custom components running. So far got a NullPointerException and have to look into it.
Btw. I'm not sure if it was caused by my usage of the Http service / configuration or if it might generally be considered a bug:
I had some trouble with the HttpServletRequestAdaptor when using a url-pattern for the FacesServlet which included an extension: /faces/*.jsf. The proxy servlet forwards the full alias for matching servlet registrations, e.g. /faces/inputnumber.jsf, which (in my case) matched the PathInfo from the point of view of the bridge servlet / proxy servlet. Thus the invocation of HttpServletRequestAdaptor.getPathInfo() returned an empty string. Per definition getPathInfo() should return null in case there's no additional path info. And that's what MyFaces expects or it will fail to find the according view. Anyhow that should happen for all extension based servlet registrations (*.jsp) making use of the path info, which makes me feel that I'm missing something.
Thanks,
Jörg
|
|
| | | | |
JSF, Equinox & FactoryFinder (was Re: MyFaces & Equinox - Issue with FactoryFinder) [message #95120 is a reply to message #85958] |
Thu, 16 August 2007 16:16  |
Eclipse User |
|
|
|
Hi all,
I am going to ping up this old thread because I believe I made some
progress on this problem. I've been looking at the same issue with
Sun's JSF RI - which uses FactoryFinder in the same way that MyFaces
does. I don't believe this problem is really that tough, but it does
require a minor change to the existing equinox JSP implementation to
allow it to work.
What I did, to get this working, is to modify JspServlet (from
org.eclipse.equinox.jsp.jasper) so that it provided a getter for the
jspLoader member. I was already using the previously recommended
approach of using a wrapper around FacesServlet to allow for the RI's
ServletContextListener to be called, and I added code for init, service
and destroy to override the thread's context classloader with the
JspServlet's classloader. It seems to me this would more accurately
emulate the conditions inside a regular JSP application, and it does
allow the JSF app I've tried so far (guessNumber from the samples) to
run without modification to the JSF implementation.
Here's what my Activator looks like... (bear in mind that this will not
compile with the "out of the box" JspServlet, but the change to add the
accessor is simple enough.)
package com.businessobjects.minjsf;
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 = "/minjsf";
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(), "/web");
httpService.registerResources(PATH, "/", commonContext);
JspServlet jspServlet = new JspServlet(context.getBundle(), "/web");
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 + "/guess", adaptedFacesServlet,
initparams, commonContext);
} catch (Exception e) {
// TODO Auto-generated catch block
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 + "/guess"); //$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 "";
}
}
}
Hope this helps
Cheers
...Mark..
Mark Allerton
Principal Architect - Vancouver Engineering
Business Objects
On 2007-04-03 06:17:29 -0700, "Simon Kaegi" <simon_kaegi@ca.ibm.com> said:
> Hi Jörg,
>
> I was thinking.... there might be something pragmatic we can do with
> the JspClassloader so that we don't need to alter the MyFaces code. The
> JspClassLoader just wraps the existing context class loader so that it
> has the right characteristics to satisfy the underlying Jasper Engine.
> What we could do is have the JspClassloader override equals and
> hashcode so that for all intents and purposes it appears to be the
> original thread context class loader. See
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=180703. I can certainly
> supply the patch however I need a bit of help to make sure that it
> actually works in your context.
>
> -Simon
>
> "Jörg Lehmann" <the.dev@ich-will-net.de> wrote in message
> news:22930303.1174986192452.JavaMail.root@cp1.javalobby.org...
>> Hi Simon,
>>
>> I had to modify the MyFaces code. Nothing to spectacular. Simply
>> defined a static String to act as key (instead of the class loader) and
>> used it for the storage of the factories . I just wanted to verify my
>> theory in the first place. I can send you the source if you want to
>> take a look.
>>
>> Currently I don't see a alternative (proper) solution, since
>> FactoryFinder is declared as final and has about 50 references in
>> MyFaces code to it.
>>
>> Your wording "how far we could get with MyFaces" is a little
>> thought-provoking to me. What is your opinion on the feasibility of
>> using MyFaces (or alternative JSF libraries / implementations) with the
>> OSGi http service? I found some footprints of trials to get JSF
>> running, but (sad enough) no confirmations about successful
>> implementations.
>>
>> I'm advancing step by step, but still a little bit wondering about a
>> big / final obstacle that prevents the usage of JSF.
>>
>> The only true obstacles i found (until now) is the class loader topic
>> currently discussed and the fact that the web.xml deployment descriptor
>> is loaded / parsed / used from within the MyFaces implementation. I
>> worked around this one by simply adding the web.xml to my MyFaces
>> bundle for now. Clearly not the desired way to work, but I have not
>> yet looked into a proper solution for this.
>>
>> Current state is that a got a simple JSF app running which uses some
>> basic extended components (input/outputText, command, validator) and
>> now am trying to get some MyFaces custom components running. So far got
>> a NullPointerException and have to look into it.
>>
>> Btw. I'm not sure if it was caused by my usage of the Http service /
>> configuration or if it might generally be considered a bug:
>> I had some trouble with the HttpServletRequestAdaptor when using a
>> url-pattern for the FacesServlet which included an extension:
>> /faces/*.jsf. The proxy servlet forwards the full alias for matching
>> servlet registrations, e.g. /faces/inputnumber.jsf, which (in my case)
>> matched the PathInfo from the point of view of the bridge servlet /
>> proxy servlet. Thus the invocation of
>> HttpServletRequestAdaptor.getPathInfo() returned an empty string. Per
>> definition getPathInfo() should return null in case there's no
>> additional path info. And that's what MyFaces expects or it will fail
>> to find the according view. Anyhow that should happen for all extension
>> based servlet registrations (*.jsp) making use of the path info, which
>> makes me feel that I'm missing something.
>>
>> Thanks,
>> Jörg
|
|
|
Goto Forum:
Current Time: Fri Apr 25 20:17:27 EDT 2025
Powered by FUDForum. Page generated in 0.07704 seconds
|