Author: cpopetz
Date: 2009-04-18 11:55:48 -0400 (Sat, 18 Apr 2009)
New Revision: 2510
Added:
doc/trunk/reference/en-US/images/wicket-conversations-snap.png
doc/trunk/reference/en-US/images/wicket-numberguess-project.png
Modified:
doc/trunk/reference/en-US/ri.xml
doc/trunk/reference/en-US/scopescontexts.xml
Log:
Document wicket integration and wicket examples (WBX-26)
Added: doc/trunk/reference/en-US/images/wicket-conversations-snap.png
===================================================================
(Binary files differ)
Property changes on: doc/trunk/reference/en-US/images/wicket-conversations-snap.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: doc/trunk/reference/en-US/images/wicket-numberguess-project.png
===================================================================
(Binary files differ)
Property changes on: doc/trunk/reference/en-US/images/wicket-numberguess-project.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Modified: doc/trunk/reference/en-US/ri.xml
===================================================================
--- doc/trunk/reference/en-US/ri.xml 2009-04-18 07:33:09 UTC (rev 2509)
+++ doc/trunk/reference/en-US/ri.xml 2009-04-18 15:55:48 UTC (rev 2510)
@@ -650,8 +650,8 @@
The numberguess for Tomcat differs in a couple of ways. Firstly,
Web Beans should be deployed as a Web Application library in
<literal>WEB-INF/lib</literal>. For your convenience we provide
a
- single jar suitable for running Web Beans on Tomcat
- <literal>webbeans-tomcat.jar</literal>.
+ single jar suitable for running Web Beans in any servlet container
+ <literal>webbeans-servlet.jar</literal>.
</para>
<tip>
@@ -663,19 +663,150 @@
</tip>
<para>
- Secondly, we need to explicitly specify the Tomcat servlet listener
+ Secondly, we need to explicitly specify the servlet listener
(used to boot Web Beans, and control it's interaction with requests)
in <literal>web.xml</literal>:
</para>
<programlisting><![CDATA[<listener>
-
<listener-class>org.jboss.webbeans.environment.tomcat.Listener</listener-class>
+
<listener-class>org.jboss.webbeans.environment.servlet.Listener</listener-class>
</listener>]]></programlisting>
</section>
+
+ <section id="numberguessWicket">
+ <title>The numberguess example in Apache Wicket</title>
+ <para>Although the JSR299 specification includes detailed information on
how WebBeans integrates
+ with Java Server Faces, it is possible to use WebBeans injection, as well as the
WebBeans conversational
+ context, with other web frameworks. In this section, we'll look at the module
which allows integration of
+ WebBeans with the Apache Wicket framework. This documentation assumes that you have
some familiarity
+ with Wicket; if not, please visit <ulink
url="http://wicket.apache.org/">http://wicket.apache.org/<...
+ to learn more. In this section we'll look at the previous "numberguess"
example as implemented with Wicket.
+ We'll look at the conversational aspects of the Wicket/WebBeans integration in
<xref linkend="wicketContexts"/></para>
+
+ <para>Like the previous example, the Wicket WebBeans examples make use of the
<literal>webbeans-servlet</literal> module.
+ The use of the <ulink
url="http://jetty.mortbay.org/">Jetty servlet
container</ulink> is common in the Wicket community,
+ and is chosen here as the runtime container in order to facilitate comparison between
the standard Wicket examples and these examples,
+ and also to show how the webbeans-servlet integration is not dependent upon tomcat as
the servlet container. Since we
+ are deploying to a servlet container, we are also building as a WAR. In addition,
these examples make use of the Eclipse IDE,
+ although instructions are also given to deploy the application from the command
line.</para>
+
+ <section>
+ <title>Creating the eclipse project</title>
+ <para>To generate an eclipse project from the example, use apache maven and the
eclipse:eclipse
+ plugin:
+ <programlisting><![CDATA[cd examples/wicket/numberguess
+mvn eclipse:eclipse -DdownloadSources]]></programlisting>
+ Then, from eclipse, choose <literal>File -> Import -> General ->
Existing Projects into Workspace</literal>, choose
+ the root directory of the numberguess example, and click finish. This should result
in a project in
+ your workspace named <literal>webbeans-wicket-numberguess</literal>:
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/wicket-numberguess-project.png"
format="png"/>
+ </imageobject>
+ </mediaobject>
+ </para>
</section>
<section>
+ <title>Running the example from eclipse</title>
+ <para>This project follows the <literal>wicket-quickstart</literal>
+ approach of creating an instance of <literal>jetty</literal> through a
<literal>Start</literal>
+ class. So running the example is as simple as right-clicking on that Start class in
src/test/java in the package
+ explorer and choosing "Run as Java Application." You should then see
console output related to jetty starting up,
+ and then be able to hit <literal>http://localhost:8080</literal> to view
the app. To stop the app, switch to the Console
+ View and click the red stop square. One can also debug in the same fashion, by
choosing "Debug as Java Application" when right-clicking.
+ </para>
+ </section>
+ <section>
+ <title>Running the example from the command line in Jboss or
Tomcat</title>
+ <para>This example can also be deployed from the command line in a fashion
similar to the other examples. Assuming you have set up the
+ <literal>build.properties</literal> file in the
<literal>examples</literal> directory to specify the location of Jboss or
Tomcat, as previously
+ described, you can simply run <literal>ant deploy</literal> from the
<literal>examples/wicket/numberguess</literal> directory, and access
+ the application at
<literal>http://localhost:8080/webbeans-numberguess-wicket</literal>.
+ </para>
+ </section>
+
+ <section>
+ <title>Understanding the code</title>
+ <para>While JSF uses unified EL expressions to bind view layer components in jsp
or xhtml to
+ WebBeans, Wicket keeps a stricter separation of concerns in place. The markup is plain
html with
+ a one-to-one mapping between html elements and the view components, which are
constructed in java code. All
+ view logic, including binding of components to models and controlling the response of
view actions,
+ is handled in java code. Therefore, the integration of WebBeans with Wicket takes
place through annotated
+ injections of WebBeans into your WebPage subclass (or into other custom wicket
component subclasses.)</para>
+
+ <para>The code in the wicket numberguess example is very similar to the JSF-based
numberguess example described previously. The business logic
+ components (Game, Generator, MaxNumber, etc.) are the same. Differences include the
following:</para>
+ <itemizedlist>
+ <listitem><para>Each wicket application must have a
<literal>WebApplication</literal> subclass,
+ and in the case of the Wicket/WebBeans integration, this class should subclass
<literal>
+ org.jboss.webbeans.wicket.WebBeansApplication</literal>. (If you would prefer
not to subclass
+ WebBeansApplication, you can manually add the small number of overrides and listeners
to your own WebApplication
+ subclass. See the javadocs on WebBeansApplication for details.) In our case, our
application class is called<literal>
+ SampleApplication</literal>:
+ <programlisting><![CDATA[public class SampleApplication extends
WebBeansApplication
+{
+ @Override
+ public Class getHomePage()
+ {
+ return HomePage.class;
+ }
+}]]></programlisting>This class specifies which page wicket should treat as our
HomePage,
+in our case, <literal>HomePage.class</literal></para>
+ </listitem>
+ <listitem>
+ <para>In <literal>HomePage</literal> we see typical wicket code to
set up page elements. The
+ bits that are interesting with respect to WebBeans are the injection of the
<literal>Game</literal>
+ WebBean the top of the class</para>
+ <programlisting><![CDATA[ @Current Game game;]]></programlisting>
which is then used later in,
+ for example, the code for submitting a guess:<programlisting><![CDATA[final
Component guessButton = new AjaxButton("GuessButton") {
+ protected void onSubmit(AjaxRequestTarget target, Form form) {
+ if (game.check()) {]]></programlisting>This injection is a proxy which
holds a transient reference to the actual
+ Game WebBean, and is therefore safe with respect to the serialization of the wicket
page. Actual
+ storage of the bean is in the session, and is managed by WebBeans. Note that
Wicket components, like the HomePage and its
+ subcomponents, are <emphasis>not</emphasis> WebBeans. Their
construction is handled directly by wicket (for
+ the page itself) and by the example code (for the nested page elements), and not by
the WebBeans
+ Manager. However, the <literal>
+ webbeans-wicket</literal> integration takes care of injecting dependencies
into the page for us. This
+ injection occurs through an
<literal>IComponentInstantiationListener</literal> which is
+ registered by the <literal>WebbeansWebApplication</literal>. This
means that although wicket
+ components can have injections, they <emphasis>cannot</emphasis> use
interceptors and the other features
+ of real WebBeans. The delegate beans used by the wicket code can of course be full
WebBeans,
+ as the <literal>Game</literal> bean is in this
example.</listitem>
+ <listitem><para>Note that this example also uses ajax for processing of
button events, and
+ dynamically hides buttons that are no longer revelant, for example when the user
has won the game.</para></listitem>
+
+ <listitem><para>In order to activate wicket for this webapp, the Wicket
filter is added to web.xml, and our application class is specified:
+ <programlisting><![CDATA[ <filter>
+ <filter-name>wicket.numberguess-example</filter-name>
+ <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+ <init-param>
+ <param-name>applicationClassName</param-name>
+
<param-value>org.jboss.webbeans.examples.wicket.SampleApplication</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>wicket.numberguess-example</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+<listener>
+
<listener-class>org.jboss.webbeans.environment.servlet.Listener</listener-class>
+</listener>]]></programlisting>Note that the servlet listener is also
added, as in the tomcat example, in order to boostrap
+WebBeans when jetty starts, and to hook WebBeans into the jetty servlet request and
session lifecycles.</para>
+</listitem>
+
+ </itemizedlist>
+
+
+ </section>
+
+ </section>
+ </section>
+
+ <section>
<title>The translator example</title>
<para>
Modified: doc/trunk/reference/en-US/scopescontexts.xml
===================================================================
--- doc/trunk/reference/en-US/scopescontexts.xml 2009-04-18 07:33:09 UTC (rev 2509)
+++ doc/trunk/reference/en-US/scopescontexts.xml 2009-04-18 15:55:48 UTC (rev 2510)
@@ -247,8 +247,147 @@
</section>
+ <section id="wicketContexts">
+ <title>Conversations using Wicket</title>
+ <para>The conversation scope can also be used in WebBeans with the Apache Wicket
web framework, through the
+ <literal>webbeans-wicket</literal> module. This module takes care of:
+ <itemizedlist>
+ <listitem><para>Setting up the conversation context at the beginning of a
wicket request, and tearing it down afterwards</para></listitem>
+ <listitem><para>Storing the id of any long-running conversation in
Wicket's WebPage metadata when the page response is
complete</para></listitem>
+ <listitem><para>Activating the correct long-running conversation based upon
which page is being accessed</para></listitem>
+ <listitem><para>Propagating the conversation context for any long-running
conversation to new pages</para></listitem>
+ </itemizedlist> </para>
+ <section>
+ <title>Starting and stopping conversations in Wicket</title>
+ <para>As in WebBeans JSF applications, a conversation
<emphasis>always</emphasis> exists for any request, but its lifetime is only
that of the current request unless it is marked as
+ <emphasis>long-running</emphasis>. For Wicket applications this is
accomplished exactly as in JSF applications, by injecting the <literal>@Current
Conversation</literal> and then
+ invoking <literal>conversation.begin()</literal>. Likewise, conversations
are ended with <literal>conversation.end()</literal>
+ </para>
+ </section>
+
+ <section>
+ <title>Long running conversation propagation in Wicket</title>
+ <para>
+ When a conversation is marked as long-running, the id of that conversation will be
stored in Wicket's WebPage metadata for the current page.
+ In addition, if a new page is created and set as the response target through
<literal>setResponsePage</literal>, this new page will also participate
+ in this conversation. This occurs for both directly instantiated pages, i.e.
<literal>setResponsePage(new OtherPage())</literal> as well as for
+ bookmarkable pages created with
<literal>setResponsePage(OtherPage.class)</literal> where
<literal>OtherPage.class</literal> is mounted as bookmarkable
+ from your <literal>WebApplication</literal> subclass (or through
annotations.) In the latter case, because the new page instance is not created until
after
+ a redirect, the conversation id will be propagated through a request parameter, and
then stored in page metadata after the redirect.
+ </para>
+ </section>
+ <section>
+ <title>The Wicket Conversations Example</title>
+ <para>In <literal>examples/wicket/conversations</literal> there is an
example application for using conversations from Wicket. To setup and run the
+ application, follow the examples in <xref
linkend="numberguessWicket"/>. If running within eclipse, the application is
available at <literal>http://localhost:8080</literal>,
+ and if running within an external container, the app is available at
<literal>http://localhost:8080/webbeans-conversations-wicket</literal>.
+ </para>
+ <section>
+ <title>Using the application</title>
+ <para>The <emphasis>conversations</emphasis> application is simply an
interface to begin and end conversations, switch between them, and store a single piece of
data in each.
+ The interface looks like the following:
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/wicket-conversations-snap.png"
format="PNG"/>
+ </imageobject>
+ </mediaobject></para>
+ <para>
+ The menu at the top will show the list of long-running conversations, along with data
about each,
+ as well as the active conversation (even if it is not long running.) The currently
selected item
+ of this menu is the current conversation for the last request that was processed.
Changing this menu
+ changes the current conversation. The "Data in conversation" text box and
the submit
+ button labeled "Change Value" allow you to change a piece of string data
associated
+ with the conversation. The "begin" button marks the conversation as long
running.
+ The "noop" button submits the form without changing the state of the
conversation.
+ The "end" button ends the current conversation. The "longop"
button
+ executes a method that takes a few seconds, which can be used to play with conversation
timeouts and
+ synchronization/locking. The "Abandon" link redirects to the HomePage
without propagating
+ the conversation, thus starting a new temporary conversation. The conversation that
has been abandoned
+ can be rejoined by selecting it in the popup.</para>
+ </section>
+ <section>
+ <title>Understanding the code</title>
+ <para>As in <xref linkend="numberguessWicket"/>, there is
boilerplate code in the
+ SampleApplication, as well as in web.xml, to ensure correct integration of Wicket and
Webbeans.
+ Other pieces of this application include:</para>
+ <itemizedlist>
+ <listitem><para>The <literal>Conversations</literal> class
exists to allow configuration of the conversation
+ timeout for the current session<programlisting><![CDATA[@Produces
+@ConversationInactivityTimeout
+@Example
+public static long getConversationTimeoutInMilliseconds()
+{
+ return 600000;
+}]]></programlisting>The <literal>Example</literal> deployment type
is used to illustrate
+custom deployment types. It is defined in
Example.java:<programlisting><![CDATA[@Target( { TYPE, METHOD, FIELD })
+@Retention(RUNTIME)
+@Documented
+@DeploymentType
+public @interface Example
+{
+}]]></programlisting> and is activated in
<literal>WEB-INF/beans.xml</literal>:
+<programlisting><![CDATA[<Beans xmlns="urn:java:ee"
xmlns:conversations="urn:java:org.jboss.webbeans.examples.conversations">
+ <Deploy>
+ <Standard />
+ <Production />
+ <conversations:Example />
+ </Deploy>
+</Beans>]]></programlisting></para></listitem>
+<listitem><para>The <literal>Data</literal> class is our
conversational component that stores a
+single string:<programlisting><![CDATA[@ConversationScoped
+@Named
+public class Data implements Serializable
+{
+ private String data;
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public void setData(String data)
+ {
+ this.data = data;
+ }
+}]]></programlisting></para></listitem>
+<listitem><para>The <literal>HomePage</literal> class is where
+the brunt of the work takes place. It injects the WebBeans-provided
<literal>ConversationManager</literal>
+component in order to access the list of long-running conversations, injects the current
<literal>Conversation</literal>
+in order to allow control over whether that conversation is long-running, and injects the
<literal>Data</literal>
+component to allow its manipulation by the
textfield:<programlisting><![CDATA[/**
+* These are injections for displaying information about existing conversations to the
user
+*/
+@Current ConversationManager conversationManager;
+@Current Conversation currentConversation;
+
+/**
+* This is our conversational data component, to illustrate how data is used in
conversations and
+* exists per-conversation.
+*/
+@Current Data data;
+]]></programlisting>The data component is referenced by the wicket TextField
using a
+<literal>PropertyModel</literal>:<programlisting><![CDATA[form.add(new
TextField("dataField", new PropertyModel(this,
"data.data")));]]></programlisting>
+This means that for each page, the text field is referring to the "data"
property of the "Data" bean that is specific to
+the conversation that is active for the request, whether that be a transient conversation
that is created for the request
+or a long-running conversation associated with the page. If one types data into the text
field
+and clicks <literal>Change Value</literal>
+when a long-running conversation is not started, and then clicks
<literal>noop</literal>, the
+value in the text field disappears, because it was associated with a transient
conversation, and
+upon redirect, the new conversation had a different Data object, which had the default
(empty) value.</para>
+<para>As you can see by the other code in this example, conversations are started
and ended programmatically,
+and no WebBeans-specific code is necessary to propagate the conversation. The only
exception to this
+is in the code to <emphasis>switch</emphasis> conversations, which is not a
typical operation in real scenarios.
+In this case, a conversation id (<literal>cid</literal>) request parameter is
passed to the <literal>setResponsePage</literal>
+invocation, and this explicit conversation id will override the id that the
wicket/webbeans integration
+code would normally generate in order to propagate the current conversation, and hence
the specified
+conversation will be active upon redirect.</para>
+</listitem>
+</itemizedlist>
+
</section>
-
+</section>
+</section>
+</section>
<section>
<title>The dependent pseudo-scope</title>