Author: laubai
Date: 2009-11-23 19:33:31 -0500 (Mon, 23 Nov 2009)
New Revision: 11654
Modified:
tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Cache.xml
tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml
Log:
Removed callout syntax, as it breaks in publican.
Modified: tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Cache.xml
===================================================================
--- tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Cache.xml 2009-11-24
00:07:11 UTC (rev 11653)
+++ tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Cache.xml 2009-11-24
00:33:31 UTC (rev 11654)
@@ -14,7 +14,7 @@
nodes of the cluster. What these silly people are really thinking of
is a "share nothing except for the database" architecture. Of course,
sharing the database is the primary problem with scaling a multi-user
- application—so the claim that this architecture is highly scalable
+ application — so the claim that this architecture is highly scalable
is absurd, and tells you a lot about the kind of applications that these
folks spend most of their time working on.
</para>
@@ -66,7 +66,7 @@
persistence context associated with a conversation-scoped stateful
session bean) acts as a cache of data that has been read in the
current conversation. This cache tends to have a pretty high
- hitrate! Seam optimizes the replication of Seam-managed persistence
+ hit rate! Seam optimizes the replication of Seam-managed persistence
contexts in a clustered environment, and there is no requirement for
transactional consistency with the database (optimistic locking is
sufficient) so you don't need to worry too much about the performance
Modified: tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml
===================================================================
--- tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2009-11-24
00:07:11 UTC (rev 11653)
+++ tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2009-11-24
00:33:31 UTC (rev 11654)
@@ -99,105 +99,107 @@
<emphasis>validation</emphasis> declaratively, via
annotations. It also needs some extra
annotations that define the class as a Seam component. </para>
<!-- Can't use code hightlighting with callouts -->
- <example>
- <title></title>
- <programlisting role="JAVA">
-@Entity <co id="registration-entity-annotation"/>
+ <formalpara><title>User.java Example</title>
+ <para>
+<programlisting role="JAVA"><![CDATA[@Entity
@Name("user")
@Scope(SESSION)
@Table(name="users")
-public class User implements Serializable
-{
- private static final long serialVersionUID = 1881413500711441951L;
-
- private String username;
- private String password;
- private String name;
-
- public User(String name, String password, String username)
- {
- this.name = name;
- this.password = password;
- this.username = username;
- }
-
- public User() {}
-
- @NotNull @Length(min=5, max=15)
- public String getPassword()
- {
- return password;
- }
+public class User implements Serializable {
+ private static final long serialVersionUID = 1881413500711441951L;
+
+ private String username;
+ private String password;
+ private String name;
+
+ public User(String name, String password, String username) {
+ this.name = name;
+ this.password = password;
+ this.username = username;
+ }
+
+ public User() {}
+
+ @NotNull @Length(min=5, max=15)
+ public String getPassword() {
+ return password;
+ }
- public void setPassword(String password)
- {
- this.password = password;
- }
-
- @NotNull
- public String getName()
- {
- return name;
- }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
- public void setName(String name)
- {
- this.name = name;
- }
-
- @Id @NotNull @Length(min=5, max=15)
- public String getUsername()
- {
- return username;
- }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Id @NotNull @Length(min=5, max=15)
+ public String getUsername() {
+ return username;
+ }
- public void setUsername(String username)
- {
- this.username = username;
- }
+ public void setUsername(String username) {
+ this.username = username;
+ }
-}</programlisting>
-
- <para> The EJB3 standard
<literal>@Entity</literal> annotation indicates that the
- <literal>User</literal> class is an
entity bean. </para>
+}]]>
+</programlisting>
+ </para>
+ </formalpara>
- <para> A Seam component needs a
<emphasis>component name</emphasis> specified by the
- <literal>@Name</literal>
- annotation. This name must be unique within the Seam
application. When JSF
- asks Seam to resolve a context variable with a name
that is the same as a Seam
- component name, and the context variable is currently
undefined (null), Seam will
- instantiate that component, and bind the new instance
to the context variable. In
- this case, Seam will instantiate a
<literal>User</literal> the first time JSF
- encounters a variable named
<literal>user</literal>. </para>
+<formalpara><title>User.java Explanatory Notes</title>
+<para>
- <para> Whenever Seam instantiates a component, it
binds the new instance to a context
- variable in the component's
<emphasis>default context</emphasis>. The default
- context is specified using the
- <literal>@Scope</literal>
- annotation. The <literal>User</literal>
bean is a session scoped component.
- </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ The EJB3 standard <literal>@Entity</literal>
annotation indicates that the <literal>User</literal> class is an entity
bean.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A Seam component must have a <emphasis>component
name</emphasis> specified by the <xref linkend="name-annotation" />
<literal>@Name</literal> annotation. This name must be unique within the Seam
application. When JSF asks Seam to resolve a currently undefined (null) context variable
whose name matches that of a Seam component, Seam will instantiate that component, and
bind the new instance to the context variable. In this case, Seam will instantiate a
<literal>User</literal> the first time JSF encounters a variable named
<literal>user</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Whenever Seam instantiates a component, it binds the new
instance to a context variable in the component's <emphasis>default
context</emphasis>. The default context is specified using the <xref
linkend="scope-annotation" /> <literal>@Scope</literal>
annotation. The <literal>User</literal> bean is a session scoped component.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The EJB standard <literal>@Table</literal>
annotation indicates that the <literal>User</literal> class is mapped to the
<literal>users</literal> table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>name</literal>,
<literal>password</literal>, and <literal>username</literal> are
the persistent attributes of the entity bean. All of our persistent attributes define
accessor methods. These are needed when this component is used by JSF in the render
response and update model values phases.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ An empty constructor is required by both the EJB
specification and by Seam.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>@NotNull</literal> and
<literal>@Length</literal> annotations are part of the Hibernate Validator
framework. Seam integrates Hibernate Validator and lets you use it for data validation
(even if you are not using Hibernate for persistence).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The EJB standard <literal>@Id</literal>
annotation indicates the primary key attribute of the entity bean.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+</formalpara>
- <para> The EJB standard
<literal>@Table</literal> annotation indicates that the
- <literal>User</literal> class is
mapped to the <literal>users</literal> table.
- </para>
-
- <para>
- <literal>name</literal>,
<literal>password</literal> and <literal>username</literal>
- are the persistent attributes of the entity bean. All
of our persistent attributes
- define accessor methods. These are needed when this
component is used by JSF in the
- render response and update model values phases.
</para>
-
- <para> An empty constructor is both required by
both the EJB specification and by Seam.
- </para>
-
- <para> The <literal>@NotNull</literal>
and <literal>@Length</literal> annotations are
- part of the Hibernate Validator framework. Seam
integrates Hibernate Validator and
- lets you use it for data validation (even if you are
not using Hibernate for
- persistence). </para>
-
- <para> The EJB standard
<literal>@Id</literal> annotation indicates the primary key
- attribute of the entity bean. </para>
- </example>
<para> The most important things to notice in this example are
the <literal>@Name</literal> and
<literal>@Scope</literal> annotations. These
annotations establish that this class is a Seam component. </para>
<para> We'll see below that the properties of our
<literal>User</literal> class are bound
@@ -221,92 +223,136 @@
<para> This is the only really interesting code in the example!
</para>
<!-- Can't use code hightlighting with callouts -->
- <example>
- <title></title>
-
- <programlisting>
-@Stateless
+
+
+<formalpara><title>RegisterAction.java Example</title>
+ <para>
+
+
+<programlisting><![CDATA[@Stateless
@Name("register")
-public class RegisterAction implements Register
-{
+public class RegisterAction implements Register {
+ @In
+ private User user;
+
+ @PersistenceContext
+ private EntityManager em;
+
+ @Logger
+ private Log log;
+
+ public String register() {
+ List existing = em.createQuery(
+ "select username from User where username = #{user.username}")
+ .getResultList();
+
+ if (existing.size()==0) {
+ em.persist(user);
+ log.info("Registered new user #{user.username}");
+ return "/registered.xhtml";
+ } else {
+ FacesMessages.instance().add("User #{user.username} already exists");
+ return null;
+ }
+ }
- @In
- private User user;
-
- @PersistenceContext
- private EntityManager em;
-
- @Logger
- private Log log;
-
- public String register()
- {
- List existing = em.createQuery(
- "select username from User where username=#{user.username}")
- .getResultList();
-
- if (existing.size()==0)
- {
- em.persist(user);
- log.info("Registered new user #{user.username}");
- return "/registered.xhtml";
- }
- else
- {
- FacesMessages.instance().add("User #{user.username} already exists");
- return null;
- }
- }
-
-}</programlisting>
-
-
- <para> The EJB standard
<literal>@Stateless</literal> annotation marks this class as
- a stateless session bean. </para>
-
- <para> The
- <literal>@In</literal>
- annotation marks an attribute of the bean as
injected by Seam. In this case,
- the attribute is injected from a context variable
named <literal>user</literal> (the
- instance variable name). </para>
-
- <para> The EJB standard
<literal>@PersistenceContext</literal> annotation is used to
- inject the EJB3 entity manager. </para>
-
- <para> The Seam
<literal>@Logger</literal> annotation is used to inject the component's
- <literal>Log</literal> instance.
</para>
-
- <para> The action listener method uses the standard
EJB3
- <literal>EntityManager</literal> API to
interact with the database, and returns the
- JSF outcome. Note that, since this is a session bean,
a transaction is automatically
- begun when the
<literal>register()</literal> method is called, and committed when it
- completes. </para>
-
- <para> Notice that Seam lets you use a JSF EL
expression inside EJB-QL. Under the
- covers, this results in an ordinary JPA
<literal>setParameter()</literal> call on
- the standard JPA <literal>Query</literal>
object. Nice, huh? </para>
-
- <para> The <literal>Log</literal> API
lets us easily display templated log messages.
+}]]>
+</programlisting>
+ </para>
+ </formalpara>
+ <!-- </example> -->
+ <formalpara><title>RegisterAction.java Explanatory
Notes</title>
+ <para>
+ <orderedlist>
+ <listitem>
+ <para>
+ The EJB <literal>@Stateless</literal>
annotation marks this class as a stateless session bean.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <xref linkend="in-annotation" />
<literal>@In</literal> annotation marks an attribute of the bean as injected
by Seam. In this case, the attribute is injected from a context variable named
<literal>user</literal> (the instance variable name).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The EJB standard
<literal>@PersistenceContext</literal> annotation is used to inject the EJB3
entity manager.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Seam <literal>@Logger</literal>
annotation is used to inject the component's <literal>Log</literal>
instance.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The action listener method uses the standard EJB3
<literal>EntityManager</literal> API to interact with the database, and
returns the JSF outcome. Note that, since this is a session bean, a transaction begins
automatically when the <literal>register()</literal> method is called, and is
committed when it completes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Notice that Seam lets you use a JSF EL expression inside
EJB-QL. This results in an ordinary JPA <literal>setParameter()</literal> call
on the standard JPA <literal>Query</literal> object.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>Log</literal> API allows easily
display templated log messages that can include JSF EL expressions.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ JSF action listener methods return a string-valued
outcome that determines the next page displayed. A null outcome (or a void action listener
method) redisplays the previous page. In plain JSF, it is normal to always use a JSF
<emphasis>navigation rule</emphasis> to determine the JSF view ID from the
outcome. For complex applications, this redirection is good practice. However, for very
simple examples like this one, Seam lets you use the JSF view ID as the outcome,
eliminating the need for a navigation rule.
+ </para>
+ <note>
+ <para>
+ When a view ID is used as an outcome, Seam always
performs a browser redirect.
</para>
+ </note>
+ </listitem>
+ <listitem>
+ <para>
+ Seam provides a number of <emphasis>built-in
components</emphasis> to help solve common problems. The
<literal>FacesMessages</literal> component makes it easy to display templated
error or success messages. (As of Seam 2.1, you can use
<literal>StatusMessages</literal> instead, to remove the semantic dependency
on JSF.) Built-in Seam components may be obtained by injection, or by calling the
<literal>instance()</literal> method on the class of the built-in component.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </formalpara>
+ <!-- </example> -->
+ <para>
+ Note that we did not explicitly specify a
<literal>@Scope</literal> this time. Each Seam component type has a default
scope, which will be used if scope is not explicitly specified. For stateless session
beans, the default scope is the stateless context.
+ </para>
+ <para>
+ The session bean action listener performs the business and
persistence logic for our mini-application. In a more complex application, a separate
service layer might be necessary, but Seam allows you to implement your own strategies for
application layering. You can make any application as simple, or as complex, as you want.
+ </para>
+ <note>
+ <para>
+ This application is more complex than necessary for the sake of
clear example code. All of the application code could have been eliminated by using
Seam's application framework controllers.
+ </para>
+ </note>
+ </section>
+
+ <section>
+ <title>The session bean local interface:
<literal>Register.java</literal></title>
+ <para>
+ The session bean requires a local interface.
+ </para>
+ <formalpara><title>Register.java Example</title>
+ <para>
+ <!-- <example>
+ <title>Register.java</title> -->
+
+<programlisting role="JAVA"><![CDATA[@Local
+public interface Register {
+ public String register();
+}]]></programlisting>
+ <!-- </example> -->
+ </para>
+ </formalpara>
+
+
+
+
- <para> JSF action listener methods return a
string-valued outcome that determines what
- page will be displayed next. A null outcome (or a
void action listener method)
- redisplays the previous page. In plain JSF, it is
normal to always use a JSF
- <emphasis>navigation rule</emphasis>
to determine the JSF view id from the
- outcome. For complex application this indirection is
useful and a good practice.
- However, for very simple examples like this one, Seam
lets you use the JSF view id
- as the outcome, eliminating the requirement for a
navigation rule. <emphasis>Note
- that when you use a view id as an outcome, Seam
always performs a browser
- redirect.</emphasis>
- </para>
-
- <para> Seam provides a number of
<emphasis>built-in components</emphasis> to help solve
- common problems. The
<literal>FacesMessages</literal> component makes it easy to
- display templated error or success messages. Built-in
Seam components may be
- obtained by injection, or by calling an
<literal>instance()</literal> method.
- </para>
- </example>
-
<para> Note that we did not explicitly specify a
<literal>@Scope</literal> this time. Each Seam
component type has a default scope if not explicitly specified.
For stateless session beans, the
default scope is the stateless context. Actually,
<emphasis>all</emphasis> stateless session
@@ -775,89 +821,99 @@
<para> We want to cache the list of messages in memory between
server requests, so we will make this a
stateful session bean. </para>
<!-- Can't use code hightlighting with callouts -->
- <example>
- <title></title>
- <programlisting>
-@Stateful
+
+<formalpara><title>MessageManagerBean.java Example</title>
+ <para>
+
+<programlisting><![CDATA[@Stateful
@Scope(SESSION)
@Name("messageManager")
-public class MessageManagerBean implements Serializable, MessageManager
-{
+public class MessageManagerBean implements Serializable, MessageManager {
+ @DataModel
+ private List<Message> messageList;
+
+ @DataModelSelection
+ @Out(required=false)
+ private Message message;
+
+ @PersistenceContext(type=EXTENDED)
+ private EntityManager em;
+
+ @Factory("messageList")
+ public void findMessages() {
+ messageList = em.createQuery("select msg from Message msg " +
+ "order by msg.datetime desc")
+ .getResultList();
+ }
+
+ public void select() {
+ message.setRead(true);
+ }
+
+ public void delete() {
+ messageList.remove(message);
+ em.remove(message);
+ message=null;
+ }
+
+ @Remove
+ public void destroy() {}
- @DataModel
- private List<Message> messageList;
-
- @DataModelSelection
- @Out(required=false)
- private Message message;
-
- @PersistenceContext(type=EXTENDED)
- private EntityManager em;
-
- @Factory("messageList")
- public void findMessages()
- {
- messageList = em.createQuery("from Message msg order by msg.datetime
desc")
- .getResultList();
- }
-
- public void select()
- {
- message.setRead(true);
- }
-
- public void delete()
- {
- messageList.remove(message);
- em.remove(message);
- message=null;
- }
-
- @Remove
- public void destroy() {}
+}]]>
+</programlisting>
+ </para>
+ </formalpara>
+ <!-- </example> -->
+ <formalpara><title>MessageManagerBean.java Explanatory
Notes</title>
+ <para>
+ <orderedlist>
+ <listitem>
+ <para>
+ The <literal>@DataModel</literal> annotation
exposes an attibute of type <literal>java.util.List</literal> to the JSF page
as an instance of <literal>javax.faces.model.DataModel</literal>. This allows
us to use the list in a JSF
<literal><![CDATA[<h:dataTable>]]></literal> with clickable links
for each row. In this case, the <literal>DataModel</literal> is made available
in a session context variable named <literal>messageList</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>@DataModelSelection</literal>
annotation tells Seam to inject the <literal>List</literal> element
corresponding to the clicked link.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>@Out</literal> annotation then
exposes the selected value directly to the page. Every time a row of the clickable list is
selected, the <literal>Message</literal> is injected to the attribute of the
stateful bean, and subsequently "outjected" to the event context variable named
<literal>message</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ This stateful bean has an EJB3 <emphasis>extended
persistence context</emphasis>. This means that messages retrieved in the query
remain in the managed state for as long as the bean exists. Any subsequent method calls to
the stateful bean can therefore update the messages without needing to make an explicit
call to the <literal>EntityManager</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The first time we navigate to the JSP page, the
<literal>messageList</literal> context variable does not hold a value. The
<literal>@Factory</literal> annotation tells Seam to create an instance of
<literal>MessageManagerBean</literal> and invoke
<literal>findMessages()</literal> — a factory method for messages — to
initialize the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>select()</literal> action
listener method marks the selected <literal>Message</literal> as read, and
updates it in the database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>delete()</literal> action
listener method removes the selected <literal>Message</literal> from the
database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ All stateful session bean Seam components
<emphasis>must</emphasis> have a method <literal>@Remove</literal>
defined, with no parameters marked. Seam uses this to remove the stateful bean and clean
up any server-side state when the Seam context ends.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </formalpara>
-}</programlisting>
-
- <para> The
<literal>@DataModel</literal> annotation exposes an attibute of type
- <literal>java.util.List</literal> to
the JSF page as an instance of
-
<literal>javax.faces.model.DataModel</literal>. This allows us to use the
list
- in a JSF
<literal><h:dataTable></literal> with clickable links for
- each row. In this case, the
<literal>DataModel</literal> is made available in a
- session context variable named
<literal>messageList</literal>. </para>
-
- <para> The
<literal>@DataModelSelection</literal> annotation tells Seam to inject the
- <literal>List</literal> element that
corresponded to the clicked link. </para>
-
- <para> The <literal>@Out</literal>
annotation then exposes the selected value directly
- to the page. So every time a row of the clickable
list is selected, the
- <literal>Message</literal> is
injected to the attribute of the stateful bean,
- and the subsequently
<emphasis>outjected</emphasis> to the event context variable
- named <literal>message</literal>.
</para>
-
- <para> This stateful bean has an EJB3
<emphasis>extended persistence context</emphasis>.
- The messages retrieved in the query remain in the
managed state as long as the bean
- exists, so any subsequent method calls to the
stateful bean can update them without
- needing to make any explicit call to the
<literal>EntityManager</literal>. </para>
-
- <para> The first time we navigate to the JSP page,
there will be no value in the
- <literal>messageList</literal>
context variable. The <literal>@Factory</literal>
- annotation tells Seam to create an instance of
<literal>MessageManagerBean</literal>
- and invoke the
<literal>findMessages()</literal> method to initialize the value. We
- call <literal>findMessages()</literal> a
<emphasis>factory method</emphasis> for
- <literal>messages</literal>.
</para>
-
- <para> The <literal>select()</literal>
action listener method marks the selected
- <literal>Message</literal> as read,
and updates it in the database. </para>
+
+
- <para> The <literal>delete()</literal>
action listener method removes the selected
- <literal>Message</literal> from the
database. </para>
-
- <para> All stateful session bean Seam components
<emphasis>must</emphasis> have a method
- with no parameters marked
<literal>@Remove</literal> that Seam uses to remove
- the stateful bean when the Seam context ends, and
clean up any server-side state.
- </para>
- </example>
-
<para> Note that this is a session-scoped Seam component. It is
associated with the user login session,
and all requests from a login session share the same instance of the
component. (In Seam
applications, we usually use session-scoped components sparingly.)
</para>