Primefaces 6.1 ajaxExceptionHandler is not working as expected in liferay 7 portlet.
Based on the Primefaces user guide, I tried to implement simple exception handling. When the commandButton is pressed, the backing bean throws a NullPointerException, which should be displayed in a dialog window. The problem is, when the dialog pops up, the exception information is not shown. It seems that the returned ajax response itself contains the exception info (as shown below), but the dialog component is not updated accordingly.
test.xhtml (snippet)
<h:body>
<h:form>
<h3 style="margin-top:0">AJAX 1410</h3>
<p:commandButton actionListener="#{policyAdminBean.throwNpe}"
ajax="true"
value="Throw NullPointerException!" />
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException"
update=":exceptionDialog"
onexception="PF('exceptionDialogVar').show();" />
<p:ajaxExceptionHandler type="java.lang.NullPointerException"
update=":exceptionDialog"
onexception="PF('exceptionDialogVar').show();" />
</h:form>
<p:dialog id="exceptionDialog" header="Exception '#{pfExceptionHandler.type}' occured!" widgetVar="exceptionDialogVar"
height="500px">
Message: #{pfExceptionHandler.message} <br/>
StackTrace: <h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" /> <br />
<p:button onclick="document.location.href = document.location.href;"
value="Reload!"
rendered="#{pfExceptionHandler.type == 'javax.faces.application.ViewExpiredException'}" />
</p:dialog>
</h:body>
TestBean.java
#Named
#ViewScoped
public class TestBean implements Serializable {
private static final long serialVersionUID = -4856350663999482370L;
public void throwNpe(){
throw new NullPointerException("test exception");
}
}
faces-config.xml (snippet)
<application>
<message-bundle>Language</message-bundle>
<locale-config>
<default-locale>hu</default-locale>
</locale-config>
<el-resolver>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver
</el-resolver>
</application>
<lifecycle>
<phase-listener>com.liferay.faces.util.lifecycle.DebugPhaseListener</phase-listener>
</lifecycle>
<factory>
<exception-handler-factory>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory
</exception-handler-factory>
</factory>
ajax response (snippet)
<partial-response id="_policyadmin_WAR_wfsadminportlets_">
<update id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog"><![CDATA[
<div id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog"
class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-shadow ui-hidden-container">
<div class="ui-dialog-titlebar ui-widget-header ui-helper-clearfix ui-corner-top"><span
id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog_title" class="ui-dialog-title">Exception 'java.lang.NullPointerException' occured!</span><a
href="#" class="ui-dialog-titlebar-icon ui-dialog-titlebar-close ui-corner-all"
aria-label="Close"><span class="ui-icon ui-icon-closethick"></span></a></div>
<div class="ui-dialog-content ui-widget-content">
Message: test exception <br/>
StackTrace: java.lang.NullPointerException: test exception<br/> at
[removed for brevity...]
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)<br/> at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)<br/> at
java.lang.Thread.run(Thread.java:745)<br/> <br/></div>
</div>
<script id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog_s" type="text/javascript">$(function () {
PrimeFaces.cw("Dialog", "exceptionDialogVar", {
id: "_policyadmin_WAR_wfsadminportlets_:exceptionDialog",
height: "500px"
});
});</script>
]]>
</update>
<eval><![CDATA[var
hf=function(type,message,timestampp){PF('exceptionDialogVar').show();};hf.call(this,"java.lang.NullPointerException","test
exception","2017-04-25 14:54:55");]]>
</eval>
</partial-response>
Good question!
This pattern of use for the PrimeFaces AJAX exception handler was working in PrimeFaces before version 6.0. So if you revert to say, PrimeFaces 5.3, you will see it working on Liferay 7. The commit that broke PrimeFaces was e22e40a, which was a complex commit, unknowingly affecting portlets by changing the way the PrimeFaces partial responses are constructed.
A pull request has been sent to the PrimeFaces integrators to fix this.
https://github.com/primefaces/primefaces/pull/2333
Once this pull request is merged, you can build PrimeFaces from the latest source, and you will see that this is fixed.
DETAILS:
Specifically, commit e22e40a changed the PrimePartialResponseWriter.startDocument() method, eliminating its call to encodeCallbackParams() which, in turn, was calling the startChangesIfNecessary() method in mojarra. Since these calls were eliminated, no "changes" element was introduced into the partial response. With no changes, no update occurs in the dialog's DOM. Here is a working stack showing the calls down into startChangesIfNecessary before the e22e40a commit.
Related
I am trying to mimic the PrimeFaces Dialog example. For some reason that I am not able to find, my PrimeFaces button does not seem to call the required managed bean method:
<h:form>
<p:commandButton value="Open" icon="ui-icon-extlink" actionListener="#{myController.createDialog()}" />
</h:form>
Managed bean:
#Named(value = "myController")
#ViewScoped
public class MyController implements Serializable {
public void createDialog() {
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%");
...
The print statement is never executed, like if the Listener was not working. When I click the button, no response is given. No backend error, no JS error, nothing. I only see that some request is done because I log when a user passes the authorization layer. So something happens but seems to fail silently.
What I have tried:
Move the button to other places in the page
Use an id:
<p:commandButton id="ex" value="Open" icon="ui-icon-extlink" actionListener="#{myController.createDialog()}" />
<h:message for="ex" />
Remove the ViewScoped
Require a javax.faces.event.ActionEvent in the method
public void createDialog(ActionEvent event) {
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%");
Change the method signature
action="#{myController.createDialog(5)}"
and
public void createDialog(int s) {
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%");
I even tried to create a WEB-INF/faces-config.xml (which I would prefer not to, and according to PrimeFaces documentation I do not need it) with:
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<application>
<action-listener>org.primefaces.application.DialogActionListener</action-listener>
<navigation-handler>org.primefaces.application.DialogNavigationHandler</navigation-handler>
<view-handler>org.primefaces.application.DialogViewHandler</view-handler>
</application>
<lifecycle>
<phase-listener>org.primefaces.component.lifecycle.LifecyclePhaseListener</phase-listener>
</lifecycle>
Other answers I have checked are: 1, 2, 3, 4, 5, 6
Apparently the use of actionListeners in PrimeFaces is not as correct as it should be... Is there another way to use PrimeFaces components?
This Dialog Framework code works for me:
index.xhtml
<p:commandButton id="openDialogButton" value="open dialog" action="#{myBean.openDialog('origin')}">
<!-- dialogReturn event: data could be passed, see page 587 in PF 6.1 manual. -->
<p:ajax event="dialogReturn" listener="#{myBean.doSthOnDialogReturn}"/>
</p:commandButton>
myDialogPage.xhtml
<p:commandButton id="closeButtonDialog" value="close dialog"
action="#{myBean.closeDialog('false')}"/>
<p:commandButton id="closeButtonDialog2" value="close dialog 2"
action="#{myBean.closeDialog('true')}"
ajax="false" validateClient="true"/>
Note: Example shows how to pass parameter from dialog. You can also notice, that the first button does just return while the second one does validation at first. I think these things can be useful.
myBean.java
public void openDialog(String origin) {
RequestContext.getCurrentInstance().openDialog("myDialogPage",
options, null);
}
public void closeDialog(Boolean param) {
RequestContext.getCurrentInstance().closeDialog(param);
}
public void doSthOnDialogReturn(SelectEvent event) {
if ((Boolean) event.getObject()) { // retrieve param value
doSth();
}
}
WEB-INF/faces-config.xml
<application>
<action-listener>
org.primefaces.application.DialogActionListener
</action-listener>
<navigation-handler>
org.primefaces.application.DialogNavigationHandler
</navigation-handler>
<view-handler>
org.primefaces.application.DialogViewHandler
</view-handler>
</application>
Finally I got to see some error:
SEVERE - /page.xhtml #159,146 actionListener="#{myController.createDialog()}": Target Unreachable, identifier 'myController' resolved to null
The trick to enable the display of error messages was to add the following in faces-config.xml:
<factory>
<exception-handler-factory>org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory</exception-handler-factory>
</factory>
After checking this, I realised that my beans.xml file had been somehow deleted (??)
I've been reading and searching among the many pages with similar questions, but I cannot find why my commandButton is not invoking the action (I have debugged it and that is the problem). My code looks simple but... doesn't work. Maybe it's a newbie problem, but I don't know where it is.
I'm writing a portlet for liferay using JSF2 and Liferay Faces Alloy.
I've also read the question commandLink/commandButton/ajax backing bean action/listener method not invoked, very educational for me, but none of the points have solved my problem.
Here is my mainView.xhtml file:
<?xml version="1.0"?>
<f:view
xmlns="http://www.w3.org/1999/xhtml"
xmlns:aui="http://liferay.com/faces/aui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<h:messages globalOnly="true" layout="table" />
<h:outputText id="esteTexto" value="#{ramSession.texto}" />
<br />
<h:commandButton action="#{ramSession.add}" styleClass="btn btn-default" value="#{ramSession.texto}">
</h:commandButton>
</h:form>
</h:body>
</f:view>
And here is my SessionScoped ManagedBean file, RamSession.java:
#ManagedBean
#SessionScoped
public class RamSession extends AbstractBaseBean implements Serializable {
private static final long serialVersionUID = 919724848720360000L;
private String texto;
public void add() {
this.texto = new String("Entrando");
}
#PostConstruct
public void postConstruct() {
this.texto = new String("Jereje");
}
public String getTexto() {
logger.info("gettingTexto");
addGlobalSuccessInfoMessage();
return this.texto;
}
public void setTexto(String texto) {
this.texto = texto;
}
}
I have also tried returning a String (even not necessary), with an actionListener method and even with ajax but nothing. Can anybody help me? Thanks a lot.
Maybe your mojarra listner is not configured correctly.
Follow one of the two following sub-steps
a. Add the liferay-faces-init.jar dependency in each Liferay JSF project by adding the following code to each pom.xml :
<dependency>
<groupId>com.liferay.faces</groupId>
<artifactId>liferay-faces-init</artifactId>
<version>3.1.3-ga4</version>
</dependency>
b. Add the following code in each WEB-INF/web.xml of all your JSF projects :
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
Why not initialize texto in the declaration?
private String texto = "Jereje";
public void addGlobalSuccessInfoMessage(){
//faces message
}
//Getter Setter
Then you can remove the entire PostConstruct method.
Also if all you want to do is set a string and update without navigation just use f:setPropertyActionListener with a f:ajax for updating your messages. You can use action if you want by returning null or void, or actionListener and set the string inside of that, but I'm not seeing why you'd want to. This link may help with those options... Answer by Balus C.
May want to remove any extra logic from your getter method as well. This won't affect your problem but it's cleaner and creating a success message on a getter seems problematic.
<h:form id="myForm">
<h:messages globalOnly="true" layout="table" />
<h:outputText id="esteTexto" value="#{ramSession.texto}" />
<br />
<h:commandButton value="#{ramSession.texto}" actionListener="#{ramSession.addGlobalSuccessInfoMessage()}" styleClass="btn btn-default">
<f:setPropertyActionListener value="Entrando" target="#{ramSession.texto}" />
<f:ajax render="myForm" />
</h:commandButton>
</h:form>
I am trying to trigger a method in the backing bean on load.
Whenever the link is clicked it throws a NPE , any idea why?, I've included snippets of my code below.
Error: listener="#{userController.validate}": java.lang.NullPointerException: javax.el.ELException
<h:form id="reg">
<h:outputLabel value="Promo" /> :
<h:inputText id="promocode" value="#{userController.promocode}">
<f:ajax render=":promoimage" event="blur" listener="#{userController.validate}"/>
</h:inputText>
<h:commandLink id="dummyclick" value="link">
<f:ajax event="click" render=":promoimage" listener="#{userController.validate}"/>
</h:commandLink>
</h:form>
#ManagedBean(name = "userController", eager= true)
#SessionScoped
public class UserController implements Serializable {
public void validate(AjaxBehaviorEvent event){
........
}
}
<script type="text/javascript">
document.getElementById("reg:dummyclick").click();
</script>
I removed the ajax call and it worked, it was probably pointless in this case. I'd still like to know why it is throwing an NPE though.
<h:commandLink id="dummyclick" value="link" action="#{userController.showPromo}">
</h:commandLink>
.......
<script type="text/javascript">
document.getElementById("reg:dummyclick").click();
</script>
Why you using command link, instead of that use command button and if you set required="true" for inputtext, it will automatically check validation on same button.
Setup:
I have 2 forms A & B
I have a commandLink in form A:
<h:commandLink actionListener="#{homeView.selectDiv('homeUpdates')}">#{msg.homeUpdates}
<f:ajax render=":B" execute="#this" />
</h:commandLink>
...which updates form B.
The problem is that when I click the ajax link, it rebuilds form A as well and gets an exception from a ui:repeat I have. Is this correct behaviour? Should it rebuild form A as well?
I am using JSF 2.2 and form A contains a ui:fragment=>ui:include=>ui:repeat
=====Added SSCCE=======
The following code does not run after pressing Update B! twice. It gives an exception of duplicate id. The value for ui:repeat is irrelevant
<h:head>
</h:head>
<h:body>
<h:form id="A">
<ul class="tableView notification">
<ui:repeat var="notification" value="#{dashboardBean.notifications}">
<li>
xx
</li>
</ui:repeat>
</ul>
<h:commandLink value="Update B!" listener="#{dashboardBean.toggleRendered}">
<f:ajax execute="#this" render=":B" />
</h:commandLink>
</h:form>
<h:form id="B">
</h:form>
</h:body>
Upon initial request the view is created, upon postbacks the view is restored. To recite some points of JSF 2.2 specification for clarity (emphasis mine):
P. 2.2.1:
If the request is not a postback ... call createView() on the ViewHandler. If the request is a postback, ... call ViewHandler.restoreView(), passing the FacesContext instance for the current request and the view identifier, and returning a UIViewRoot for the restored view.
P. 2.5.8:
Selected components in a JSF view can be priocessed (known as partial processing) and selected components can be rendered to the client (known as partial rendering).
P. 13.4:
The JavaServer Faces lifecycle, can be viewed as consisting of an execute phase and a render phase. Partial traversal is the technique that can be used to “visit” one or more components in the view, potentially to have them pass through the “execute” and/or “render” phases of the request processing lifecycle.
When you use AJAX, PartialViewContext class will contain all the information that's needed to traverse the restored view.
So, to get back to your question, under <f:ajax render=":B" execute="#this" /> setup, only the form with id="B" will be rerendered, which implies <h:form id="B">, no form nestings, etc.
Regarding your 'doesn't work' comment the simple test case with a plain view scoped managed bean gave me the expected results:
<h:form id="A" >
<h:outputText value="#{twoFormsBean.a}"/>
<h:commandLink actionListener="#{twoFormsBean.actionA}">
Update B!
<f:ajax execute="#this" render=":B"/>
</h:commandLink>
</h:form>
<h:form id="B" >
<h:outputText value="#{twoFormsBean.b}"/>
<h:commandLink>
Update Both!
<f:ajax execute="#this" render=":A :B"/>
</h:commandLink>
</h:form>
with
#ManagedBean
#ViewScoped
public class TwoFormsBean implements Serializable {
private String a = "A";//getter
private String b = "B";//getter
public void actionA(ActionEvent ae) {
a = "newA";
b = "newB";
}
}
I'm running into an odd issue with myfaces 2.1.10 (packaged with TomEE) involving composite components and action methods. Essentially, looking at the example below, myfaces seems to thing that the action method is a property instead and throws an ElException. This same code works fine with Mojarra (under jBoss 7.1.2).
Any idea what I'm doing wrong?
Exception:
javax.el.ELException: /index.xhtml: Property 'act' not found on type com.company.dept.beans.SomeBean
org.apache.myfaces.view.facelets.compiler.AttributeInstruction.write(AttributeInstruction.java:55)
org.apache.myfaces.view.facelets.compiler.UIInstructions.encodeBegin(UIInstructions.java:46)
org.apache.myfaces.view.facelets.compiler.UILeaf.encodeAll(UILeaf.java:505)
javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:541)
javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:541)
org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1981)
org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:285)
javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:59)
org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:116)
org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
Composite component named "menu":
<composite:interface displayName="Navigation Menu Bar" shortDescription="Navigation menu bar">
<composite:attribute name="action" method-signature="java.lang.String action()"/>
</composite:interface>
<composite:implementation>
<div id="#{cc.clientId}:menuComponent">
<h:form>
<h:commandButton action="#{cc.attrs.action}" value="execute action" />
</h:form>
</div>
</composite:implementation>
The following page uses the component above
<h:head>
</h:head>
<h:body>
<menu:menu action="#{someBean.act}"/>
</h:body>
</html>
The backing bean with the action method
package com.company.dept.beans;
import javax.inject.Named;
#Named
public class SomeBean {
public String act() {
System.out.println("ACT CALLED");
return "SUCCESS";
}
}
This was due to the way the application was packaged. One of the jars that contained the xhtml was missing a faces-config.xml file and that caused MyFaces not to find it. Oddly enough, Mojarra didn't seem to care...