The heart of a Click application is the click.xml
configuration file. This file specifies the application pages, headers, the
format object and the applications mode.
By default the ClickServlet will attempt to load the application
configuration file using the path: /WEB-INF/click.xml
If this file is not found under the WEB-INF
directory,
then ClickServlet will attempt to load it from the classpath as
/click.xml
.
See Click DTD for the click-app XML definition.
A complete Click configuration example is available here which can be used as a quick reference when configuring Click.
A basic Click app config file is provided below:
<click-app> <!-- Specify the Java package where Page classes can be found --> <pages package="com.mycorp.page"/> <mode value="profile"/> </click-app>
An advanced config file would look like this:
<click-app charset="UTF-8" locale="de"> <!-- Specify the Java package where Page classes can be found --> <pages package="com.mycorp.banking.page"> <page path="index.htm" classname="Home"/> </pages> <!-- Specify a second Java package where Page classes can be found --> <pages package="com.mycorp.common.page"/> <format classname="com.mycorp.util.Format"/> <mode value="profile"/> <log-service classname="org.apache.click.extras.service.Log4JLogService"/> </click-app>
The take away point is that there is not much to configure, even for advanced uses.
The root click-app element defines two application
localization attributes charset
and locale
.
<!ELEMENT click-app (pages*, headers?, format?, mode?, controls?,
file-upload-service?, log-service?, template-service?)>
<!ATTLIST click-app charset
CDATA #IMPLIED>
<!ATTLIST click-app locale
CDATA #IMPLIED>
The charset
attribute defines the character encoding
set for:
Velocity templates
HttpServletRequest character encoding
Page Content-Type charset, see Page getContentType()
The locale
attribute defines the default application
Locale. If this value is defined it will override Locale returned by the request.
Please see the Context
getLocale()
for details. For example the following configuration sets the application
character set to UTF-8 and the default Locale as German (de):
<click-app charset=" UTF-8" locale="de"> .. </click-app>
The first child element of the click-app is the mandatory
pages
element which defines the list of Click pages.
<!ELEMENT pages
(page*)>
<!ATTLIST pages package
CDATA #IMPLIED>
<!ATTLIST pages automapping
(true|false) "true">
<!ATTLIST pages autobinding
(true|false) "true">
The pages element can specify a default package
name
which is prepended to the classname of any pages defined.
The pages element also defines the automapping
and
automapping
attributes which is discussed in the
Page Automapping and
Page Autobinding sections
respectively.
Click can support multiple pages elements to enable the automapping of multiple packages.
<click-app> <pages package="com.mycorp.banking.page"/> <pages package="com.mycorp.common.page"/> </click-app>
With multiple pages elements, pages are loaded in the order of the page elements, with manual page elements being loaded before automapped pages. Once a page template has been mapped to a Page class it will not be replaced by a subsequent potential match. So pages elements at the top take priority over lower pages elements.
The page element defines the Click application pages.
<!ELEMENT page(header
*)>
<!ATTLIST page path
CDATA #REQUIRED>
<!ATTLIST page classname
CDATA #REQUIRED>
Each page path
must be unique, as the Click
application maps HTTP requests to the page paths.
The Click application will create a new Page instance for
the given request using the configured page classname
.
All pages must subclass
Page and provide
a public no arguments constructor, so they can be instantiated.
Pages can also define header
values which are
discussed in the next topic.
When the Click application starts up it will check all the page
definitions. If there is a critical configuration error the ClickSerlvet
will log an ERROR
message and throw an
UnavailableException.
If this occurs the click application will be permanently unavailable until
the error is fixed and the web app is restarted.
Page automapping will automatically configure application pages using a simple set of rules. This enables you to greatly streamline your configuration file as you only need to define pages which don't fit the automapping rules.
Automapping will attempt to associate each page template (*.htm) and JSP file in the web application (excluding those under the WEB-INF and click directories) to a Page class. Automapped pages are loaded after the manually defined pages are loaded, and manually defined pages takes preference. When automapping is enabled the Click application will log the page mappings when in debug or trace mode.
For example, given the following page path to class mapping:
index.htm => com.mycorp.page.Home
search.htm => com.mycorp.page.Search
contacts/contacts.htm => com.mycorp.page.contacts.Contacts
security/login.htm => com.mycorp.page.security.Login
security/logout.htm => com.mycorp.page.security.Logout
security/change-password.htm => com.mycorp.page.security.ChangePassword
The above mapping could be configured manually by setting the automapping attribute to "false" and using the package prefix, for example:
<click-app> <pages package="com.mycorp.page" automapping="false"> <page path="index.htm" classname="Home"/> <page path="search.htm" classname="Search"/> <page path="contacts/contacts.htm" classname="contacts.Contacts"/> <page path="security/login.htm" classname="security.Login"/> <page path="security/logout.htm" classname="security.Logout"/> <page path="security/change-password.htm" classname="security.ChangePassword"/> </pages> </click-app>
By using automapping the page paths will automatically map to page classes: (except for Home page which doesn't automatically map to index.html)
<click-app> <pages package="com.mycorp.page" automapping="true"> <page path="index.htm" classname="Home"/> </pages> </click-app>
Note automapping is true by default, so it could be omitted from the configuration file.
The page template name to classname convention is:
change-password.htm => ChangePassword
change_password.htm => ChangePassword
changePassword.htm => ChangePassword
ChangePassword.htm => ChangePassword
When automapping pages, if a class cannot be found Click will attempt to add the 'Page' suffix to the classname if not already present and map this. For example:
customer.htm => CustomerPage
change-password.htm => ChangePasswordPage
With Page automapping there can be resources where you don't want
automapping applied. For example when using a JavaScript library with lots
of .htm
files, you don't want automapping to try and
find Page class for each of these files. In these situations you can use
the pages excludes element.
<!ELEMENT excludes (#PCDATA)>
<!ATTLIST excludes pattern
CDATA #REQUIRED>
For example if our application uses the TinyMCE JavaScript library
we could configure our pages automapping to exclude all .htm
files under the /tiny_mce
directory.
<click-app>
<pages package="com.mycorp.page">
<excludes pattern="/tiny_mce/*
"/>
</pages>
</click-app>
The excludes pattern can specify multiple directories or files using a comma separated notation. For example:
<click-app>
<pages package="com.mycorp.page">
<excludes pattern="/dhtml/*, /tiny_mce/*, banner.htm, about.htm
"/>
</pages>
</click-app>
HTM files excluded from Page automapping are handled by an internal Page class with caching headers enabled.
By default all pages have autobinding enabled. With autobinding the ClickServlet will automatically:
add any public controls to the page, after the page constructor has been invoked
if the public control name is not defined, its name will be set to the value of its field name
bind any request parameters to public page fields, after page constructor has been invoked. See ClickServlet.processPageRequestParams(Page) for more details
add any public page fields to the page model (this step occurs right before the page is rendered)
For example:
public class EmployeePage extends Page { public Form employeeForm = new Form(); public Table myTable = new Table(); }
In the example above the employeeForm
and
myTable
controls were not added to the page. Also note
that Form and Table do not have their names defined.
When autobinding is enabled, ClickServlet will create a new Page and
add the public controls to the page. In the example above the
employeeForm
and myTable
will be
added to the page, as if you had invoked,
addControl(employeeForm)
and
addControl(myTable)
.
The control's names were not defined so ClickServlet will set their
names to the value of their field/variable name. In this case the Form
name will be set to employeeForm
while the Table name
will set to myTable
.
The above example is thus a shorthand way of writing the following:
public class EmployeePage extends Page { private Form employeeForm = new Form(); private Table myTable = new Table(); public void onInit() { employeeForm.setName("employeeForm"); addControl(employeeForm); myTable.setName("myTable"); addControl(myTable); } }
You can turn this behaviour off by setting the autobinding attribute to false, for example:
<click-app>
<pages package="com.mycorp.page" autobinding="false
"/>
</click-app>
Click provides the
Bindable
annotation which enables autobinding of Page fields. The Bindable
annotation can bind private, protected and public Page fields.
However by default, Click's autobinding feature operates only on
public
fields. The reason for this is keeping
backwards compatibility with earlier versions which did not support
the Bindable annotation.
To enable Click to recognize the @Bindable
annotation you need to set the autobinding
attribute to annotation
, for example:
<click-app>
<pages package="com.mycorp.page" autobinding="annotation
"/>
</click-app>
You can now use the @Bindable annotation in your Pages:
public class EmployeePage extends Page { @Bindable protected Form employeeForm = new Form(); @Bindable protected Table myTable = new Table(); }
The optional headers
element defines a list of
header
elements which are applied to all pages.
<!ELEMENT headers
(header*)>
The header element defines header name and value pairs which are applied to the HttpServletResponse.
<!ELEMENT header (#PCDATA)>
<!ATTLIST header name
CDATA #REQUIRED>
<!ATTLIST header value
CDATA #REQUIRED>
<!ATTLIST header type
(String|Integer|Date) "String">
Page headers are set after the Page has been constructed and before
onInit()
is called. Pages can then modify their
headers
property using the
setHeader()
method.
Headers are typically used to switch off browser caching. By
default Click will use the following no caching header values if you don't
define a headers
element in your application:
<click-app> <pages> .. </pages> <headers> <header name="Pragma" value="no-cache"/> <header name="Cache-Control" value="no-store, no-cache, must-revalidate, post-check=0, pre-check=0"/> <header name="Expires" value="1" type="Date"/> </headers> </click-app>
Alternatively you can define your headers individually in pages or for all application pages by setting header values. For example to switch off caching in the login page, note the value for a Date type should be a long number value:
<pages package="com.mycorp.page"> <page path="login.htm" classname="Login"> <header name="Pragma" value="no-cache"/> <header name="Expires" value="1" type="Date"/> </page> </pages>
If you wanted to enable caching for a particular page you could set the following page cache control header. This will mark the page as cachable for a period of 1 hour after which it should be reloaded.
<pages package="com.mycorp.page"> <page path="home.htm" classname="Home"> <header name="Cache-Control" value="max-age=3600, public, must-revalidate"/> </page> </pages>
To apply header values globally define header values in the headers element. For example:
<click-app> <pages> .. </pages> <headers> <header name="Pragma" value="no-cache"/> <header name="Cache-Control" value="no-store, no-cache, must-revalidate, post-check=0, pre-check=0"/> <header name="Expires" value="1" type="Date"/> </headers> </click-app>
The optional format
element defines the Format
object classname which is applied to all pages.
<!ELEMENT format (#PCDATA)>
<ATTLIST format classname
CDATA #FIXED "org.apache.click.util.Format">
By default all Click pages are configured with a
org.apache.click.util.Format
object. The format object is made available in the Velocity page templates
using the name $format
.
To specify a custom format class configure a format
element in the click-app descriptor. For example:
<click-app>
..
<format classname="com.mycorp.util.CustomFormat
"/>
</click-app>
The optional mode
element defines the application
logging and caching mode.
<!ELEMENT mode (#PCDATA)>
<ATTLIST mode value (production|profile|development|debug|trace
) "development">
By default Click applications run in development
mode,
which switches off page template caching, and the logging level is set to
INFO
.
To change the default application mode configure a mode element in the
click-app descriptor. For example to specify production
mode you would add the following mode element:
<click-app>
..
<mode value="production
">
</click-app>
The application mode configuration can be overridden by setting the
system property "click.mode"
. This can be use in the scenario
of debugging a problem on a production system, where you change the mode to
trace
by setting the following system property and
restarting the application.
-Dclick.mode=trace
The Click Application modes and their settings for Page auto loading, template caching and logging levels are:
Application mode |
Page auto loading |
Template caching |
Click log level |
Velocity log level |
---|---|---|---|---|
production |
No |
Yes |
WARN |
ERROR |
profile |
No |
Yes |
INFO |
ERROR |
development |
Yes |
No |
INFO |
ERROR |
debug |
Yes |
No |
DEBUG |
ERROR |
trace |
Yes |
No |
TRACE |
WARN |
When Page Auto Loading is enabled any new page templates and classes will be automatically loaded at runtime. These pages are loaded using the Page Automapping rules.
Page auto loading is a very handy feature for rapid development as you do not have to restart you application server to pick up new pages.
The Click and Velocity runtimes use
LogService
for logging messages. The default LogService implementation is
ConsoleLogService
which will send messages to the console [System.out]. For example the
following logging output is for a HomePage request when the application
mode is trace
:
[Click] [debug] GET http://localhost:8080/quickstart/home.htm
[Click] [trace] invoked: HomePage.<<init>>
[Click] [trace] invoked: HomePage.onSecurityCheck() : true
[Click] [trace] invoked: HomePage.onInit()
[Click] [trace] invoked: HomePage.onGet()
[Click] [trace] invoked: HomePage.onRender()
[Click] [info ] renderTemplate: /home.htm - 6 ms
[Click] [trace] invoked: HomePage.onDestroy()
[Click] [info ] handleRequest: /home.htm - 24 ms
Any unhandled Throwable
errors are logged by the
ClickServlet.
Note that Click Extras also provide log adaptors for Log4J and the JDK Logging API.
When an application is not in production
mode the
error page displays detailed debugging information. When the application
mode is production
no debug information is displayed to
prevent sensitive information being revealed. This behaviour can be changed
by modifying the deployed click/error.htm
page template.
The optional controls
element defines a list of
control
elements which will be deployed on application
startup.
<!ELEMENT controls
(control*)>
The control registers Control classes which will have their onDeploy() method invoked when the click application starts.
<!ELEMENT control (#PCDATA)>
<!ATTLIST control classname
CDATA #REQUIRED>
For example to have a CustomField
control
deploy its resources on application startup, you would add the following
elements to your click.xml
file:
<click-app>
..
<controls>
<control classname="com.mycorp.control.CustomField
"/>
</controls>
</click-app>