lunes, 13 de enero de 2014

What's new in MyFaces 2.2

JSF 2.2 spec was released around March/April of 2013. Over the last year (2013), the attention of MyFaces community has been on deliver a robust and compliant JSF implementation. In the end of October 2013, it was released a new beta, which includes 100% of the features required by the spec. An official release of MyFaces Core 2.2.0 has been released recently (January 2014), but on the way some new and interesting features has been added (besides what's new in JSF 2.2) that are worth to mention. Some of them are completely new, and some others has been added based on the interpretation done of the new spec.

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.
In my personal opinion, it is better to let JSF handle the state problem and don't use stateless views at all. But on the way, it was found a way to reuse JSF views effectively and get a good improvement in performance, adding some additional complexity at the time to create components. Please note MyFaces Core even without the view pool gives a very good performance, so most users will not bother about enable this feature, but for some others this can be useful.

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.
In MyFaces Core 2.0.x/2.1.x the previous problems were fixed and a proper syntax was introduced. This is necessary for improvements like EL expression caching and view pooling, but some users found these differences annoying specially when they try to migrate from Mojarra to MyFaces.

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(...)
The perceived effect compared for example with Mojarra is a reduction in some cases of 80%-90% of the session size used or even more according to the view design and the components used, which lead to an optimal performance level never seen before.

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.

TomEE 1.6.x compatibility

 

The code has been done in a way that allow run 2.2.0 artifacts in TomEE 1.6.x containers. In other words, the easiest way to try MyFaces Core 2.2.0 jars is just take a distribution of TomEE 1.6.x from the download page and replace the 2.1.x jars with the new ones. As simple as that!.