| <?xml version='1.0' encoding='UTF-8'?> | |
| <!-- | |
| 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. | |
| --> | |
| <chapter id="chapter-pages" remap="h1"> | |
| <title>Pages</title> | |
| <para>Pages are the heart of web applications. In Apache Click, Pages encapsulate | |
| the processing of HTML requests and the rendering of HTML responses. | |
| This chapter discusses Apache Click pages in detail. | |
| </para> | |
| <para>In Click, a logical page is composed of a Java class and a Velocity | |
| template, with these components being defined in page elements of the | |
| <link linkend="application-configuration">click.xml</link> | |
| file: | |
| </para> | |
| <literallayout><page path="<varname>search.htm</varname>" classname="<token>com.mycorp.page.Search</token>"/></literallayout> | |
| <para>The path attribute specifies the location of the page Velocity template, | |
| and the classname attribute specifies the page Java class name. If you use | |
| the Freemarker template engine instead of Velocity, the setup is the same. | |
| </para> | |
| <para>The template path should have an <varname>.htm</varname> extension which | |
| is specified in <link linkend="servlet-configuration">web.xml</link> to route | |
| *.htm requests to the <classname>ClickServlet</classname>. | |
| </para> | |
| <para>Please note if you want Click to process templates with a different | |
| extension e.g. <varname>.xml</varname>, you need to implement the method | |
| <ulink url="../../click-api/org/apache/click/service/ConfigService.html#isTemplate(java.lang.String)">isTemplate(String path)</ulink> | |
| and specify the extra extensions. The simplest way is to subclass | |
| <classname>XmlConfigService</classname> and override the default implementation | |
| as described <ulink url="../../click-api/org/apache/click/service/XmlConfigService.html#isTemplate(java.lang.String)">here</ulink>. | |
| Also remember to map the new extensions in <filename>web.xml</filename>. | |
| </para> | |
| <para>If you use JSP pages for rendering, the <varname>.jsp</varname> extension | |
| must be used. For example: | |
| </para> | |
| <literallayout><page path="<varname>search.jsp</varname>" classname="<token>com.mycorp.page.Search</token>"/></literallayout> | |
| <para>Please note, Click does not handle JSP requests directly, instead it forwards | |
| JSP requests to the servlet container. Do not map the ClickServlet to handle | |
| <filename>*.jsp</filename> requests in <filename>web.xml</filename>. Instead | |
| <varname>.jsp</varname> templates are accessed with a <varname>.htm</varname> | |
| extension. At runtime Click will convert the page path from | |
| <varname>.jsp</varname> to <varname>.htm</varname> and back. | |
| </para> | |
| <sect1 id="classes" remap="h2"> | |
| <title>Classes</title> | |
| <para> All custom Click pages must subclass the | |
| <ulink url="../../click-api/org/apache/click/Page.html">Page</ulink> base class. | |
| The Page class and its associated companion classes, Context and Control, | |
| are depicted in the figure below. | |
| </para> | |
| <figure id="page-class-diagram"> | |
| <title>Page Class Diagram | |
| </title> | |
| <inlinemediaobject> | |
| <imageobject> | |
| <imagedata fileref="images/pages/click-class-diagram.png" format="PNG" scale="65"/> | |
| </imageobject> | |
| </inlinemediaobject> | |
| </figure> | |
| <para>The Page class provides a | |
| <ulink url="../../click-api/org/apache/click/Page.html#model">model</ulink> | |
| attribute which is used to hold all the objects that are rendered in the | |
| page Velocity template. The model may also contain | |
| <ulink url="../../click-api/org/apache/click/Control.html">Control</ulink> | |
| objects, which provide user interface controls on the Page. | |
| </para> | |
| <para>Pages also provides access to the | |
| <ulink url="../../click-api/org/apache/click/Context.html">Context</ulink> | |
| object which references all the javax.servlet objects associated with the | |
| request. When programming in Click you use the Context object to access | |
| HttpServletRequest attributes, parameters and the HttpSession object. | |
| </para> | |
| </sect1> | |
| <sect1 id="execution" remap="h2"> | |
| <title>Execution</title> | |
| <para>The Page class provide a number of empty handler methods which | |
| subclasses can override to provide functionality: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onSecurityCheck()">onSecurityCheck()</ulink> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onInit()">onInit()</ulink> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onGet()">onGet()</ulink> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onPost()">onPost()</ulink> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onRender()">onRender()</ulink> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../click-api/org/apache/click/Page.html#onDestroy()">onDestroy()</ulink> | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| <para>The ClickServlet relies on instantiating Pages using a public no | |
| arguments constructor, so when you create Page subclasses you must ensure | |
| you don't add an incompatible constructor. The GET request execution sequence | |
| for Pages is summarized below in the Figure 2. | |
| </para> | |
| <figure id="get-sequence-diagram"> | |
| <title>GET Request Sequence Diagram | |
| </title> | |
| <inlinemediaobject> | |
| <imageobject> | |
| <imagedata fileref="images/pages/get-sequence-diagram.png" format="PNG" scale="65"/> | |
| </imageobject> | |
| </inlinemediaobject> | |
| </figure> | |
| <para>Stepping through this GET request sequence, a new Page instance is | |
| created and the attributes for the Page are set (format, headers, | |
| path). Next, request parameter values are bound to any matching public | |
| Page variables. | |
| </para> | |
| <para>Then the <methodname>onSecurityCheck()</methodname> handler is executed. | |
| This method can be used to ensure the user is authorized to access the page, | |
| and if necessary abort any further processing. | |
| </para> | |
| <para>The next method invoked is <methodname>onInit()</methodname>, this is | |
| where you place any post constructor initialization code. | |
| <methodname>onInit()</methodname> is the ideal place to create controls such | |
| as Forms, Fields and Tables. As illustrated by the diagram, after a Page's | |
| <methodname>onInit()</methodname> is called, each Control, available at that | |
| stage, will have their <methodname>onInit()</methodname> method called. | |
| </para> | |
| <para> | |
| The next step is the processing of the Page's | |
| <ulink url="../../click-api/org/apache/click/Page.html#controls">controls</ulink>. | |
| The ClickServlet gets the list of Controls from the page and then iterates | |
| through the list calling <methodname>onProcess()</methodname>. If any of the | |
| Control's <methodname>onProcess()</methodname> methods return false, | |
| processing of subsequent controls and the Page's <methodname>onGet()</methodname> | |
| method is aborted. | |
| </para> | |
| <para>If everything is executing normally the Page's | |
| <methodname>onGet()</methodname> method is now called. | |
| </para> | |
| <para>The next step is rendering the page template to generate the displayed | |
| HTML. The ClickServlet gets the model (<classname>Map</classname>) from the | |
| Page then adds the following objects to the model: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para>any public Page variable using the variable name</para> | |
| </listitem> | |
| <listitem> | |
| <para>context - the Servlet context path, e.g. /mycorp</para> | |
| </listitem> | |
| <listitem> | |
| <para>format - the | |
| <ulink url="../../click-api/org/apache/click/util/Format.html">Format</ulink> | |
| object for formatting the display of objects. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>headElements - the HEAD <ulink url="../../click-api/org/apache/click/element/Element.html">elements</ulink>, | |
| excluding JavaScript, to include in the page header. Please see | |
| <ulink url="../../click-api/org/apache/click/util/PageImports.html">PageImports</ulink> | |
| for more details. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>jsElements - the JavaScript imports and script blocks to | |
| include in the pages footer. Please see | |
| <ulink url="../../click-api/org/apache/click/util/PageImports.html">PageImports</ulink> | |
| for more details. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>messages - the | |
| <ulink url="../../click-api/org/apache/click/util/MessagesMap.html">MessagesMap</ulink> | |
| adaptor for the Page | |
| <ulink url="../../click-api/org/apache/click/Page.html#getMessage(java.lang.String)">getMessage()</ulink> | |
| method | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>path - the | |
| <ulink url="../../click-api/org/apache/click/Page.html#path">path</ulink> of | |
| the page template to render | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>request - the pages | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html">HttpServletRequest</ulink> | |
| object | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>response - the pages | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletResponse.html">HttpServletResponse</ulink> | |
| object | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>session - the | |
| <ulink url="../../click-api/org/apache/click/util/SessionMap.html">SessionMap</ulink> | |
| adaptor for the users | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSession.html">HttpSession</ulink> | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| <para>It then merges the template with the page model and writes out results | |
| to the HttpServletResponse. When the model is being merged with the template, | |
| any Controls in the model may be rendered using their | |
| <methodname>toString()</methodname> method. | |
| </para> | |
| <para>The final step in this sequence is invoking each control's | |
| <methodname>onDestroy()</methodname> method and lastly invoke the Page's | |
| <methodname>onDestroy()</methodname> method. This method can be used to | |
| clean up resource associated with the Control or Page before it is garbage | |
| collected. The <methodname>onDestroy()</methodname> method is guaranteed to | |
| be called even if an exception occurs in the previous steps. | |
| </para> | |
| <para>The execution sequence for POST requests is almost identical, except | |
| the <methodname>onPost()</methodname> method is invoked instead on | |
| <methodname>onGet()</methodname>. See the | |
| <ulink url="../../../images/post-sequence-diagram.png">POST Request Sequence Diagram</ulink>. | |
| </para> | |
| <para>Another view on the execution flow of Pages is illustrated in the | |
| Activity diagram below. | |
| </para> | |
| <figure id="activity-diagram"> | |
| <title>Page Execution Activity Diagram | |
| </title> | |
| <inlinemediaobject> | |
| <imageobject> | |
| <imagedata fileref="images/pages/activity-diagram-small.png" format="PNG" scale="65"/> | |
| </imageobject> | |
| </inlinemediaobject> | |
| </figure> | |
| </sect1> | |
| <sect1 id="request-param-auto-binding" remap="h2"> | |
| <title>Request Parameter Auto Binding</title> | |
| <para>Click will automatically bind any request parameter values to public | |
| Page variable with the same name. You can also use the | |
| <ulink url="../../click-api/org/apache/click/util/Bindable.html">Bindable</ulink> | |
| annotation to bind private and protected Page variables. When binding these | |
| values Click will also attempt to convert them to the correct type. | |
| </para> | |
| <para>The best way to understand this is to walk through an example. Our | |
| application receives a GET request: | |
| </para> | |
| <literallayout>http://localhost:8080/mycorp/customer-details.htm?<varname>customerId</varname>=<symbol>7203</symbol></literallayout> | |
| <para>This request is automatically handled by our | |
| <classname>CustomerDetails</classname> page: | |
| </para> | |
| <programlisting language="java">package com.mycorp.page; | |
| public class CustomerDetails extends Page { | |
| @Bindable protected Integer <varname>customerId</varname>; | |
| }</programlisting> | |
| <para>After the CustomerDetails page has been created the | |
| "<varname>customerId</varname>" request parameter value "<symbol>7023</symbol>" | |
| will be converted into an Integer and assigned to the public page variable | |
| <varname>customerId</varname>. | |
| </para> | |
| <para>Another feature of Click is that any public Page variables are | |
| automatically added to the page's model before it is rendered. This will | |
| make these values available in the page template for display. In our example | |
| the public <varname>customerId</varname> variable will be added to the Page | |
| model and will be available for rendering in the page template. | |
| </para> | |
| <para>Our customer-details.htm page template contains: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <body> | |
| Customer ID: <symbol>$</symbol><varname>customerId</varname> | |
| </body> | |
| </html></programlisting> | |
| <para>After processing the request our page would be rendered as: | |
| </para> | |
| <literallayout>Customer ID: 7203</literallayout> | |
| <sect2 id="customizing-auto-binding" remap="h3"> | |
| <title>Customizing Auto Binding</title> | |
| <para>Auto binding supports the conversion of request string parameters | |
| into the Java classes: Integer, Double, Boolean, Byte, Character, Short, | |
| Long, Float, BigInteger, BigDecimal, String and the various Date classes. | |
| </para> | |
| <para>By default type conversion is performed by the | |
| <ulink url="../../click-api/org/apache/click/util/RequestTypeConverter.html">RequestTypeConverter</ulink> | |
| class which is used by the ClickServlet method | |
| <ulink url="../../click-api/org/apache/click/ClickServlet.html#getTypeConverter()">getTypeConverter()</ulink>. | |
| </para> | |
| <para>If you need to add support for additional types, you would write your | |
| own type converter class and specify it as a ClickServlet init parameter. | |
| </para> | |
| <para>For example if you wanted to automatically load a | |
| <classname>Customer</classname> object from the database when a customer | |
| id request parameter is specified, you could write your own type converter: | |
| </para> | |
| <programlisting language="java">public class CustomTypeConverter extends RequestTypeConverter { | |
| private CustomerService customerService = new CustomerService(); | |
| /** | |
| * @see RequestTypeConverter#convertValue(Object, Class) | |
| */ | |
| protected Object convertValue(Object value, Class toType) { | |
| if (toType == Customer.class) { | |
| return customerService.getCustomerForId(value); | |
| } else { | |
| return super.convertValue(value, toType); | |
| } | |
| } | |
| }</programlisting> | |
| <para>This type converter would handle the following request: | |
| </para> | |
| <literallayout>http://localhost:8080/mycorp/customer-details.htm?<varname>customer</varname>=<symbol>7203</symbol></literallayout> | |
| <para>This request will load the <varname>customer</varname> object from | |
| the database using "<symbol>7203</symbol>" as the customer id value. The | |
| ClickServlet would then assign this <varname>customer</varname> object to | |
| the matching page variable: | |
| </para> | |
| <programlisting language="java">package com.mycorp.page; | |
| public class CustomerDetails extends Page { | |
| @Bindable protected Customer <varname>customer</varname>; | |
| }</programlisting> | |
| <para>To make your custom type converter available you will need to | |
| add an init parameter to ClickServlet in <filename>web.xml</filename>. For example: | |
| </para> | |
| <programlisting language="xml"><web-app> | |
| ... | |
| <servlet> | |
| <servlet-name>ClickServlet</servlet-name> | |
| <servlet-class>org.apache.click.ClickServlet</servlet-class> | |
| <init-param> | |
| <param-name>type-converter-class</param-name> | |
| <param-value>com.mycorp.util.CustomTypeConverter</param-value> | |
| </init-param> | |
| <load-on-startup>0</load-on-startup> | |
| </servlet> | |
| <servlet-mapping> | |
| <servlet-name>ClickServlet</servlet-name> | |
| <url-pattern>*.htm</url-pattern> | |
| </servlet-mapping> | |
| ... | |
| </web-app></programlisting> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="page-security" remap="h2"> | |
| <title>Security</title> | |
| <para>Pages provide an | |
| <ulink url="../../click-api/org/apache/click/Page.html#onSecurityCheck()">onSecurityCheck</ulink> | |
| event handler which application pages can override to implement a | |
| programmatic security model. | |
| </para> | |
| <para>Please note you generally don't need to use this capability, and where | |
| possible you should use the declarative JEE security model. See the Best | |
| Practices <link linkend="security">Security</link> topic for more details. | |
| </para> | |
| <sect2 id="applications-authentication" remap="h3"> | |
| <title>Application Authentication</title> | |
| <para>Applications can use the <methodname>onSecurityCheck()</methodname> | |
| method to implement their own security model. The example class below | |
| provides a base Secure page class which other pages can extend to ensure | |
| the user is logged in. In this example the login page creates a session | |
| when a user successfully authenticates. This Secure page then checks to | |
| make sure the user has a session, otherwise the request is redirected to | |
| the login page. | |
| </para> | |
| <programlisting language="java">public class Secure extends Page { | |
| /** | |
| * @see Page#onSecurityCheck() | |
| */ | |
| public boolean onSecurityCheck() { | |
| if (getContext().hasSession()) { | |
| return true; | |
| } else { | |
| setRedirect(LoginPage.class); | |
| return false; | |
| } | |
| } | |
| }</programlisting> | |
| </sect2> | |
| <sect2 id="container-authentication" remap="h3"> | |
| <title>Container Authentication</title> | |
| <para>Alternatively you can also use the security services provided by | |
| the JEE Servlet Container. For instance to ensure users have been | |
| authenticated by the Servlet Container you could use a Secure page of: | |
| </para> | |
| <programlisting language="java">public class Secure extends Page { | |
| /** | |
| * @see Page#onSecurityCheck() | |
| */ | |
| public boolean onSecurityCheck() { | |
| if (getContext().getRequest().<ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html#getRemoteUser()"><varname>getRemoteUser</varname></ulink>() != null) { | |
| return true; | |
| } else { | |
| setRedirect(LoginPage.class); | |
| return false; | |
| } | |
| } | |
| }</programlisting> | |
| </sect2> | |
| <sect2 id="container-access-control" remap="h3"> | |
| <title>Container Access Control</title> | |
| <para>The Servlet Container also provides facilities to enforce role | |
| based access control (authorization). The example below is a base page | |
| to ensure only users in the "admin" role can access the page, otherwise | |
| users are redirected to the login page. Application Admin pages would | |
| extend this secure page to provide their functionality. | |
| </para> | |
| <programlisting language="java">public class AdminPage extends Page { | |
| /** | |
| * @see Page#onSecurityCheck() | |
| */ | |
| public boolean onSecurityCheck() { | |
| if (getContext().getRequest().<ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)"><varname>isUserInRole</varname></ulink>("admin")) { | |
| return true; | |
| } else { | |
| setRedirect(LoginPage.class); | |
| return false; | |
| } | |
| } | |
| }</programlisting> | |
| </sect2> | |
| <sect2 id="logging-out" remap="h3"> | |
| <title>Logging Out</title> | |
| <para>To logout using the application or container based security models | |
| you would simply invalidate the session. | |
| </para> | |
| <programlisting language="java">public class Logout extends Page { | |
| /** | |
| * @see Page#onInit() | |
| */ | |
| public void onInit() { | |
| getContext().getSession().<ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSession.html#invalidate()"><varname>invalidate</varname></ulink>(); | |
| } | |
| }</programlisting> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="page-navigation" remap="h2"> | |
| <title>Page Navigation</title> | |
| <para> Navigation between pages is achieved by using forwards, redirects | |
| and by setting the page template path. | |
| </para> | |
| <sect2 id="forward" remap="h3"> | |
| <title>Forward</title> | |
| <para> To forward to another page using the servlet | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/RequestDispatcher.html">RequestDispatcher</ulink>, | |
| set the Page's forward property. For example to forward to a page with a | |
| path <varname>index.htm</varname>: | |
| </para> | |
| <programlisting language="java">/** | |
| * @see Page#onPost() | |
| */ | |
| public void onPost() { | |
| // Process form post | |
| .. | |
| setForward("index.htm"); | |
| }</programlisting> | |
| <para>This will invoke a new Page class instance mapped to the path | |
| <varname>index.htm</varname>. | |
| </para> | |
| <para><emphasis role="bold">Please note</emphasis> when a request is | |
| forwarded to another Page, the controls on the second page will not be | |
| processed. This prevents confusion and bugs, like a form on the second page | |
| trying to process a POST request from the first page. | |
| </para> | |
| <sect3 id="forward-parameter-passing" remap="h4"> | |
| <title>Forward Parameter Passing</title> | |
| <para>When you forward to another page the request parameters are | |
| maintained. This is a handy way of passing through state information | |
| with the request. For example you could add a customer object as a | |
| request parameter which is displayed in the template of the forwarded | |
| page. | |
| </para> | |
| <programlisting language="java">public boolean onViewClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| // Set the customer object as a request parameter | |
| getContext().setRequestAttribute("customer", customer); | |
| setForward("view-customer.htm"); | |
| return false; | |
| }</programlisting> | |
| <para>The snippet above forwards to the page template | |
| <varname>view-customer.htm</varname>: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <head> | |
| <title>Customer Details</title> | |
| </head> | |
| <body> | |
| <h1>Customer Details</h1> | |
| <pre> | |
| Full Name: <varname>$customer.fullName</varname> | |
| Email: <varname>$customer.email</varname> | |
| Telephone: <varname>$customer.telephone</varname> | |
| </pre> | |
| </body> | |
| </html></programlisting> | |
| <para>Request attributes are automatically added to the Velocity Context | |
| object so are available in the page template. | |
| </para> | |
| </sect3> | |
| <sect3 id="page-forwarding" remap="h4"> | |
| <title>Page Forwarding</title> | |
| <para>Page forwarding is another way of passing information between | |
| pages. In this case you create the page to be forwarded to using the | |
| Context <ulink url="../../click-api/org/apache/click/Context.html#createPage(java.lang.String)">createPage(String)</ulink> | |
| method and then set properties directly on the Page. Finally set this | |
| page as the page to forward the request to. For example: | |
| </para> | |
| <programlisting language="java">public boolean onEditClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| // Create a new EditPage instance based on the specified path | |
| EditPage editPage = (EditPage) getContext().createPage("/edit-customer.htm"); | |
| editPage.setCustomer(customer); | |
| setForward(editPage); | |
| return false; | |
| }</programlisting> | |
| <para>When creating a page with the <methodname>createPage()</methodname> | |
| method, ensure you prefix the page path with the <varname>"/"</varname> | |
| character. | |
| </para> | |
| <para>You can also specify the target page using its class as long as | |
| the Page has a unique path. Using this technique the above code becomes: | |
| </para> | |
| <programlisting language="java">public boolean onEditClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| // Create a new EditPage instance based on its class | |
| EditPage editPage = (EditPage) getContext().createPage(EditPage.class); | |
| editPage.setCustomer(customer); | |
| setForward(editPage); | |
| return false; | |
| }</programlisting> | |
| <para>This Page forwarding technique is best practice as it provides you | |
| with compile time safety and alleviates you from having to specify page | |
| paths in your code. Please always use the Context | |
| <methodname>createPage()</methodname> methods to allow Click to inject | |
| Page dependencies. | |
| </para> | |
| <para>Although uncommon it is possible to map more than one path to the | |
| same class. In these cases invoking Context | |
| <methodname>createPage(Class)</methodname> will throw an exception, because | |
| Click will not be able to determine which path to use for the Page. | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2 id="template-path" remap="h3"> | |
| <title>Template Path</title> | |
| <para>An alternative method of forwarding to a new page is to simply set | |
| the current Page's path to the new page template to render. With this | |
| approach the page template being rendered must have everything it needs | |
| without having its associated Page object created. Our modified example | |
| would be: | |
| </para> | |
| <programlisting language="java">public boolean onViewClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| addModel("customer", customer); | |
| // Set the Page's path to a new value | |
| setPath("view-customer.htm"); | |
| return false; | |
| }</programlisting> | |
| <para>Note how the <varname>customer</varname> object is passed through to | |
| the template in the Page model. This approach of using the Page model is | |
| not available when you forward to another Page, as the first Page object is | |
| "<ulink url="../../click-api/org/apache/click/Page.html#onDestroy()">destroyed</ulink>" | |
| before the second Page object is created and any model values would be lost. | |
| </para> | |
| </sect2> | |
| <sect2 id="redirect" remap="h3"> | |
| <title>Redirect</title> | |
| <para>Redirects are another very useful way to navigate between pages. | |
| See HttpServletResponse. | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletResponse.html#sendRedirect(java.lang.String)">sendRedirect</ulink> | |
| (location) for details. | |
| </para> | |
| <para>The great thing about redirects are that they provide a clean URL in | |
| the users browser which matches the page that they are viewing. This is | |
| important for when users want to bookmark a page. The downside of | |
| redirects are that they involve a communications round trip with the users | |
| browser which requests the new page. Not only does this take time, it also | |
| means that all the page and request information is lost. | |
| </para> | |
| <para>An example of a redirect to a <varname>logout.htm</varname> page is | |
| provided below: | |
| </para> | |
| <programlisting language="java">public boolean onLogoutClick() { | |
| setRedirect("/logout.htm"); | |
| return false; | |
| }</programlisting> | |
| <para>If the redirect location begins with a <symbol>"/"</symbol> character | |
| the redirect location will be prefixed with the web applications context | |
| path. For example if an application is deployed to the context | |
| <varname>"mycorp"</varname> calling | |
| <methodname>setRedirect(<varname>"/customer/details.htm"</varname>)</methodname> | |
| will redirect the request to: <varname>"/mycorp/customer/details.htm"</varname>. | |
| </para> | |
| <para>You can also obtain the redirect path via the target Page's class. | |
| For example: | |
| </para> | |
| <programlisting language="java">public boolean onLogoutClick() { | |
| String path = getContext().getPagePath(Logout.class); | |
| setRedirect(path); | |
| return false; | |
| }</programlisting> | |
| <para>Note when using this redirect method, the target Page class must have | |
| a unique path. | |
| </para> | |
| <para>A short hand way of redirecting is to simply specify the target Page | |
| class in the redirect method. For example: | |
| </para> | |
| <programlisting language="java">public boolean onLogoutClick() { | |
| setRedirect(Logout.class); | |
| return false; | |
| }</programlisting> | |
| <sect3 id="redirect-parameter-passing" remap="h4"> | |
| <title>Redirect Parameter Passing</title> | |
| <para>You can pass information between redirected pages using URL | |
| request parameters. The ClickServlet will encode the URL for you using | |
| HttpServletResponse.<ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletResponse.html#encodeRedirectURL(java.lang.String)">encodeRedirectURL</ulink> | |
| (url). | |
| </para> | |
| <para>In the example below a user will click on an OK button to confirm | |
| a payment. The <methodname>onOkClick()</methodname> button handler | |
| processes the payment, gets the payment transaction id, and then | |
| redirects to the <varname>trans-complete.htm</varname> page with the | |
| transaction id encoded in the URL. | |
| </para> | |
| <programlisting language="java">public class Payment extends Page { | |
| .. | |
| public boolean onOkClick() { | |
| if (form.isValid()) { | |
| // Process payment | |
| .. | |
| // Get transaction id | |
| Long transId = OrderDAO.purchase(order); | |
| setRedirect("trans-complete.htm?transId=" + transId); | |
| return false; | |
| } | |
| return true; | |
| } | |
| }</programlisting> | |
| <para>The Page class for the trans-complete.htm page can then get the | |
| transaction id through the request parameter <varname>"transId"</varname>: | |
| </para> | |
| <programlisting language="java">public class TransComplete extends Page { | |
| /** | |
| * @see Page#onInit() | |
| */ | |
| public void onInit() { | |
| String transId = getContext().getRequest().getParameter("transId"); | |
| if (transId != null) { | |
| // Get order details | |
| Order order = OrderDAO.findOrderByPK(new Long(transId)); | |
| if (order != null) { | |
| addModel("order", order); | |
| } | |
| } | |
| } | |
| }</programlisting> | |
| </sect3> | |
| <sect3 id="post-redirect" remap="h4"> | |
| <title>Post Redirect</title> | |
| <para>The parameter passing example above is also an example of a Post | |
| Redirect. The Post Redirect technique is a very useful method of | |
| preventing users from submitting a form twice by hitting the refresh | |
| button. | |
| </para> | |
| </sect3> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="page-templating" remap="h2"> | |
| <title>Page Templating</title> | |
| <para>Click supports page templating (a.k.a. <emphasis>Tiles</emphasis> in | |
| Struts) enabling you to create a standardized look and feel for your web | |
| application and greatly reducing the amount of HTML you need to maintain. | |
| </para> | |
| <para>To implement templating define a border template base Page which | |
| content Pages should extend. The template base Page class overrides the Page | |
| <ulink url="../../click-api/org/apache/click/Page.html#getTemplate()">getTemplate()</ulink> | |
| method, returning the path of the border template to render. For example: | |
| </para> | |
| <programlisting language="java">package com.mycorp.page; | |
| public class BorderedPage extends Page { | |
| /** | |
| * @see Page#getTemplate() | |
| */ | |
| public String getTemplate() { | |
| return "/border.htm"; | |
| } | |
| }</programlisting> | |
| <para>The BorderedPage template <varname>border.htm</varname>: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <head> | |
| <title><varname>$title</varname></title> | |
| <link rel="stylesheet" type="text/css" href="style.css" title="Style"/> | |
| </head> | |
| <body> | |
| <h2 class="title"><varname>$title</varname></h2> | |
| <command>#parse</command>(<varname>$path</varname>) | |
| </body> | |
| </html> | |
| </programlisting> | |
| <para>Other pages insert their content into this template using the Velocity | |
| <ulink url="../../velocity/vtl-reference-guide.html#parse">#parse</ulink> | |
| directive, passing it their contents pages | |
| <ulink url="../../click-api/org/apache/click/Page.html#path">path</ulink>. The | |
| <varname>$path</varname> value is automatically added to the VelocityContext | |
| by the ClickServlet. | |
| </para> | |
| <para>An example bordered Home page is provided below: | |
| </para> | |
| <literallayout><page path="<varname>home.htm</varname>" classname="<token>com.mycorp.page.Home</token>"/></literallayout> | |
| <programlisting language="java">package com.mycorp.page; | |
| public class Home extends BorderedPage { | |
| public String title = "Home"; | |
| }</programlisting> | |
| <para>The Home page's content <varname>home.htm</varname>: | |
| </para> | |
| <literallayout><b>Welcome</b> to Home page your starting point for the application.</literallayout> | |
| <?dbfo-need height="1.2in" ?> | |
| <para>When a request is made for the Home page (home.htm) Velocity will | |
| merge the <varname>border.htm</varname> page and <varname>home.htm</varname> | |
| page together returning: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <head> | |
| <title>Home</title> | |
| <link rel="stylesheet" type="text/css" href="style.css" title="Style"/> | |
| </head> | |
| <body> | |
| <h2 class="title">Home</h2> | |
| <b>Welcome</b> to Home page your application starting point. | |
| </body> | |
| </html></programlisting> | |
| <para>Which may be rendered as: | |
| </para> | |
| <figure id="home-page-screenshot"> | |
| <title>Home Page</title> | |
| <mediaobject> | |
| <imageobject> | |
| <imagedata fileref="images/pages/home-page-screenshot.png" format="PNG" scale="65"/> | |
| </imageobject> | |
| </mediaobject> | |
| </figure> | |
| <para>Note how the Home page class defines a <varname>title</varname> model | |
| value which is referenced in the <varname>border.htm</varname> template as | |
| <varname>$title</varname>. Each bordered page can define their own title | |
| which is rendered in this template. | |
| </para> | |
| <para>Templating with JSP pages is also supported using the same pattern. | |
| Please see the Click Examples application for a demonstration. | |
| </para> | |
| </sect1> | |
| <sect1 id="page-actions" remap="h2"> | |
| <title>Page Actions</title> | |
| <para>Page Action is a feature to directly invoke a <literal>Page method</literal> | |
| from the browser. The Page Action method returns an | |
| <ulink url="../../click-api/org/apache/click/ActionResult.html">ActionResult</ulink> | |
| object that is rendered directly to the browser. In other words the Page template will | |
| not be rendered. | |
| </para> | |
| <para>To invoke a Page Action, specify the parameter <varname>"pageAction"</varname> | |
| and the name of the page method, for example: <symbol>"onRenderImage"</symbol>. | |
| </para> | |
| <para>Let's take a quick look at how a Page Action can be leveraged to retrieve | |
| an image. In this example we'll create an HTML <literal><img></literal> | |
| element which <literal>src</literal> attribute specifies the Page Action | |
| that will return the image data. | |
| </para> | |
| <para>First we create our template: | |
| </para> | |
| <programlisting language="xml"><img src="$context/mycorp/image.htm?<varname>pageAction</varname>=<symbol>onRenderImage</symbol>"/> | |
| </programlisting> | |
| <para>Next we create our ImagePage with a Page Action method called | |
| <symbol>onRenderImage</symbol> that returns an <token>ActionResult</token> | |
| instance: | |
| </para> | |
| <programlisting language="java">public class ImagePage extends Page { | |
| public <token>ActionResult</token> <symbol>onRenderImage()</symbol> { | |
| byte[] imageData = getImageAsBytes(); | |
| String contentType = ClickUtils.getMimeType("png"); | |
| return new <token>ActionResult</token>(imageData, contentType); | |
| } | |
| } </programlisting> | |
| <para>A Page Action is a normal Page method with the following signature: | |
| a <symbol>public no-arg</symbol> method returning an <token>ActionResult</token> | |
| instance: | |
| </para> | |
| <programlisting language="java"> | |
| // The Page Action method is public, doesn't accept any arguments and returns an ActionResult | |
| public <token>ActionResult</token> <symbol>onRenderImage()</symbol> { | |
| byte[] imageData = getImageAsBytes(); | |
| String contentType = ClickUtils.getMimeType("png"); | |
| return new <token>ActionResult</token>(imageData, contentType); | |
| } </programlisting> | |
| <para>The <token>ActionResult</token> contains the data that is rendered to | |
| the client browser. In the example above, the result will the Image byte array | |
| with a Content-Type of: <literal>"images/png"</literal>. | |
| </para> | |
| <sect2 id="page-action-execution" remap="h3"> | |
| <title>Page Action Execution</title> | |
| <para>Page Actions are page methods that handle the processing of a user | |
| request and render a result to the browser. The execution sequence for a | |
| Page Action being processed and rendered is illustrated in the figure below. | |
| </para> | |
| <figure id="page-action-sequence-diagram"> | |
| <title>Page Action Request Sequence Diagram | |
| </title> | |
| <inlinemediaobject> | |
| <imageobject> | |
| <imagedata fileref="images/pages/page-action-sequence-diagram.png" format="PNG" scale="65"/> | |
| </imageobject> | |
| </inlinemediaobject> | |
| </figure> | |
| <para>Stepping through this Page Action request sequence, a new Page instance | |
| is created and the attributes for the Page are set (format, headers). Next, | |
| request parameter values are bound to matching Page fields. | |
| </para> | |
| <para>Then the <methodname>onSecurityCheck()</methodname> handler is executed. | |
| This method can be used to ensure the user is authorized to access the Page Action, | |
| and if necessary abort any further processing. If | |
| <methodname>onSecurityCheck()</methodname> return false, no response is | |
| sent back to the client. Note, if you want to send a specific response to | |
| the client you have to do that from the | |
| <methodname>onSecurityCheck()</methodname> event, since other Page events | |
| are not executed. Please see | |
| <ulink url="http://click.avoka.com/click-examples/ajax/ajax-secure.htm">this</ulink> | |
| example for some strategies on implementing | |
| <methodname>onSecurityCheck</methodname> to handle ajax requests. | |
| </para> | |
| <para>Next the target <methodname>page method</methodname> is invoked | |
| which returns an <classname>ActionResult</classname> that is rendered to | |
| the client.</para> | |
| <para>If the page method returns <literal>null</literal> no response is | |
| rendered to the browser. | |
| </para> | |
| </sect2> | |
| <sect2 id="page-action-result" remap="h3"> | |
| <title>ActionResult</title> | |
| <para>An ActionResult represents the content returned by a Page Action | |
| which is then rendered to the client browser. ActionResults normally | |
| contains HTML or image data that is rendered to the browser. When a Page | |
| Action is invoked the Page template rendering is bypassed and only the | |
| ActionResult content is rendered to the browser. This allows a Page Action | |
| to return a "partial" response, as opposed to a "full" response, because | |
| the Page template (which can be viewed as a "full" response) is bypassed | |
| when invoking a Page Action. | |
| </para> | |
| </sect2> | |
| <sect2 id="page-action-example" remap="h3"> | |
| <title>Page Action Example</title> | |
| <para>Let's step through a Page Action example. First we create an ImagePage | |
| class with the method "getImageData" which is the Page Action we want to invoke: | |
| </para> | |
| <programlisting language="java">public ImagePage extends Page { | |
| public ActionResult getImageData() { | |
| byte[] imageData = loadImageData(); | |
| String contentType = ClickUtils.getContentType("png"); | |
| return new ActionResult(imageData, contentType); | |
| } | |
| } </programlisting> | |
| <para>Next we have the page template image.htm: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <body> | |
| <img src="/mycorp/image.htm?<varname>pageAction</varname>=<symbol>getImageData</symbol>"/> | |
| </body> | |
| </html> </programlisting> | |
| <para>The browser renders the <literal><img></literal> element and | |
| requests the image src url. Click invokes the page method <symbol>getImageData</symbol> | |
| and renders the result to the browser. | |
| </para> | |
| <para>Looking at the output log we see the following trace: | |
| </para> | |
| <literallayout>[Click] [info ] handleRequest: /image.htm - 84 ms | |
| [Click] [debug] GET http://localhost:8080/mycorp/image.htm | |
| [Click] [trace] is Ajax request: false | |
| [Click] [trace] request param: pageAction=getImageData | |
| [Click] [trace] invoked: ImagePage.<<init>> | |
| [Click] [trace] invoked: ImagePage.onSecurityCheck() : true | |
| [Click] [trace] invoked: ImagePage.getImageData() : ActionResult | |
| [Click] [info ] renderActionResult (image/png) - 0 ms | |
| [Click] [trace] invoked: ImagePage.onDestroy() | |
| [Click] [info ] handleRequest: /image.htm - 98 ms</literallayout> | |
| </sect2> | |
| <sect2 id="page-action-accessing-request-parameters" remap="h3"> | |
| <title>Accessing Request Parameters</title> | |
| <para>Request parameters can be accessed through the <classname>Context</classname> | |
| as shown below: | |
| </para> | |
| <programlisting language="java">public ImagePage extends Page { | |
| public ActionResult getImageData() { | |
| // Retrieve a request parameter through the Context | |
| Context context = getContext(); | |
| String imageName = context.getRequestParameter("imageName"); | |
| byte[] imageData = loadImageData(imageName); | |
| String contentType = ClickUtils.getContentType("png"); | |
| return new ActionResult(imageData, contentType); | |
| } | |
| } </programlisting> | |
| </sect2> | |
| <sect2 id="page-action-set-response-headers" remap="h3"> | |
| <title>Set response headers and status code</title> | |
| <para>When handling a Page Action you might need to set the HTTP response | |
| headers or status code. You do this through the Servlet API's, | |
| <classname>HttpServletResponse</classname> which can be accessed | |
| through the <classname>Context</classname>. | |
| </para> | |
| <para>For example: | |
| </para> | |
| <programlisting language="java">package examples.page; | |
| import java.util.Date; | |
| import org.apache.click.Page; | |
| public ImagePage extends Page { | |
| public ActionResult getImageData() { | |
| // Headers and Status code are set on the HttpServletResponse | |
| HttpServletResponse response = getContext().getResponse(); | |
| // The headers can be set as follows: | |
| response.setHeader("Content-Disposition", "attachment; filename=\"report.xls\""); | |
| ... | |
| // The response status can be set as follows: | |
| response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); | |
| ... | |
| } | |
| } </programlisting> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="page-direct-rendering" remap="h2"> | |
| <title>Direct Rendering</title> | |
| <para>Pages support a direct rendering mode where you can render directly | |
| to the servlet response and bypass the page template rendering. This is | |
| useful for scenarios where you want to render non HTML content to the | |
| response, such as a PDF or Excel document. To do this: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> get the servlet response object</para> | |
| </listitem> | |
| <listitem> | |
| <para> set the content type on the response</para> | |
| </listitem> | |
| <listitem> | |
| <para> get the response output stream</para> | |
| </listitem> | |
| <listitem> | |
| <para> write to the output stream</para> | |
| </listitem> | |
| <listitem> | |
| <para> close the output stream</para> | |
| </listitem> | |
| <listitem> | |
| <para> set the page path to null to inform the ClickServlet that | |
| rendering has been completed</para> | |
| </listitem> | |
| </itemizedlist> | |
| <?dbfo-need height="1.2in" ?> | |
| <para>A direct rendering example is provided below. | |
| </para> | |
| <programlisting language="java">/** | |
| * Render the Java source file as "text/plain". | |
| * | |
| * @see Page#onGet() | |
| */ | |
| public void onGet() { | |
| String filename = .. | |
| HttpServletResponse response = getContext().getResponse(); | |
| response.setContentType("text/plain"); | |
| response.setHeader("Pragma", "no-cache"); | |
| ServletContext context = getContext().getServletContext(); | |
| InputStream inputStream = null; | |
| try { | |
| inputStream = context.getResourceAsStream(filename); | |
| PrintWriter writer = response.getWriter(); | |
| BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); | |
| String line = reader.readLine(); | |
| while (line != null) { | |
| writer.println(line); | |
| line = reader.readLine(); | |
| } | |
| setPath(null); | |
| } catch (IOException ioe) { | |
| ioe.printStackTrace(); | |
| } finally { | |
| ClickUtils.close(inputStream); | |
| } | |
| }</programlisting> | |
| </sect1> | |
| <sect1 id="stateful-pages" remap="h2"> | |
| <title>Stateful Pages</title> | |
| <para><symbol>PLEASE NOTE:</symbol> stateful pages have been deprecated in | |
| Click 2.3.0 and will be removed in a future release. Do not use stateful pages | |
| in your applications. Instead use stateful controls or HttpSession to store | |
| state between requests. | |
| </para> | |
| <para>Click supports stateful pages where the state of the page is saved | |
| between the users requests. Stateful pages are useful in a number of | |
| scenarios including: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para>Search page and edit page interactions. In this scenario you | |
| navigage from a stateful search page which may have filter criteria | |
| applied to an object edit page. Once object update has been completed | |
| on the edit page, the user is redirected to the search page and the | |
| stateful filter criteria still applies. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>Complex pages with multiple forms and or tables which need to | |
| maintain their state between interactions. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| <para>To make a page stateful you simply need to set the page | |
| <ulink url="../../click-api/org/apache/click/Page.html#stateful">stateful</ulink> | |
| property to true, have the page implement the <classname>Serializable</classname> | |
| interface and set the <literal>serialVersionUID</literal> indicator. | |
| For example: | |
| </para> | |
| <programlisting language="java">package com.mycorp.page; | |
| import java.io.Serializable; | |
| import org.apache.click.Page; | |
| public class SearchPage extends Page implements Serializable { | |
| private static final long serialVersionUID = 1L; | |
| public SearchPage() { | |
| setStateful(true); | |
| .. | |
| } | |
| }</programlisting> | |
| <para>Stateful page instances are stored in the user's | |
| <ulink url="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSession.html">HttpSession</ulink> | |
| using the pages class name as the key. In the example above the page would | |
| be stored in the users session using the class name: | |
| <classname>com.mycorp.page.SearchPage</classname> | |
| </para> | |
| <sect2 id="page-creation" remap="h3"> | |
| <title>Page Creation</title> | |
| <para>With stateful pages they are only created once, after which they | |
| are retrieved from the session. However page event handlers are invoked | |
| for each request, including the <methodname>onInit()</methodname> method. | |
| </para> | |
| <para>When you are creating stateful pages you typically place all your | |
| control creation code in the Pages constructor so it is invoked only once. | |
| It is important not to place control creation code in the | |
| <methodname>onInit()</methodname> method which will be invoked with each | |
| request. | |
| </para> | |
| <para>If you have dynamic control creation code you would typically place | |
| this in the <methodname>onInit()</methodname> method, but you will need to | |
| take care that controls and or models are not already present in the page. | |
| </para> | |
| </sect2> | |
| <sect2 id="page-execution" remap="h3"> | |
| <title>Page Execution</title> | |
| <para>The default Click page execution model is thread safe as a new | |
| Page instance is created for each request and thread. With stateful | |
| pages a user will have a single page instance which is reused in multiple | |
| requests and threads. To ensure page execution is thread safe, users page | |
| instances are synchronized so only one request thread can execute a page | |
| instance at any one time. | |
| </para> | |
| </sect2> | |
| <sect2 id="page-destruction" remap="h3"> | |
| <title>Page Destruction</title> | |
| <para>After normal page instances have been executed, they are | |
| de-referenced and garbage collected by the JVM. However with stateful | |
| pages they are stored in the users <classname>HttpSession</classname> so | |
| care needs to be take not to store too many objects in stateful page | |
| instances which may cause memory and performance issues. | |
| </para> | |
| <para>When pages have completed their execution, all the Page's controls | |
| <methodname>onDestroy()</methodname> methods are invoked, and then the | |
| Page's <methodname>onDestroy()</methodname> method is invoked. This is | |
| your opportunity to de-reference any large sets or graphs. For example the | |
| Table control by default de-references its rowList in its | |
| <ulink url="../../click-api/org/apache/click/control/Table.html#onDestroy()">onDestory()</ulink> | |
| method. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="page-error-handling" remap="h2"> | |
| <title>Error Handling</title> | |
| <para>If an Exception occurs processing a Page object or rendering a | |
| template the error is delegated to the registered handler. The default | |
| Click error handler is the | |
| <ulink url="../../click-api/org/apache/click/util/ErrorPage.html">ErrorPage</ulink>, | |
| which is automatically configured as: | |
| </para> | |
| <literallayout><page path="<varname>click/error.htm</varname>" classname="<symbol>org.apache.click.util.ErrorPage</symbol>"/></literallayout> | |
| <para>To register an alternative error handler you must subclass ErrorPage | |
| and define your page using the path <varname>"click/error.htm"</varname>. | |
| For example: | |
| </para> | |
| <literallayout><page path="<varname>click/error.htm</varname>" classname="<symbol>com.mycorp.page.ErrorPage</symbol>"/></literallayout> | |
| <para>When the ClickServlet starts up it checks to see whether the | |
| <varname>error.htm</varname> template exists in the <varname>click</varname> | |
| web sub directory. If it cannot find the page the ClickServlet will | |
| automatically deploy one. You can tailor the <varname>click/error.htm</varname> | |
| template to suite you own tastes, and the ClickServlet will | |
| not overwrite it. | |
| </para> | |
| <para>The default error template will display extensive debug information | |
| when the application is in <literal>development</literal> or | |
| <literal>debug</literal> mode. Example error page displays include: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| <ulink url="../../error-npe.html">NullPointerException</ulink> - in a page | |
| method | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <ulink url="../../error-parsing.html">ParseErrorException</ulink> - in a | |
| page template | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| <para>When the application is in <literal>production</literal> mode only | |
| a simple error message is displayed. See | |
| <link linkend="application-mode">Configuration</link> for details on how to | |
| set the application mode. | |
| </para> | |
| <para>Please also see the <ulink url="../../examples.html">Examples</ulink> web | |
| app Exception Demo for demonstrations of Clicks error handling. | |
| </para> | |
| </sect1> | |
| <sect1 id="page-not-found" remap="h2"> | |
| <title>Page Not Found</title> | |
| <para>If the ClickServlet cannot find a requested page in the | |
| <literal>click.xml</literal> config file it will use the registered | |
| <ulink url="../../not-found.html">not-found.htm</ulink> page. | |
| </para> | |
| <para>The Click <literal>not found page</literal> is automatically configured | |
| as: | |
| </para> | |
| <literallayout><page path="<varname>click/not-found.htm</varname>" classname="<symbol>org.apache.click.Page</symbol>"/></literallayout> | |
| <para>You can override the default configuration and specify your own class, | |
| but you cannot change the path. | |
| </para> | |
| <para>When the ClickServlet starts up it checks to see whether the | |
| <varname>not-found.htm</varname> template exists in the <varname>click</varname> | |
| web sub directory. If it cannot find the page the ClickServlet will | |
| automatically deploy one. | |
| </para> | |
| <para>You can tailor the <varname>click/not-found.htm</varname> template to | |
| suite you own needs. This page template has access to the usual Click objects. | |
| </para> | |
| </sect1> | |
| <sect1 id="page-message-properties" remap="h2"> | |
| <title>Page Message Properties</title> | |
| <para>The Page class provides a | |
| <ulink url="../../click-api/org/apache/click/Page.html#messages">messages</ulink> | |
| property which is a | |
| <ulink url="../../click-api/org/apache/click/util/MessagesMap.html">MessagesMap</ulink> | |
| of localized messages for the page. These messages are made available in the | |
| VelocityContext when the page is rendered under the key | |
| <literal>messages</literal>. So for example if you had a page title message | |
| you would access it in your page template as: | |
| </para> | |
| <literallayout><h1> <symbol>$</symbol><varname>messages.title</varname> </h1></literallayout> | |
| <para>This messages map is loaded from the page class property bundle. For | |
| example if you had a page class <classname>com.mycorp.page.CustomerList</classname> | |
| you could have an associated property file containing the pages localized | |
| messages: | |
| </para> | |
| <literallayout>/com/mycorp/page/CustomerList.properties</literallayout> | |
| <para>You can also defined a application global page messages properties file: | |
| </para> | |
| <literallayout>/click-page.properties</literallayout> | |
| <para>Messages defined in this file will be available to all pages throughout | |
| your application. Note messages defined in your page class properties file | |
| will override any messages defined in the application global page properties | |
| file. | |
| </para> | |
| <para>Page messages can also be used to override Control messages, see the | |
| Controls <link linkend="control-message-properties">Message Properties</link> | |
| topic for more details. | |
| </para> | |
| </sect1> | |
| <sect1 id="page-head-elements" remap="h2"> | |
| <title>Page HEAD Elements</title> | |
| <para>The Page class provides the method | |
| <ulink url="../../click-api/org/apache/click/Page.html#getHeadElements()">getHeadElements()</ulink> | |
| for contributing HEAD <ulink url="../../click-api/org/apache/click/element/Element.html">elements</ulink> | |
| such as <ulink url="../../click-api/org/apache/click/element/JsImport.html">JsImport</ulink>, | |
| <ulink url="../../click-api/org/apache/click/element/JsScript.html">JsScript</ulink>, | |
| <ulink url="../../click-api/org/apache/click/element/CssImport.html">CssImport</ulink> | |
| and <ulink url="../../click-api/org/apache/click/element/CssStyle.html">CssStyle</ulink>. | |
| </para> | |
| <para>Here is an example of adding HEAD elements to the | |
| <classname>MyPage</classname> class: | |
| </para> | |
| <programlisting language="java">public class MyPage extends Page { | |
| public MyPage() { | |
| // Add the JavaScript import "/mypage.js" to the page | |
| getHeadElements().add(new JsImport("/mypage.js")); | |
| // Add some inline JavaScript content to the page | |
| getHeadElements().add(new JsScript("alert('Welcome to MyPage');")); | |
| // Add the Css import "/mypage.css" to the page | |
| getHeadElements().add(new CssImport("/mypage.css")); | |
| // Add some inline Css content to the page | |
| getHeadElements().add(new CssStyle("body { font-family: Verdana; }")); | |
| } | |
| ... | |
| } </programlisting> | |
| <para>In the example above we added the HEAD elements from the Page constructor, | |
| however you can add HEAD elements from anywhere in the Page including the | |
| event handlers <literal>onInit</literal>, <literal>onGet</literal>, | |
| <literal>onPost</literal>, <literal>onRender</literal> etc. | |
| Please see <ulink url="../../click-api/org/apache/click/Page.html#getHeadElements()">getHeadElements()</ulink> | |
| for more details. | |
| </para> | |
| <para>Below is the <filename>/my-page.htm</filename> template: | |
| </para> | |
| <programlisting language="xml"><html> | |
| <head> | |
| <varname>$headElements</varname> | |
| </head> | |
| <body> | |
| ... | |
| <varname>$jsElements</varname> | |
| </body> | |
| </html> </programlisting> | |
| <para>The two variables, <varname>$headElements</varname> and | |
| <varname>$jsElements</varname>, are automatically made available to the Page | |
| template. These variables references the JavaScript and Css HEAD elements | |
| specified in <classname>MyPage</classname>. | |
| </para> | |
| <para>The following HTML will be rendered (assuming the application context | |
| is "/myapp"): | |
| </para> | |
| <programlisting language="xml"><html> | |
| <head> | |
| <link rel="stylesheet" type="text/css" href="<symbol>/myapp/mypage.css</symbol>"></link> | |
| <style rel="stylesheet" type="text/css"> | |
| <symbol>body { font-family: Verdana; }</symbol> | |
| </style> | |
| </head> | |
| <body> | |
| ... | |
| <script type="text/javascript" src="<symbol>/myapp/mypage.js</symbol>"/> | |
| <script type="text/javascript"> | |
| <symbol>alert('Welcome to MyPage');</symbol> | |
| </script> | |
| </body> | |
| </html> </programlisting> | |
| <para>A live demo showing how to add HEAD elements to a Page can be seen | |
| <ulink url="http://click.avoka.com/click-examples/general/page-head-demo.htm">here</ulink>. | |
| </para> | |
| </sect1> | |
| </chapter> |