I have problem with org.omnifaces.util.Faces#redirect and conversation scoped bean:
there is a button
<p:commandButton action="#{navigationHandler.gotoCreateCar}"
actionListener="#{createHandler.init(searchHandler.search())}
value="#{msg.search}" update=":articleSearchForm">
<f:param name="cid" value="#{javax.enterprise.context.conversation.id}"/>
</p:commandButton>
which must do a navigation to createCar page within the same conversation scope after init of my conversation scoped bean: createHandler.
In the NavigationHandler#gotoCreateCar is just a call of Faces.redirect(createCarPage).
If I do like this the parameter cid is not transfered and I lose my conversation.
If I define a navigation rule in faces-config.xml:
<navigation-case>
<from-outcome>createCar</from-outcome>
<to-view-id>/portal/createCar.xhtml</to-view-id>
<redirect />
</navigation-case>
and in the NavigationHandler#gotoCreateCar just return the needed outcome - then it works fine.
Maybe I do not understand every detail in the difference between this two navigation approaches. I would be appreciated if somebody could help me to understand the problem.
Thanks!
The conversation propagation is handled by the navigation handler. The Faces#redirect() delegates to ExternalContext#redirect() which does not use the navigation handler. You'd better use Faces#navigate() instead which delegates to NavigationHandler#handleNavigation().
public void gotoCreateCar() {
// ...
Faces.navigate("/portal/createCar.xhtml?faces-redirect=true");
}
(note: no <navigation-case> is needed in this case)
Alternatively, just return exactly that string from the action method.
public String gotoCreateCar() {
// ...
return "/portal/createCar.xhtml?faces-redirect=true";
}
The Faces#navigate() is only useful when you're inside a (listener) method which doesn't support returning a navigation case outcome, such as #PostConstruct or preRenderView.
Related
What is the difference between action and actionListener, and when should I use action versus actionListener?
actionListener
Use actionListener if you want have a hook before the real business action get executed, e.g. to log it, and/or to set an additional property (by <f:setPropertyActionListener>), and/or to have access to the component which invoked the action (which is available by ActionEvent argument). So, purely for preparing purposes before the real business action gets invoked.
The actionListener method has by default the following signature:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
And it's supposed to be declared as follows, without any method parentheses:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Note that you can't pass additional arguments by EL 2.2. You can however override the ActionEvent argument altogether by passing and specifying custom argument(s). The following examples are valid:
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
Note the importance of the parentheses in the argumentless method expression. If they were absent, JSF would still expect a method with ActionEvent argument.
If you're on EL 2.2+, then you can declare multiple action listener methods via <f:actionListener binding>.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
Note the importance of the parentheses in the binding attribute. If they were absent, EL would confusingly throw a javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean, because the binding attribute is by default interpreted as a value expression, not as a method expression. Adding EL 2.2+ style parentheses transparently turns a value expression into a method expression. See also a.o. Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?
action
Use action if you want to execute a business action and if necessary handle navigation. The action method can (thus, not must) return a String which will be used as navigation case outcome (the target view). A return value of null or void will let it return to the same page and keep the current view scope alive. A return value of an empty string or the same view ID will also return to the same page, but recreate the view scope and thus destroy any currently active view scoped beans and, if applicable, recreate them.
The action method can be any valid MethodExpression, also the ones which uses EL 2.2 arguments such as below:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
With this method:
public void edit(Item item) {
// ...
}
Note that when your action method solely returns a string, then you can also just specify exactly that string in the action attribute. Thus, this is totally clumsy:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
With this senseless method returning a hardcoded string:
public String goToNextpage() {
return "nextpage";
}
Instead, just put that hardcoded string directly in the attribute:
<h:commandLink value="Go to next page" action="nextpage" />
Please note that this in turn indicates a bad design: navigating by POST. This is not user nor SEO friendly. This all is explained in When should I use h:outputLink instead of h:commandLink? and is supposed to be solved as
<h:link value="Go to next page" outcome="nextpage" />
See also How to navigate in JSF? How to make URL reflect current page (and not previous one).
f:ajax listener
Since JSF 2.x there's a third way, the <f:ajax listener>.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
The ajaxListener method has by default the following signature:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
In Mojarra, the AjaxBehaviorEvent argument is optional, below works as good.
public void ajaxListener() {
// ...
}
But in MyFaces, it would throw a MethodNotFoundException. Below works in both JSF implementations when you want to omit the argument.
<h:commandXxx ...>
<f:ajax execute="#form" listener="#{bean.ajaxListener()}" render="#form" />
</h:commandXxx>
Ajax listeners are not really useful on command components. They are more useful on input and select components <h:inputXxx>/<h:selectXxx>. In command components, just stick to action and/or actionListener for clarity and better self-documenting code. Moreover, like actionListener, the f:ajax listener does not support returning a navigation outcome.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="#form" render="#form" />
</h:commandXxx>
For explanation on execute and render attributes, head to Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes.
Invocation order
The actionListeners are always invoked before the action in the same order as they are been declared in the view and attached to the component. The f:ajax listener is always invoked before any action listener. So, the following example:
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
Will invoke the methods in the following order:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Exception handling
The actionListener supports a special exception: AbortProcessingException. If this exception is thrown from an actionListener method, then JSF will skip any remaining action listeners and the action method and proceed to render response directly. You won't see an error/exception page, JSF will however log it. This will also implicitly be done whenever any other exception is being thrown from an actionListener. So, if you intend to block the page by an error page as result of a business exception, then you should definitely be performing the job in the action method.
If the sole reason to use an actionListener is to have a void method returning to the same page, then that's a bad one. The action methods can perfectly also return void, on the contrary to what some IDEs let you believe via EL validation. Note that the PrimeFaces showcase examples are littered with this kind of actionListeners over all place. This is indeed wrong. Don't use this as an excuse to also do that yourself.
In ajax requests, however, a special exception handler is needed. This is regardless of whether you use listener attribute of <f:ajax> or not. For explanation and an example, head to Exception handling in JSF ajax requests.
As BalusC indicated, the actionListener by default swallows exceptions, but in JSF 2.0 there is a little more to this. Namely, it doesn't just swallows and logs, but actually publishes the exception.
This happens through a call like this:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
The default listener for this event is the ExceptionHandler which for Mojarra is set to com.sun.faces.context.ExceptionHandlerImpl. This implementation will basically rethrow any exception, except when it concerns an AbortProcessingException, which is logged. ActionListeners wrap the exception that is thrown by the client code in such an AbortProcessingException which explains why these are always logged.
This ExceptionHandler can be replaced however in faces-config.xml with a custom implementation:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Instead of listening globally, a single bean can also listen to these events. The following is a proof of concept of this:
#ManagedBean
#RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
#Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(note, this is not how one should normally code listeners, this is only for demonstration purposes!)
Calling this from a Facelet like this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Will result in an error page being displayed.
ActionListener gets fired first, with an option to modify the response, before Action gets called and determines the location of the next page.
If you have multiple buttons on the same page which should go to the same place but do slightly different things, you can use the same Action for each button, but use a different ActionListener to handle slightly different functionality.
Here is a link that describes the relationship:
http://www.java-samples.com/showtutorial.php?tutorialid=605
TL;DR:
The ActionListeners (there can be multiple) execute in the order they were registered BEFORE the action
Long Answer:
A business action typically invokes an EJB service and if necessary also sets the final result and/or navigates to a different view
if that is not what you are doing an actionListener is more appropriate i.e. for when the user interacts with the components, such as h:commandButton or h:link they can be handled by passing the name of the managed bean method in actionListener attribute of a UI Component or to implement an ActionListener interface and pass the implementation class name to actionListener attribute of a UI Component.
i am new in JSF.I wonder one point at JSF/navigation rules.i have four pages, index,p1,p2,p3.When i am trying to navigate to a page with action="#{bean.gotoP1()}", it is giving error like that ;
"Unable to find matching navigation case with from-view-id '/index.xhtml' for action '#{bean.gotoP1()}' with outcome 'success'"
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
My codes are below;
index.xhtml
<h:body>
<h:form>
<h:commandButton action="#{mybean.gotoP1()}" value="P1"/>
<h:commandButton action="#{mybean.gotoP2()}" value="P2"/>
<h:commandButton action="#{mybean.gotoP3()}" value="P3"/>
</h:form>
</h:body>
mybean.java
#ManagedBean
#RequestScoped
public class Mybean implements Serializable{
private static final long serialVersionUID=1L;
public Mybean() {
}
public String gotoP1(){
return "success";
}
public String gotoP2(){
return "success";
}
public String gotoP3(){
return "positive";
}
}
faces-config.xml
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{mybean.gotoP1}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p1.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP2}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p2.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP3}</from-action>
<from-outcome>positive</from-outcome>
<to-view-id>/p3.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
Thanks....
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
Because the EL syntax doesn't match with the navigation case. You defined #{bean.gotoP1} instead of #{bean.gotoP1()} as from-action in navigation case. Simple as that.
Those argumentless parentheses are actually unnecessary. They started to spread over JSF pages since introduction of EL 2.2, because the average EL 2.2 aware IDE thinks to be smarter than it is and unnecessarily auto-completes the method expressions with parentheses and all, confusingly making the JSF starter to think that they are actually required. I've even seen code snippets coming along from starters who actually used #{bean.getProperty()} instead of #{bean.property} to output a property, which would then later fail with a javax.el.PropertyNotWritableException when used in an input component.
Just leave out those argumentless parentheses. It's not true that this syntax is required and "normal" in JSF. Moreover, navigation rules are very JSF 1.x-ish. Also, performing navigation using POST requests is very JSF 1.x-ish. Maybe you're just learning and playing around. That's OK, but to learn about the right ways and a bit of history, carefully read below links:
Invoke direct methods or methods with arguments / variables / parameters in EL
Differences between action and actionListener
JSF implicit vs. explicit navigation
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between JSP EL, JSF EL and Unified EL
Last but not least, our JSF wiki page is a great place to start.
i am new in JSF.I wonder one point at JSF/navigation rules.i have four pages, index,p1,p2,p3.When i am trying to navigate to a page with action="#{bean.gotoP1()}", it is giving error like that ;
"Unable to find matching navigation case with from-view-id '/index.xhtml' for action '#{bean.gotoP1()}' with outcome 'success'"
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
My codes are below;
index.xhtml
<h:body>
<h:form>
<h:commandButton action="#{mybean.gotoP1()}" value="P1"/>
<h:commandButton action="#{mybean.gotoP2()}" value="P2"/>
<h:commandButton action="#{mybean.gotoP3()}" value="P3"/>
</h:form>
</h:body>
mybean.java
#ManagedBean
#RequestScoped
public class Mybean implements Serializable{
private static final long serialVersionUID=1L;
public Mybean() {
}
public String gotoP1(){
return "success";
}
public String gotoP2(){
return "success";
}
public String gotoP3(){
return "positive";
}
}
faces-config.xml
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{mybean.gotoP1}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p1.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP2}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p2.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP3}</from-action>
<from-outcome>positive</from-outcome>
<to-view-id>/p3.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
Thanks....
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
Because the EL syntax doesn't match with the navigation case. You defined #{bean.gotoP1} instead of #{bean.gotoP1()} as from-action in navigation case. Simple as that.
Those argumentless parentheses are actually unnecessary. They started to spread over JSF pages since introduction of EL 2.2, because the average EL 2.2 aware IDE thinks to be smarter than it is and unnecessarily auto-completes the method expressions with parentheses and all, confusingly making the JSF starter to think that they are actually required. I've even seen code snippets coming along from starters who actually used #{bean.getProperty()} instead of #{bean.property} to output a property, which would then later fail with a javax.el.PropertyNotWritableException when used in an input component.
Just leave out those argumentless parentheses. It's not true that this syntax is required and "normal" in JSF. Moreover, navigation rules are very JSF 1.x-ish. Also, performing navigation using POST requests is very JSF 1.x-ish. Maybe you're just learning and playing around. That's OK, but to learn about the right ways and a bit of history, carefully read below links:
Invoke direct methods or methods with arguments / variables / parameters in EL
Differences between action and actionListener
JSF implicit vs. explicit navigation
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between JSP EL, JSF EL and Unified EL
Last but not least, our JSF wiki page is a great place to start.
I'working on a enterprise application that uses JSF 2.0, with Netbeans 7.0 and Glassfish 3.1
I have a managed bean that is ViewScoped. this is the declaration of the class:
#ManagedBean(name = "myBean")
#ViewScoped
public class MyMBean implements Serializable {
Inside its #PostConstruct, it has the following:
String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
if (id == null) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("home.xhtml");
FacesContext.getCurrentInstance().responseComplete();
} catch (Exception e) { }
return;
}
if I go to the page that uses this managed bean, and the id is null, everything works fine, and I get redirected to home page.
The problem is that when I navigate to a different page that does NOT use this managed bean (lets say for example "otherpage.xhtml") the PostConstruct method is executed, and it shouldn't! And it gets worse: since the url of this other page doesn't have the "id" parameter, the bean tries to redirect to home page; and I get a IllegalStateException.
Any idea of why a viewscoped managed bean is constructed when navigating to a page that does not use it?
Edit:
If in order to navigate to "otherpage.xhtml" I use the commandlink in "home.xhtml", 6 extra beans are created.
But, if instead of using the link, I type the url in the browser; it works fine. No extra bean is created. Maybe there's something wrong in how I implemented the link. This is the code:
<h:form>
<h:commandLink value="Go to other page" action="otherPage" />
</h:form>
And this is the navigation rule in faces-config:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>otherPage</from-outcome>
<to-view-id>/views/otherPage.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
Is there anything wrong there?
Thanks!
Damian
You surely have a #{myBean} somewhere in the view or one of its templates/include/tag/composite files, or as a #ManagedProperty of the beans referenced by the view. Putting a breakpoint in the (post)constructor and investigating the stacktrace should give enough insights who/what has triggered the bean's construction.
Unrelated to the concrete problem, the ExternalContext#redirect() already implicitly calls FacesContext#responseComplete(), you don't need to call it yourself. See also the method's javadoc.
Update: a <h:commandLink> submits its parent POST <form> to the current page (and thus creates all its related beans!) and then depending on the navigation outcome, it will forward/redirect to the result page. You shouldn't be using commandlinks/commandbuttons for plain page-to-page navigation. Use <h:link> instead.
<h:link value="Go to other page" outcome="views/otherPage" />
You can eventually also get rid of that <navigation-case>. If you really insist in keeping that navigation case, then use outcome="otherPage" instead.
See also:
When should I use h:outputLink instead of h:commandLink?
Communication in JSF 2.0 - Implicit navigation
Can someone tell me how to catch parameters passed from URI in JSF's managed bean?
I have a navigation menu all nodes of which link to some navigation case. And i have two similar items there: Acquiring products and Issuing products. They have the same page but one different parameter: productType. I try to set it just by adding it to URL in "to-view-id" element like this:
<navigation-case>
<from-outcome>acquiring|products</from-outcome>
<to-view-id>/pages/products/list_products.jspx?productType=acquiring</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>issuing|products</from-outcome>
<to-view-id>/pages/products/list_products.jspx?productType=issuing</to-view-id>
</navigation-case>
But i can't get this "productType" from my managed bean. I tried to get it through FacesContext like this:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("productType")
And like this:
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getParameter("productType");
And i tried to include it as a parameter of managed bean in faces-config.xml and then getting it through ordinary setter:
<managed-bean>
<managed-bean-name>MbProducts</managed-bean-name>
<managed-bean-class>my.package.product.MbProducts</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>productType</property-name>
<value>#{param.productType}</value>
</managed-property>
</managed-bean>
...
public class MbProducts {
...
public void setProductType(String productType) {
this.productType = productType;
}
...
}
But neither of these ways have helped me. All of them returned null. How can i get this productType? Or how can i pass it some other way?
The navigation rule by default does a forward. I.e. it reuses the initial request. Whatever way you try to access the request parameters in the forwarded resource, it will always try to grab them from the initial and already-processed request.
To fix this, you need to fire a redirect instead of forward. It creates a brand new request (you also see this reflecting back in the browser address bar).
In JSF, adding
<redirect/>
to the navigation case should do.