JSF, actionlistener at facelets - java

I'm using JSF (Mojarra 1.2) with Richfaces (3.3.2) within some facelets which are used as portlets (I'm using the Jboss Portlet Bridge 2.0 here). Now I'm facing something strange: I've got an actionlistener on my <h:commandButton> which is triggered, when the button is clicked but when I simply reload the page, the action is executed everytime I load the page again. This happens only if I already triggered the action before. Is this behaviour normal?
I should notice that Spring 2.5 is used to manage my beans, the mentioned beans are session-scope beans, maybe this is a interessting point?!

Yes, reloading a HTTP POST request will execute the HTTP POST request again and thus trigger all associated server-side actions again. This issue affects all webapplications in general and is not per se related to JSF.
A well known fix to this is the POST-Redirect-GET (PRG) pattern. Basically you need to redirect the POST request to a GET request immediately after processing the action, so that the result page will be delivered by a HTTP GET request. Refreshing this HTTP GET request won't execute the initial HTTP POST request anymore.
This pattern has however one caveat: since it concerns a brand new request, all request scoped beans are garbaged and renewed in the new request. So if you'd like to retain the data in the new request, you would need to either pass them as GET parameters or to store it in the session scope. Usually just reloading the data in bean's constructor is sufficient. But since you mention to use session scoped beans only (which is however not the best practice, but this aside), this shouldn't be a big concern for you.
Turning on PRG in JSF is relatively easy, just add the following entry to the associated <navigation-case>:
<redirect />
Or if you prefer to fire it programmatically, then make use of ExternalContext#redirect() in the bean's action method:
public void submit(ActionEvent event) {
// ...
FacesContext.getCurrentInstance().getExternalContext().redirect(someURL);
}

Related

Managing session and request attributes in Servlet

I have a very simple JSP page where it has one search box and based off the input, in the search box, it will return a response with a submit button to get the following response.
I noticed that whenever I use request.getattribute("foo") in my servlet to retrieve some request it returns null due to the request ending so I looked at the answers on here and started using session.getattribute("foo") instead. However, now I am stuck having session variables responses being set and it is causing my view to have old session data that isn't suppose to be there so now I have to use session.removeAttribute("foo"), whenever, I don't want that particular response data to be shown.
Is there a better way to go about managing this instead of having to use session.getattribute("foo"), session.removeAttribute("foo") and session.setattribute("foo")?
You should work with request.getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
Set an attribute:
request.getSession().setAttribute("foo")
And get attribute using:
request.getSession().getAttribute("foo")
It will be used in the context of the request and not effect other requests, so you don't need to remove attribute.
Read more in Servlets tutorial
Servlets provide an outstanding technical solution: the HttpSession API. This is a high-level interface that allows the server to "remember" a set of information relevant to a particular user's on-going transaction, so that it can retrieve this information to handle any future requests from the same user.
You can go for request.getparameter("foo") or request.setparameter("foo", obj)
This can be used for every request, and it will not add to your session variables and basically will not make your "session object heavy".
Java doc:
Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.

Can a jsf managed bean behave like a servlet?

Normally, a servlet has doGet() and doPost() methods. They are utilized to capture the incoming request parameters, which can then be used in any part of the application, if the developer wishes so.
Now, If instead of using a servlet, a developer wishes to use a jsf managed bean, is there a way to get the request parameters in the bean itself ? If so , how can it be done ?
I have seen this POST which shows a way of getting stuff from request in JSF. Can this be used to get a request parameter in managed bean like this :
HttpServletRequest origRequest = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String myReqQuery1 = origRequest.getParameter("ReqQuery1");
In this case, will the application follow a jsf life cycle or a servlet life cycle or both ?
JSF does not really work like that. The form fields in the view (.jsf or whatever) are mirrored by fields and properties in the bean. They are automatically populated by JSF when the servlet is invoked further up the stack.
This makes the need to read HTTP parameters redundant except when the browser lands on a JSF page from a non-JSF based form. For that something like Spring-MVC can accept the URI being targetted and make a connection to the ManagedBean instance before redirecting the browser to a JSF powered URL.

Prevent session's last access time update in Jetty

Is it possible to instruct a Jetty server not to update the session's last access time when a particular servlet is accessed?
Our use case is an HTML page that sends asynchronous requests in the background every 5 miniutes to refresh its contents. The session's timeout is set to 30 minutes.
The unfortunate problem with this configuration is that when a user leaves that page open in a browser's tab, the session never expires because the access time of the session is updated by every asynchronous request.
For correctness' sake I have to admit that I didn't try anything yet because I wasn't able to find any help for my issue on the Internet. If what I'm asking for is not possible, I'm thinking of storing the access time in a session's variable that is controlled directly by the application. This value would have to be checked early before a request is processed (in the doGet and doPost methods of the servlets) and the session would need to be invalidated manually. Is there a better solution?
Servlet can't distinguish if the request is generated by some script or human, since both requests come from a same browser, consequently sending the same JSESSIONID. So you have to mark those requests in order to distinguish its source. You can mark them by some header or request parameter.
I like your idea of storing access time in session's variable (it will piggy back on servlet session expiry)
Your algorithm will be in this case:
if isUser(request){
session.lastRobotAccess == null
}else{
if (session.lastRobotAccess == null) {
session.lastRobotAccess = current_time
} else {
if(current_time - session.lastRobotAccess > session.timeout){
session.invalidate
}
}
}
When request arrives at servlet container it is first processed by the filters (if you have defined) and then by the servlet. Filters are useful for:
A common scenario for a filter is one in which you want to apply
preprocessing or postprocessing to requests or responses for a group
of servlets, not just a single servlet. If you need to modify the
request or response for just one servlet, there is no need to create a
filter—just do what is required directly in the servlet itself.
Since you can reach session from filter, they are more suitable place for your logic. You won't pollute servlet's logic with additional checking, and you can apply it to other servlets. Filters are also part of servlet specification so this will work in any container.
You already knew this things, but I've just put them on "paper" :-D

How servlet filter will dispatch error message on request page?

I have written a servlet filter which is configured to be invoked for each url (/*). On the basis of some condition, if the condition is passed, I want to proceed normal execution by chain.doFilter(request,response), I also want to open same request URL with error message..
"say value entered in particular textbox is incorrect". Is this possible?
Do I have to use response.sendRedirect(request.getURL())? I hope I wont end up in infinite loop as I have configured filter on each URL. I am doing validation check on request parameter.
Just do the same as you'd do in a servlet: perform a forward.
request.getRequestDispatcher("/WEB-INF/some.jsp").forward(request, response);
A filter is by default not (re)invoked on a forward. Additional advantage is that the JSP reuses the same request and thus you can just set the validation error messages as a request attribute without the need for session or cookie based workarounds/hacks.
Unrelated to the concrete problem, this isn't entirely the right approach. Form-specific validation job should be performed in a servlet, not in a filter. If you'd like to keep your servlet(s) DRY, then look at the front controller pattern or just adopt a MVC framework which already offers a front controller servlet and decent validation out the box, such as JSF or Spring MVC.

Persist user name and page name to database

I have a small JSF application and the scope of the pages are request. I would like to have a method in my JSF's managed bean for logging user_id and page name to database. When I added this method to the constructor of bean, details are getting logged for every method is being called due to the fact that scope of the page is request.
What is the best way to log the above details only once when user first access the pages after logging into my application? Idea is which all pages user visited for each logging.
What is the best way to achieve this?
My JSF version is 1.1.
Thanks
You can add a method to the bean and invoke it from the page when the page is loaded. For example
add this into the page:
<h:outputText value="#{fooBean.logUser}"/>
bean method:
public void logUser(){
//log user and page
}
This way the method is only invoked once the page is loaded. If you get a method not found
error, then another option is to use a hidden form hack. For example:
<body onload="document.getElementById('formId:buttonId').click()">
<h:form id="formId" style="display: none;">
<h:commandButton id="buttonId" value="submit" action="#{fooBean.logUser()}" />
</h:form>
...
</body>
So, you want to log into a database table all accesses of all users to the different pages of your site but, avoiding logging post-backs, right? (a post-back happens when a user performs an action in one of your pages and the URL that receives the action is the same than the one from where the action was launched - it's very common in JSF, specially on versions prior to 2.x)
So, basically, what you need is to recognize when a post-back happens and avoid logging under that condition. The ResponseStateManager will provide you with a isPostback(...) method that returns true when processing post-back requests:
FacesContext context = FacesContext.getCurrentInstance();
ResponseStateManager rsm = context.getRenderKit().getResponseStateManager();
if (!rsm.isPostback(context)) {
// do whatever you need here
}
By the way, I wouldn't recommend to put that code in the bean constructor at all as different JSF implementations may perform some bean lifecycle management tasks right after invoking the bean's constructor. If you think that logic should be part of the "bean initialization process" I suggest putting that code in a separate public method annotated with a #PostConstruct annotation.
However, if you want that logic to be run in every single access to the given pages, using a managed bean will force you to either copy & paste that logic in every bean or define an abstract/base class with that logic and make all your beans extend that one. I like to keep all my managed beans as close as possible to the POJO concept so, as an alternative, I would consider implementing the same logic but using a PhaseListener tied to the RENDER_RESPONSE phase. It will give you a under-the-hood (much cleaner) and versatile approach: if some day you want to log actions instead of renders then you tie your listener to the INVOKE_APPLICATION phase, etc.
P.D.: I hope you are using some kind of cache or 'batching' technique to log those records to your database, otherwise you will have a noticeable performance impact when too many users are surfing your site. Also, in my own opinion, you should update your JSF version to, at least, 1.2, and you'll avoid some annoying bugs or unexpected behaviour...

Categories

Resources