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.

Thursday, October 25, 2012

Speedup jetty-maven-plugin startup time

  • Create a own profile - this allows more flexibility
  • <profile>
        <id>jetty-run</id>
    </profile>
    
  • Add jetty-maven-plugin to the profile. We also configure the plugin to get all resources from the src directory and only scan the java sources
  • <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <configuration>
            <webAppSourceDirectory>${basedir}/src/main/webapp</webAppSourceDirectory>
            <scanIntervalSeconds>2</scanIntervalSeconds>
            <scanTargets>
                <scanTarget>src/main/java</scanTarget>
            </scanTargets>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>run</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    
  • Skip unit testing via profile property
  • <properties>
        <maven.test.skip>true</maven.test.skip>
    </properties>
    
  • Skip building the WAR file
  • <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <executions>
            <execution>
                <id>default-war</id>
                <phase>none</phase>
            </execution>
        </executions>
    </plugin>
    
  • If you optimize and aggregate your javascript or CSS files, skip this too! Compression of this files is on localhost just prevents debugging. We created an own servlet which merges the files on-the-fly. Changes on JS or CSS will be also available after F5 in your browser - that's the nice side effect of the servlet :)
    • Skip optimzation (we use the primefaces-extensions plugin for this)
    • <plugin>
          <groupId>org.primefaces.extensions</groupId>
          <artifactId>resources-optimizer-maven-plugin</artifactId>
          <executions>
              <execution>
                  <id>optimize</id>
                  <phase>none</phase>
              </execution>
          </executions>
      </plugin>
      
    • Create a servlet to merge the resources (we also implemented a init-param called includeDirectory to read all source files)
    • @Override
      protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
          throws ServletException, IOException
      {
          final OutputStream ouputStream = response.getOutputStream();
          response.setContentType(getServletConfig().getInitParameter("contentType");
      
          final List<File> filesToMerge = getFiles(getServletContext().getRealPath(getServletConfig().getInitParameter("includeDirectory")));
      
          for (final File fileToMerge : filesToMerge) {
          final FileInputStream inputStream = new FileInputStream(fileToMerge);
              IOUtils.copy(inputStream, ouputStream);
              inputStream.close();
          }
      
          ouputStream.close();
      }
      
      
    • For example, if your optimizer plugin aggregates your javascript files to "/javascript/bundle.js", we must overwrite this URL via a servlet mapping.
      We just create a second web.xml (this is just for localhost and jetty) with the name "web-localhost.xml" in your "src/main/webapp/WEB-INF" directory with the following servlet mapping
    • <servlet>
          <servlet-name>Merge Javascript Servlet</servlet-name>
          <servlet-class>xxx.servlet.MergeResourceServlet</servlet-class>
          <init-param>
              <param-name>includeDirectory</param-name>
              <param-value>/javascript/</param-value>
          </init-param>
          <init-param>
              <param-name>contentType</param-name>
              <param-value>application/x-javascript</param-value>
          </init-param>
      </servlet>
      <servlet-mapping>
          <servlet-name>Merge Javascript Servlet</servlet-name>
          <url-pattern>/javascript/bundle.js</url-pattern>
      </servlet-mapping>
      
    • Now we configure jetty to use our "web-localhost.xml" as overrideDescriptor
    • <plugin>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <configuration>
              <webAppConfig>
                  <overrideDescriptor>src/main/webapp/WEB-INF/web-localhost.xml</overrideDescriptor>
              </webAppConfig>
              ...
          </configuration>
      </plugin>
Finished! You will be able to start jetty now via "mvn package -P jetty-run".

Wednesday, October 3, 2012

Introducing PrimeFaces Extensions

In march 2011, I founded my first open source project called "PrimeFaces Extensions".

Our new application required a functionality to resize/rotate images and select a part of the image to do OCR (Optical Character Recognition), both with client-server communication.

I already had experience with JSF2 and PrimeFaces 2.2, so I decided to develop those components in my spare time based on PrimeFaces and commit it to a open source platform (Google Code).

After talking to Cagatay Civici (PrimeFaces founder and lead developer), I got green light to start the "PrimeFaces Extensions" project.

The first release contained this two components: ImageRotateAndResize and ImageAreaSelect.

Months later Oleg Varaksin joined my project as second lead and developer.
For the first big release (0.2), we developed many new components like CKEditor, MasterDetail, ResetInput and Layout.


Nevertheless, after 1,5 years of hard work, we can proudly say that we created some really unique and useful components which are used by many PrimeFaces users and also used in real-world applications!

Currently we are 6 developers around the world and we have about 25 components, functions, behaviors and converters.

Also some of our components and enhancements are now part of PrimeFaces and we also have a little influence on JSF 2.2 with our ResetInput component (JIRA Issue).


Thanks to Cagatay for PrimeFaces, Oleg for the great cooperation and the other PrimeFaces Extensions developers for their great work!

Thursday, September 6, 2012

Increase your JSF application performance (Part 2 - Design Patterns)

  • Use Facelets instead of JSP
  • If possible, always use HTML instead of JSF tags
  • Never put logic in getters because they can be called multiple times - especially for the rendered attribute
  • Avoid much logic in EL expression
  • Avoid using h:outputText. Just use EL expressions. If you need to escape HTML, it's better to use a EL function
  • Use AJAX as much as possible
  • Only process and update components which are really required to process or update
  • Cache data, which is required multiple times in the same view, in @RequestScoped beans
  • Avoid using @SessionScoped, @ViewScoped and other long living scopes
  • Split your beans. Its better to have a seperate bean for logic and a seperate bean for values which are required for multiple requests (@ViewScoped, @ViewAccessScoped...). I call them *Controller and *StateHolder

Friday, August 24, 2012

Get bean instance in CDI

In some cases it's required to get the bean instance instead of the reference.
You can simply do it with the following method:

public static <T> T getBeanInstance(final Class<T> type, final Class<? extends Annotation> scope, final BeanManager beanManager)
{
   final Context context = beanManager.getContext(scope);
   final Set<<Bean<?>> beans = beanManager.getBeans(type);
   final Bean<T> bean = (Bean<T>) beanManager.resolve(beans);
   final CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);

   return context.get(bean, creationalContext);
}

Tuesday, August 21, 2012

Increase your JSF application performance (Part 1 - Environment & Configuration)

  • Always use the newest MyFaces version (As you can read here: Blog Entry)
  • If you just need a plain servlet container, use Tomcat instead of Jetty
  • Use JUEL as EL implementation 
    • Add the newest JUEL API + implementation as depedency
    • Configure MyFaces to use JUEL:
    • <context-param>
              <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
              <param-value>de.odysseus.el.ExpressionFactoryImpl</param-value>
      </context-param>
  • Increase expression cache in JUEL
    • Create src/main/resources/el.properties
    • Add property javax.el.cacheSize with a custom size. The default size is 1000. In my application i use a size of 3000.
  • If you use CDI, consider to use OpenWebBeans as implementation and configure this in your web.xml:
  • <context-param>
        <param-name>org.apache.myfaces.EL_RESOLVER_COMPARATOR</param-name>
        <param-value>org.apache.myfaces.el.unified.OpenWebBeansELResolverComparator</param-value>
    </context-param>
  • Enable MyFaces EL caching as described in MyFaces Wiki
  • Disable JSP support in MyFaces:
  • <context-param>
        <param-name>org.apache.myfaces.SUPPORT_JSP_AND_FACES_EL</param-name>
        <param-value>false</param-value>
    </context-param>
    Attention: If you set this, you need to provide the "org.apache.myfaces.EXPRESSION_FACTORY" parameter.
  • Other params to increase performance:
  • <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Production</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
        <param-value>-1</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.CHECK_ID_PRODUCTION_MODE</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.VIEW_UNIQUE_IDS_CACHE_ENABLED</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.SAVE_STATE_WITH_VISIT_TREE_ON_PSS</param-name>
        <param-value>false</param-value>
    </context-param>
    
  • Configure state management as described in MyFaces Wiki
  • Use a custom ServletFilter to set the correct expires/cache headers of your resources (images, stylesheets, javascripts)
  • Compress and optimize your Javascripts in your build process. If you use maven, try primefaces-extensions' closure compiler maven plugin

Monday, August 20, 2012

Enable failover with OpenWebBeans (> 1.1.3)

With Tomcat 7.0.22, some changes has be done when

    ServletRequestListener
           #requestDestroyed(javax.servlet.ServletRequestEvent)

will be called. This caused that session replication was done before OpenWebBeans prepared the beans for the failover.

Therefore a new ServletFilter, which prepares the bean failover before session replication, was added in OpenWebBeans 1.1.4.

Just add it as FIRST filter in your web.xml:

org.apache.webbeans.web.failover.FailOverFilter

and map it for example to the FacesServlet.

Also don't forget the src/main/resources/META-INF/openwebbeans/openwebbeans.properties with following entries:

    configuration.ordinal=100
    org.apache.webbeans.web.failover.issupportfailover=true
    org.apache.webbeans.web.failover.issupportpassivation=true


Update for OWB 1.2.0 -> Click