| <!DOCTYPE' HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
| "http://www.w3.org/TR/html4/loose.dtd"> | |
| <!-- | |
| 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. | |
| --> | |
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> | |
| <meta name="Author" content="Malcolm Edgar"/> | |
| <meta name="description" lang="en" content="Apache Click Java web application framework"/> | |
| <meta name="keywords" lang="en" content="Apache Click, Click Framework, Java, JEE, J2EE, web application framework, open source"/> | |
| <title>Apache Click</title> | |
| <link rel="stylesheet" type="text/css" href="../help.css"/> | |
| <link rel="stylesheet" type="text/css" href="../syntax-highlighter.css"/> | |
| <script type="text/javascript" src="../syntax-highlighter.js"></script> | |
| </head> | |
| <!--Activate syntax highlighting--> | |
| <body onload="prettyPrint();"> | |
| <h1>Best Practices</h1> | |
| This section discusses Best Practices for designing and building Click application. | |
| The following topics are covered: | |
| <ol> | |
| <li><a href="#security">Security</a> - use JEE role based security | |
| </li> | |
| <li><a href="#packages-classes">Packages and Classes</a> - project package structures and page classes | |
| </li> | |
| <li><a href="#automapping">Page Auto Mapping</a> - use Convention over Configuration | |
| </li> | |
| <li><a href="#navigation">Navigation</a> - use Page classes to forward and redirect | |
| </li> | |
| <li><a href="#templating">Templating</a> - to standardize your web application | |
| </li> | |
| <li><a href="#menus">Menus</a> - centralize your page navigation | |
| </li> | |
| <li><a href="#logging">Logging</a> - use Log4j in a base page | |
| </li> | |
| <li><a href="#error-handling">Error Handling</a> - use custom error page | |
| </li> | |
| <li><a href="#performance">Performance</a> - enhancing page performance | |
| </li> | |
| </ol> | |
| <p> </p> | |
| <a name="security" class="heading"></a><h2>1. Security</h2> | |
| For application security it is highly recommended that you use the declarative | |
| JEE Servlet path role based security model. While Click pages provide an | |
| <tt>onSecurityCheck()</tt> method for rolling your own programatic security model, | |
| the declarative JEE model provides numerous advantages. | |
| <p/> | |
| These advantages include: | |
| <ul> | |
| <li> | |
| Its an industry standard pattern making development and maintenance easier. | |
| </li> | |
| <li> | |
| Application servers generally provide numerous ways of integration with an | |
| organisations security infrastructure, including LDAP directories and | |
| relational databases. | |
| </li> | |
| <li> | |
| Servlet security model support users bookmarking pages. When users go to access | |
| these pages later, the container will automatically authenticate them before | |
| allowing them to access the resource. | |
| </li> | |
| <li> | |
| Using this security model you can keep your Page code free of security | |
| concerns. This makes you code more reusable, or at least easier to write. | |
| </li> | |
| </ul> | |
| If your application has very fine grained or complex security requirements you | |
| may need to combine both the JEE declarative security model and a programmatic | |
| security model to meet your needs. In these cases its recommended you use declarative | |
| security for course grained access and programmatic security for finner grained | |
| access control. | |
| <h4>Declarative Security</h4> | |
| The declarative JEE Servlet security model requires users to be authenticated and | |
| in the right roles before they can access secure resources. Relative to many of | |
| the JEE specifications the Servlet security model is surprisingly simple. | |
| <p/> | |
| For example to secure admin pages, you add a security | |
| constraint in your <tt>web.xml</tt> file. This requires users to be in the | |
| <span class="blue">admin</span> role before they can access to any resources | |
| under the <span class="red">admin</span> directory: | |
| <pre class="codeConfig"> | |
| <security-constraint> | |
| <web-resource-collection> | |
| <web-resource-name>admin</web-resource-name> | |
| <url-pattern><span class="red">/admin/*</span></url-pattern> | |
| </web-resource-collection> | |
| <auth-constraint> | |
| <role-name><span class="blue">admin</span></role-name> | |
| </auth-constraint> | |
| </security-constraint> </pre> | |
| The application user roles are defined in the <tt>web.xml</tt> file as | |
| <tt>security-role</tt> elements: | |
| <pre class="codeConfig"> | |
| <security-role> | |
| <role-name><span class="blue">admin</span></role-name> | |
| </security-role> </pre> | |
| The Servlet security model supports three different authentication method: | |
| <ul> | |
| <li> | |
| <tt>BASIC</tt> - only recommended for internal applications where security | |
| is not important. This is the easiest authentication method, which simply | |
| displays a dialog box to users requiring them to authenticate before | |
| accessing secure resources. The BASIC method is relatively unsecure as the | |
| username and password are posted to the server as a Base64 encoded string. | |
| </li> | |
| <li> | |
| <tt>DIGEST</tt> - recommended for internal applications with a moderate level | |
| of security. As with BASIC authentication, this method simply displays a | |
| dialog box to users requiring them to authenticate before accessing | |
| secure resources. Not all application servers support DIGEST authentication, | |
| with only more recent versions of Apache Tomcat supporting this method. | |
| </li> | |
| <li> | |
| <tt>FORM</tt> - recommended applications for where you need a customised | |
| login page. For applications requiring a high level of security it is | |
| recommended that you use the FORM method over HTTPS. | |
| </li> | |
| </ul> | |
| The authentication method is specified in the <login-method> element. For | |
| example to use the BASIC authentication method you would specify: | |
| <pre class="codeConfig"> | |
| <login-config> | |
| <auth-method><span class="blue">BASIC</span></auth-method> | |
| <realm-name>Admin Realm</realm-name> | |
| </login-config> </pre> | |
| To use the FORM method you also need to specify the path to the login page and | |
| the login error page: | |
| <pre class="codeConfig"> | |
| <login-config> | |
| <auth-method><span class="blue">FORM</span></auth-method> | |
| <realm-name>Secure Realm</realm-name> | |
| <form-login-config> | |
| <form-login-page><span class="red">/login.htm</span></form-login-page> | |
| <form-error-page><span class="red">/login.htm?auth-error=true</span></form-error-page> | |
| </form-login-config> | |
| </login-config> </pre> | |
| In your Click <tt>login.htm</tt> page you need to include a special | |
| <span class="blue">j_security_check</span> form which includes the input | |
| fields <span class="blue">j_username</span> and <span class="blue">j_password</span>. | |
| For example: | |
| <pre class="codeHtml"> | |
| <span class="kw">#if</span> ($request.getParameter(<span class="red">"auth-error"</span>)) | |
| <div style="margin-bottom:1em;margin-top:1em;color:red;"> | |
| Invalid User Name or Password, please try again.<br/> | |
| Please ensure Caps Lock is off. | |
| </div> | |
| <span class="kw">#end</span> | |
| <form method="POST" action="<span class="blue">j_security_check</span>" name="form"> | |
| <table border="0" style="margin-left:0.25em;"> | |
| <tr> | |
| <td><label>User Name</label><font color="red">*</font></td> | |
| <td><input type="text" name="<span class="blue">j_username</span>" maxlength="20" style="width:150px;"/></td> | |
| <td>&nbsp;</td> | |
| </tr> | |
| <tr> | |
| <td><label>User Password</label><font color="red">*</font></td> | |
| <td><input type="password" name="<span class="blue">j_password</span>" maxlength="20" style="width:150px;"/></td> | |
| <td><input type="image" src="$context/images/login.png" title="Click to Login"/></td> | |
| </tr> | |
| </table> | |
| </form> | |
| <script type="text/javascript"> | |
| document.form.j_username.focus(); | |
| </script> </pre> | |
| When using FORM based authentication do <b>NOT</b> put application logic in a | |
| Click Login Page class, as the role of this page is to simply render the login | |
| form. If you attempt to put navigation logic in your Login Page class, the | |
| JEE Container may simply ignore it or throw errors. | |
| <p/> | |
| Putting this all together below is a <tt>web.xml</tt> snippet which features | |
| security constraints for pages under the admin path and the user path. This | |
| configuration uses the FORM method for authentication, and will also redirect | |
| unauthorized (403) requests to the <tt>/not-authorized.htm</tt> page. | |
| <pre class="codeConfig"> | |
| <web-app> | |
| .. | |
| <error-page> | |
| <error-code>403</error-code> | |
| <location><span class="green">/not-authorized.htm</span></location> | |
| </error-page> | |
| <security-constraint> | |
| <web-resource-collection> | |
| <web-resource-name>admin</web-resource-name> | |
| <url-pattern><span class="blue">/admin/*</span></url-pattern> | |
| </web-resource-collection> | |
| <auth-constraint> | |
| <role-name><span class="red">admin</span></role-name> | |
| </auth-constraint> | |
| </security-constraint> | |
| <security-constraint> | |
| <web-resource-collection> | |
| <web-resource-name>user</web-resource-name> | |
| <url-pattern><span class="blue">/user/*</span></url-pattern> | |
| </web-resource-collection> | |
| <auth-constraint> | |
| <role-name><span class="red">admin</span></role-name> | |
| <role-name><span class="red">user</span></role-name> | |
| </auth-constraint> | |
| </security-constraint> | |
| <login-config> | |
| <auth-method><span class="green">FORM</span></auth-method> | |
| <realm-name>Secure Zone</realm-name> | |
| <form-login-config> | |
| <form-login-page><span class="green">/login.htm</span></form-login-page> | |
| <form-error-page><span class="green">/login.htm?auth-error=true</span></form-error-page> | |
| </form-login-config> | |
| </login-config> | |
| <security-role> | |
| <role-name><span class="red">admin</span></role-name> | |
| </security-role> | |
| <security-role> | |
| <role-name><span class="red">user</span></role-name> | |
| </security-role> | |
| </web-app> | |
| </pre> | |
| <h4>Alternative Security solutions</h4> | |
| There are also alternative security solutions that provide extra features not | |
| available in JEE, such as RememberMe functionality, better resource mapping | |
| and <tt>Post Logon Page</tt> support. (<tt>Post Logon Page</tt> support allows one to | |
| specify a default URL where the user will be forwarded after successful login. | |
| This feature allows one to embed a login form in all non-secure pages and after | |
| successful authentication the user will be forwarded to their home page.) | |
| <p/> | |
| Below are some of the alternative security solutions available: | |
| <ul> | |
| <li> | |
| <a class="external" target="_blank" href="http://static.springframework.org/spring-security/site/index.html">Spring Security</a> | |
| </li> | |
| <li> | |
| <a class="external" target="_blank" href="http://securityfilter.sourceforge.net/">SecurityFilter</a> | |
| </li> | |
| <li> | |
| <a class="external" target="_blank" href="http://www.jsecurity.org/">JSecurity</a> | |
| </li> | |
| </ul> | |
| <h4>Resources</h4> | |
| For more information on using security see the resources below: | |
| <ul> | |
| <li><a href="http://stc.cis.brown.edu/~stc/Projects/Shibboleth/Version-3/Checklist/Tomcat-Authn/FormBasedAuthentication.pdf">Form Based Authentication</a> by Louis E. Mauget | |
| </li> | |
| <li><a href="http://java.sun.com/products/servlet/download.html">Servlet Specification</a> by Sun Microsystems | |
| </li> | |
| <li><a href="http://en.wikipedia.org/wiki/Basic_authentication_scheme">Basic authentication scheme</a> | |
| </li> | |
| <li><a href="http://en.wikipedia.org/wiki/Digest_access_authentication">Digest authentication scheme</a> | |
| </li> | |
| <li><a href="http://en.wikipedia.org/wiki/Https">Https URI scheme</a> | |
| </li> | |
| </ul> | |
| <a name="packages-classes" class="heading"></a><h2>2. Packages and Classes</h2> | |
| An excellent way to design your project package structure is the classify packages | |
| initially by technology. So in a Click application all of our pages would be contained | |
| under a <tt>page</tt> package. This also works very well with the Page automapping feature. | |
| <p/> | |
| All the projects domain entity classes would be contained under a <tt>entity</tt> package, | |
| and service classes would be contained under a <tt>service</tt> directory. Note alternative | |
| names for the <tt>entity</tt> package include domain or model. We also typically have a | |
| <tt>util</tt> package for any stray classes which don't quite fit into the other packages. | |
| <p/> | |
| In Java package names are singular by convention, so we have a util package rather than | |
| an utils package. | |
| <p/> | |
| An example project structure for a MyCorp web application is illustrated below: | |
| <blockquote> | |
| <img alt="Example Project Structure" src="../images/packages-classes.png"/> | |
| </blockquote> | |
| In this example application we use declarative role and path based security. | |
| All the pages in the <tt>admin</tt> package and directory require the <tt>"admin"</tt> | |
| role to be access, while all the pages in the <tt>user</tt> package and directory | |
| require the <tt>"user"</tt> role to be accessed. | |
| <h4>Page Classes</h4> | |
| A best practice when developing application Page classes is to place common | |
| methods in a base page class. This is typically used for providing access methods | |
| to application services and logger objects. | |
| <p/> | |
| For example the BasePage below provides access to Spring configured service objects | |
| and a Log4J logger object: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> BasePage <span class="kw">extends</span> Page <span class="kw">implements</span> ApplicationContextAware { | |
| <span class="cm">/** The Spring application context. */</span> | |
| <span class="kw">protected</span> ApplicationContext applicationContext; | |
| <span class="cm">/** The page Logger instance. */</span> | |
| <span class="kw">protected</span> Logger logger; | |
| <span class="cm">/** | |
| * Return the Spring configured Customer service. | |
| * | |
| * @return the Spring configured Customer service | |
| */</span> | |
| <span class="kw">public</span> CustomerService getCustomerService() { | |
| <span class="kw">return</span> (CustomerService) getBean(<span class="st">"customerService"</span>); | |
| } | |
| <span class="cm">/** | |
| * Return the Spring configured User service. | |
| * | |
| * @return the Spring configured User service | |
| */</span> | |
| <span class="kw">public</span> UserService getUserService() { | |
| <span class="kw">return</span> (UserService) getBean(<span class="st">"userService"</span>); | |
| } | |
| <span class="cm">/** | |
| * Return the page Logger instance. | |
| * | |
| * @return the page Logger instance | |
| */</span> | |
| <span class="kw">public</span> Logger getLogger() { | |
| <span class="kw">if</span> (logger == <span class="kw">null</span>) { | |
| logger = Logger.getLogger(getClass()); | |
| } | |
| <span class="kw">return</span> logger; | |
| } | |
| <span class="cm">/** | |
| * @see ApplicationContextAware#setApplicationContext(ApplicationContext) | |
| */</span> | |
| <span class="kw">public void</span> setApplicationContext(ApplicationContext applicationContext) { | |
| this.applicationContext = applicationContext; | |
| } | |
| <span class="cm">/** | |
| * Return the configured Spring Bean for the given name. | |
| * | |
| * @param beanName the configured name of the Java Bean | |
| * @return the configured Spring Bean for the given name | |
| */</span> | |
| <span class="kw">public</span> Object getBean(String beanName) { | |
| return applicationContext.getBean(beanName); | |
| } | |
| } </pre> | |
| Applications typically use a border template and have a <tt>BorderPage</tt> which | |
| extends <tt>BasePage</tt> and defines the template. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> BorderPage <span class="kw">extends</span> BasePage { | |
| <span class="cm">/** The root Menu item. */</span> | |
| <span class="kw">public</span> Menu rootMenu = <span class="kw">new</span> Menu(); | |
| <span class="cm">/** | |
| * @see Page#getTemplate() | |
| */</span> | |
| <span class="kw">public</span> String getTemplate() { | |
| <span class="kw">return</span> <span class="st">"/border-template.htm"</span>; | |
| } | |
| } </pre> | |
| Most application pages subclass <tt>BorderPage</tt>, except AJAX pages which | |
| have no need for a HTML border template and typically extend <tt>BasePage</tt>. | |
| The <tt>BorderPage</tt> class should not include common logic, other than that | |
| required for rendering the border template. Common page logic should be defined | |
| in the <tt>BasePage</tt> class. | |
| <p/> | |
| To prevent these base Page classes being auto mapped, and becoming directly | |
| acessible web pages, ensure that there are no page templates which could match | |
| their class name. For example the <tt>BorderPage</tt> class above will not be | |
| auto mapped to <span class="st">border-template.htm</span>. | |
| <a name="automapping" class="heading"></a><h2>3. Page Auto Mapping</h2> | |
| You should use the Click page automapping configuration feature. See | |
| the <a href="configuration.html#application-automapping">Page Automapping</a> | |
| topic for details. | |
| <p/> | |
| Automapping will save you from having to manually configure URL path to Page class | |
| mappings in your <tt>click.xml</tt> file. If you follow this convention it is very | |
| easy to maintain and refactor applications. | |
| <p/> | |
| You can also quickly determine what the corresponding Page class is for a page | |
| HTML template and visa versa, and if you use the ClickIDE Eclipse plugin you can | |
| switch between a page's class and template by pressing Ctrl+Alt+S. | |
| <p/> | |
| An example <tt>click.xml</tt> automapping configuration is provided below | |
| (automapping is enabled by default): | |
| <pre class="codeConfig"> | |
| <click-app> | |
| <pages <span class="blue">package</span>="<span class="red">com.mycorp.dashboard.page</span>"/> | |
| </click-app> </pre> | |
| To see how the page templates are mapped to Page classes set the application | |
| <a href="configuration.html#application-mode">mode</a> to <tt>debug</tt> and | |
| at startup the mappings will be listed out. An example Click startup listing is | |
| provided below: | |
| <pre class="codeConfig"> | |
| [Click] [debug] automapped pages: | |
| [Click] [debug] /category-tree.htm -> com.mycorp.dashboard.page.CategoryTree | |
| [Click] [debug] /process-list.htm -> com.mycorp.dashboard.page.ProcessList | |
| [Click] [debug] /user-list.htm -> com.mycorp.dashboard.page.UserList </pre> | |
| <a name="navigation" class="heading"></a><h2>4. Navigation</h2> | |
| When navigating between Pages using forwards and redirects, you should refer | |
| to the target page using the Page class rather than using path. | |
| This provides you compile time checking and will save you from having to update | |
| path strings in Java code if you move pages about. | |
| <p/> | |
| To forward to another page using the Page class: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomerListPage <span class="kw">extends</span> Page { | |
| <span class="kw">public</span> ActionLink customerLink = <span class="kw">new</span> ActionLink(<span class="kw">this</span>, <span class="st">"onCustomerClick"</span>); | |
| .. | |
| <span class="kw">public boolean</span> onCustomerClick() { | |
| Integer id = customerLink.getValueInteger(); | |
| Customer customer = getCustomerService().getCustomer(id); | |
| CustomerDetailPage customerDetailPage = (CustomerDetailPage) | |
| getContext().createPage(CustomerDetailPage.<span class="kw">class</span>); | |
| customerDetailPage.setCustomer(customer); | |
| setForward(customerDetailPage); | |
| <span class="kw">return false</span>; | |
| } | |
| } </pre> | |
| To redirect to another page using the Page class you can obtain the pages path | |
| from the <tt>Context</tt>. In the example below we are passing through the | |
| customer id as a request parameter to the target page. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomerListPage <span class="kw">extends</span> Page { | |
| <span class="kw">public</span> ActionLink customerLink = <span class="kw">new</span> ActionLink(<span class="kw">this</span>, <span class="st">"onCustomerClick"</span>); | |
| .. | |
| <span class="kw">public boolean</span> onCustomerClick() { | |
| String id = customerLink.getValueInteger(); | |
| String path = getContext().getPagePath(CustomerDetailPage.<span class="kw">class</span>); | |
| setRedirect(path + <span class="st">"?id="</span> + id); | |
| <span class="kw">return false</span>; | |
| } | |
| } </pre> | |
| A quick way of redirecting to another page is to simply refer to the target class. | |
| The example below logs a user out, by invalidating their session, and then redirects | |
| them to the applications home page. | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onLogoutClick() { | |
| getContext().getSession().invalidate(); | |
| setRedirect(HomePage.<span class="kw">class</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| <a name="templating" class="heading"></a><h2>5. Templating</h2> | |
| Use Page templating it is highly recommended. Page templates provide numerous | |
| advantages including: | |
| <ul> | |
| <li>greatly reduce the amount of HTML you need to maintain</li> | |
| <li>ensure you have a common look and feel across your application</li> | |
| <li>make global application changes very easy</li> | |
| </ul> | |
| To see how to use templates see the <a href="pages.html#page-templating">Page Templating</a> topic. | |
| Also see the Click <a href="examples.html">Examples</a> use of page templating. | |
| <a name="menus" class="heading"></a><h2>6. Menus</h2> | |
| For many applications using the <a href="extras-api/org/apache/click/extras/control/Menu.html">Menu</a> | |
| control to centralize application navigation is very useful. | |
| Menus are defined in a <tt>WEB-INF/menu.xml</tt> file which is very easy to change. | |
| <p/> | |
| An menu is typically defined in the a page border template so they are available | |
| through out the application. The Menu control does not support HTML rendering, | |
| so you need to define a Velocity macro to programmatically render the menu. | |
| You would call the macro in your border template with code like this: | |
| <pre class="codeHtml"> | |
| <span class="red">#</span><span class="blue">writeMenu</span>(<span class="red">$</span>rootMenu) </pre> | |
| An advantage of using a macro to render your menu is that you can reuse the code | |
| across different applications, and to modify an applications menu you simply need | |
| to edit the <tt>WEB-INF/menu.xml</tt> file. | |
| A good place to define your macros is in the webroot <tt>/macro.vm</tt> file | |
| as it is automatically included by Click. | |
| <p/> | |
| Using macros you can create dynamic menu behaviour such as only rendering menu items | |
| a user is authorized to access with <a href="extras-api/org/apache/click/extras/control/Menu.html#isUserInRoles()">isUserInRoles()</a>. | |
| <pre class="codeHtml"> | |
| <span class="kw">#if</span> (<span class="red">$</span>menu.isUserInRoles()) | |
| .. | |
| <span class="kw">#end</span> </pre> | |
| You can also use JavaScript to add dynamic behaviour such as drop down menus, | |
| for example see the Menu page in Click <a href="examples.html">Examples</a>. | |
| <a name="logging" class="heading"></a><h2>7. Logging</h2> | |
| For page logging you should use <a href="http://logging.apache.org/log4j/docs/">Log4j</a> | |
| library. An alternative library is the | |
| <a href="http://jakarta.apache.org/commons/logging/">Commons Logging</a>. | |
| If you are using Commons Logging please be aware that there have been class loader | |
| issues with this library on some application servers. If you are using | |
| Commons Logging please make sure you have the latest version. | |
| <p/> | |
| The best place to define your logger is in a common base page, for example: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> BasePage <span class="kw">extends</span> Page { | |
| <span class="kw">protected</span> Logger logger; | |
| <span class="kw">public</span> Logger getLogger() { | |
| <span class="kw">if</span> (logger == <span class="kw">null</span>) { | |
| logger = Logger.getLogger(getClass()); | |
| } | |
| <span class="kw">return</span> logger; | |
| } | |
| } </pre> | |
| Using this pattern all your application bases should extend <tt>BasePage</tt> | |
| so they can use the <tt>getLogger()</tt> method. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomerListPage <span class="kw">extends</span> BasePage { | |
| <span class="kw">public void</span> onGet() { | |
| <span class="kw">try</span> { | |
| .. | |
| } <span class="kw">catch</span> (Exception e) { | |
| getLogger().error(e); | |
| } | |
| } | |
| } </pre> | |
| If you have some very heavy debug statement you should possibly use an | |
| <tt>isDebugEnabled</tt> switch so it is not invoked if debug is not required. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomerListPage <span class="kw">extends</span> BasePage { | |
| <span class="kw">public void</span> onGet() { | |
| <span class="kw">if</span> (getLogger().isDebugEnabled()) { | |
| String msg = .. | |
| getLogger().debug(msg); | |
| } | |
| .. | |
| } | |
| } </pre> | |
| <p/> | |
| Please note the Click logging facility is not designed for application use, and is | |
| for Click internal use only. When Click is running in <tt>production</tt> mode | |
| it will not produce any logging output. | |
| <a name="error-handling" class="heading"></a><h2>8. Error Handling</h2> | |
| In Click unhandled errors are directed to the <a href="click-api/org/apache/click/util/ErrorPage.html">ErrorPage</a> | |
| for display. If applications require additional error handling they can create and | |
| register a custom error page in <tt>WEB-INF/click.xml</tt>. For example: | |
| <pre class="codeConfig"> | |
| <pages package="<span class="red">com.mycorp.page</span>" automapping="true"/> | |
| <page path="<span class="blue">click/error.htm</span>" classname="<span class="red">ErrorPage</span>"/> | |
| </pages> </pre> | |
| Generally application handle transactional errors using service layer code or via a | |
| servlet <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/Filter.html">Filter</a> and would not | |
| need to include error handling logic in an error page. | |
| <p/> | |
| Potential uses for a custom error page include custom logging. | |
| <p/> | |
| For example if an application requires unhandled errors to be logged to an | |
| application log (rather than System.out) then a custom | |
| <a href="click-api/org/apache/click/util/ErrorPage.html">ErrorPage</a> could be | |
| configured. An example <tt>ErrorPage</tt> error logging page is provided | |
| below: | |
| <pre class="codeJava"> | |
| <span class="kw">package</span> com.mycorp.page.ErrorPage; | |
| .. | |
| <span class="kw">public class</span> ErrorPage <span class="kw">extends</span> org.apache.click.util.ErrorPage { | |
| <span class="kw">public void</span> onDestory() { | |
| Logger.getLogger(getClass()).error(getError()); | |
| } | |
| } </pre> | |
| <a name="performance" class="heading"></a><h2>9. Performance</h2> | |
| Yahoo published a list of <a target="_blank" class="external" href="http://developer.yahoo.com/performance/rules.html">best practices</a> | |
| for improving web application performance. | |
| <p/> | |
| Click Framework provides a <a href="extras-api/org/apache/click/extras/filter/PerformanceFilter.html">PerformanceFilter</a> | |
| which caters for some of these rules. However not all rules can be easily automated. | |
| <p/> | |
| This section will outline ways to apply rules which are not covered by the PerformanceFilter namely, <a target="_blank" class="external" href="http://developer.yahoo.com/performance/rules.html#num_http">#1 - Minimize HTTP Requests (by combining files)</a> | |
| and <a target="_blank" class="external" href="http://developer.yahoo.com/performance/rules.html#minify">#10 - Minify Javascript and CSS</a>. | |
| <p/> | |
| Rule #1 also mentions <a target="_blank" class="external" href="http://alistapart.com/articles/sprites">CSS Sprites</a>, | |
| a method for combining multiple images into a single master image. CSS Sprites | |
| is not covered here. | |
| <p/> | |
| It is worth pointing out that its not necessary to blindly optimize every page in your application. | |
| Instead concentrate on popular pages, for example a web site's <em>Home Page</em> | |
| would be a good candidate. | |
| <p/> | |
| There are a couple of tools that are useful in applying Rule #1 and #10: | |
| <ul> | |
| <li> | |
| <a target="_blank" class="external" href="http://developer.yahoo.com/yui/compressor/">YUICompressor</a> | |
| - minifies and compresses JavaScript and CSS files so less | |
| bytes have to be transferred across the wire. | |
| </li> | |
| <li> | |
| <a target="_blank" class="external" href="http://code.google.com/p/javaflight-code/">Ant Task for YUICompressor</a> | |
| - an Ant task that uses YUICompressor to compress JavaScript and CSS files. | |
| </li> | |
| <li> | |
| <a target="_blank" class="external" href="http://www.crockford.com/javascript/jsmin.html">JSMin</a> | |
| - similar to YUICompressor but only minifies (remove whitespace and newlines) JavaScript files and | |
| does no compression at all. An advantage of JSMin over YUICompressor | |
| is that its faster and can be used at runtime to minify JavaScript, while YUICompressor | |
| is most often used at build time. | |
| </li> | |
| </ul> | |
| Below are some articles outlining how to use YUICompressor and Ant to concatenate and | |
| compress JavaScript and CSS files: | |
| <ul> | |
| <li> | |
| <a target="_blank" class="external" href="http://www.julienlecomte.net/blog/2007/09/16/">Article</a> explaining | |
| how to use Ant and YUICompressor for compression. | |
| </li> | |
| <li> | |
| <a target="_blank" class="external" href="http://javaflight.blogspot.com/2008/01/introducing-yui-compressor-ant-task.html">Article</a> | |
| outlining how to use a special YUICompressor Ant Task for compression. | |
| </li> | |
| </ul> | |
| <p/> | |
| Using one of the approaches above you can concatenate and compress all JavaScript and CSS | |
| for your Pages into two separate files, for example <tt>home-page.css</tt> and <tt>home-page.js</tt>. | |
| Note that the two files must include all the JavaScript and CSS that is generated | |
| by the Page and its Controls. Then you can instruct Click to <em>only</em> | |
| include the two compressed files, home-page.css and home-page.js. | |
| <p/> | |
| Click makes use of the utility class <a href="click-api/org/apache/click/util/PageImports.html">PageImports</a> | |
| to include the CSS and JavaScript. PageImports exposes the method | |
| <a href="click-api/org/apache/click/util/PageImports.html#setInitialized(boolean)">setInitialized(boolean)</a>, | |
| which controls when PageImports are fully initialized. Once PageImports have been | |
| initialized, no other CSS and JavaScript will be included. | |
| <p/> | |
| Knowing this one can override <a href="click-api/org/apache/click/Page.html#getPageImports()">Page.getPageImports()</a>, | |
| and import the necessary JavaScript and CSS files and then set PageImports to <tt>initialized</tt>, | |
| forcing PageImports to skip other CSS and JavaScript files. | |
| <p/> | |
| Here is an example: | |
| <pre class="prettyprint"> public class HomePage extends Page { | |
| private Form form = new Form("form"); | |
| public void onInit() { | |
| form.add(new EmailField("email"); | |
| addControl(form); | |
| } | |
| public void getPageImports () { | |
| PageImports pageImports = super.getPageImports(); | |
| String contextPath = getContext().getRequest().getContextPath(); | |
| String cssInclude = contextPath + "/assets/css/home-page.css"; | |
| pageImports.addImport("<link type=\"text/javascript\" href=\"" + cssInclude + "\"/>"); | |
| String jsInclude = contextPath + "/assets/js/home-page.js"; | |
| pageImports.addImport("<script type=\"text/javascript\" src=\"" + jsInclude + "\"></script>"); | |
| // Set pageImports to initialized so that no other CSS and JavaScript files will be included. | |
| pageImports.setInitialized(true); | |
| } | |
| } </pre> | |
| Using the following <tt>border-template.htm</tt>: | |
| <pre class="prettyprint"> | |
| <html> | |
| <head> | |
| <title>Click Examples</title> | |
| ${cssImports} | |
| </head> | |
| <body> | |
| ... | |
| ${jsImports} | |
| </body> | |
| </html> | |
| </pre> | |
| the rendered HTML will include one CSS and one JavaScript import: | |
| <pre class="prettyprint"> | |
| <html> | |
| <head> | |
| <title>Click Examples</title> | |
| <link type="text/css" rel="stylesheet" href="/click-examples/assets/css/home-page.css" title="Style"/> | |
| </head> | |
| <body> | |
| ... | |
| <script type="text/javascript" src="/click-examples/assets/js/home-page.js"></script> | |
| </body> | |
| </html> | |
| </pre> | |
| <p/> | |
| A live demo is available <a target="_blank" class="external" href="http://www.avoka.com/click-examples/general/page-imports-example.htm">here</a> | |
| <p/> | |
| </body> | |
| </html> |