You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@click.apache.org by sa...@apache.org on 2010/10/17 06:11:27 UTC

svn commit: r1023422 - in /click/trunk/click/framework/src/org/apache/click: Stateful.java util/ClickUtils.java

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.
+ * <p/>
+ * <b>Please note:</b> 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.
+ * <p/>
+ * 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.
+ * <p/>
+ * An example implementation is shown below:
+ *
+ * <pre class="prettyprint">
+ * 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);
+ *     }
+ *
+ * } </pre>
+ *
+ * Saving and restoring Control state is controlled by the developer.
+ * <p/>
+ * For example:
+ *
+ * <pre class="prettyprint">
+ * 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);
+ *     }
+ * }
+ * </pre>
+ */
+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}.
+     * <p/>
+     * Example implementation below:
+     * <pre class="prettyprint">
+     * public Object getState() {
+     *     Object stateArray[] = new Object[3];
+     *     stateArray[0] = getValue();
+     *     stateArray[1] = Number.valueOf(getNumber());
+     *     stateArray[2] = Boolean.valueOf(getBoolean());
+     *     return stateArray;
+     * } </pre>
+     *
+     * @return the control internal state
+     */
+    public Object getState();
+
+    /**
+     * Restore the Control internal state from the given state object.
+     * <p/>
+     * Example below:
+     * <pre class="prettyprint">
+     * 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);
+     * } </pre>
+     *
+     * @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.
+     * <p/>
+     * 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.
+     * <p/>
+     * * 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