In my app, before upgrading to jsf 2, when doing a custom redirect I used to manually put a request parameter with a specific value in external context like this:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()
.put(CmwNavigationControllerBean.PARAM_DISPLAY_TARGET_POPUP, "true");
Now this line, throws an exception because it seems that this map is no longer allowed to be modified:
at java.util.Collections$UnmodifiableMap.put(Unknown Source) [rt.jar:1.7.0]
Isn't really no other way to bypass this exception? I'm doing refactoring because of upgrade and I try to keep the changes at minimal level.
You can either use a view parameter or use the flash scope for that. A view parameter is in practice a GET parameter which you can pass when you request the page you want to redirect to. For your case, you should redirect to it with the parameter appended.
Return the navigation case with the parameter appended:
//Will be reflected in browser's address bar as /context/myDestinationView.xhtml?displayTargetPopUp=true
return "myDestinationView?displayTargetPopUp=true&faces-redirect=true&includeViewParams=true";
Catch it from your destination view:
<f:viewParam name="displayTargetPopUp" value="#{displayTargetPopUp}" />
Another way if you want to avoid including it in your GET request, is to use flash scope, which is supposed to be fixed for Mojarra 2.1.27 and 2.2.5 versions. Flash scoped values are designed to support a redirection, while the request ones are not.
See also:
Understand Flash Scope in JSF2
How do you pass view parameters when navigating from an action in JSF2?
Rather than getRequestParameterMap() (which is read-only) you should invoke getRequestMap() on the ExternalContext.
For example:
FacesContext.getCurrentInstance()
.getExternalContext()
.getRequestMap()
.put(CmwNavigationControllerBean.PARAM_DISPLAY_TARGET_POPUP, "true");
Related
My problem is that when I am trying to redirect my users to another URL in the #ActionMapping phase spring tries to set the render parameters after the redirect. This causes the following error to always appear in my logs:
"Cannot set renderparameter after sendredirect"
I have found that in previous, deprecated versions of the controller classes you had the possibility to use "setRedirectAction" to a boolean value to be able to decide if you should set the render parameter or not.
I am now wondering how you can set this parameter in an annotade controller to be able to get rid of the problem above.
I have solved the issue. The problem was that we where redirecting to another URL outside the Scope of the portlet. But before that was done spring was trying to handle the org.springframework.ui.ModelMap and then it tryed to modify renderparameters.
I cleared the modelMap using the "clear" method and then spring had no modelmap to handle so therefore the error message dissappeared.
I'm trying to develop a basic portlet with LifeRay 6.1. I'm well versed with various MVC implementations, but I find Liferay / java portlets somewhat confusing - especially the execution pipeline.
With most MVC frameworks I've worked with the premise is simple request > router > controller > view. The view selection is usually based the controller / action naming convention, a parameter passed in with the request or is manually loaded in the controller action.
With LifeRay MVCPortlet it doesn't work like this; there's at least two types of URL that can be generated - a render url and an action url.
The render URL seems to totally bypass what I perceive to be the controller - a subclass of MVCPortlet. It seems as though these urls are relatively easy to generate and the request loads the expected view, if you can call it that considering for all intents and purposes it completely bypasses the controller and has nothing to do with a model.
<portlet:renderURL var="badminURL"><portlet:param name="mvcPath" value="/views/edit.jsp" /></portlet:renderURL>
The action URL goes through the controller, the action is called and then the default view is used to render the portlet regardless of what I supply as an mvc path.
<portlet:actionURL var="adminURL" name="editSlide"><portlet:param name="mvcPath" value="/views/edit.jsp" /></portlet:actionURL>
Reading up through the class tree I can see that a property is used to define the view that gets used depending on the portlet mode. i.e.
this.viewTemplate = "/views/edit.jsp";
this.editTemplate = "/views/edit.jsp";
Again setting this after init() is called only seems to have any effect when not accessed via an actionURL.
So I guess my question is pretty basic, how are views selected and how to I select one to use when going via an actionURL. Also any outline on execution pipeline would be very helpful
I found the solution. You can allocate a render parameter on the ActionResponse object that is passed to the controller action. This tells liferay to load the supplied view. i.e.
public void editSlide(ActionRequest actionRequest, ActionResponse actionResponse) throws IOException, PortletException {
// action code goes here
// set up the view
actionResponse.setRenderParameter("mvcPath", "/views/edit.jsp");
}
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...
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);
}
I am using Stripes but i'm not sure if this problem is because of that. I have an actionBean with a setter method setSearchView. In this setter, I set a cookie. The problem I'm seeing is that if i call that method from my jsp, the cookie does not get set (i have debugged the code and it does go through the code). If i call the same setSearchView from an action handler, the cookie is set.
Is there something I'm missing? Is this a Stripes thing or a jsp/javabean thing?
I think you are misunderstanding the programming model, I'm guessing you are coming from a CGI/Php background.
Setters/getters on Stripes action beans are used to allow the ActionBean to receive the request parameters (URL parameters in the case of GET requests, form parameters in the case of POST requests) from the browser.
You wouldn't set them manually from JSPs because you wouldn't be putting controller logic in the JSPs but in the ActionBean.
The JSP will only be used to display ('View') any data provided by the controller from the model/view-model and to display input elements to allow the user to provide input. (See MVC on Wikipedia)