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.

2 comments:

  1. wow, while i was looking at this post, i thought about asking you something, and then i see this at the bottom...

    > 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.

    so my question, did you add any of this to PrimeFaces 4.0 ?

    also, you can always keep blogging here and sharing these type of tips/posts. I am definitely using some of your tips/advise that you posted in the JSF Performance series. :)

    ReplyDelete
  2. No Howard. This depends on CDI and CODI or DS, so PrimeFaces isn't a good place.
    It does also not work in Mojarra, maybe it will be defined in the future directly in the specs.
    A good place would be DS but first it should work in mojarra, too.

    ReplyDelete