click-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sa...@apache.org
Subject svn commit: r939282 - in /click/trunk/click: documentation/docs/ examples/src/org/apache/click/examples/page/introduction/ examples/src/org/apache/click/examples/page/table/ extras/src/org/apache/click/extras/spring/
Date Thu, 29 Apr 2010 11:38:34 GMT
Author: sabob
Date: Thu Apr 29 11:38:33 2010
New Revision: 939282

URL: http://svn.apache.org/viewvc?rev=939282&view=rev
Log:
SpringClickServlet should re-inject beans after page deserialization. CLK-667

Modified:
    click/trunk/click/documentation/docs/roadmap-changes.html
    click/trunk/click/examples/src/org/apache/click/examples/page/introduction/AdvancedTable.java
    click/trunk/click/examples/src/org/apache/click/examples/page/table/SearchTablePage.java
    click/trunk/click/examples/src/org/apache/click/examples/page/table/TableStyles.java
    click/trunk/click/extras/src/org/apache/click/extras/spring/SpringClickServlet.java

Modified: click/trunk/click/documentation/docs/roadmap-changes.html
URL: http://svn.apache.org/viewvc/click/trunk/click/documentation/docs/roadmap-changes.html?rev=939282&r1=939281&r2=939282&view=diff
==============================================================================
--- click/trunk/click/documentation/docs/roadmap-changes.html (original)
+++ click/trunk/click/documentation/docs/roadmap-changes.html Thu Apr 29 11:38:33 2010
@@ -189,6 +189,13 @@ includes improved Ajax support and @Bind
         </ul>
       </li>
       <li class="change">
+        Added improved stateful page support when adding controls to containers.
+        In previous releases an exception was raised if the control is
+        already present in the container or page. The new behavior is to silently
+        replace the existing control
+        [<a target="_blank" href="https://issues.apache.org/jira/browse/CLK-666">CLK-666</a>].
+      </li>
+      <li class="change">
         Added methods to Fields for styling their labels. See new methods
         <a href="click-api/org/apache/click/control/Field.html#setLabelStyle(java.lang.String)">Field.setLabelStyle(String)</a>
         and <a href="click-api/org/apache/click/control/Field.html#setLabelStyleClass(java.lang.String)">Field.setLabelStyleClass(String)</a>.
@@ -249,6 +256,12 @@ includes improved Ajax support and @Bind
         [<a target="_blank" href="https://issues.apache.org/jira/browse/CLK-647">CLK-647</a>].
       </li>
       <li class="change">
+        Improved SpringClickServlet to re-inject transient beans after stateful
+        page deserialization. This feature is only supported when the stateful
+        page instance is created by Click, not Spring
+        [<a target="_blank" href="https://issues.apache.org/jira/browse/CLK-667">CLK-667</a>].
+      </li>
+      <li class="change">
         Replaced Page and Control getMessage methods with varargs equivalents
         [<a target="_blank" href="https://issues.apache.org/jira/browse/CLK-604">CLK-604</a>].
       </li>

Modified: click/trunk/click/examples/src/org/apache/click/examples/page/introduction/AdvancedTable.java
URL: http://svn.apache.org/viewvc/click/trunk/click/examples/src/org/apache/click/examples/page/introduction/AdvancedTable.java?rev=939282&r1=939281&r2=939282&view=diff
==============================================================================
--- click/trunk/click/examples/src/org/apache/click/examples/page/introduction/AdvancedTable.java
(original)
+++ click/trunk/click/examples/src/org/apache/click/examples/page/introduction/AdvancedTable.java
Thu Apr 29 11:38:33 2010
@@ -32,9 +32,6 @@ import org.apache.click.examples.service
 import org.apache.click.extras.control.LinkDecorator;
 import org.apache.click.util.Bindable;
 import org.apache.click.dataprovider.DataProvider;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
 
 /**
  * Provides an advanced Table usage example Page.
@@ -42,7 +39,7 @@ import org.springframework.context.Appli
  * This example also demonstrates how a stateful Page can be used to preserve
  * the Table sort and paging state while editing customers.
  */
-public class AdvancedTable extends BorderPage implements ApplicationContextAware {
+public class AdvancedTable extends BorderPage {
 
     private static final long serialVersionUID = 1L;
 
@@ -51,10 +48,11 @@ public class AdvancedTable extends Borde
     @Bindable protected ActionLink deleteLink = new ActionLink("Delete", this, "onDeleteClick");
 
     /**
-     * Spring's application context from where a CustomerService instance can be
-     * retrieved.
+     * Spring injected CustomerService bean. The service is marked as transient
+     * since the page is stateful and we don't want to serialize the service
+     * along with the page.
      */
-    private transient ApplicationContext applicationContext;
+    private transient CustomerService customerService;
 
     // Constructor ------------------------------------------------------------
 
@@ -119,17 +117,15 @@ public class AdvancedTable extends Borde
      * @return CustomerService instance
      */
     public CustomerService getCustomerService() {
-        return (CustomerService) applicationContext.getBean("customerService");
+        return customerService;
     }
 
     /**
-     * Set Spring application context as defined by
-     * {@link org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)}.
+     * Set the CustomerService instance from Spring application context.
      *
-     * @param applicationContext set Spring application context
+     * @param customerService the customerService instance to inject
      */
-    public void setApplicationContext(ApplicationContext applicationContext)
-        throws BeansException {
-        this.applicationContext = applicationContext;
+    public void setCustomerService(CustomerService customerService) {
+        this.customerService = customerService;
     }
 }

Modified: click/trunk/click/examples/src/org/apache/click/examples/page/table/SearchTablePage.java
URL: http://svn.apache.org/viewvc/click/trunk/click/examples/src/org/apache/click/examples/page/table/SearchTablePage.java?rev=939282&r1=939281&r2=939282&view=diff
==============================================================================
--- click/trunk/click/examples/src/org/apache/click/examples/page/table/SearchTablePage.java
(original)
+++ click/trunk/click/examples/src/org/apache/click/examples/page/table/SearchTablePage.java
Thu Apr 29 11:38:33 2010
@@ -38,14 +38,11 @@ import org.apache.click.extras.control.L
 import org.apache.click.extras.control.TableInlinePaginator;
 import org.apache.click.util.Bindable;
 import org.apache.click.dataprovider.DataProvider;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
 
 /**
  * Provides an demonstration of Table control paging.
  */
-public class SearchTablePage extends BorderPage implements ApplicationContextAware {
+public class SearchTablePage extends BorderPage {
 
     private static final long serialVersionUID = 1L;
 
@@ -57,7 +54,12 @@ public class SearchTablePage extends Bor
     private TextField nameField = new TextField(Customer.NAME_PROPERTY);
     private DateField dateField = new DateField(Customer.DATE_JOINED_PROPERTY, "Start Date");
 
-    private transient ApplicationContext applicationContext;
+    /**
+     * Spring injected CustomerService bean. The service is marked as transient
+     * since the page is stateful and we don't want to serialize the service
+     * along with the page.
+     */
+    private transient CustomerService customerService;
 
     // Constructor ------------------------------------------------------------
 
@@ -168,17 +170,15 @@ public class SearchTablePage extends Bor
      * @return CustomerService instance
      */
     public CustomerService getCustomerService() {
-        return (CustomerService) applicationContext.getBean("customerService");
+        return customerService;
     }
 
     /**
-     * Set Spring application context as defined by
-     * {@link org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)}.
+     * Set the CustomerService instance from Spring application context.
      *
-     * @param applicationContext set Spring application context
+     * @param customerService the customerService instance to inject
      */
-    public void setApplicationContext(ApplicationContext applicationContext)
-        throws BeansException {
-        this.applicationContext = applicationContext;
+    public void setCustomerService(CustomerService customerService) {
+        this.customerService = customerService;
     }
 }

Modified: click/trunk/click/examples/src/org/apache/click/examples/page/table/TableStyles.java
URL: http://svn.apache.org/viewvc/click/trunk/click/examples/src/org/apache/click/examples/page/table/TableStyles.java?rev=939282&r1=939281&r2=939282&view=diff
==============================================================================
--- click/trunk/click/examples/src/org/apache/click/examples/page/table/TableStyles.java (original)
+++ click/trunk/click/examples/src/org/apache/click/examples/page/table/TableStyles.java Thu
Apr 29 11:38:33 2010
@@ -32,14 +32,11 @@ import org.apache.click.examples.service
 import org.apache.click.extras.control.TableInlinePaginator;
 import org.apache.click.util.Bindable;
 import org.apache.click.dataprovider.DataProvider;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
 
 /**
  * Provides an demonstration of Table control styles.
  */
-public class TableStyles extends BorderPage implements ApplicationContextAware {
+public class TableStyles extends BorderPage {
 
     private static final long serialVersionUID = 1L;
 
@@ -49,7 +46,12 @@ public class TableStyles extends BorderP
     private Select styleSelect = new Select("style", "Table Style:");
     private Checkbox hoverCheckbox = new Checkbox("hover", "Hover Rows:");
 
-    private transient ApplicationContext applicationContext;
+    /**
+     * Spring injected CustomerService bean. The service is marked as transient
+     * since the page is stateful and we don't want to serialize the service
+     * along with the page.
+     */
+    private transient CustomerService customerService;
 
     // Constructor -----------------------------------------------------------
 
@@ -132,17 +134,15 @@ public class TableStyles extends BorderP
      * @return CustomerService instance
      */
     public CustomerService getCustomerService() {
-        return (CustomerService) applicationContext.getBean("customerService");
+        return customerService;
     }
 
     /**
-     * Set Spring application context as defined by
-     * {@link org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)}.
+     * Set the CustomerService instance from Spring application context.
      *
-     * @param applicationContext set Spring application context
+     * @param customerService the customerService instance to inject
      */
-    public void setApplicationContext(ApplicationContext applicationContext)
-        throws BeansException {
-        this.applicationContext = applicationContext;
+    public void setCustomerService(CustomerService customerService) {
+        this.customerService = customerService;
     }
 }

Modified: click/trunk/click/extras/src/org/apache/click/extras/spring/SpringClickServlet.java
URL: http://svn.apache.org/viewvc/click/trunk/click/extras/src/org/apache/click/extras/spring/SpringClickServlet.java?rev=939282&r1=939281&r2=939282&view=diff
==============================================================================
--- click/trunk/click/extras/src/org/apache/click/extras/spring/SpringClickServlet.java (original)
+++ click/trunk/click/extras/src/org/apache/click/extras/spring/SpringClickServlet.java Thu
Apr 29 11:38:33 2010
@@ -44,9 +44,13 @@ import org.springframework.web.context.s
  * Provides a Spring framework integration <tt>SpringClickServlet</tt>.
  * <p/>
  * This Spring integration servlet provides a number of integration options
- * using Spring with Click pages. These options detailed below.
+ * using Spring with Click pages. These options are detailed below.
+ * <p/>
+ * <b>Stateful pages caveat:</b> please note that stateful pages do not work
+ * with all options.
  *
- * <h3>1. Spring instantiated Pages with &#64;Component configuration</h3>
+ * <h3><a name="option1"></a>1. Spring instantiated Pages with &#64;Component
+ * configuration</h3>
  *
  * With this option Page classes are configured with Spring using the
  * &#64;Component annotation. When the SpringClickServlet receives a page
@@ -85,9 +89,20 @@ import org.springframework.web.context.s
  * } </pre>
  *
  * This is the most powerful and convenient Spring integration option, but does
- * require Spring 2.5.x and Java 1.5 or later.
+ * require Spring 2.5.x or later.
+ *
+ * <p/>
+ * <b><a name="stateful-page-caveat"></a>Stateful page caveat:</b>
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
+ * <tt>transient</tt>. 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 <a href="#option3">option 3</a> below.
  *
- * <h3>2. Spring instantiated Pages with Spring XML configuration</h3>
+ * <h3><a name="option2"></a>2. Spring instantiated Pages with Spring XML
+ * configuration</h3>
  *
  * With this option Page classes are configured using Spring XML configuration.
  * When the SpringClickServlet receives a page request it converts the auto-mapped
@@ -107,10 +122,10 @@ import org.springframework.web.context.s
  *
  * 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 and Java 1.4. An example page bean configuration is
+ * support Spring 1.x or later. An example page bean configuration is
  * provided below:
  *
- * <pre class="codeConfig">
+ * <pre class="prettyprint">
  * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  * &lt;beans&gt;
  *
@@ -121,15 +136,23 @@ import org.springframework.web.context.s
  * <b>Please Note</b> 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.
+ * <p/>
+ * <b>Stateful page caveat:</b> option 2 has the same caveat as
+ * <a href="#stateful-page-caveat">option 1</a>.
  *
- * <h3>3. Click instantiated Pages with injected Spring beans and/or ApplicationContext</h3>
+ * <h3><a name="option3"></a>3. Click instantiated Pages with injected
Spring
+ * beans and/or ApplicationContext</h3>
  *
  * With this integration option Click will instantiate page instances and
  * automatically inject any page properties which match Spring beans defined in
- * the ApplicationContext.
+ * the ApplicationContext. In order to enable bean injection, you need to
+ * configure the SpringClickServlet init parameter:
+ * <a href="#inject-page-beans">inject-page-beans</a>.
  * <p/>
  * While this option is not as powerful as &#64;Component configured pages it is
- * much more convenient than Spring XML configured pages and supports Spring 1.x and Java
1.4.
+ * 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.
  * <p/>
  * An example Page class is provided below which has the customerService property
  * automatically injected by the SpringClickServlet. Note the customerService
@@ -157,7 +180,7 @@ import org.springframework.web.context.s
  * configuration. Continuing our example the Spring XML configuration is provided
  * below:
  *
- * <pre class="codeConfig">
+ * <pre class="prettyprint">
  * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  * &lt;beans&gt;
  *
@@ -165,7 +188,7 @@ import org.springframework.web.context.s
  *
  * &lt;/beans&gt; </pre>
  *
- * This option will also automatically inject the ApplicationContext into new
+ * This option will also automatically inject the ApplicationContext into
  * page instances which implement the {@link org.springframework.context.ApplicationContextAware}
  * interface. Using the applicationContext you can lookup Spring beans manually
  * in your pages. For example:
@@ -186,6 +209,54 @@ import org.springframework.web.context.s
  *
  * This last strategy is probably the least convenient integration option.
  *
+ * <h4><a name="option31"></a>3.1 Spring beans and Stateful pages</h4>
+ *
+ * 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 <tt>transient</tt>.
+ * Transient beans won't be serialized to disk. However once the page is
+ * deserialized the transient beans will need to be injected again.
+ * <p/>
+ * <a href="#option3">Option 3</a> will re-inject Spring beans and the
+ * ApplicationContext after every request. This allows beans to be marked as
+ * <tt>transient</tt> and still function properly when used with stateful pages.
+ *
+ * <pre class="prettyprint">
+ * 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;
+ *     }
+ *
+ *     ..
+ * } </pre>
+ *
  * <h3>Servlet Configuration</h3>
  *
  * The SpringClickServlet can obtain the ApplicationContext either from
@@ -233,9 +304,9 @@ import org.springframework.web.context.s
  *
  * &lt;/web-app&gt; </pre>
  *
- * To configure page Spring bean injection (option 3 above), you need to configure
- * the <span class="blue">inject-page-beans</span> servlet init parameter. For
- * example:
+ * <a name="inject-page-beans"></a>To configure page Spring bean injection
+ * (<a href="#option3">option 3</a> above), you need to configure the
+ * <span class="blue">inject-page-beans</span> servlet init parameter. For example:
  *
  * <pre class="codeConfig">
  * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
@@ -403,25 +474,6 @@ public class SpringClickServlet extends 
 
         } else {
             page = (Page) pageClass.newInstance();
-
-            // Inject any Spring beans into the page instance
-            if (!pageSetterBeansMap.isEmpty()) {
-                List beanList = (List) pageSetterBeansMap.get(page.getClass());
-                if (beanList != null) {
-                    for (int i = 0; i < beanList.size(); i++) {
-                        BeanNameAndMethod bnam = (BeanNameAndMethod) beanList.get(i);
-                        Object bean = getApplicationContext().getBean(bnam.beanName);
-
-                        try {
-                            Object[] args = { bean };
-                            bnam.method.invoke(page, args);
-
-                        } catch (Exception error) {
-                            throw new RuntimeException(error);
-                        }
-                    }
-                }
-            }
         }
 
         return page;
@@ -438,8 +490,8 @@ public class SpringClickServlet extends 
 
     /**
      * This method associates the <tt>ApplicationContext</tt> with any
-     * <tt>ApplicationContextAware</tt> pages and supports the deserialized of
-     * stateful pages.
+     * <tt>ApplicationContextAware</tt> pages and supports the deserialization
+     * of stateful pages.
      *
      * @see ClickServlet#activatePageInstance(Page)
      *
@@ -447,10 +499,43 @@ public class SpringClickServlet extends 
      */
     @Override
     protected void activatePageInstance(Page page) {
+        ApplicationContext applicationContext = getApplicationContext();
+
         if (page instanceof ApplicationContextAware) {
             ApplicationContextAware aware =
                 (ApplicationContextAware) page;
-            aware.setApplicationContext(getApplicationContext());
+            aware.setApplicationContext(applicationContext);
+        }
+
+        Class pageClass = page.getClass();
+        String beanName = toBeanName(pageClass);
+
+        if (applicationContext.containsBean(beanName)
+            || applicationContext.containsBean(pageClass.getName())) {
+
+            // Beans are injected through Spring
+        } else {
+
+            // Inject any Spring beans into the page instance
+            if (!pageSetterBeansMap.isEmpty()) {
+                // TODO in development mode, lazily loaded page instances won't
+                // have their setters mapped
+                List beanList = (List) pageSetterBeansMap.get(page.getClass());
+                if (beanList != null) {
+                    for (int i = 0; i < beanList.size(); i++) {
+                        BeanNameAndMethod bnam = (BeanNameAndMethod) beanList.get(i);
+                        Object bean = applicationContext.getBean(bnam.beanName);
+
+                        try {
+                            Object[] args = { bean };
+                            bnam.method.invoke(page, args);
+
+                        } catch (Exception error) {
+                            throw new RuntimeException(error);
+                        }
+                    }
+                }
+            }
         }
     }
 



Mime
View raw message