Not able to put url and actionListener together - jsf

I am new to JSF and UI.
I want that when I click on submenu my business logic should execute and after that my page get renders. I tried below snippet but its not working, page is getting rendered but actionListener is not getting executed. when I remove the url part, the actionListener is working but now I am stuck like how to render the page.
<ace:menuItem id="RedactionCapture" value="Redaction"
actionListener="#{redactionController.getRedactionList}"
url="#{firmUtility.legalHoldCreationOrRemovalUrl}"
style="width:220px" styleClass="dropdownmenu"
target="imagepgframe">
</ace:menuItem>

That is expected behavior. An actionListener is a listener for an action and not for a URL. You could create an action which does a redirect to the URL in combination with the listener or do all the work in the action. Please note that this not only the case in IceFaces, but also in PrimeFaces.
For example (with a listener), XHTML:
<ace:menuItem action="#{yourBean.redirect(firmUtility.legalHoldCreationOrRemovalUrl)}"
actionListener="#{redactionController.getRedactionList}"
... />
Bean:
public void redirect(String url) throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.redirect(url);
}
See also:
Redirect to external URL in JSF
Differences between action and actionListener

Related

How do I get JSF to redirect to the default 401 page from within a managed bean? [duplicate]

In a JSF managed bean constructor, I load a entity from database usint a request parameter. Some times, the entity is not in database and I want to show other JSF (.xhtml) page with 404 message.
This is a sample of managed bean:
#ManagedBean(name = "someBean")
#RequestScoped
public class SomeBean implements Serializable {
private static final long serialVersionUID = 1L;
private SomeData someData;
public SomeBean() throws IOException {
someData = ... loads from database using JPA features
if(someData == null){
HttpServletResponse response = (HttpServletResponse) FacesContext
.getCurrentInstance().getExternalContext().getResponse();
response.sendError(404);
}
}
public SomeData getSomeData(){
return someData;
}
}
I configured the web.xml file something like that:
<error-page>
<error-code>404</error-code>
<location>/404.xhtml</location>
</error-page>
I have a JSF page to handle the entity loaded by managed bean. When the entity exists, I will use it in the page. Like that:
<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
The page above works when the managed loads the data successfully.
The Problem
When the entity not exists and I send a 404 ERROR CODE, the JSF still process methods defined in the expression language of the first page.
This behavior makes the managed bean throws a NullPointerException, and a HTTP 500 ERRO CODE.
My 404 error page is not called. I do not know why.
I try send the 404 error even when the entity is found in database and the 404 error page works.
Enyone can explain this JSF behavior to this happiness? Or offer some kind to show the 404 error page without URL change ?
You're basically trying to perform front controller logic while rendering the view. You should do it before rendering the view. Because, once you start rendering the view, it's already too late to change the view to a different destination, e.g. an error page as in your case. You namely cannot take the already sent response back from the client.
In JSF 2.2 you can use <f:viewAction> for this.
<f:metadata>
<f:viewAction action="#{bean.init}" />
</f:metadata>
public void init() {
// ...
if (someCondition) {
context.getExternalContext().responseSendError(404, "some message");
context.responseComplete();
}
}
(note that whenever you need to import javax.servlet.* classes into your JSF backing bean, you should absolutely stop and look if the functionality isn't already available in ExternalContext or otherwise think twice if you're doing things the right way, e.g. perhaps you needed a servlet filter; also note that you need to explicitly tell JSF that you've completed the response, otherwise it will still attempt to render the view)
In JSF 2.0/2.1 you can use <f:event type="preRenderView"> for this. See also among others What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
In case you're actually trying to validate a HTTP request parameter and you also happen to use OmniFaces, you may consider using <f:viewParam> with a true JSF validator and control the sendError with OmniFaces <o:viewParamValidationFailed>.

JSF calls methods when managed bean constructor sends 404 ERROR CODE

In a JSF managed bean constructor, I load a entity from database usint a request parameter. Some times, the entity is not in database and I want to show other JSF (.xhtml) page with 404 message.
This is a sample of managed bean:
#ManagedBean(name = "someBean")
#RequestScoped
public class SomeBean implements Serializable {
private static final long serialVersionUID = 1L;
private SomeData someData;
public SomeBean() throws IOException {
someData = ... loads from database using JPA features
if(someData == null){
HttpServletResponse response = (HttpServletResponse) FacesContext
.getCurrentInstance().getExternalContext().getResponse();
response.sendError(404);
}
}
public SomeData getSomeData(){
return someData;
}
}
I configured the web.xml file something like that:
<error-page>
<error-code>404</error-code>
<location>/404.xhtml</location>
</error-page>
I have a JSF page to handle the entity loaded by managed bean. When the entity exists, I will use it in the page. Like that:
<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
The page above works when the managed loads the data successfully.
The Problem
When the entity not exists and I send a 404 ERROR CODE, the JSF still process methods defined in the expression language of the first page.
This behavior makes the managed bean throws a NullPointerException, and a HTTP 500 ERRO CODE.
My 404 error page is not called. I do not know why.
I try send the 404 error even when the entity is found in database and the 404 error page works.
Enyone can explain this JSF behavior to this happiness? Or offer some kind to show the 404 error page without URL change ?
You're basically trying to perform front controller logic while rendering the view. You should do it before rendering the view. Because, once you start rendering the view, it's already too late to change the view to a different destination, e.g. an error page as in your case. You namely cannot take the already sent response back from the client.
In JSF 2.2 you can use <f:viewAction> for this.
<f:metadata>
<f:viewAction action="#{bean.init}" />
</f:metadata>
public void init() {
// ...
if (someCondition) {
context.getExternalContext().responseSendError(404, "some message");
context.responseComplete();
}
}
(note that whenever you need to import javax.servlet.* classes into your JSF backing bean, you should absolutely stop and look if the functionality isn't already available in ExternalContext or otherwise think twice if you're doing things the right way, e.g. perhaps you needed a servlet filter; also note that you need to explicitly tell JSF that you've completed the response, otherwise it will still attempt to render the view)
In JSF 2.0/2.1 you can use <f:event type="preRenderView"> for this. See also among others What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
In case you're actually trying to validate a HTTP request parameter and you also happen to use OmniFaces, you may consider using <f:viewParam> with a true JSF validator and control the sendError with OmniFaces <o:viewParamValidationFailed>.

Why jsf life cycle skips render response after Invoke application when redirect the page?

I have two scenario
I have two actions which have logic in bean like
My buttons
<h:commandButton value="Submit" action="#{bean.test}" />
<h:commandButton value="Submit" action="#{bean.testOne}" />
This are the two commnadButtons and there logic in bean
public void test() {
log.info("I m in test");
}
public void testOne() {
log.info("I m in testOne");
try {
FacesContext.getCurrentInstance()
.addMessage("", new FacesMessage("Record Saved successfully."));
FacesContext
.getCurrentInstance()
.getExternalContext()
.redirect(
FacesContext.getCurrentInstance()
.getExternalContext().getRequestContextPath()
+ "/cycle/page");
} catch (IOException e) {
log.error(e.getMessage());
}
}
When I am going to click on 1st button (test action) that time jsf life cycle goes to every phase like restore view Apply request valuesProcess validationupdate modelsinvoke applicationrender response
But when I click on testOne button that time jsf life cycle skip render response after invoke application like restore view Apply request valuesProcess validationupdate modelsinvoke applicationrestore viewrender response
In simple language When I am navigate the page through facesContext that time jsf skips that phase.
But why this happens? I am not getting the problem.
According to the JSF docs, that's what the INVOKE_APPLICATION phase does:
During this phase, the JavaServer Faces implementation handles any application-level events, such as submitting a form or linking to another page.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call the FacesContext.responseComplete method.
If the view being processed was reconstructed from state information from a previous request and if a component has fired an event, these events are broadcast to interested listeners.
Finally, the JavaServer Faces implementation transfers control to the Render Response phase.
What you're doing is calling FacesContext#getCurrentInstance#getExternalContext#redirect in this phase, which performs your redirection. This method triggers FacesContext#getCurrentInstance#responseComplete, which ends the JSF lifecycle. The redirection is performed to a JSF view, so a new cycle starts after that.
Apart from that and unrelated to the concrete issue, do not perform redirections like that if you want to redirect to an internal JSF view. Just return the navigation case + ?faces-redirect=true in your action method (i.e. /cycle/page?faces-redirect=true). Use the external context only if you want to access external urls.
See also:
JSF INVOKE_APPLICATION
Redirection in JSF

further continuing of double press

In a previous question BalusC gave me good advice on how a button, in place of a commandButton is useful for non ajax navigation. In particular it updates the destination address in the http: position which is useful for the user to bookmark a page.
I tried to use this information to my advantage until I came upon a problem. In a button I tried to use outcome="#{backing.something}" to find out that it gives me a null result. This looks like a timing problem in that action="#{}" is evaluated only when the button is pressed whereas outcome apparently wants a fixed string which gets checked when the page is loaded.
So I went back to commandButton with ajax="false". This has a problem that my navigation address is the page I came from, not the one I am navigating to. This is the wrong bookmark for the user.
I appreciate all the help I have received in stackoverflow on my learning exercise.
Ilan
The <h/p:button outcome> is not intented to invoke a bean action method, but to contain the outcome string directly. Any EL in there is evaluated immediately as a value expression. So the method behind it would immediately be invoked when you just open the page containing the <h/p:button>.
There are in your particular case basically two ways to invoke a bean action method on navigation. If you need to invoke it before the navigation takes place and the action isn't intented to be re-invoked everytime when the enduser reopens/reloads the GET request, then make it a POST-Redirect-GET request. It's a matter of adding faces-redirect=true to the outcome value in query string syntax.
E.g.
<p:commandButton action="#{bean.submit}" ... />
with
public String submit() {
// ...
return "nextpage?faces-redirect=true";
}
This way the browser will be redirected to the target page after POST, hence the enduser will see the target URL being reflected in the address bar.
Or if you need to invoke the action everytime when the enduser reopens/reloads the GET request, do the job in the (post)constructor or preRenderView listener method of the request/view scoped backing bean instead.
E.g.
<p:button outcome="nextpage" ... />
with
#ManagedBean
#RequestScoped
public class NextpageBacking {
public NextpageBacking() {
// In constructor.
}
#PostConstruct
public void onPostConstruct() {
// Or in postconstructor (will be invoked after construction AND injection).
}
public void onPreRenderView() {
// Or before rendering the view (will be invoked after all view params are set).
}
// ...
}
The pre render view listener method needs to be definied as follows in the nextpage
<f:event type="preRenderView" listener="#{nextpageBacking.onPreRenderView}" />
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters

Redirecting to an external URL in a new tab and performing an action in backing bean at the same time

I'm working at a jsf application that at a certain time need to open an external page in a new tab, leaving the first page active. I need to find a way to make the application perform, in a single button click:
a redirect to an external URL in a new tab
an action which disables the button itself in the original page
I've tried using an <outputLink /> but it has no action attribute.
I've tried using a <commandLink />but it's unable to redirect outside.
I've also tried a <commandLink /> with target="_blank" and a redirection coded in the backing bean:
<h:commandLink onclick="submit();" target="_blank" action="#{myBean.execute}" disabled="#{myBean.linkDisabled}" value="external link" />
and, in the backing bean:
public String execute() {
linkDisabled = true;
try{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.redirect(Constants.EXTERNAL_URL);
} catch(Exception e){
throw new FacesException("Redirection failed");
}
return THIS_PAGE;
}
A page is opened in a new tab but it's the current page instead of the that with URL Constants.EXTERNAL_URLand the button is still enabled. No error message is shown. Any suggestion?
Thanks in advance, Andrea
Your question is confusing. You're mixing "link" and "button". You basically need to disable the element in the client side by JavaScript because the response does not return to the current browser window/tab, but to a different browser window/tab. In JavaScript, it's easy to disable a button, but not a link. For simplicity, I'll assume that you mean and can use a <h:commandButton> and that this is the only button in the current form.
To solve your problem, you need to remove onclick="submit()" (because it's disturbing the default behaviour) and you need to remove the navigation outcome (it should not matter, but you never know in some JSF impls) and you need to disable the button by JS in the client side.
All with all your code should look just like this:
<h:form target="_blank">
<h:commandButton
value="external"
action="#{myBean.execute}"
onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" />
</h:form>
And
public void execute() throws IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect(Constants.EXTERNAL_URL);
}
The setTimeout() is necessary because the button is otherwise disabled before the form data is sent which would cause that the button's own name=value pair won't be sent as request parameter and so JSF won't invoke any action.
why don't you use action="someaction" and map it in faces-config.xml to go to another page?

Resources