How to use FacesContext.getCurrentInstance(), it returns null
Asked Answered
T

1

12

I've been struggling for the last couple of days with the login part of my web app. I've gotten to the point where I can succesfully authenticate a user using the JDBCRealm on tomcat(by reading users from a sql server database). Now I want to send some kind of feedback when the user's account has been blocked, or when the credentials are incorrect, this is where I'm stuck now.

I wanted to use this:

    try {
        request.login(request.getParameter("user"), request.getParameter("pass"));
    } catch (ServletException se) {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Wrong Username/Password combination"));
        log(se.getMessage());
    }

But FacesContext.getCurrentInstance() always returns null..

After doing some research I found out that the request must come from a page located in /faces so that the FacesServlet gets called and the FacesContext gets initialized(at least that's what I understood).

So I moved the login page to a new folder named faces, inside the Web Pages folder. But now everytime I try to call the login.xhtml page, I get this error:

/login.xhtml Not Found in ExternalContext as a Resource  

And this is the stacktrace:

com.sun.faces.context.FacesFileNotFoundException: /login.xhtml Not Found in ExternalContext as a Resource
at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:232)
at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:273)
at com.sun.faces.facelets.impl.DefaultFaceletFactory.getFacelet(DefaultFaceletFactory.java:201)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:764)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:100)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:410)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:304)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)  

I get this error even when I enter the URL directly into the browser.

Im using Netbeans 7.1 with Apache Tomcat 7(which by the way is a pain because I get a lot of PermGen out of memory exceptions -.-)

Any help on how to fix this would be greatly appreciated.

Tate answered 2/4, 2012 at 23:47 Comment(0)
N
13

It will return null when you're not in a managed bean or any other JSF artifact. For example, in a plain vanilla servlet or a servlet filter which runs before FacesServlet runs. The FacesServlet is namely the one who creates the FacesContext and puts it as a ThreadLocal in the current HTTP request. You need to do the login job in a JSF managed bean instead the usual way. That piece of code login which you've there belongs in a JSF managed bean.

As to the login page, it's not different from any other JSF page which you've ever developed. Or have you actually never developed with JSF and is this your first JSF attempt ever? Well, you should have been more explicit about this in your question as well. Get rid of that /faces folder, just put the login.xhtml straight in the webcontent and make sure that the URL pattern of the FacesServlet in web.xml is set to *.xhtml. Then you can just open it by http://localhost:8080/yourapp/login.xhtml.

To learn JSF better, go through a bit decent book/tutorial first and don't try to cobble loose pieces which you found on the Internet together without really understanding what those lines of code are doing. You're supposed to be able to write/explain it yourself once you really understand it. Start here: Our JSF wiki page.

Noam answered 3/4, 2012 at 2:51 Comment(1)
Yea, this is my first JSF attempt :) Thanks for your answer, it does answer my question. Basically I can't access the FacesContext anywhere before the FacesServlet runs, so I have to use a managed bean whenever I like to access the Fctx. About the learning part, I like to try out doing basic stuff on a language before I start reading a book, that way when I'm reading it, it will come easier and I'll really know what the book is talking about. Either way I'm still not sure why I can't place the page inside a /faces folder? I'll follow your advice and change the Faces Servlet pattern.Tate

© 2022 - 2024 — McMap. All rights reserved.