org.apache.click.extras.spring
Class SpringClickServlet

java.lang.Object
  extended by javax.servlet.GenericServlet
      extended by javax.servlet.http.HttpServlet
          extended by org.apache.click.ClickServlet
              extended by org.apache.click.extras.spring.SpringClickServlet
All Implemented Interfaces:
Serializable, Servlet, ServletConfig

public class SpringClickServlet
extends ClickServlet

Provides a Spring framework integration SpringClickServlet.

This Spring integration servlet provides a number of integration options using Spring with Click pages. These options are detailed below.

Stateful pages caveat: please note that stateful pages do not work with all options.

1. Spring instantiated Pages with @Component configuration

With this option Page classes are configured with Spring using the @Component annotation. When the SpringClickServlet receives a page request it converts the auto-mapped page class to the equivalent Spring bean name and gets a new instance from the Spring ApplicationContext.
 customer-list.htm  ->  com.mycorp.page.CustomerListPage  -> customerListPage
 HTML Request           Click Page Class                     Spring Bean Name 
When using this strategy use the PageScopeResolver class to ensure new Page instances are created with each request, rather than Spring's default "singleton" creation policy. Please see the PageScopeResolver Javadoc for more information on configuring this option.

An example Page class is provided below which uses the Spring @Component annotation. Note in this example page the customerService with the @Resource annotation is injected by Spring after the page instance has been instantiated.

 package com.mycorp.page;

 import javax.annotation.Resource;
 import org.apache.click.Page;
 import org.springframework.stereotype.Component;

 import com.mycorp.service.CustomerService;

 @Component
 public class CustomerListPage extends Page {

     @Resource(name="customerService")
     private CustomerService customerService;

     ..
 } 
This is the most powerful and convenient Spring integration option, but does require Spring 2.5.x or later.

Stateful page caveat: Spring beans injected on stateful pages will be serialized along with the page, meaning those beans must implement the Serializable interface. If you do not want the beans to be serialized, they need to be marked as transient. Transient beans won't be serialized but when the page is deserialized, the transient beans won't be re-injected, causing a NullPointerException when invoked. If you want to use transient beans on stateful pages, see option 3 below.

2. Spring instantiated Pages with Spring XML configuration

With this option Page classes are configured using Spring XML configuration. When the SpringClickServlet receives a page request it converts the auto-mapped page class to the equivalent Spring bean name and gets a new instance from the Spring ApplicationContext.
 customer-list.htm  ->  com.mycorp.page.CustomerListPage  -> customerListPage
 HTML Request           Click Page Class                     Spring Bean Name 
If the page bean is not found in the ApplicationContxt then the full Page class name is used.
 customer-list.htm  ->  com.mycorp.page.CustomerListPage  -> com.mycorp.page.CustomerListPage
 HTML Request           Click Page Class                     Spring Bean Name 
This integration option requires you to configure all your Spring Page beans in your Spring XML configuration. While this may be quite laborious, it does support Spring 1.x or later. An example page bean configuration is provided below:
 <?xml version="1.0" encoding="UTF-8"?>
 <beans>

    <bean id="customerListPage" class="com.mycorp.page.CustomerListPage" scope="prototype"/>

 </beans> 
Please Note ensure the page beans scope is set to "prototype" so a new page instance will be created with every HTTP request. Otherwise Spring will default to using singletons and your code will not be thread safe.

Stateful page caveat: option 2 has the same caveat as option 1.

3. Click instantiated Pages with injected Spring beans and/or ApplicationContext

With this integration option Click will instantiate page instances and automatically inject any page properties which match Spring beans defined in the ApplicationContext. In order to enable bean injection, you need to configure the SpringClickServlet init parameter: inject-page-beans.

While this option is not as powerful as @Component configured pages it is much more convenient than Spring XML configured pages and supports Spring 1.x. You can also use annotation based injection which requires Spring 2.5.x or later.

An example Page class is provided below which has the customerService property automatically injected by the SpringClickServlet. Note the customerService property will need to be defined in a Spring XML configuration.

 package com.mycorp.page;

 import org.apache.click.Page;

 import com.mycorp.service.CustomerService;

 public class CustomerListPage extends Page {

     private CustomerService customerService;

     public void setCustomerService(CustomerService customerService) {
         this.customerService = customerService;
     }

     ..
 } 
Page property bean name must match the bean name defined in the Spring XML configuration. Continuing our example the Spring XML configuration is provided below:
 <?xml version="1.0" encoding="UTF-8"?>
 <beans>

    <bean id="customerService" class="com.mycorp.service.CustomerService"/>

 </beans> 
This option will also automatically inject the ApplicationContext into page instances which implement the ApplicationContextAware interface. Using the applicationContext you can lookup Spring beans manually in your pages. For example:
 public class CustomerListPage extends Page implements ApplicationContextAware {

     protected ApplicationContext applicationContext;

     public void setApplicationContext(ApplicationContext applicationContext)  {
         this.applicationContext = applicationContext;
     }

     public CustomerService getCustomerService() {
         return (CustomerService) applicationContext.getBean("customerService");
     }
 } 
This last strategy is probably the least convenient integration option.

3.1 Spring beans and Stateful pages

Stateful pages are stored in the HttpSession and Spring beans referenced by a stateful page must implement the Serializable interface. If you do not want beans to be serialized they can be marked as transient. Transient beans won't be serialized to disk. However once the page is deserialized the transient beans will need to be injected again.

Option 3 will re-inject Spring beans and the ApplicationContext after every request. This allows beans to be marked as transient and still function properly when used with stateful pages.

 package com.mycorp.page;

 import org.apache.click.Page;

 import com.mycorp.service.CustomerService;

 public class CustomerListPage extends Page implements ApplicationContextAware {

     // Note the transient keyword
     private transient CustomerService customerService;

     protected transient ApplicationContext applicationContext;

     public CustomerListPage {
         // Page is marked as stateful
         setStateful(true);
     }

     // Inject the customer service
     public void setCustomerService(CustomerService customerService) {
         this.customerService = customerService;
     }

     public CustomerService getCustomerService() {
         return (CustomerService) applicationContext.getBean("customerService");
     }

     // Inject Spring's ApplicationContext
     public void setApplicationContext(ApplicationContext applicationContext)  {
         this.applicationContext = applicationContext;
     }

     ..
 } 

Servlet Configuration

The SpringClickServlet can obtain the ApplicationContext either from WebApplicationContextUtils which is configured with a ContextLoaderListener. For example:
 <?xml version="1.0" encoding="UTF-8"?>
 <web-app>

    <listener>
       <listener-class>
          org.springframework.web.context.ContextLoaderListener
       </listener-class>
    </listener>

    <servlet>
       <servlet-name>SpringClickServlet</servlet-name>
       <servlet-class>org.apache.click.extras.spring.SpringClickServlet</servlet-class>
       <load-on-startup>0</load-on-startup>
    </servlet>

    ..

 </web-app> 
Alternatively you can specify the path to the ApplicationContext as a servlet init parameter. For example:
 <?xml version="1.0" encoding="UTF-8"?>
 <web-app>

    <servlet>
       <servlet-name>SpringClickServlet</servlet-name>
       <servlet-class>org.apache.click.extras.spring.SpringClickServlet</servlet-class>
       <init-param>
         <param-name>spring-path</param-name>
         <param-value>/applicationContext.xml</param-value>
       </init-param>
       <load-on-startup>0</load-on-startup>
    </servlet>

    ..

 </web-app> 
To configure page Spring bean injection (option 3 above), you need to configure the inject-page-beans servlet init parameter. For example:
 <?xml version="1.0" encoding="UTF-8"?>
 <web-app>

    ..

    <servlet>
       <servlet-name>SpringClickServlet</servlet-name>
       <servlet-class>org.apache.click.extras.spring.SpringClickServlet</servlet-class>
       <init-param>
         <param-name>inject-page-beans</param-name>
         <param-value>true</param-value>
       </init-param>
       <load-on-startup>0</load-on-startup>
    </servlet>

    ..

 </web-app> 

See Also:
PageScopeResolver, Serialized Form

Field Summary
protected  ApplicationContext applicationContext
          Spring application context bean factory.
static String INJECT_PAGE_BEANS
          The Servlet initialization parameter name for the option to have the SpringClickServlet inject Spring beans into page instances:   "inject-page-beans".
protected  Map<Class<? extends Page>,List<org.apache.click.extras.spring.SpringClickServlet.BeanNameAndMethod>> pageSetterBeansMap
          The list of page injectable Spring beans, keyed on page class name.
static String SPRING_PATH
          The Servlet initialization parameter name for the path to the Spring XML application context definition file:   "spring-path".
 
Fields inherited from class org.apache.click.ClickServlet
CLICK_FORWARD, CONFIG_SERVICE_CLASS, configService, FORWARD_PAGE, logger, memberAccess, resourceService, TYPE_CONVERTER_CLASS, typeConverter
 
Constructor Summary
SpringClickServlet()
           
 
Method Summary
protected  void activatePageInstance(Page page)
          This method associates the ApplicationContext with any ApplicationContextAware pages and supports the deserialization of stateful pages.
protected  ApplicationContext getApplicationContext()
          Return the configured Spring application context.
 void init()
          Initialize the SpringClickServlet and the Spring application context bean factory.
protected  Page newPageInstance(String path, Class<? extends Page> pageClass, HttpServletRequest request)
          Create a new Spring Page bean if defined in the application context, or a new Page instance otherwise.
protected  String toBeanName(Class<?> aClass)
          Return the Spring beanName for the given class.
 
Methods inherited from class org.apache.click.ClickServlet
createActionEventDispatcher, createContext, createControlRegistry, createErrorPage, createPage, createPage, createPage, createPageImports, createTemplateModel, destroy, doGet, doPost, getConfigService, getTypeConverter, handleAjaxException, handleException, handleRequest, initPage, performOnInit, performOnPostOrGet, performOnProcess, performOnRender, performOnSecurityCheck, performPageAction, performRender, performRender, processAjaxPageEvents, processAjaxTargetControls, processPage, processPageEvents, processPageOnDestroy, processPageRequestParams, renderActionResult, renderJSP, renderTemplate, setPageResponseHeaders, setRequestAttributes
 
Methods inherited from class javax.servlet.http.HttpServlet
doDelete, doHead, doOptions, doPut, doTrace, getLastModified, service, service
 
Methods inherited from class javax.servlet.GenericServlet
getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, log, log
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

INJECT_PAGE_BEANS

public static final String INJECT_PAGE_BEANS
The Servlet initialization parameter name for the option to have the SpringClickServlet inject Spring beans into page instances:   "inject-page-beans".

See Also:
Constant Field Values

SPRING_PATH

public static final String SPRING_PATH
The Servlet initialization parameter name for the path to the Spring XML application context definition file:   "spring-path".

See Also:
Constant Field Values

applicationContext

protected ApplicationContext applicationContext
Spring application context bean factory.


pageSetterBeansMap

protected Map<Class<? extends Page>,List<org.apache.click.extras.spring.SpringClickServlet.BeanNameAndMethod>> pageSetterBeansMap
The list of page injectable Spring beans, keyed on page class name.

Constructor Detail

SpringClickServlet

public SpringClickServlet()
Method Detail

init

public void init()
          throws ServletException
Initialize the SpringClickServlet and the Spring application context bean factory. An Spring ClassPathXmlApplicationContext bean factory is used and initialize with the servlet init-param named "spring-path".

Overrides:
init in class ClickServlet
Throws:
ServletException - if the click app could not be initialized
See Also:
ClickServlet.init()

newPageInstance

protected Page newPageInstance(String path,
                               Class<? extends Page> pageClass,
                               HttpServletRequest request)
                        throws Exception
Create a new Spring Page bean if defined in the application context, or a new Page instance otherwise.

If the "inject-page-beans" option is enabled this method will inject any Spring beans matching the Page's properties.

Overrides:
newPageInstance in class ClickServlet
Parameters:
path - the request page path
pageClass - the page Class the request is mapped to
request - the page request
Returns:
a new Page object
Throws:
Exception - if an error occurs creating the Page
See Also:
ClickServlet.newPageInstance(String, Class, HttpServletRequest)

getApplicationContext

protected ApplicationContext getApplicationContext()
Return the configured Spring application context.

Returns:
the configured Spring application context.

activatePageInstance

protected void activatePageInstance(Page page)
This method associates the ApplicationContext with any ApplicationContextAware pages and supports the deserialization of stateful pages.

Overrides:
activatePageInstance in class ClickServlet
Parameters:
page - the page instance to activate
See Also:
ClickServlet.activatePageInstance(Page)

toBeanName

protected String toBeanName(Class<?> aClass)
Return the Spring beanName for the given class.

Parameters:
aClass - the class to get the Spring bean name from
Returns:
the class bean name