Return-Path: Delivered-To: apmail-click-commits-archive@www.apache.org Received: (qmail 97869 invoked from network); 17 Oct 2010 04:12:30 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 17 Oct 2010 04:12:30 -0000 Received: (qmail 92785 invoked by uid 500); 17 Oct 2010 04:12:30 -0000 Delivered-To: apmail-click-commits-archive@click.apache.org Received: (qmail 92766 invoked by uid 500); 17 Oct 2010 04:12:29 -0000 Mailing-List: contact commits-help@click.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: click-dev@click.apache.org Delivered-To: mailing list commits@click.apache.org Received: (qmail 92758 invoked by uid 99); 17 Oct 2010 04:12:28 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 17 Oct 2010 04:12:28 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 17 Oct 2010 04:12:24 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9A96323889F7; Sun, 17 Oct 2010 04:11:27 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1023422 - in /click/trunk/click/framework/src/org/apache/click: Stateful.java util/ClickUtils.java Date: Sun, 17 Oct 2010 04:11:27 -0000 To: commits@click.apache.org From: sabob@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20101017041127.9A96323889F7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: sabob Date: Sun Oct 17 04:11:26 2010 New Revision: 1023422 URL: http://svn.apache.org/viewvc?rev=1023422&view=rev Log: added Stateful interface and helper methods. CLK-715 Added: click/trunk/click/framework/src/org/apache/click/Stateful.java Modified: click/trunk/click/framework/src/org/apache/click/util/ClickUtils.java Added: click/trunk/click/framework/src/org/apache/click/Stateful.java URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/Stateful.java?rev=1023422&view=auto ============================================================================== --- click/trunk/click/framework/src/org/apache/click/Stateful.java (added) +++ click/trunk/click/framework/src/org/apache/click/Stateful.java Sun Oct 17 04:11:26 2010 @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.click; + +/** + * Provides an interface that controls can implement that need to preserve + * state across multiple requests. + *

+ * Please note: Control state is not saved and restored automatically by + * Click. Instead, state saving and restoring is under full control of the + * developer through a public API. + *

+ * Controls implementing this interface are expected to {@link #getState() save} + * and {@link #setState(java.lang.Object) restore} their internal state, as well + * as the state of their child controls. Controls can further expose a public + * API for saving and restoring their state. + *

+ * An example implementation is shown below: + * + *

+ * public class MyControl extends AbstractControl implements Stateful {
+ *
+ *     private String value;
+ *
+ *     ...
+ *
+ *     // Return the Control internal state
+ *     public Object getState() {
+ *         return getValue();
+ *     }
+ *
+ *     // Set the Control internal state
+ *     public void setState(Object state) {
+ *         String fieldState = (String) state;
+ *         setValue(fieldState);
+ *     }
+ *
+ *    // A save state helper method
+ *     public void saveState(Context context) {
+ *         // Save the control state in the session
+ *         ClickUtils.saveState(this, getName(), context);
+ *     }
+ *    // A restore state helper method
+ *     public void restoreState(Context context) {
+ *         // Load the control state from the session
+           ClickUtils.restoreState(this, getName(), context);
+ *     }
+ *
+ *    // A remove state helper method
+ *     public void removeState(Context context) {
+ *         // Remove the control state from the session
+*          ClickUtils.removeState(this, getName(), context);
+ *     }
+ *
+ * } 
+ * + * Saving and restoring Control state is controlled by the developer. + *

+ * For example: + * + *

+ * public class MyPage extends Page {
+ *
+ *    private MyControl control = new MyControl("mycontrol");
+ *
+ *     public MyPage() {
+ *         // Load the control state from the session
+ *         control.loadState(getContext());
+ *     }
+ *
+ *     public void onPost() {
+ *
+ *         Context context = getContext();
+ *
+ *         String id = context.getParameter("id");
+ *         control.setValue(id);
+ *
+ *         // Save control state to the session
+ *         control.saveState(context);
+ *     }
+ * }
+ * 
+ */ +public interface Stateful { + + /** + * Return the Control internal state. State will generally be stored in the + * Session, so it is recommended to ensure the state is + * {@link java.io.Serializable serializable}. + *

+ * Example implementation below: + *

+     * public Object getState() {
+     *     Object stateArray[] = new Object[3];
+     *     stateArray[0] = getValue();
+     *     stateArray[1] = Number.valueOf(getNumber());
+     *     stateArray[2] = Boolean.valueOf(getBoolean());
+     *     return stateArray;
+     * } 
+ * + * @return the control internal state + */ + public Object getState(); + + /** + * Restore the Control internal state from the given state object. + *

+ * Example below: + *

+     * public void setState(Object state) {
+     *
+     *     Object[] stateArray = (Object[]) state;
+     *     String storedValue = stateArray[0];
+     *     setValue(storedValue);
+     *
+     *     int storedNumber = ((Integer) stateArray[1]).intValue();
+     *     setNumber(storedNumber);
+     *
+     *     boolean storedBoolen = ((Boolean) stateArray[2]).booleanValue();
+     *     setBoolean(storedBoolean);
+     * } 
+ * + * @param state the control state to restore + */ + public void setState(Object state); +} Modified: click/trunk/click/framework/src/org/apache/click/util/ClickUtils.java URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/util/ClickUtils.java?rev=1023422&r1=1023421&r2=1023422&view=diff ============================================================================== --- click/trunk/click/framework/src/org/apache/click/util/ClickUtils.java (original) +++ click/trunk/click/framework/src/org/apache/click/util/ClickUtils.java Sun Oct 17 04:11:26 2010 @@ -61,6 +61,7 @@ import org.apache.click.Context; import org.apache.click.Control; import org.apache.click.Page; import org.apache.click.ActionResult; +import org.apache.click.Stateful; import org.apache.click.control.AbstractControl; import org.apache.click.control.AbstractLink; import org.apache.click.control.ActionLink; @@ -2566,6 +2567,112 @@ public class ClickUtils { } /** + * Remove the control state from the session for the given stateful control, + * control name and request context. + * + * @param control the stateful control which state to restore + * @param controlName the name of the control which state to restore + * @param context the request context + */ + public static void removeState(Stateful control, String controlName, Context context) { + if (control == null) { + throw new IllegalStateException("Control cannot be null."); + } + if (controlName == null) { + throw new IllegalStateException(ClassUtils.getShortClassName(control.getClass()) + + " name has not been set. State cannot be restored until the name is set"); + } + if (context == null) { + throw new IllegalStateException("Context cannot be null."); + } + + String resourcePath = context.getResourcePath(); + Map pageMap = ClickUtils.getPageState(resourcePath, context); + if (pageMap != null) { + Object pop = pageMap.remove(controlName); + + // Check if control state was emoved + if (pop != null) { + // If control state was removed, set session attribute to force + // session replication in a cluster + context.setSessionAttribute(resourcePath, pageMap); + } + } + } + + /** + * Restore the control state from the session for the given stateful control, + * control name and request context. + *

+ * This method delegates to {@link org.apache.click.Stateful#setState(java.lang.Object)} + * to restore the control state. + * + * @param control the stateful control which state to restore + * @param controlName the name of the control which state to restore + * @param context the request context + */ + public static void restoreState(Stateful control, String controlName, Context context) { + if (control == null) { + throw new IllegalStateException("Control cannot be null."); + } + if (controlName == null) { + throw new IllegalStateException(ClassUtils.getShortClassName(control.getClass()) + + " name has not been set. State cannot be restored until the name is set"); + } + if (context == null) { + throw new IllegalStateException("Context cannot be null."); + } + + String resourcePath = context.getResourcePath(); + Map pageMap = ClickUtils.getPageState(resourcePath, context); + if (pageMap != null) { + control.setState(pageMap.get(controlName)); + } + } + + /** + * Save the control state in the session for the given stateful control, + * control name and request context. + *

+ * * This method delegates to {@link org.apache.click.Stateful#getState()} + * to retrieve the control state to save. + * + * @param control the stateful control which state to save + * @param controlName the name of the control control which state to save + * @param context the request context + */ + public static void saveState(Stateful control, String controlName, Context context) { + if (control == null) { + throw new IllegalStateException("Control cannot be null."); + } + if (controlName == null) { + throw new IllegalStateException(ClassUtils.getShortClassName(control.getClass()) + + " name has not been set. State cannot be saved until the name is set"); + } + if (context == null) { + throw new IllegalStateException("Context cannot be null."); + } + + String resourcePath = context.getResourcePath(); + Map pageMap = getOrCreatePageState(resourcePath, context); + Object state = control.getState(); + if (state == null) { + // Set null state to see if it differs from previous state + Object pop = pageMap.put(controlName, state); + if(pop != null) { + // Previous state differs from current state, so set the + // session attribute to force session replication in a cluster + context.setSessionAttribute(resourcePath, pageMap); + } + } else { + pageMap.put(controlName, state); + // After control state has been added to the page state, set the + // session attribute to force session replication in a cluster + context.setSessionAttribute(resourcePath, pageMap); + } + } + + /** * Return the getter method name for the given property name. * * @param property the property name @@ -3129,6 +3236,42 @@ public class ClickUtils { } /** + * Retrieve or create the map where page state is stored in. + * + * @see #getPageState(java.lang.String, org.apache.click.Context) + * + * @param pagePath the path under which the page state is stored in the + * session + * @param context the request context + * @return the map where page state is stored in + */ + private static Map getOrCreatePageState(String pagePath, Context context) { + Map pageMap = getPageState(pagePath, context); + if (pageMap == null) { + pageMap = new HashMap(); + } + return pageMap; + } + + /** + * Retrieve the map for the given pagePath from the session where page state + * is stored in. + * + * @param pagePath the path under which the page state is stored in the + * session + * @param context the request context + * @return the map where page state is stored in + */ + private static Map getPageState(String pagePath, Context context) { + Object storedPageValue = context.getSessionAttribute(pagePath); + Map pageMap = null; + if (storedPageValue != null) { + pageMap = (Map) storedPageValue; + } + return pageMap; + } + + /** * Invoke the named method on the given target object and return the result. * * @param target the target object with the method to invoke