View Pooling (Going beyond JSF 2.2 stateless views)
In JSF 2.2 now it is possible to define a view as "stateless" just writing something like this on the top level page:
<f:view transient="true" ...>
but the research done in MyFaces community has led to the conclusion that from performance perspective, there is no a real gain in speed or memory by multiple reasons:
- The size of a view in the session is very small.
- Save or restore the state is quite fast, compared with the work spent creating or rendering the view.
- The view still needs to be built.
There are two ways to enable this feature:
1. Add an entry into a faces-config.xml file like this:
<faces-config-extension>
<view-pool-mapping>
<url-pattern>/*</url-pattern>
<parameter>
<name>org.apache.myfaces.VIEW_POOL_MAX_POOL_SIZE</name>
<value>5</value>
</parameter>
</view-pool-mapping>
</faces-config-extension>
With this mode you can override the global web config parameters.
2. Encapsulate your top level page with
<f:view oamEnableViewPool=true>
A previous blog talks about the fundamentals of the technique. Please note third party libraries needs to be compatible with view pooling, so for now only the components included in JSF 2.2 and some MyFaces Tomahawk components support this mode.
SPI intefaces for custom flow and view scope
Many members of MyFaces community prefer use CDI and specially Apache OpenWebBeans and Apache TomEE for its projects, but the community is also aware of people who use other alternate technologies. In JSF 2.2 some CDI annotations were added like @FlowScoped and @ViewScoped, but it was not provided a general solution for users who don't want or can use CDI. In Myfaces 2.2 we have added the following SPI interfaces:
- org.apache.myfaces.spi.ViewScopeProvider
- org.apache.myfaces.spi.FacesFlowProvider
In that way it is possible to fill the gap and create implementations of those scopes. Inside MyFaces code there are 2 implementations of each SPI interface, one using CDI and one without CDI, so I hope it will be easy for the interested developers to fill the gap according to their needs.
Compatibility mode for Facelets 1.1.x / Mojarra syntax
In Facelets 1.1.x and in current versions of Mojarra, there is still some tags that does not behave properly. For example:
- Declarations like <c:set var="..." value="..."> applies for everything below the declaration and pass through any facelet, including composite components, breaking encapsulation principle.
- <ui:param ...> implementation is the same as <c:set ...>, and it should theorically add a template scope parameter.
- <ui:include ...> is not isolated properly, mixing declarations of <ui:define ...> and <ui:insert ...> from outer levels. In cases where this is valid <ui:decorate ...> should be used instead.
With this web config parameter:
<context-param>
<param-name>org.apache.myfaces.STRICT_JSF_2_FACELETS_COMPATIBILITY</param-name>
<param-value>true</param-value>
</context-param>
A special mode is enabled that allows facelets 1.1.x / Mojarra ugly syntax. Anyway, I encourage users to fix their apps and use the syntax available in MyFaces, because it follows the spec more strictly and it keeps compatibility with Mojarra. But keep in mind, from MyFaces perspective, the current syntax in Mojarra does not follow the spec wording.
Partial State Saving algorithm is applied even in dynamic sections and programatically created components
The current algorithm implemented inside MyFaces 2.2 uses Partial State Saving (PSS) technique in every possible situation:
- Using dynamic facelet tags like <c:if ...>, <c:choose ...>, <c:forEach>, <ui:include src="#{...}">, <ui:decorate template="#{...}"> or <ui:composition template="#{...}">.
- Composite components that use <cc:insertChildren ...> or <cc:insertFacet ...>
- Components created by effect of ViewDeclarationLanguage.createComponent(...)
ViewDeclarationLanguage.createComponent(...) supports non JSF component tags
ViewDeclarationLanguage.createComponent(...) was added in JSF 2.2 to allow create composite components programatically. But it is possible to extend that syntax a little bit to allow use other non component tags like <ui:include ...> as if they were components. For example:
ViewDeclarationLanguage vdl = facesContext.getApplication().
getViewHandler().getViewDeclarationLanguage(
facesContext, facesContext.getViewRoot().getViewId());
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("src", "/addSimpleIncludeVDL_1_1.xhtml");
UIComponent component = vdl.createComponent(facesContext,
"http://java.sun.com/jsf/facelets",
"include", attributes);
panel.getChildren().add(component);
The idea is create automatically a wrapper component when it is necessary. In this way it is possible to avoid a hack over FaceletFactory that in my opinion it will never work well.
<c:forEach ...> has been fixed once for all
It is well known that <c:forEach> tags sometimes does not work as it should. For example, if the collection iterated by <c:forEach> tag changes somehow, the state of the inner components are not restored correctly. The reason is the original algorithm from facelets 1.1.x don't include the necessary logic to deal with this problem, and it was required many big changes inside facelets algorithm before make an attempt to fix it. In MyFaces 2.2.0 we finally have all necessary changes in place, so the long awaited fix has been finally done. The only thing you need to remember is, the elements in the iterated collection must be Serializable and implement hashCode() and equals(...) method properly, otherwise the old algorithm is used.
This tag has been also aligned with PSS algorithm, so now it is possible to use it in combination to dynamic facelet tags and keep the state small. Please remember in previous versions of MyFaces Core, the components created by effect of <c:forEach> tag needs to be saved and restored fully. See MYFACES-3811 for details.
View slots are reused for ajax request and the information stored in view scope is discarded when the view is removed from state on server side state saving
In MyFaces Core 2.0 and 2.1, each ajax request requires one slot in the view storage on server side state saving. A change was added to reuse view slots in those cases, reducing the space required in session, and in that way make a better use of the available space.
Additionally, it was included an algorithm that detect and discard view scopes when they are no longer used, keeping the session size as small as possible.
Early Flush for resources inside <head> or <h:head> tag
Using the following web config parameter:
<context-param>
<param-name>org.apache.myfaces.EARLY_FLUSH_ENABLED</param-name>
<param-value>true</param-value>
</context-param>
flush all resources that are rendered in html <head> tag early, which allows web browsers to fetch them as soon as the flush is done but while the page is loaded, improving response time.
CDI Injection for Converter and Validators
Using these two web config parameters:
<context-param>
<param-name>org.apache.myfaces.CDI_MANAGED_CONVERTERS_ENABLED</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.CDI_MANAGED_VALIDATORS_ENABLED</param-name>
<param-value>true</param-value>
</context-param>
MyFaces activates a built-in mode that enables CDI Injection for JSF Converters and Validators. This was implemented using an override over Application.createConverter(...) and Application.createValidator(...).
For example:
@FacesConverter("cdiConverter")
public class ConverterAsCdiBean implements Converter {
@Inject
private ConverterService converterService;
/*... */
}
in the page:
<h:inputText id="name" value="#{helloWorld.name}" required="true">
<f:converter converterId="cdiConverter"/>
</h:inputText>
That's it. But there are some considerations:
- JSF use a wrapper around the converter/validator to keep control of the instantiation or lookup, but you can get the real instance through a cast to FacesWrapper and calling getWrapped().
- The lifetime of a converter like the one from the example by default is request scope, because in this case CDI manages the lifecycle of the converter/validator, so in that sense it is detached from the view. For example, by default @PostConstruct and @PreDestroy are called at each request.