Friday, December 14, 2012

Dynamical switching of JSF state saving method

By default, it's only possible to configure the state saving method (client or server) globally for all views in your application.

This is sometimes really annoying as server side performs better but needs more memory.
Also with server side state saving, it's not possible to cache views (if they have actions) because you will get a ViewExpiredException soon.

So what about using client-side state for some views and using server-side state for all other views?

Currently this is only possible with MyFaces (since 2.1.9). Mojarra doesn't support this feature.
I created a specifiation improvement ticket (http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1147) and hopefully this will be supported in Mojarra soon.

So how can we use this feature?

To switch the state saving method, we just need to overwrite/wrap the following method: StateManager#isSavingStateInClient(FacesContext).

In my application i combined this feature with CODI ViewConfig.

Create a ViewMetaData:
@Inherited
@ViewMetaData(override = true)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StateSaving {

  Method value();

  enum Method {
   SERVER,
   CLIENT
  }
}

Wrap the StateManager:
public class ExtensionsStateManager extends StateManagerWrapper {

  @Override
  public boolean isSavingStateInClient(final FacesContext context) {
    boolean isSavingStateInClient;

    final StateSaving stateSaving = getStateSavingAnnotationViaCodiViewConfigResolver(context);
    if (stateSaving == null) {
      isSavingStateInClient = getWrapped().isSavingStateInClient(context);
    } else {
      isSavingStateInClient = stateSaving.value() == StateSaving.Method.CLIENT;
    }

    return isSavingStateInClient;
  }
}

Configure that JSF should use our StateManager:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
  version="2.0">
  <application>
    <state-manager>xxx.xxx.ExtensionsStateManager</state-manager>
  </application>
</faces-config>

Usage:
@Page(navigation = NavigationMode.REDIRECT)
public interface Pages extends ViewConfig {

  @Page
  @StateSaving(Method.SERVER)
  class ViewA implements Pages { }
 
  @Page
  @StateSaving(Method.CLIENT)
  class View implements Pages { }
}


Currently i'm not a member of a library/framework, where i could add this nice feature.
Maybe i will release my own lib for such stuff someday.