OCPSoft.com - Simple SolutionsCommunity Documentation

Chapter 9. Extend PrettyFaces

9.1. com.ocpsoft.pretty.faces.spi.ConfigurationProvider
9.2. com.ocpsoft.pretty.faces.spi.ConfigurationPostProcessor
9.3. com.ocpsoft.pretty.faces.spi.ELBeanNameResolver
9.4. com.ocpsoft.pretty.faces.spi.DevelopmentModeDetector

As a modern web-framework, it is important to provide extension and integration points, enabling complex functionality that goes beyond the scope of the core framework itself. In order to do this, PrettyFaces provides several extension points, described below:

It may sometimes be necessary to provide custom configuration options in PrettyFaces. Loading URL-mappings from a database, for example, or generating mappings based on the state of the file-system. Due to this requirement, PrettyFaces offers an extension point for configuration providers to supply their own additional configuration to be merged with the master configuration at the time when PrettyFaces boots up. This is when you would implement a custom ConfigurationProvider.

public class MyConfigurationProvider implements ConfigurationProvider {
   
   public PrettyConfig loadConfiguration(ServletContext servletContext)
   {
      // add new configuration elements here
      return new PrettyConfig(); 
   }
}

To let PrettyFaces know about your provider, you'll have to register your implementation by creating a file named META-INF/services/com.ocpsoft.pretty.faces.spi.ConfigurationProvider in your classpath and add the fully-qualified class name of your implementation class there.

         META-INF/services/com.ocpsoft.pretty.faces.spi.ConfigurationProvider
         com.example.MyConfigurationProvider
       

After all configurations have been loaded and merged from any built-in or registered ConfigurationProvider sources, there is an additional opportunity to post-process the entire configuration, for instance, if you wanted to programmatically add security constraints to mappings based on various patterns. This is when you would implement a custom ConfigurationPostProcessor.

public class MyPostProcessor implements ConfigurationPostProcessor {
   
   public PrettyConfig processConfiguration(ServletContext servletContext, PrettyConfig config)
   {
      // make changes to the configuration here
      return config; 
   }
}

To let PrettyFaces know about your post-processor, you'll have to register your implementation by creating a file named META-INF/services/com.ocpsoft.pretty.faces.spi.ConfigurationPostProcessor in your classpath and add the fully-qualified class name of your implementation class there.

         META-INF/services/com.ocpsoft.pretty.faces.spi.ConfigurationPostProcessor
         com.example.MyPostProcessor
       

As part of the Annotations scanning (one of PrettyFaces' configuration methods,) it may sometimes be necessary to integrate with a custom bean-container that is not one of the built in containers supported natively. It is in these cases when you should implement a custom ELBeanNameResolver. The following example shows a resolver that will resolve the bean name by searching for a @Named annotation.

public class MyBeanNameResolver implements ELBeanNameResolver {
   
      public boolean init(ServletContext servletContext, ClassLoader classLoader) {
         // tell PrettyFaces that initialization was successful
         return true;
      }
   
      public String getBeanName(Class<?> clazz) {
         
         // try to find @Named annotation
         Named annotation = clazz.getAnnotation(Named.class);
         
         // return name attribute if annotation has been found
         if(annotation != null) {
            return annotation.value();
         }
         
         // we don't know the name
         return null;
         
      }
      
   }

To let PrettyFaces know about your resolver, you'll have to register your implementation by creating a file named META-INF/services/com.ocpsoft.pretty.faces.spi.ELBeanNameResolver in your classpath and add the fully-qualified class name of your implementation class there.

         META-INF/services/com.ocpsoft.pretty.faces.spi.ELBeanNameResolver
         com.example.MyBeanNameResolver
       

If PrettyFaces is executed in development mode, the configuration will be automatically reloaded every few seconds. This allows the developer to modify the pretty-config.xml and immediately test the changes without restarting the servlet container.

The DevelopmentModeDetector SPI allows the user to implement custom strategies to determine whether the application is in development mode. The following class shows a simple detector which enables the development mode if the system property devmode is set to true.

public class CustomDevelopmentModeDetector implements DevelopmentModeDetector {

   public int getPriority() {
      return 10;
   }

   public Boolean isDevelopmentMode(ServletContext servletContext) {
      return System.getProperty("devmode", "false").equals("true");
   }

}

To let PrettyFaces know about your custom detector, you'll have to register your implementation by creating a file named META-INF/services/com.ocpsoft.pretty.faces.spi.DevelopmentModeDetector in your classpath and add the fully-qualified class name of your implementation class there.

         META-INF/services/com.ocpsoft.pretty.faces.spi.DevelopmentModeDetector
         com.example.CustomDevelopmentModeDetector