I use Mojarra implementation of JSF (version 2.2.1). I have a big problem
with performance during ajax requests.
My page has a lot of components so I understand why first rendering takes
much time, but what with ajax requests?
They takes also a lot of time although they do almost nothing. Here is my
simplified example:
In below example pressing "performance test" button takes several ms:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
Hello World
<h:form>
<h:commandButton value="performance test">
<f:ajax execute="#this" render="#none" />
</h:commandButton>
</h:form>
</h:body>
</html>
But if add 1000 <h:inputText /> elements to the <h:form></h:form> the same action takes
over 100ms !
I have checked that 80% of time is consumed in RESTORE_VIEW phase, 20 % in RENDER_RESPONSE phase, rest of phases do not take significant amount of time.
Is there any possibility to fix it?
I tried also to disable javax.faces.PARTIAL_STATE_SAVING (memory consumption is not the problem in my case) but also without any success.
EDIT:
A thousand of <h:inputText> added to a <h:form> was only a simplified example. I just wanted to emphasize the fact that big amount of components has significant influence on the ajax request (that does almost nothing) - which is a severe problem on my website.
In the reality, of course, I don't have 1000 inputs. I display very big table with a lot of data - if data is empty in any cell there should by an hyphen instead. I used composite component for that - where I had more than one ui:fragment with render=true/false
Today I tried to use my own component instead of composite one - and response time and memory usage have decreased.
But I'm still not satisfied because my very simple ajax request on that page takes much more time than the same ajax request used on another - thinner page (i.e. with less number of components). Isn't it any JSF architecture issue?
Not really, JSF always rebuilds the entire component tree in restore view phase. You would do better with <ui:repeat> in this case but I realize your test is artificial and real page could have a lot of unique components.
There are quite a few ways to reduce the amount of components, like mentioned <ui:repeat>. Also you can use plain html in your facelets. Chunks of html free of JSF tags are represented as a single UIInstructions component. Still you can use EL expressions in there. It is hard to recommend something particular without more details of your problematic scenario.
EDIT:
Component tree is restored top-bottom, no idea whether it's feasible to somehow optimize it and skip parts not needed by a request. The problem is you don't know in which part of the component tree nodes with particular id specified in ajax tag would be, you can only attempt some optimizations. Looks like the authors did not consider these complications worth the effort.
As for multiple conditional sections - I haven't found anything directly supporting this in JSF. A dedicated custom component sounds like the best bet here. We did something similar, our own implementation of <ui:include>, which supports dynamic src attribute working inside <ui:repeat>.
Related
I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards
I have a complex problem with order of 'JSF bean life cycle actions'.
I have two beans with different scopes. The first, let's call it, managerBean is session scope bean. The second one, someBean has view scope (someBean really is many different beans). ManagerBean takes some action once per page loading and few others view scope beans are using the results of this action in their constructors.
Everything was working just fine until I've started getting forms IDs in xhtml files from java beans. Now action from managerBean is taken after someBean is created and I'm getting expected result only when the page is reloaded (on refresh, so someBean is using the first results of ManagerBean work).
This is how it looks like now:
<!-- mainTemplate is a main templete of the page which is rendered once
per page view (every other actions are taken via ajax). This is a place
of ManagerBean work after re rendering the page -->
<ui:composition template="/mainTemplate.xhtml">
<ui:define name="mainContent">
<h:form id="#{someBean.formID}">
some inputs
</h:form>
(...)
</ui:define>
</ui:composition>
So when form id was constant String everything worked like I want and now it doesn't. It looks like JSF must calculate ID first and take any other after this (including ManagerBean action).
My question is: Is there a way to change this situation?
If something isn't clear enought, please ask. I was trying to simplify the problem because it has many factors. Maybe all my thinking is wrong (the way I want to take some action per page and some actions after it).
Any help will be good!
The id (and binding) attribute of a JSF UI component is evaluated during view build time. The view build time is that moment when the XHTML source code is turned into a JSF UI component tree. All other attributes of a JSF UI component like value and all events like preRenderView are evaluated/executed after the view build time, usually during view render time (when the JSF UI component tree needs to produce HTML output). This is not something which you can change by just turning a setting or so. It's just the way how JSF works. You can't render something which isn't built yet. You can only change this by writing code the right way.
I can't think of any real world scenario why you need to make the ID attribute dynamic like this. If it were inside a <c:forEach>, or part of dynamic component generation, then okay, but this seems just to be a static form. So I would in first place recommend to forget it and just hardcode the ID in the view and rely on other variables (perhaps a hidden input field? depends all on concrete functional requirement which isn't mentioned anywhere in the question nor guessable based on the code posted so far).
If you really need to make it dynamic, then you need to split the formID property off from the view scoped bean and move it to a different and independent bean, perhaps an application scoped one.
See also:
JSTL in JSF2 Facelets... makes sense? - component's id attribute has same lifecycle as JSTL tags
I'm facing the following exception in a very simple JSF 2 page after adding <h:form>:
java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2758)
at org.apache.catalina.connector.Request.getSession(Request.java:2268)
I'm using Mojarra 2.1.3 and PrimeFaces3.0M4, on Tomcat 7.0.22 and JDK 7.
The page is a very basic data table:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h:form>
<p:dataTable var="car" value="#{tableBean.cars}">
......
</p:dataTable>
</h:form>
</h:body>
</html>
The page shows correctly on the browser, but on the console I see the exception. The Exception does disappear if I remove the <h:form>.
How is this caused and how can I solve it?
This is a known problem and has been reported by yours truly as issue 2215. This will occur when the response buffer has overflowed (due to large content) and the response is been committed before the session is been created. This is result of bit overzealous attempts of Mojarra to postpone "unnecessary" session creation as much as possible (which is at its own a Good Thing though).
Until they get it fixed, there are several workarounds:
Create a Filter which does HttpServletRequest#getSession() before FilterChain#doFilter(). Advantage: no need to change JSF configuration/code. Disadvantage: when you want to avoid unnecessary session creation yourself as well.
Call ExternalContext#getSession() with true in bean's (post)constructor or preRenderView listener. Advantage: actually, nothing. Disadvantage: too hacky.
Add a context parameter with name of com.sun.faces.writeStateAtFormEnd and value of false to web.xml. Advantage: unnecessary session creation will be really avoided as opposed to #1 and #2. Disadvantage: response will now be fully buffered in memory until </h:form> is reached. If your forms are not extremely large, the impact should however be minimal. It would however still fail if your <h:form> starts relatively late in the view. This may be combined with #4.
Add a context parameter with name of javax.faces.FACELETS_BUFFER_SIZE and a value of the Facelets response buffer size in bytes (e.g. 65535 for 64KB) so that the entire HTML output or at least the <h:form> (see #3) fits in the response buffer. Advantage/disadvantage, see #3.
Add a context parameter with name of javax.faces.STATE_SAVING_METHOD and value of client to web.xml. Advantage: session will not be created at all unless you have session scoped beans. It also immediately solves potential ViewExpiredException cases. Disadvantage: increased network bandwidth usage. If you're using partial state saving, then the impact should however be minimal.
As to why the problem disappears when you remove <h:form>, this is because no session needs to be created in order to store the view state.
Update: this has as per the duplicate issue 2277 been fixed since Mojarra 2.1.8. So, you can also just upgrade to at least that version.
With the new version 2.1.21 released yesterday of javax.faces this problem seems to have disappeared.
Declare the new version:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.1.21</version>
</dependency>
and replace the javax.faces.jar in the glassfish modules folder replacing the javax.faces.jar for the new version 2.1.21.
In my case (myfaces-2.2.8 & Tomcat 8.0.23) the Problem was a typo in the welcome-file of web.xml.
While debugging i saw, that Tomcat created as expected a 404, but somehow myfaces tried to access afterwards the Session, which caused then a java.lang.IllegalStateException: Cannot create a session after the response has been committed.
Using a valid page in welcome-file of web.xml fixed the Problem for me.
You may need to add an <f:view> and </f:view> before and after h:form elements, plus add the link to you html tag for jsf tags
<html xmlns:f="http://java.sun.com/jsf/core">
for this to work.
If you are using Spring MVC and call is made by Spring Forms then we should use GET method instead of POST(to fetch data) and there should be no input field we can use intead.
I have a composite component, which represents an item that will be stored in a list. I would like to display these items using <ui:repeat>, but I have problems making ajax calls. The thing is that for <f:ajax> render attribute, I want to give the id of my component through
#{cc.clientId}
However this raises error when I use it with <ui:repeat>, because of the reasons that are explained in this document https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat.
<cc:implementation>
<div id="#{cc.clientId}">
<h:form>
<h:commandLink styleClass="btn btn-info" value="Click me">
<f:ajax execute="#form"
render=":#{cc.clientId}"/>
</h:commandLink>
</h:form>
</div>
</cc:implementation>
Is there a way to make the above component work using <ui:repeat> (for example is there a component which can replace the <f:ajax> tag handler, or are we stuck to <c:forEach> construct)?
<ui:repeat id="myComponent" value="#{backingBean.myComponentItem}" var="item" varStatus="itemIndex">
<components:exampleComponent id="myComponent"/>
</ui:repeat>
So I start using <c:forEach> instead of <ui:repeat>, and I was able to use the id of my component in the render attribute of <f:ajax>. But this time when I make pagination, if the size of the list decreases I start having empty components in my page. For solving this I started doing pagination through ajax calls and this solved the empty component problem.
Just I thought everything was solved I encountered another problem: lets say I have a page listing 10 components, and I went to another page, and from that page I came to the component displaying page again, but for some reason lets say this time I retrieved only 3 items from database, and I just want to display these 3 items through my components but nothing else.. Unfortunately in this scenario, 3 items are displayed correctly, but the page also contains 7 empty components too. For overcoming this I need to redirect to this page one-more time. So I just gave up at this point. Apart from this I also eventually get the exception below, when the number of the components on the page changes.
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.sun.faces.application.view.StateHolderSaver
I tried using the suggestion explained in the post Jsf Error : java.lang.ClassCastException, but it didn't work for me, I started getting another error which is similar to above exception.
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/pagename.xhtml</param-value>
</context-param>
So after these long explanations I would just like to learn what is the best approach for creating composite components which are ajax-enabled, who are fully responsible of their own-states and independent of other components, and that can be displayed in the page more than once and the number of components may vary during the page life-cycle (through pagination, navigation etc).
So far the best solution I came up with is, to check number of components in the page and when that number changes through an ajax call or because of a navigation from another page, redirect to the destination page one more time, this refreshes the empty components in the page without creating much disturbance to users. If you come up with any better solution please let us know.
I have another problem to solve. I have a code on my xhtml page:
<t:dataList id="myDataList" value="#{myBean.myList}" var="element" first="0" `rows="10" dir="LTR" frame="hsides" rules="all">`
<c:set target="#{myBean}" property="fid" value="#{element[0]}"/>
...
</t:dataList>
The problem is that value of 'fid' in a bean is null when I`m checking it. When I wrote:
<c:set target="#{myBean}" property="fid" value="8"/>
everything works fine and value is set to '8'. How should i fix this? Thanks for replies.
JSTL tags runs during view build time. JSF tags runs during view render time. You can visualize it as follows: JSTL runs from top to bottom first when the JSF component tree is to be populated, then hands over the component tree to JSF and finally JSF runs from top to bottom to render the HTML.
The element[0] is not there when JSTL is creating the view. It's only there when JSF is rendering the HTML. However, 8 is hardcoded and it is always there.
There are several ways to achieve it the proper way, but since the functional requirement is unclear, I can't suggest a proper approach. Maybe you need f:setPropetyActionListener. Maybe you need DataModel#getRowData() or UIData#getRowData(). Or maybe you don't need it at all.