I am Nicolas Labrot, a software engineer at 4Dconcept. I have interrest in Java, JEE (JSF, Hibernate...), Maven, Agile, etc. You can follow me on http://twitter.com/#!/NicolasLabrot Nicolas has posted 3 posts at DZone. View Full User Profile

How to create a stateful Richfaces popup

10.06.2010
| 12509 views |
  • submit to reddit

I use JSF and especially Richfaces for 1 year. During this year I had a few issues with Richfaces popups.

Richfaces popups had the following issues

  • The popup component is stored in the components tree although it is not displayed. On some use cases, the complete popup sub tree can be stored in the tree.
  • Because popups are usually displayed using javascript, there are not sync with the components tree and vice versa.
  • So popups are display off  when user reloads the page, that generates inconsistent state.
  • A lot of popups on the same page, that significates a lot of rich:modalPanel components, increases file size and decreases readability.
  • Popups don't stack easily (A calls B or B calls A mean different zindex for A and B).

One of my coworker said richfaces popup component doesn’t scale because each sort of popup requires a specific declaration. The team had create a JSF fragment file that contains all the popup components whatever their domains or the business logic location in package and module.

My opinion is that a popup should be part of the UI logic. It should not be a component you add like a textbox but it would rather be a window you create with a createPopup method.

Ok let's try to improve popup logic.

First step : Java logic

The first step is to create a popup controller which manage the active popups displayed on the page.  The controller is a session bean named popupController that can be wired to any controllers.


The interface will be :
public interface IPopupController {

void add(String uri, IPopupBean bean);

void removeLast();

List<IPopupDescriptor> getPopups();

UIComponent getPopupContainer();

void setPopupContainer(UIComponent popupContainer);
}
The add method will be used to add and display popup.
The following example will display the popup foo.xhtml with the bean fooBean:
popupController.add("foo.xhtml" , fooBean);
 

Second step : UI logic

The second step is to create the UI logic that will display the popups.  This is a simple JSF fragment that contains the UI logic:
<a4j:outputPanel binding="#{popupController.popupContainer}" id="popupContainer">
<c:forEach items="#{popupController.popups}" var="popup">
<f:subview id="popupView#{popup.id}">
<ui:include src="#{popup.uri}">
<ui:param name="popupBean" value="#{popup.popupBean}"/>
</ui:include>
</f:subview>
</c:forEach>
</a4j:outputPanel>

The popups are contained in a <a4j:outputPanel> to allow AJAX refresh. The facelet iterates on the popups managed by the popupController bean.  Each popup is in a subview with a custom id to avoid duplicate id exception.

The previous fragment had to be included in all pages that used popups :
<ui:include src="/popup/popup.xhtml"/>
With facelet it is easy to create a page template that will hold this fragment.

To simplify the article it's the user responsibility to create the popup file that should respect the following template :
<rich:modalPanel id="anId" zindex="#{popupBean.popupDescriptor.zIndex}">
[...]
</rich:modalPanel>
<a4j:outputPanel>
<script type="text/javascript">
javascript:Richfaces.showModalPanel('anId')
</script>
</a4j:outputPanel>
The zIndex is computed automatically by the popupController. The javascript ensures at each Ajax refresh or page reload that all popups will be redisplayed.
 

Finally

With the following article, I show how to improve popup logic that keeps client and server sync. The drawback of this method is it needs a request to be sync with the server. On a low latency network it should not be an issue. But on a medium or high latency it may be different.

I have attached a small Maven war project that contains the code of this article.

What is your opinion ?

 

 
Legacy
Article Resources: 
Published at DZone with permission of its author, Nicolas Labrot.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jay Balunas replied on Wed, 2010/10/13 - 3:01pm

Thanks for the ideas and feedback on RichFaces! We're going to review and discuss, to see if these are applicable for 4.0. It would be great if you could stop by the RichFaces dev forum and share more.

Thanks
Jay Balunas
RichFaces Project Lead

Rafael Blanco replied on Sat, 2010/12/04 - 10:53am in response to: Jay Balunas

hi.. the example is very complete..

 but. i need much help.. i catch erros when run my application.

the error is the next..

/gym/admin/popupprincipal.jspx @8,86 binding="#{popupController.popupContainer}": Target Unreachable, identifier 'popupController' resolved to null

MY JSPX

 

popupprincipal.jspx

<f:subview xmlns="http://www.w3.org/1999/xhtml"
        xmlns:c="http://java.sun.com/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"
        xmlns:a4j="http://richfaces.org/a4j"
        xmlns:rich="http://richfaces.org/rich" id="popupContainerView">
    <a4j:outputPanel binding="#{popupController.popupContainer}" id="popupContainer">
        <c:forEach items="#{popupController.popups}" var="popup">
            <f:subview id="popupView#{popup.id}">
                <ui:include src="#{popup.uri}">
                    <ui:param name="popupBean" value="#{popup.popupBean}"/>
                </ui:include>
            </f:subview>
        </c:forEach>
    </a4j:outputPanel>
</f:subview>

 ----------------------------------------- ----------------------------------------- -----------------------------------------

 my config is..

----------------------------------------- ----------------------------------------- -----------------------------------------

web.xml

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/WEB-INF/applicationContext-bean.xml</param-value>
    </context-param>

OR 

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext-bean.xml</param-value>
    </context-param>

 ----------------------------------------- ----------------------------------------- -----------------------------------------

 faces-config.xml

i have comment..

<!--<managed-bean>
        <managed-bean-name>mainPage</managed-bean-name>
        <managed-bean-class>com.raflanco.gym.popup.ejemplos.MainPage</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    <managed-bean>
        <managed-bean-name>popupController</managed-bean-name>
        <managed-bean-class>com.raflanco.gym.popup.UI.controller.PopupController</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>-->

----------------------------------------- ----------------------------------------- -----------------------------------------

 applicationContext-bean.xml

<bean id="popupController" class="com.raflanco.gym.popup.UI.controller.PopupController" scope="session"/>

<bean id="mainPage" class="com.raflanco.gym.popup.ejemplos.MainPage" scope="session">
      <property name="popupController" ref="popupController">
</bean>

----------------------------------------- ----------------------------------------- -----------------------------------------

 MainPage.java

    @Autowired    
    private IPopupController popupController;

    public void createSimple() {
        SimplePopup sp = new SimplePopup();
        sp.setEventHandler(new SimpleEventHandler(sp));
        ********* popupController.add(PopupViewEnum.SimplePopup.getUri() , sp);
    }

    public void createTwice() {
        MainPopup mainPopup = new MainPopup();
        mainPopup.setEventHandler(new SimpleEventHandler(mainPopup));        
        ********* popupController.add(PopupViewEnum.TwicePopup.getUri() , mainPopup);
    }

************ popupController always is NULL.. ?? why ?? 

@Autowired    
private IPopupController popupController; never is load when i use in faces-config.xml

<managed-bean>
        <managed-bean-name>mainPage</managed-bean-name>
        <managed-bean-class>com.raflanco.gym.popup.ejemplos.MainPage</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    <managed-bean>
        <managed-bean-name>popupController</managed-bean-name>
        <managed-bean-class>com.raflanco.gym.popup.UI.controller.PopupController</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>

 

i catch NullPointerException in ******* popupController.add(PopupViewEnum.TwicePopup.getUri() , mainPopup);

----------------------------------------- ----------------------------------------- -----------------------------------------

 

Thank You...

Rafael.. Programmer

 

Rafael Blanco replied on Sat, 2010/12/04 - 2:49pm in response to: Jay Balunas

Help ..

 

the above problem was solve..

the next problem is..

 when up popup and click en actiom cerrar.. display the following Exception..

javax.faces.application.ViewExpiredException: viewId:/gym/popup/hijos/main.jspx - No se pudo restablecer la vista /gym/popup/hijos/main.jspx.
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:206)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)

any idea..

Thank You

 

 

Nicolas Labrot replied on Wed, 2010/12/15 - 8:53am

Hello,

Sorry for this late answer but I'm not alerted then there is a comment.

Do you use a server STATE_SAVING_METHOD in web.xml ?

ie. :

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>

Jaikrat Singh replied on Wed, 2012/01/18 - 7:08am

Hello Nic,
Thanks for posting this very useful article. I tried the above code with RichFaces3.3 jars and its working perfectly fine. But I am facing real trouble, when I switch to RichFaces 4.x. I get the landing page of the application with the two links on the page but when I click on either it gets failed with the below error.

16:15:05,154 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException: Argument Error: Parameter viewId is null
at com.sun.faces.util.Util.notNull(Util.java:305)
at com.sun.faces.application.view.MultiViewHandler.getActionURL(MultiViewHandler.java:272)
at org.ajax4jsf.framework.ViewHandlerWrapper.getActionURL(ViewHandlerWrapper.java:92)
at javax.faces.application.ViewHandlerWrapper.getActionURL(ViewHandlerWrapper.java:166)
at org.ajax4jsf.framework.ViewHandlerWrapper.getActionURL(ViewHandlerWrapper.java:92)


Could you please provide your inputs in how to migrate this application with RichFaces4.x jars and JSF2.0 on the same.

I really need your help on this.

Thanks
Jaik

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.