Return-Path: Delivered-To: apmail-click-commits-archive@www.apache.org Received: (qmail 83223 invoked from network); 11 Jul 2010 15:43:40 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 11 Jul 2010 15:43:40 -0000 Received: (qmail 72672 invoked by uid 500); 11 Jul 2010 15:43:40 -0000 Delivered-To: apmail-click-commits-archive@click.apache.org Received: (qmail 72657 invoked by uid 500); 11 Jul 2010 15:43:40 -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 72649 invoked by uid 99); 11 Jul 2010 15:43:40 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 11 Jul 2010 15:43:40 +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, 11 Jul 2010 15:43:37 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3C5642388A02; Sun, 11 Jul 2010 15:42:14 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r963094 - /click/trunk/click/framework/src/org/apache/click/ControlRegistry.java Date: Sun, 11 Jul 2010 15:42:14 -0000 To: commits@click.apache.org From: sabob@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100711154214.3C5642388A02@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: sabob Date: Sun Jul 11 15:42:13 2010 New Revision: 963094 URL: http://svn.apache.org/viewvc?rev=963094&view=rev Log: added a guard against duplicate callbacks and javadoc Modified: click/trunk/click/framework/src/org/apache/click/ControlRegistry.java Modified: click/trunk/click/framework/src/org/apache/click/ControlRegistry.java URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/ControlRegistry.java?rev=963094&r1=963093&r2=963094&view=diff ============================================================================== --- click/trunk/click/framework/src/org/apache/click/ControlRegistry.java (original) +++ click/trunk/click/framework/src/org/apache/click/ControlRegistry.java Sun Jul 11 15:42:13 2010 @@ -27,9 +27,50 @@ import org.apache.click.service.LogServi import org.apache.commons.lang.Validate; /** - * Provides a registry for Controls. + * Provides a centralized registry where Controls can be registered, allowing + * Click to provide advanced functionality such as AJAX + * {@link org.apache.click.Behavior Behaviors} and + * {@link org.apache.click.Callback Callbacks}. + *

+ * Please note: the registry is recreated each request and Controls have + * to be registered for every request. * - * TODO: javadoc + *

Behavior Usage

+ * TODO + * + *

Callback Usage

+ * This class will only rarely be used by Control developers who want to create + * a custom Control with {@link org.apache.click.Callback Callback} functionality. + *

+ * Example: + *

+ * public class MyControl extends AbstractControl {
+ *
+ *     // The Callback is registered during onInit to cater for both stateless and
+ *     // stateful pages
+ *     public void onInit() {
+ *         Callback callback = getCallback();
+ *         ControlRegistry.registerCallback(this, callback);
+ *     }
+ *
+ *     private Callback getCallback() {
+ *         callback = new Callback() {
+ *             public void preResponse(Control source) {
+ *                 // Invoked before the controls are rendered to the client
+ *                 addIndexToControlNames();
+ *             }
+ *
+ *             public void preGetHeadElements(Control source) {
+ *                 // Invoked before the HEAD elements are retrieved for each Control
+ *             }
+ *
+ *             public void preDestroy(Control source) {
+ *                 // Invoked before onDestroy event
+ *             }
+ *         };
+ *         return callback;
+ *     }
+ * } 
*/ public class ControlRegistry { @@ -52,6 +93,11 @@ public class ControlRegistry { // Constructors ----------------------------------------------------------- + /** + * Construct the ControlRegistry with the given ConfigService. + * + * @param configService the click application configuration service. + */ public ControlRegistry(ConfigService configService) { this.logger = configService.getLogService(); } @@ -62,16 +108,46 @@ public class ControlRegistry { * Register the control to be processed by the ClickServlet if the control * is the Ajax target. A control is an Ajax target if the * {@link Control#isAjaxTarget(org.apache.click.Context)} method returns true. - * Target controls have their {@link Control#onProcess()} method invoked. + * Once a target control is identified, ClickServlet invokes its + * {@link Control#onProcess()} method invoked. + *

+ * Please note: the ControlRegistry is stateless. For each request + * a new registry is created. This means a control is only registered for + * a single request and must be registered again for subsequent requests. * - * @param control the control to register + * Stateful Page note: when invoking this method directly from a stateful + * page, ensure the control is registered on every request. Generally this + * means that for stateful pages this method should be used in the Page + * onInit method (which is invoked for every request) instead of the + * Page constructor (which is invoked only once). This warning can be ignored + * for stateless pages since both the constructor and onInit method is invoked + * every request. + * + * @param control the control to register as an Ajax target */ public static void registerAjaxTarget(Control control) { + if (control == null) { + throw new IllegalArgumentException("control cannot be null"); + } + ControlRegistry instance = getThreadLocalRegistry(); instance.internalRegisterAjaxTarget(control); } + /** + * Register the source control and associated callback. + * + * @param source the behavior source control + * @param callback the callback to register + */ public static void registerCallback(Control control, Callback callback) { + if (control == null) { + throw new IllegalArgumentException("control cannot be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + ControlRegistry instance = getThreadLocalRegistry(); instance.internalRegisterCallback(control, callback); } @@ -103,9 +179,9 @@ public class ControlRegistry { } /** - * Register the ajax target control. + * Register the AJAX target control. * - * @param control the ajax target control + * @param control the AJAX target control */ void internalRegisterAjaxTarget(Control control) { Validate.notNull(control, "Null control parameter"); @@ -113,16 +189,22 @@ public class ControlRegistry { } /** - * Register the behavior source control. + * Register the source control and associated callback. * * @param source the behavior source control + * @param callback the callback to register */ void internalRegisterCallback(Control source, Callback callback) { Validate.notNull(source, "Null source parameter"); Validate.notNull(callback, "Null callback parameter"); CallbackHolder callbackHolder = new CallbackHolder(source, callback); - getCallbacks().add(callbackHolder); + + // Guard against adding duplicate callbacks + List localCallbacks = getCallbacks(); + if (!localCallbacks.contains(callbackHolder)) { + localCallbacks.add(callbackHolder); + } } void processPreResponse(Context context) { @@ -350,5 +432,48 @@ public class ControlRegistry { public void setControl(Control control) { this.control = control; } + + /** + * @see Object#equals(java.lang.Object) + * + * @param o the reference object with which to compare + * @return true if this object equals the given object + */ + @Override + public boolean equals(Object o) { + + //1. Use the == operator to check if the argument is a reference to this object. + if (o == this) { + return true; + } + + //2. Use the instanceof operator to check if the argument is of the correct type. + if (!(o instanceof CallbackHolder)) { + return false; + } + + //3. Cast the argument to the correct type. + CallbackHolder that = (CallbackHolder) o; + + boolean equals = this.control == null ? that.control == null : this.control.equals(that.control); + if (!equals) { + return false; + } + + return this.callback == null ? that.callback == null : this.callback.equals(that.callback); + } + + /** + * @see java.lang.Object#hashCode() + * + * @return the CallbackHolder hashCode + */ + @Override + public int hashCode() { + int result = 17; + result = 37 * result + (control == null ? 0 : control.hashCode()); + result = 37 * result + (callback == null ? 0 : callback.hashCode()); + return result; + } } }