Hi All,
I'be been tearing my hair out for a couple of weeks over this one and would 
appreciate any assistance anyone could give.  It's a bit of a unique scenario, 
so it'll take me a little while to explain:
We have a legacy struts app, forwarding to a jsf app (details of how below) 
running on tomcat 5.5.17.  99.9% of the time everythign works great, but every 
now and then (which in users speak translates to 'I keep on getting', hence we 
can't ignore it) a NullPointerException gets thrown from 
org.apache.catalina.connector.Request.setAttribute.
The flow is:
Third party application ---<<http redirect>>---> JSFBridgeFilter (will explain 
later) -----> Struts application ----> JSFBridge--->JSF Application--->Response 
back to third party app.
The struts application contains proprietary logic to interface with the third 
party app, so we can't get rid of it. Business wants all development internally 
to be done in JSF, so we can't get rid of that.
The JSFBridgeFilter instantiates the JSF Context for later use, and wraps the 
request that is used to instantiate it in a request wrapper that translates 
".do" context paths to ".jsf" context paths (otherwise all the forms submit 
back to ".do" after coming from the struts framework.  It looks like this:
public void doFilter(ServletRequest strutsRequest, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {

HttpServletRequest jsfRequest = new 
StrutsToJsfRequestWrapper((HttpServletRequest)strutsRequest);

JSFBridge.getFacesContext(viewId, (HttpServletRequest)jsfRequest, 
(HttpServletResponse)response);

chain.doFilter(strutsRequest, response); 

}

...and the StrutsToJsfRequestWrapper contains only one override method (it 
extends HttpServletRequestWrapper):
@Override

public String getServletPath() {

        String oldPath = super.getServletPath();

        String newPath = null;

        int index = oldPath.lastIndexOf(".do");

        if (index >= 0) {

                newPath = oldPath.substring(0, index + 1) + ".jsf";

        } else {

                newPath = oldPath;

        }

        return newPath;

}

 

Now, you'll notice in the filter that the request wrapper is used to 
instantiate the faces context, and the original request passed onto the struts 
application.  The 'getFacesContext' method implements some code from the apache 
myfaces wiki that shows a way to call into the JSF framework from non jsf 
artifacts:

 

It looks like this:

 

public class JSFBridge {

 

        private abstract static class InnerFacesContext extends FacesContext {

                protected static void setFacesContextAsCurrentInstance(final 
FacesContext facesContext) {

                        FacesContext.setCurrentInstance(facesContext);

                }

        }

 

        public static FacesContext getFacesContext(final String viewId, final 
ServletRequest request, final ServletResponse response) { 

                FacesContext facesContext = FacesContext.getCurrentInstance();

                if (facesContext != null) { 

                        return facesContext;

                } 

                return getNewFacesContext(viewId, request, response);

        }

 

        public static FacesContext getNewFacesContext(final String viewId, 
final ServletRequest request, final ServletResponse response) {

                FacesContext facesContext;

                FacesContextFactory contextFactory = (FacesContextFactory) 
FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);

                LifecycleFactory lifecycleFactory = (LifecycleFactory) 
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);

                Lifecycle lifecycle = 
lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);

                facesContext = 
contextFactory.getFacesContext(((HttpServletRequest)request).getSession().getServletContext(),request,
 response, lifecycle);

                
InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);

                UIViewRoot view = 
facesContext.getApplication().getViewHandler().createView(facesContext, viewId);

                facesContext.setViewRoot(view); 

                return facesContext;

        } 

}

 

And the final piece of the puzzle is a struts action that actually loads the 
context and forwards to the appropriate JSF method...which looks like this:

 

public class ForwardToJSFAction extends Action {

        

        public ActionForward execute(ActionMapping mapping, ActionForm form, 
HttpServletRequest request, HttpServletResponse response) throws Exception { 

                JSFMapping viewMapping = (JSFMapping) mapping;

                FacesContext ctx = 
JSFBridge.getFacesContext(viewMapping.getViewId(), request, response); 

                MethodBinding mb = lookupMethodBinding(viewMapping, ctx); 

                navigateToMethodBinding(viewMapping, ctx, mb);

                return null;

        }

 

        private MethodBinding lookupMethodBinding(JSFMapping viewMapping, 
FacesContext ctx) {

                return ctx.getApplication().createMethodBinding("#{" + 
viewMapping.getJsfAction() + "}", new Class[] {});

        }

 

        private void navigateToMethodBinding(JSFMapping viewMapping, 
FacesContext ctx, MethodBinding mb) {

                Object obj = mb.invoke(ctx, new Object[] {});

                NavigationHandler navHandler = 
ctx.getApplication().getNavigationHandler();

                navHandler.handleNavigation(ctx, "#{" + 
viewMapping.getJsfAction() + "}", (String) obj);

        }

}

 

Now, as odd as all this looks, it actually works quite well in 99.9% of the 
cases.  We get a request in struts, which forwards quite nicely onto a JSF 
method and completes the business process in JSF.  Every now and then though, 
we get the following error when we try to invoke the method binding:

Caused by: java.lang.NullPointerException
        at org.apache.catalina.connector.Request.setAttribute(Request.java:1376)
        at 
org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:500)
        at 
javax.servlet.ServletRequestWrapper.setAttribute(ServletRequestWrapper.java:283)
        at 
org.apache.myfaces.context.servlet.RequestMap.setAttribute(RequestMap.java:46)
        at 
org.apache.myfaces.context.servlet.AbstractAttributeMap.put(AbstractAttributeMap.java:104)
        at 
org.apache.myfaces.el.VariableResolverImpl.resolveVariable(VariableResolverImpl.java:301)
        at 
org.apache.myfaces.config.LastVariableResolverInChain.resolveVariable(LastVariableResolverInChain.java:42)
        at 
org.apache.myfaces.el.ValueBindingImpl$ELVariableResolver.resolveVariable(ValueBindingImpl.java:574)
        at org.apache.commons.el.NamedValue.evaluate(NamedValue.java:124)
        at 
org.apache.myfaces.el.ValueBindingImpl.resolveToBaseAndProperty(ValueBindingImpl.java:455)
        at 
org.apache.myfaces.el.MethodBindingImpl.resolveToBaseAndProperty(MethodBindingImpl.java:180)
        at 
org.apache.myfaces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:114)
Diving into Request.java(Line 1376), shows that it's happening on this line:
Object listeners[] = context.getApplicationEventListeners();
So I'm guessing that 'context' is null for some reason.  Since it is so rare, 
it's almost impossible to reproduce in a manner consistent enough to actually 
diagnose and debug it.
Can anyone see, from the above, anything that could shed some light on this?
Cheers
Adam

Number 1 in Truck Insurance

______________________________________________________________________
CAUTION - This message is intended for the addressee named above.

It may contain privileged or confidential information. If you are 
not the intended recipient of this message you must not use, 
copy, distribute or disclose it to anyone other than the addressee.
If you have received this email in error please return the message to the 
sender by replying to it and then delete the message from your computer.

Internet e-mails are not necessarily secure. 
National Transport Insurance does not accept responsibility for changes made to 
this message after it was sent.
______________________________________________________________________

Reply via email to