| /* |
| * 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; |
| |
| import java.io.Serializable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.servlet.ServletContext; |
| |
| import org.apache.click.element.Element; |
| import org.apache.click.util.HtmlStringBuffer; |
| |
| /** |
| * Provides the interface for Page controls. Controls are also referred to |
| * as components or widgets. |
| * <p/> |
| * When a Page request event is processed Controls may perform server side event |
| * processing through their {@link #onProcess()} method. Controls are generally |
| * rendered in a Page by calling their <tt>toString()</tt> method. |
| * <p/> |
| * The Control execution sequence is illustrated below: |
| * <p/> |
| * <img src="control-post-sequence-diagram.png"/> |
| * |
| * <h4>HTML HEAD Elements</h4> |
| * |
| * Control HTML HEAD elements can be included in the Page by overriding the |
| * {@link #getHeadElements()} method. |
| * <p/> |
| * Below is an example of a custom TextField control specifying that the |
| * <tt>custom.js</tt> file should be included in the HTML HEADer: |
| * |
| * <pre class="prettyprint"> |
| * public class CustomField extends TextField { |
| * |
| * <span class="kw">public</span> List getHeadElements() { |
| * if(headElements == null) { |
| * // If headElements is null, create default headElements |
| * headElements = super.getHeadElements(); |
| * |
| * // Add a new JavaScript Import Element for the "/custom.js" script |
| * headElements.add(new JsImport("/click/custom.js")); |
| * } |
| * return headElements; |
| * } |
| * |
| * .. |
| * } </pre> |
| * |
| * <a name="on-deploy"></a> |
| * <h4>Deploying Resources</h4> |
| * |
| * The Click framework uses the Velocity Tools <tt>WebappResourceLoader</tt> for loading templates. |
| * This avoids issues associate with using the Velocity <tt>ClasspathResourceLoader</tt> and |
| * <tt>FileResourceLoader</tt> on J2EE application servers. |
| * To make preconfigured resources (templates, JavaScript, stylesheets, etc.) |
| * available to web applications Click automatically deploys configured classpath |
| * resources to the <tt class="blue">/click</tt> directory at startup |
| * (existing files will not be overwritten). |
| * <p/> |
| * Click supports two ways of deploying pre-configured resources. The recommended |
| * deployment strategy (which also the simplest) relies on packaging resources |
| * into a special folder of the JAR, called <tt>'META-INF/resources'</tt>. At |
| * startup time Click will scan this folder for resources and deploy them to the |
| * web application. This deployment strategy is the same approach taken by the |
| * Servlet 3.0 specification. Please see the section |
| * <a href="../../../../user-guide/html/ch05s03.html#deploying-custom-resources">Deploying Custom Resources</a> |
| * for more details. |
| * <p/> |
| * An alternative approach to deploying static resources on startup is provided |
| * by the Control interface through the {@link #onDeploy(ServletContext)} method. |
| * <p/> |
| * Continuing our example, the <tt>CustomField</tt> control deploys its |
| * <tt>custom.js</tt> file to the <tt>/click</tt> directory: |
| * |
| * <pre class="codeJava"> |
| * <span class="kw">public class</span> CustomField <span class="kw">extends</span> TextField { |
| * .. |
| * |
| * <span class="kw">public void</span> onDeploy(ServletContext servletContext) { |
| * ClickUtils.deployFile |
| * (servletContext, <span class="st">"/com/mycorp/control/custom.js"</span>, <span class="st">"click"</span>); |
| * } |
| * } </pre> |
| * |
| * Controls using the <tt>onDeploy()</tt> method must be registered in the |
| * application <tt>WEB-INF/click.xml</tt> for them to be invoked. |
| * For example: |
| * |
| * <pre class="codeConfig"> |
| * <click-app> |
| * <pages package="com.mycorp.page" automapping="true"/> |
| * |
| * <controls> |
| * <control classname=<span class="st">"com.mycorp.control.CustomField"</span>/> |
| * </controls> |
| * </click-app> </pre> |
| * |
| * When the Click application starts up it will deploy any control elements |
| * defined in the following files in sequential order: |
| * <ul> |
| * <li><tt>/click-controls.xml</tt> |
| * <li><tt>/extras-controls.xml</tt> |
| * <li><tt>WEB-INF/click.xml</tt> |
| * </ul> |
| * |
| * <b>Please note</b> {@link org.apache.click.control.AbstractControl} provides |
| * a default implementation of the Control interface to make it easier for |
| * developers to create their own controls. |
| * |
| * @see org.apache.click.util.PageImports |
| */ |
| public interface Control extends Serializable { |
| |
| /** |
| * The global control messages bundle name: <tt>click-control</tt>. |
| */ |
| public static final String CONTROL_MESSAGES = "click-control"; |
| |
| /** |
| * Return the Page request Context of the Control. |
| * |
| * @deprecated getContext() is now obsolete on the Control interface, |
| * but will still be available on AbstractControl: |
| * {@link org.apache.click.control.AbstractControl#getContext()} |
| * |
| * @return the Page request Context |
| */ |
| public Context getContext(); |
| |
| /** |
| * Return the list of HEAD {@link org.apache.click.element.Element elements} |
| * to be included in the page. Example HEAD elements include |
| * {@link org.apache.click.element.JsImport JsImport}, |
| * {@link org.apache.click.element.JsScript JsScript}, |
| * {@link org.apache.click.element.CssImport CssImport} and |
| * {@link org.apache.click.element.CssStyle CssStyle}. |
| * <p/> |
| * Controls can contribute their own list of HEAD elements by implementing |
| * this method. |
| * <p/> |
| * The recommended approach when implementing this method is to use |
| * <tt>lazy loading</tt> to ensure the HEAD elements are only added |
| * <tt>once</tt> and when <tt>needed</tt>. For example: |
| * |
| * <pre class="prettyprint"> |
| * public MyControl extends AbstractControl { |
| * |
| * public List getHeadElements() { |
| * // Use lazy loading to ensure the JS is only added the |
| * // first time this method is called. |
| * if (headElements == null) { |
| * // Get the head elements from the super implementation |
| * headElements = super.getHeadElements(); |
| * |
| * // Include the control's external JavaScript resource |
| * JsImport jsImport = new JsImport("/mycorp/mycontrol/mycontrol.js"); |
| * headElements.add(jsImport); |
| * |
| * // Include the control's external Css resource |
| * CssImport cssImport = new CssImport("/mycorp/mycontrol/mycontrol.css"); |
| * headElements.add(cssImport); |
| * } |
| * return headElements; |
| * } |
| * } </pre> |
| * |
| * Alternatively one can add the HEAD elements in the Control's constructor: |
| * |
| * <pre class="prettyprint"> |
| * public MyControl extends AbstractControl { |
| * |
| * public MyControl() { |
| * |
| * JsImport jsImport = new JsImport("/mycorp/mycontrol/mycontrol.js"); |
| * getHeadElements().add(jsImport); |
| * |
| * CssImport cssImport = new CssImport("/mycorp/mycontrol/mycontrol.css"); |
| * getHeadHeaders().add(cssImport); |
| * } |
| * } </pre> |
| * |
| * One can also add HEAD elements from event handler methods such as |
| * {@link #onInit()}, {@link #onProcess()}, {@link #onRender()} |
| * etc. |
| * <p/> |
| * The order in which JS and CSS files are included will be preserved in the |
| * page. |
| * <p/> |
| * <b>Note:</b> this method must never return null. If no HEAD elements |
| * are available this method must return an empty {@link java.util.List}. |
| * <p/> |
| * <b>Also note:</b> a common problem when overriding getHeadElements in |
| * subclasses is forgetting to call <em>super.getHeadElements</em>. Consider |
| * carefully whether you should call <em>super.getHeadElements</em> or not. |
| * |
| * @return the list of HEAD elements to be included in the page |
| */ |
| public List<Element> getHeadElements(); |
| |
| /** |
| * Return HTML element identifier attribute "id" value. |
| * |
| * {@link org.apache.click.control.AbstractControl#getId()} |
| * |
| * @return HTML element identifier attribute "id" value |
| */ |
| public String getId(); |
| |
| /** |
| * Set the controls event listener. |
| * <p/> |
| * The method signature of the listener is:<ul> |
| * <li>must have a valid Java method name</li> |
| * <li>takes no arguments</li> |
| * <li>returns a boolean value</li> |
| * </ul> |
| * <p/> |
| * An example event listener method would be: |
| * |
| * <pre class="codeJava"> |
| * <span class="kw">public boolean</span> onClick() { |
| * System.out.println(<span class="st">"onClick called"</span>); |
| * <span class="kw">return true</span>; |
| * } </pre> |
| * |
| * @param listener the listener object with the named method to invoke |
| * @param method the name of the method to invoke |
| * |
| * @deprecated this method is now obsolete on the Control interface, but |
| * will still be available on AbstractControl: |
| * {@link org.apache.click.control.AbstractControl#setListener(java.lang.Object, java.lang.String)} |
| */ |
| public void setListener(Object listener, String method); |
| |
| /** |
| * Return the localized messages <tt>Map</tt> of the Control. |
| * |
| * @return the localized messages <tt>Map</tt> of the Control |
| */ |
| public Map<String, String> getMessages(); |
| |
| /** |
| * Return the name of the Control. Each control name must be unique in the |
| * containing Page model or the containing Form. |
| * |
| * @return the name of the control |
| */ |
| public String getName(); |
| |
| /** |
| * Set the name of the Control. Each control name must be unique in the |
| * containing Page model or the parent container. |
| * <p/> |
| * <b>Please note:</b> changing the name of a Control after it has been |
| * added to its parent container is undefined. Thus it is best <b>not</b> |
| * to change the name of a Control once its been set. |
| * |
| * @param name of the control |
| * @throws IllegalArgumentException if the name is null |
| */ |
| public void setName(String name); |
| |
| /** |
| * Return the parent of the Control. |
| * |
| * @return the parent of the Control |
| */ |
| public Object getParent(); |
| |
| /** |
| * Set the parent of the Control. |
| * |
| * @param parent the parent of the Control |
| */ |
| public void setParent(Object parent); |
| |
| /** |
| * The on deploy event handler, which provides classes the |
| * opportunity to deploy static resources when the Click application is |
| * initialized. |
| * <p/> |
| * For example: |
| * <pre class="codeJava"> |
| * <span class="kw">public void</span> onDeploy(ServletContext servletContext) <span class="kw">throws</span> IOException { |
| * ClickUtils.deployFile |
| * (servletContext, <span class="st">"/com/mycorp/control/custom.js"</span>, <span class="st">"click"</span>); |
| * } </pre> |
| * <b>Please note:</b> a common problem when overriding onDeploy in |
| * subclasses is forgetting to call <em>super.onDeploy</em>. Consider |
| * carefully whether you should call <em>super.onDeploy</em> or not. |
| * <p/> |
| * Click also supports an alternative deployment strategy which relies on |
| * packaging resource (stylesheets, JavaScript, images etc.) following a |
| * specific convention. See the section |
| * <a href="../../../../user-guide/html/ch05s03.html#deploying-custom-resources">Deploying Custom Resources</a> |
| * for further details. |
| * |
| * @param servletContext the servlet context |
| */ |
| public void onDeploy(ServletContext servletContext); |
| |
| /** |
| * The on initialize event handler. Each control will be initialized |
| * before its {@link #onProcess()} method is called. |
| * <p/> |
| * {@link org.apache.click.control.Container} implementations should recursively |
| * invoke the onInit method on each of their child controls ensuring that |
| * all controls receive this event. |
| * <p/> |
| * <b>Please note:</b> a common problem when overriding onInit in |
| * subclasses is forgetting to call <em>super.onInit()</em>. Consider |
| * carefully whether you should call <em>super.onInit()</em> or not, |
| * especially for {@link org.apache.click.control.Container}s which by default |
| * call <em>onInit</em> on all their child controls as well. |
| */ |
| public void onInit(); |
| |
| /** |
| * The on process event handler. Each control will be processed when the |
| * Page is requested. |
| * <p/> |
| * ClickServlet will process all Page controls in the order they were added |
| * to the Page. |
| * <p/> |
| * {@link org.apache.click.control.Container} implementations should recursively |
| * invoke the onProcess method on each of their child controls ensuring that |
| * all controls receive this event. However when a control onProcess method |
| * return false, no other controls onProcess method should be invoked. |
| * <p/> |
| * When a control is processed it should return true if the Page should |
| * continue event processing, or false if no other controls should be |
| * processed and the {@link Page#onGet()} or {@link Page#onPost()} methods |
| * should not be invoked. |
| * <p/> |
| * <b>Please note:</b> a common problem when overriding onProcess in |
| * subclasses is forgetting to call <em>super.onProcess()</em>. Consider |
| * carefully whether you should call <em>super.onProcess()</em> or not, |
| * especially for {@link org.apache.click.control.Container}s which by default |
| * call <em>onProcess</em> on all their child controls as well. |
| * |
| * @return true to continue Page event processing or false otherwise |
| */ |
| public boolean onProcess(); |
| |
| /** |
| * The on render event handler. This event handler is invoked prior to the |
| * control being rendered, and is useful for providing pre rendering logic. |
| * <p/> |
| * The on render method is typically used to populate tables performing some |
| * database intensive operation. By putting the intensive operations in the |
| * on render method they will not be performed if the user navigates away |
| * to a different page. |
| * <p/> |
| * {@link org.apache.click.control.Container} implementations should recursively |
| * invoke the onRender method on each of their child controls ensuring that |
| * all controls receive this event. |
| * <p/> |
| * <b>Please note:</b> a common problem when overriding onRender in |
| * subclasses is forgetting to call <em>super.onRender()</em>. Consider |
| * carefully whether you should call <em>super.onRender()</em> or not, |
| * especially for {@link org.apache.click.control.Container}s which by default |
| * call <em>onRender</em> on all their child controls as well. |
| */ |
| public void onRender(); |
| |
| /** |
| * The on destroy request event handler. Control classes should use this |
| * method to add any resource clean up code. |
| * <p/> |
| * This method is guaranteed to be called before the Page object reference |
| * goes out of scope and is available for garbage collection. |
| * <p/> |
| * {@link org.apache.click.control.Container} implementations should recursively |
| * invoke the onDestroy method on each of their child controls ensuring that |
| * all controls receive this event. |
| * <p/> |
| * <b>Please note:</b> a common problem when overriding onDestroy in |
| * subclasses is forgetting to call <em>super.onDestroy()</em>. Consider |
| * carefully whether you should call <em>super.onDestroy()</em> or not, |
| * especially for {@link org.apache.click.control.Container}s which by default |
| * call <em>onDestroy</em> on all their child controls as well. |
| */ |
| public void onDestroy(); |
| |
| /** |
| * Render the control's HTML representation to the specified buffer. The |
| * control's {@link java.lang.Object#toString()} method should delegate the |
| * rendering to the render method for improved performance. |
| * <p/> |
| * An example implementation: |
| * <pre class="prettyprint"> |
| * public class Border extends AbstractContainer { |
| * |
| * public String toString() { |
| * int estimatedSizeOfControl = 100; |
| * HtmlStringBuffer buffer = new HtmlStringBuffer(estimatedSizeOfControl); |
| * render(buffer); |
| * return buffer.toString(); |
| * } |
| * |
| * /** |
| * * @see Control#render(HtmlStringBuffer) |
| * */ |
| * public void render(HtmlStringBuffer buffer) { |
| * buffer.elementStart("div"); |
| * buffer.appendAttribute("name", getName()); |
| * buffer.closeTag(); |
| * buffer.append(getField()); |
| * buffer.elementEnd("div"); |
| * } |
| * } |
| * </pre> |
| * |
| * @param buffer the specified buffer to render the control's output to |
| */ |
| public void render(HtmlStringBuffer buffer); |
| |
| /** |
| * Returns <tt>true</tt> if this control has any |
| * <tt>Behavior</tt>s registered, <tt>false</tt> otherwise. |
| * |
| * @return <tt>true</tt> if this control has any |
| * <tt>Behavior</tt>s registered, <tt>false</tt> otherwise |
| */ |
| public boolean hasBehaviors(); |
| |
| /** |
| * Returns the list of behaviors for this control. |
| * |
| * @return the list with this control behaviors. |
| */ |
| public Set<Behavior> getBehaviors(); |
| |
| /** |
| * Returns <tt>true</tt> if this control is an Ajax target, <tt>false</tt> |
| * otherwise. |
| * <p/> |
| * In order for a Control to be considered as an Ajax target it must be |
| * registered through {@link org.apache.click.ControlRegistry#registerAjaxTarget(org.apache.click.Control) ControlRegistry.registerAjaxTarget}. |
| * <p/> |
| * When the Click handles an Ajax request it iterates the Controls |
| * registered with the {@link org.apache.click.ControlRegistry ControlRegistry} |
| * and checks if one of them is the Ajax target by calling |
| * {@link #isAjaxTarget(org.apache.click.Context) isAjaxTarget}. If <tt>isAjaxTarget</tt> |
| * returns true, Click will process that Control's {@link #getBehaviors() behaviors}. |
| * <p/> |
| * <b>Please note:</b> there can only be one target control, so the first |
| * Control that is identified as the Ajax target will be processed, the other |
| * controls will be skipped. |
| * <p/> |
| * The most common way to check whether a Control is the Ajax target is to |
| * check if its {@link #getId ID} is available as a request parameter: |
| * |
| * <pre class="prettyprint"> |
| * public MyControl extends AbstractControl { |
| * |
| * ... |
| * |
| * public boolean isAjaxTarget(Context context) { |
| * return context.hasRequestParameter(getId()); |
| * } |
| * } </pre> |
| * |
| * Not every scenario can be covered through an ID attribute though. For example |
| * if an ActionLink is rendered multiple times on the same page, it cannot have an |
| * ID attribute, as that would lead to duplicate IDs, which isn't allowed by |
| * the HTML specification. Control implementations has to cater for how the |
| * control will be targeted. In the case of ActionLink it might check against |
| * its <tt>id</tt>, and if that isn't available check against its <tt>name</tt>. |
| * |
| * @param context the request context |
| * @return <tt>true</tt> if this control is an Ajax target, <tt>false</tt> |
| * otherwise |
| */ |
| public boolean isAjaxTarget(Context context); |
| } |