blob: 38a7af2336f8d22e7cb7be41951edb105d421034 [file] [log] [blame]
<chapter id="wug.chapter2">
<title>Hello World!</title>
<subtitle>Everyone's favorite example program</subtitle>
<sect1>
<title>A simple program</title>
<para>People learn best by example, and so this User’s Guide is example
driven. Our first example is the famous and traditional “Hello
World” program.</para>
<sect2>
<title>Building HelloWorld</title>
<para>Simply unzip your Wicket SDK archive somewhere on your hard
drive. Then go to
<filename>WICKET_HOME/examples/HelloWorld</filename> (where
<varname>WICKET_HOME</varname> is the folder where you unzipped
the Wicket SDK) and simply type "<command>ant</command>". You
should see this:</para>
<screen><![CDATA[C:\Wicket-SDK-0.5a\examples\HelloWorld>ant
Buildfile: build.xml
buildContext:
[delete] Deleting directory C:\Wicket-SDK-0.5a\build\examples\HelloWorld
buildClasses:
[mkdir] Created dir: C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEB-INF\classes
[javac] Compiling 2 source files to C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEBIN
F\classes
[copy] Copying 1 file to C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEB-INF\classes
[mkdir] Created dir: C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEB-INF\lib
[copy] Copying 1 file to C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEB-INF
[copy] Copying 21 files to C:\Wicket-SDK-0.5a\build\examples\HelloWorld\WEB-INF\lib
buildWar:
[war] Building war: C:\Wicket-SDK-0.5a\build\examples\HelloWorld\HelloWorld.war
buildAll:
BUILD SUCCESSFUL
Total time: 10 seconds]]></screen>
<para>The build process will create
<filename>WICKET_HOME/build/examples/HelloWorld</filename>.
This folder is a web application context, complete with the
standard <filename>WEB-INF</filename> folder structure and
<filename>web.xml</filename> file. You will also find a
<filename>HelloWorld.war</filename> file suitable for
deployment on any web application server.</para>
<mediaobject>
<imageobject>
<imagedata fileref="images/image001-explorer.png"
format="PNG"></imagedata>
</imageobject>
</mediaobject>
</sect2>
<sect2>
<title>Running HelloWorld</title>
<para>To run the HelloWorld web application, I suggest using the
Jetty application server because it is so easy to set up.
Simply download and unzip the latest Jetty web server (<ulink
url="http://jetty.mortbay.org"></ulink>). Then copy the
<filename>HelloWorld.war</filename> file from
<filename>WICKET_HOME/build/examples/HelloWorld</filename> to
the webapps folder under <varname>JETTY_HOME</varname>. Start
Jetty with "<command>java –jar start.jar</command>". Then go to
<ulink url="http://localhost:8080/HelloWorld" /> and you should
see this:</para>
<mediaobject>
<imageobject>
<imagedata fileref="images/image002-helloworld.png"
format="PNG"></imagedata>
</imageobject>
</mediaobject>
</sect2>
</sect1>
<sect1>
<title>The HelloWorld Source Code</title>
<para>The source code for HelloWorld consists of 4 files: the
<filename>web.xml</filename> descriptor, the
<filename>HelloWorldApplication.java</filename> servlet and the
<filename>HelloWorld.java</filename> page with its associated
markup file <filename>HelloWorld.html</filename>.</para>
<sect2>
<title>web.xml</title>
<para>The web.xml below defines a servlet called "HelloWorld" of
class <classname>helloworld.HelloWorldApplication</classname>
and maps all URLs in the web app context to this servlet. Since
<filename>HelloWorld.war</filename> is automatically deployed
on the HelloWorld context, the URL <ulink
url="http://localhost:8080/HelloWorld/" /> is mapped to the
HelloWorldApplication servlet.</para>
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>HelloWorld</display-name>
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>helloworld.HelloWorldApplication</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>]]></programlisting>
</sect2>
<sect2>
<title>HelloWorldApplication.java</title>
<para>The <filename>HelloWorldApplication.java</filename> file
looks like this:</para>
<programlisting><![CDATA[public class HelloWorldApplication extends WebApplication
{
public HelloWorldApplication()
{
getSettings().setHomePage(HelloWorld.class);
}
}]]></programlisting>
<para>All of the magic in Wicket comes from the
<classname>WebApplication</classname> class, which knows how to
deal with things like URLs, GET/POST requests and session
state. The only thing we need to do here is define the
<emphasis>home page</emphasis> for the application. When no
resource path is specified by a web page request, the
<classname>HelloWorldApplication</classname> servlet will
respond with the HelloWorld home page as a default.</para>
</sect2>
<sect2>
<title>HelloWorld.java</title>
<para>The actual HelloWorld page is a very simple class which
extends <classname>WebPage</classname> and takes a
<classname>PageParameters</classname> value in its
constructor.</para>
<programlisting><![CDATA[public class HelloWorld extends WebPage
{
public HelloWorld(final PageParameters parameters)
{
add(new Label("message", "Hello world!"));
}
}]]></programlisting>
<para>A page which has such a constructor can be invoked at any
time and is known as <emphasis>external</emphasis> since it can
be accessed from a browser that has not yet established a
session. Since it can be accessed at any time, an external page
is <emphasis>bookmarkable</emphasis>. Your home page must be
external (and therefore bookmarkable) since it will be accessed
before a session has been established!</para>
<para>All non-external pages in Wicket are not bookmarkable because
they will contain information in the URL (query parameters)
that refers to session information (which will not be available
at a later time). Accessing such a page (after it has expired)
via a bookmark will give the user a page that looks like
this:</para>
<mediaobject>
<imageobject>
<imagedata fileref="images/image003-pageexpired.png"
format="PNG"></imagedata>
</imageobject>
</mediaobject>
<para>Notice all the information in the URL? Those query parameters
refer to (expired) session information.</para>
</sect2>
</sect1>
<sect1>
<title>The Label Component</title>
<para>Getting back to the HelloWorld.java page, this line</para>
<programlisting><![CDATA[add(new Label("message", "Hello world!"));]]>
</programlisting>
<para>creates a Label component with the name "message" and the model
"Hello world!" The label component attaches to the associated
markup file <filename>HelloWorld.html</filename>.</para>
<programlisting><![CDATA[<html>
<body>
<span id = "wcn-message"/>
</body>
</html>]]></programlisting>
<sect2>
<title>Component names</title>
<para>It attaches to the <markup><![CDATA[<span>]]></markup> tag
with the Wicket component name attribute that matches the name
of the Label component. Wicket component names are specified in
three possible ways:</para>
<orderedlist>
<listitem>
<para>The component name can be specified using the
attribute <firstterm>"wcn"</firstterm> (for Wicket
component name). For example, <markup><![CDATA[<span wcn = "message">]]>
</markup>. The "wcn" attribute has the downside of
being an invalid HTML attribute that will be flagged by
validating HTML editor. On the upside, it should not
conflict with other attributes in your markup.</para>
</listitem>
<listitem>
<para>The component name can be specified as a value of the
id attribute prefixed by "wcn-" (for Wicket component
name). The use of the <emphasis>id</emphasis> attribute
allows Wicket HTML to validate correctly in validating
HTML editors. The "wcn-" prefix ensures that Wicket
knows which id attributes are being used for Wicket
component names and which are being used for other
purposes, such as CSS or JavaScript. This is necessary
because Wicket requires that all wicket component names
in a markup resource reference a Java component of the
same name. If this check fails, an exception is thrown.
This makes it easy to catch component wiring
problems.</para>
</listitem>
<listitem>
<para>You can specify your own attribute name using the
<classname>ApplicationSettings</classname> object
obtained in your WebApplication’s constructor:</para>
<programlisting><![CDATA[public class HelloWorldApplication extends WebApplication
{
public HelloWorldApplication()
{
getSettings().setHomePage(HelloWorld.class)
.setComponentNameAttribute("myAttributeName");
}
}]]></programlisting>
</listitem>
</orderedlist>
<para>In the case of our HelloWorld example, the Wicket component
name is specified with the id attribute value "wcn-message".
This matches the name of the Label component ("message").</para>
<para>Although some other component types will attach to other
kinds of tags, Label components will <emphasis>only</emphasis>
attach to <markup><![CDATA[<span>]]> </markup> tags.</para>
<para>When the HelloWorld page renders, the Label component simply
replaces the body of its tag with the value of its model
(components and their models can be considerably more complex
than Label, which will we see later in this guide). The
resulting markup will look like this:</para>
<programlisting><![CDATA[<html>
<body>
<span id = "wcn-message">Hello world!</span>
</body>
</html>]]></programlisting>
</sect2>
<sect2>
<title>Previewability</title>
<para>Note that if we had wanted our HelloWorld.html to be more
previewable in an HTML editor or browser, we could have made it
look like this instead:</para>
<programlisting><![CDATA[<html>
<body>
<span id = "wcn-message">Message goes here!</span>
</body>
</html>]]></programlisting>
<para>The final rendered page would still look the same since the
body of the span tag will be replaced with the model
value.</para>
</sect2>
</sect1>
<sect1>
<title>Component Rendering and Tags</title>
<para>It’s also interesting to note that the <markup><![CDATA[<span>]]>
</markup> tag that our Label is attached to will retain any other
attributes it might have originally had. This makes it a natural
place to apply a CSS style attribute, for example.</para>
<para>In general, the following rules are observed by Wicket when
rendering components:</para>
<formalpara>
<title>Wicket components MAY:</title>
<para>
<itemizedlist>
<listitem>
<para>Add attributes to a tag</para>
</listitem>
<listitem>
<para>Overwrite well-documented and appropriate tag
attributes</para>
</listitem>
<listitem>
<para>Replace a tag’s body</para>
</listitem>
<listitem>
<para>Insert markup before or after a tag’s body or
(very rarely) after a tag</para>
</listitem>
</itemizedlist>
</para>
</formalpara>
<formalpara>
<title>Wicket components WILL NOT:</title>
<para>
<itemizedlist>
<listitem>
<para>Remove tags from your markup</para>
</listitem>
<listitem>
<para>Remove a tag body that holds nested components
(more on this later)</para>
</listitem>
<listitem>
<para>Change the name of a tag <footnote> <para>One
notable exception: a disabled Link component will
change the anchor tag’s name from “a” to “span” so
as to disable the linking behavior of the anchor
tag.</para> </footnote> </para>
</listitem>
</itemizedlist>
</para>
</formalpara>
<para>The fact that Wicket mostly leaves your markup tags and their
attributes alone is very important to graphic designers because it
means that they don’t have to worry about being stepped on by the
toolkit. They can style away and know that their tags won’t be
modified in inappropriate ways.</para>
</sect1>
</chapter>