Cookie set in web filter is not available in request bean - jsf

I'm trying to create a localized JSF web application which allows user to select a language via dropdown. When language is selected, I simulate a redirect to the same page but with URL parameter:
window.location.replace(urlToMyApp + '?locale=DE');
Next, I read 'locale' parameter in application's web filter and write it in a cookie with the same name:
String localeValue = httpRequest.getParameter("locale");
Cookie cookie = new Cookie("locale", localeValue);
cookie.setMaxAge(-1);
cookie.setDomain(cookieDomain);
cookie.setPath(cookiePath);
httpResponse.addCookie(cookie);
Now when I try to read that cookie in request bean init method, cookie is not available. If I select another language via dropdown (EN for example), previously selected language (DE) is read in init method.
I assume that cookie written in filter is not available before next "request - response" cycle, can someone confirm that?
If that's true I'm asking for an idea to translate my application immediately after selecting another language.
Just one thing that I think I need to mention - language dropdown is not part of my application. It's part of some kind of framework for several applications to be included (like portal).

I assume that cookie written in filter is not available before next "request - response" cycle, can someone confirm that?
That's correct.
You've added the new cookie to the response, not to the request. So any attempt to read it from the same request won't work. The cookie will only be available in the request if the browser has actually sent it. But it can only do that if it has obtained the cookie data from a previous response.
If that's true I'm asking for an idea to translate my application immediately after selecting another language.
If the request scoped bean is managed by CDI #Named, then just inject it in the filter and set the locale over there.
#Inject
private Bean bean;
public void doFilter(...) {
// ...
bean.setLocale(locale);
// ...
}
Else if it's not managed by CDI, but by the since JSF 2.3 deprecated #ManagedBean, then manually instantiate it and put it in request scope so that JSF will just reuse the same bean.
public void doFilter(...) {
// ...
Bean bean = new Bean();
bean.init(); // If necessary.
bean.setLocale(locale);
request.setAttribute("bean", bean); // "bean" is managed bean name.
// ...
}
See also:
Get JSF managed bean by name in any Servlet related class
Localization in JSF, how to remember selected locale per session instead of per request/view

Related

Writing plain HTML in a JSF based web application

I have this use case in a JSF application.
Supposed in a JSF web application, I have a button that calls an external service that returns a complete HTML response then how can I show that HTML response to my users browsers?
The sequence of events are like this.
In user browser, my application is displayed. A button is there that user can click.
Clicking the button will call an external service. The external service will return information about a certain HTML tags. The HTML is complete with both head/body and with javascript. Currently the service can be implemented thru REST service or a plain DB call then
How can I display that HTML tag in my user browser?
Is this possible to write non-JSF output in a JSF web application?
Just to add, I think my problem is how to write an HTML in my backing bean and write it back to the users browser.
Just write it outright to the HTTP response body whereafter you instruct JSF that the response is manually completed. The principle is not much different from How to provide a file download from a JSF backing bean?, except that you need to set content disposition to inline (which is already the default anyway).
public void writeHtmlResponse() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.setResponseContentType("text/html;charset=UTF-8");
ec.setResponseCharacterEncoding("UTF-8");
ec.getResponseOutputStream().write(html.getBytes("UTF-8"));
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

JSF to Bean to JSF

So I'm having a problem trying to pass a String value.
The String value is entered through a login page as username.
The JSF then calls the Bean to verify log in information then proceeds to another JSF page.
I was wondering how to pass the username along to the new JSF page. Thank you.
If you're performing a navigation instead of a redirect, then you basically don't need to do anything. The information is also just available in the navigated page.
E.g. in login page,
<h:inputText value="#{bean.username}" />
and in the navigated page:
<p>You have entered the following username: #{bean.username}</p>
If you're however performing a redirect instead of a navigation, then you basically need to store the information in a bit broader scope. You didn't clearly elaborate the concrete functional requirement in the question, but if I guess it right, you just wanted to remember the currently logged-in user for the remaining of the HTTP session. In that case, just store it in the session scope during the login action.
public String login() {
// ...
User user = userService.find(username, password);
// ...
externalContext.getSessionMap().put("user", user);
// ...
return "nextpage?faces-redirect=true";
}
This way it's available by #{user} throughout the entire HTTP session.
<p>You're logged in as #{user.name}.</p>
You can also use <t:saveState> without using session scope. <t:saveState> is longer than the request scope but shorter than session scope.
This may help you : http://myfaces.apache.org/tomahawk-project/tomahawk12/tagdoc/t_saveState.html

JSF I'm Losing Session State When Changing From Managed To CDI

Edit: This is an epic face palm situation. Wrong import for SessionScoped. So tired last night while checking it I was sure I was using enterprise sessionscoped import while I was still using faces sessionscoped import. I'm leaving this up as an aid to doofuses like me. :)
It is early in this project. After implementing up to this point with managed beans, I changed my managed beans to CDI beans as this seems to be the latest consensus on the best way to do things But this has broken previously working code. I cannot for the life of me figure out why. Help and advice is appreciated.
Happy Path (Summary... detail below code extracts)
If user not logged in, show login or register links.
If user logged in show user preferences or logout links.
Now Crappy Path with CDI (I don't blame CDI)
If user not logged in, show login or register links.
If user logged in still see login or register links. (bad, bad app)
The objects involved are
a facelet menu panel (with a primefaces login dialog... I don't think this has any thing to do with it but included for completeness) with render attributes if logged in or not,
a session scoped user bean,
a request scoped authentication bean to log the user in and out.
Objects used listed below. Implemented as CDI beans.
facelet
<h:panelGroup id="loginPanel" rendered="#{!user.loggedIn}">
Show login buttons and stuff
</h:panelGroup>
<h:panelGroup id="logoutPanel" rendered="#{user.loggedIn}">
Show logout buttons and stuff
</h:panelGroup
authentication bean
#Named(value = "webAuthenticationBean") //formerly managedbean
#RequestScoped
public class WebAuthenticationBean implements Serializable {
#Inject private UserBean user; //formerly a managed property which worked
...
request.login(uername, password);
user.setuserdata(username); // sessionscoped user state here used to check login state among other things later.
...
return(true) // they are now logged in
user bean
#Named(value = "user") //formerly managedbean
#SessionScoped
public class UserBean implements Serializable {
#EJB
private UserService userService; //stateless session bean
private userInfo = new UserInfo(); // keeps user state and can be used as a DTO/VO
#PostConstruct
public void init() {
//sets default state to "guest user". This is NOT a logged in state
}
public void setuserdata(String username){
userInfo = userService.getUserInfo(username);
// method called from WebAuthenticationBean
// sets the user state to a non-guest user (they're logged in).
// I can see in debug mode that this is being called and retrieving
// the user data from the database and setting "userInfo"
}
public void isLoggedIn() throws InvalidUserException{
// checks state to see if they are logged in, basically a bit more than are they still a guest or not
returns (true) if logged in
returns (false) if not logged in
// this worked with managed beans
}
...
So here is the actual use case when I watch in debug mode:
Happy Path (prior to change to CDI bean)
1) User navigates to the welcome page
2) the user bean is queried to see if they are logged in (user.loggedIn in the facelet).
3) userbean checks logged in state. If they are still a guest they aren’t logged in.
4) They are identified as a guest so isLoggedIn() returns false.
5) Login button is shown.
6) User requests logs in
7) authentication bean begins login process: request.login returns successfully
8) authenticationbean sets user data: user.setuserdata(username) returns successfuly.
9) authentication bean loginMethod returns (they are logged userprincipal on the server)
Alternate (crappy) path branch here (happy path continues)
10) The menu rechecks login state (user.loggedIn)
11) userbean checks for appropriate state and sees they are valid non guest user
12) userbean returns (true) they are logged in
13) menu shows logout button
Crappy Path (what happens after I changed these to CDI beans)
10) The menu rechecks login state (user.loggedIn)
11) userbean checks for appropriate state and sees they are a guest //the updated user state seems to have disappeared from this user in this session.
12) userbean returns (false) they are not logged in //but they are
13) menu shows login button // they can’t login anyway since the server already sees them as logged in, in this session (ServletException: Attempt to re-login while the user identity already exists).
Why using managedbeans would I be able to see the userbean maintain its data in session scope but with cdi beans it does not? I am stumped. I’ll switch back to managed beans if I have to, it isn’t a big issue, but I would like to find out what I messed up.
I added some debugging code in the init method of the UserBean, and it appears as if the system is treating the SessionScoped UserBean as if it were RequestScoped. That is it is initializing on every call.
#PostConstruct
public void init() {
if (userInfo == null) {
userInfo = new UserInfoDTO();
userInfo.setUserName("Guest");
List<String> guestGroup = Arrays.asList(CoreUserGroupType.GUEST.toString());
userInfo.setUserGroups(guestGroup);
System.out.println("UserBean.init INSIDE Init If Statement");
}
System.out.println("UserBean.init OUTSIDE Init If Statement");
}
If it were really acting like it was SessionScoped the userInfo object would not be null every time and the 'if' statement would not be executed every time. But it is executing on every call to UserBean. So this is at the crux of the problem. As a matter of fact if it acted like it were in session scope it would not hit the init method at all on every call as it would still be initialized.
Am I not creating a sessionscoped bean properly? It would appear so, but I don't see how. As mentioned, this code ran fine when defined as a managedbean.
changed to the correct sessionscoped import and all is well. nothing hurt but my pride.

JSF 2.0; MyFaces; Form submit only with POST

i've got a security question and i don't know, how to do this in JSF.
In PHP i can react on a form submit that is defined as POST, that i only want values via POST so there is no way to get an value via GET from the same name of the field.
Example:
fieldname in form: username
in my PHP site i can get the value via $_POST["username"] but not with $_GET["username"], because i don't implement the GET way, only POST.
So, now i want this in my JSF site too.
The problem is, that i can't only implement POST for all requests, i must react on GET also.
I only want, that my form data will come via POST to my bean and not via GET.
How can i reach this?
With a filter or something else?
For your interest: i'm not able to use JavaScript in my application.
Thanks a lot!
I'm not sure I understood your question but if you just need to check if a method on your backing bean was invoked using POST or GET you can get that information from the HttpServletRequest object like so :
#ManagedBean(name="myBean")
#ViewScoped
public class MyMBean implements Serializable{
public void handleForm(){
HttpServletRequest req = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
if(req.getMethod().equalsIgnoreCase("POST")){
//Handle your form data
}
}
Just check FacesContext#isPostback().
if (FacesContext.getCurrentInstance().isPostback()) {
// It's a JSF POST request.
}

How to detect session has been invalidated in JSF 2?

In my application I have a quit button, on clicking of which the session for the current user is invalidated by the following piece of the code..
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
And I redirect the user to a different page.
But now I want if user click on the back button I will take him to the start page of the application instead of the last page visted by him.
I have an application phase listener which sets the page cache related headers to 'none', now all I want is to detect that for that user session has been invalidated.
But I guess whenever the user is clicking the back button it is creating a new session for the user. Is there any way to prevent it?
How to detect session has been invalidated in JSF 2?
Check if the user has requested a session ID which is not valid.
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
// Session has been invalidated during the previous request.
}
it is creating a new session for the user. Is there any way to prevent it?
Just don't let your application code create the session then. The session will implicitly be created when your application needs to store something in the session, e.g. view or session scoped beans, or the view state of a <h:form>, etc.
I have an application phase listener which sets the page cache related headers to 'none'
A servlet filter is a better place for this. See also Avoid back button on JSF web application

Resources