SeamFramework.orgCommunity Documentation
The Web Beans (JSR-299) specification defines a set of services for the Java EE environment that makes applications much easier to develop. Web Beans layers an enhanced lifecycle and interaction model over existing Java component types including JavaBeans and Enterprise Java Beans. As a complement to the traditional Java EE programming model, the Web Beans services provide:
an improved lifecycle for stateful components, bound to well-defined contexts,
a typesafe approach to dependency injection,
interaction via an event notification facility, and
a better approach to binding interceptors to components, along with a new kind of interceptor, called a decorator, that is more appropriate for use in solving business problems.
Dependency injection, together with contextual lifecycle management, saves the user of an unfamiliar API from having to ask and answer the following questions:
what is the lifecycle of this object?
how many simultaneous clients can it have?
is it multithreaded?
where can I get one from?
do I need to explicitly destroy it?
where should I keep my reference to it when I'm not using it directly?
how can I add an indirection layer, so that the implementation of this object can vary at deployment time?
how should I go about sharing this object between other objects?
A Web Bean specifies only the type and semantics of other Web Beans it depends upon. It need not be aware of the actual lifecycle, concrete implementation, threading model or other clients of any Web Bean it depends upon. Even better, the concrete implementation, lifecycle and threading model of a Web Bean it depends upon may vary according to the deployment scenario, without affecting any client.
Events, interceptors and decorators enhance the loose-coupling that is inherent in this model:
event notifications decouple event producers from event consumers,
interceptors decouple technical concerns from business logic, and
decorators allow business concerns to be compartmentalized.
Most importantly, Web Beans provides all these facilities in a typesafe way. Web Beans never uses string-based identifiers to determine how collaborating objects fit together. And XML, though it remains an option, is rarely used. Instead, Web Beans uses the typing information that is already available in the Java object model, together with a new pattern, called binding annotations, to wire together Web Beans, their dependencies, their interceptors and decorators and their event consumers.
The Web Beans services are general and apply to the following types of components that exist in the Java EE environment:
all JavaBeans,
all EJBs, and
all Servlets.
Web Beans even provides the necessary integration points so that other kinds of components defined by future Java EE specifications or by non-standard frameworks may be cleanly integrated with Web Beans, take advantage of the Web Beans services, and interact with any other kind of Web Bean.
Web Beans was influenced by a number of existing Java frameworks, including Seam, Guice and Spring. However, Web Beans has its own very distinct character: more typesafe than Seam, more stateful and less XML-centric than Spring, more web and enterprise-application capable than Guice.
Most importantly, Web Beans is a JCP standard that integrates cleanly with Java EE, and with any Java SE environment where embeddable EJB Lite is available.
Table of Contents
So you're already keen to get started writing your first Web Bean? Or perhaps you're skeptical, wondering what kinds of hoops the Web Beans specification will make you jump through! The good news is that you've probably already written and used hundreds, perhaps thousands of Web Beans. You might not even remember the first Web Bean you wrote.
With certain, very special exceptions, every Java class with a constructor that accepts no parameters is a Web Bean. That includes every JavaBean. Furthermore, every EJB 3-style session bean is a Web Bean. Sure, the JavaBeans and EJBs you've been writing every day have not been able to take advantage of the new services defined by the Web Beans specification, but you'll be able to use every one of them as Web Beansinjecting them into other Web Beans, configuring them via the Web Beans XML configuration facility, even adding interceptors and decorators to themwithout touching your existing code.
Suppose that we have two existing Java classes, that we've been using for years in various applications. The first class parses a string into a list of sentences:
public class SentenceParser {
public List<String> parse(String text) { ... }
}
The second existing class is a stateless session bean front-end for an external system that is able to translate sentences from one language to another:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
Where Translator is the local interface:
@Local
public interface Translator {
public String translate(String sentence);
}
Unfortunately, we don't have a preexisting class that translates whole text documents. So let's write a Web Bean that does this job:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
We may obtain an instance of TextTranslator by
injecting it into a Web Bean, Servlet or EJB:
@Initializer
public setTextTranslator(TextTranslator textTranslator) {
this.textTranslator = textTranslator;
}
Alternatively, we may obtain an instance by directly calling a method of the Web Bean manager:
TextTranslator tt = manager.getInstanceByType(TextTranslator.class);
But wait: TextTranslator does not have a constructor
with no parameters! Is it still a Web Bean? Well, a class that does not have a
constructor with no parameters can still be a Web Bean if it has a constructor
annotated @Initializer.
As you've guessed, the @Initializer annotation has
something to do with dependency injection! @Initializer
may be applied to a constructor or method of a Web Bean, and tells the
Web Bean manager to call that constructor or method when instantiating the
Web Bean. The Web Bean manager will inject other Web Beans to the parameters
of the constructor or method.
At system initialization time, the Web Bean manager must validate that
exactly one Web Bean exists which satisfies each injection point. In our example,
if no implementation of Translator availableif the
SentenceTranslator EJB was not deployedthe Web Bean
manager would throw an UnsatisfiedDependencyException. If
more than one implementation of Translator was available,
the Web Bean manager would throw an
AmbiguousDependencyException.
So what, exactly, is a Web Bean?
A Web Bean is an application class that contains business logic. A Web Bean may be called directly from Java code, or it may be invoked via Unified EL. A Web Bean may access transactional resources. Dependencies between Web Beans are managed automatically by the Web Bean manager. Most Web Beans are stateful and contextual. The lifecycle of a Web Bean is always managed by the Web Bean manager.
Let's back up a second. What does it really mean to be "contextual"? Since Web Beans may be stateful, it matters which bean instance I have. Unlike a stateless component model (for example, stateless session beans) or a singleton component model (such as servlets, or singleton beans), different clients of a Web Bean see the Web Bean in different states. The client-visible state depends upon which instance of the Web Bean the client has a reference to.
However, like a stateless or singleton model, but unlike stateful session beans, the client does not control the lifecycle of the instance by explicitly creating and destroying it. Instead, the scope of the Web Bean determines:
the lifecycle of each instance of the Web Bean and
which clients share a reference to a particular instance of the Web Bean.
For a given thread in a Web Beans application, there may be an active context associated with the scope of the Web Bean. This context may be unique to the thread (for example, if the Web Bean is request scoped), or it may be shared with certain other threads (for example, if the Web Bean is session scoped) or even all other threads (if it is application scoped).
Clients (for example, other Web Beans) executing in the same context will see the same instance of the Web Bean. But clients in a different context will see a different instance.
One great advantage of the contextual model is that it allows stateful Web Beans to be treated like services! The client need not concern itself with managing the lifecycle of the Web Bean it is using, nor does it even need to know what that lifecyle is. Web Beans interact by passing messages, and the Web Bean implementations define the lifecycle of their own state. The Web Beans are loosely coupled because:
they interact via well-defined public APIs
their lifecycles are completely decoupled
We can replace one Web Bean with a different Web Bean that implements the same API and has a different lifecycle (a different scope) without affecting the other Web Bean implementation. In fact, Web Beans defines a sophisticated facility for overriding Web Bean implementations at deployment time, as we will see in Section 4.2, “Deployment types”.
Note that not all clients of a Web Bean are Web Beans. Other objects such as Servlets or Message-Driven Beanswhich are by nature not injectable, contextual objectsmay also obtain references to Web Beans by injection.
Enough hand-waving. More formally, according to the spec:
A Web Bean comprises:
A (nonempty) set of API types
A (nonempty) set of binding annotation types
A scope
A deployment type
Optionally, a Web Bean name
A set of interceptor binding types
A Web Bean implementation
Let's see what some of these terms mean, to the Web Bean developer.
Web Beans usually acquire references to other Web Beans via dependency injection. Any injected attribute specifies a "contract" that must be satisfied by the Web Bean to be injected. The contract is:
an API type, together with
a set of binding types.
An API is a user-defined class or interface. (If the Web Bean is an
EJB session bean, the API type is the @Local interface or
bean-class local view). A binding type represents some client-visible semantic
that is satisfied by some implementations of the API and not by others.
Binding types are represented by user-defined annotations that are
themselves annotated @BindingType. For example, the following
injection point has API type PaymentProcessor and binding
type @CreditCard:
@CreditCard PaymentProcessor paymentProcessor
If no binding type is explicitly specified at an injection point, the
default binding type @Current is assumed.
For each injection point, the Web Bean manager searches for a Web Bean which satisfies the contract (implements the API, and has all the binding types), and injects that Web Bean.
The following Web Bean has the binding type @CreditCard
and implements the API type PaymentProcessor. It could
therefore be injected to the example injection point:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
If a Web Bean does not explicitly specify a set of binding types, it has
exactly one binding type: the default binding type @Current.
Web Beans defines a sophisticated but intuitive resolution algorithm that helps the container decide what to do if there is more than one Web Bean that satisfies a particular contract. We'll get into the details in Chapter 4, Dependency injection.
Deployment types let us classify our Web Beans by
deployment scenario. A deployment type is an annotation that represents a particular
deployment scenario, for example @Mock, @Staging
or @AustralianTaxLaw. We apply the annotation to Web Beans which
should be deployed in that scenario. A deployment type allows a whole set of Web Beans
to be conditionally deployed, with a just single line of configuration.
Many Web Beans just use the default deployment type @Production,
in which case no deployment type need be explicitly specified. All three Web Bean
in our example have the deployment type @Production.
In a testing environment, we might want to replace the SentenceTranslator
Web Bean with a "mock object":
@Mock
public class MockSentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
We would enable the deployment type @Mock in our testing
environment, to indicate that MockSentenceTranslator and any other
Web Bean annotated @Mock should be used.
We'll talk more about this unique and powerful feature in Section 4.2, “Deployment types”.
The scope defines the lifecycle and visibility of instances of the Web Bean. The Web Beans context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built-in to the specification, and provided by the Web Bean manager. A scope is represented by an annotation type.
For example, any web application may have session scoped Web Beans:
@SessionScoped
public class ShoppingCart { ... }
An instance of a session scoped Web Bean is bound to a user session and is shared by all requests that execute in the context of that session.
By default, Web Beans belong to a special scope called the dependent pseudo-scope. Web Beans with this scope are pure dependent objects of the object into which they are injected, and their lifecycle is bound to the lifecycle of that object.
We'll talk more about scopes in Chapter 5, Scopes and contexts.
A Web Bean may have a name, allowing it to be used in Unified EL expressions. It's easy to specify the name of a Web Bean:
@SessionScoped @Named("cart")
public class ShoppingCart { ... }
Now we can easily use the Web Bean in any JSF or JSP page:
<h:dataTable value="#{cart.lineItems}" var="item">
....
</h:dataTable>It's even easier to just let the name be defaulted by the Web Bean manager:
@SessionScoped @Named
public class ShoppingCart { ... }
In this case, the name defaults to shoppingCartthe
unqualified class name, with the first character changed to lowercase.
Web Beans supports the interceptor functionality defined by EJB 3, not only for EJB beans, but also for plain Java classes. In addition, Web Beans provides a new approach to binding interceptors to EJB beans and other Web Beans.
It remains possible to directly specify the interceptor class via
use of the @Interceptors annotation:
@SessionScoped
@Interceptors(TransactionInterceptor.class)
public class ShoppingCart { ... }
However, it is more elegant, and better practice, to indirect the interceptor binding through an interceptor binding type:
@SessionScoped @Transactional
public class ShoppingCart { ... }
We'll discuss Web Beans interceptors and decorators in Chapter 7, Interceptors and Chapter 8, Decorators.
We've already seen that JavaBeans, EJBs and some other Java classes can be Web Beans. But exactly what kinds of objects are Web Beans?
The Web Beans specification says that a concrete Java class is a simple Web Bean if:
it is not an EE container-managed component, like an EJB, a Servlet or a JPA entity,
it is not a non-static static inner class,
it is not a parameterized type, and
it has a constructor with no parameters, or a constructor annotated
@Initializer.
Thus, almost every JavaBean is a simple Web Bean.
Every interface implemented directly or indirectly by a simple Web Bean is an API type of the simple Web Bean. The class and its superclasses are also API types.
The specification says that all EJB 3-style session and singleton beans are enterprise Web Beans. Message driven beans are not Web Beanssince they are not intended to be injected into other objectsbut they can take advantage of most of the functionality of Web Beans, including dependency injection and interceptors.
Every local interface of an enterprise Web Bean that does not have a wildcard type parameter or type variable, and every one of its superinterfaces, is an API type of the enterprise Web Bean. If the EJB bean has a bean class local view, the bean class, and every one of its superclasses, is also an API type.
Stateful session beans should declare a remove method with no parameters
or a remove method annotated @Destructor. The Web Bean
manager calls this method to destroy the stateful session bean instance at the
end of its lifecycle. This method is called the destructor
method of the enterprise Web Bean.
@Stateful @SessionScoped
public class ShoppingCart {
...
@Remove
public void destroy() {}
}
So when should we use an enterprise Web Bean instead of a simple Web Bean? Well, whenever we need the advanced enterprise services offered by EJB, such as:
method-level transaction management and security,
concurrency management,
instance-level passivation for stateful session beans and instance-pooling for stateless session beans,
remote and web service invocation, and
timers and asynchronous methods,
we should use an enterprise Web Bean. When we don't need any of these things, a simple Web Bean will serve just fine.
Many Web Beans (including any session or application scoped Web Bean) are available for concurrent access. Therefore, the concurrency management provided by EJB 3.1 is especially useful. Most session and application scoped Web Beans should be EJBs.
Web Beans which hold references to heavy-weight resources, or hold a lot
of internal state benefit from the advanced container-managed lifecycle defined
by the EJB @Stateless/@Stateful/@Singleton
model, with its support for passivation and instance pooling.
Finally, it's usually obvious when method-level transaction management, method-level security, timers, remote methods or asynchronous methods are needed.
It's usually easy to start with simple Web Bean, and then turn it into an
EJB, just by adding an annotation: @Stateless,
@Stateful or @Singleton.
A producer method is a method that is called by the Web Bean manager to obtain an instance of the Web Bean when no instance exists in the current context. A producer method lets the application take full control of the instantiation process, instead of leaving instantiation to the Web Bean manager. For example:
@ApplicationScoped
public class Generator {
private Random random = new Random( System.currentTimeMillis() );
@Produces @Random int next() {
return random.nextInt(100);
}
}
The result of a producer method is injected just like any other Web Bean.
@Random int randomNumber
The method return type and all interfaces it extends/implements directly or indirectly are API types of the producer method. If the return type is a class, all superclasses are also API types.
Some producer methods return objects that require explicit destruction:
@Produces @RequestScoped Connection connect(User user) {
return createConnection( user.getId(), user.getPassword() );
}
These producer methods may define matching disposal methods:
void close(@Disposes Connection connection) {
connection.close();
}
This disposal method is called automatically by the Web Bean manager at the end of the request.
We'll talk much more about producer methods in Chapter 6, Producer methods.
Finally, a JMS queue or topic can be a Web Bean. Web Beans relieves the developer from the tedium of managing the lifecycles of all the various JMS objects required to send messages to queues and topics. We'll discuss JMS endpoints in Section 13.4, “JMS endpoints”.
Let's illustrate these ideas with a full example. We're going to implement user login/logout for an application that uses JSF. First, we'll define a Web Bean to hold the username and password entered during login:
@Named @RequestScoped
public class Credentials {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
This Web Bean is bound to the login prompt in the following JSF form:
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputText id="password" value="#{credentials.password}"/>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" acion="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>
The actual work is done by a session scoped Web Bean that maintains
information about the currently logged-in user and exposes the User
entity to other Web Beans:
@SessionScoped @Named
public class Login {
@Current Credentials credentials;
@PersistenceContext EntityManager userDatabase;
private User user;
public void login() {
List<User> results = userDatabase.createQuery(
"select u from User u where u.username=:username and u.password=:password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if ( !results.isEmpty() ) {
user = results.get(0);
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user!=null;
}
@Produces @LoggedIn User getCurrentUser() {
return user;
}
}
Of course, @LoggedIn is a binding annotation:
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface LoggedIn {}
Now, any other Web Bean can easily inject the current user:
public class DocumentEditor {
@Current Document document;
@LoggedIn User currentUser;
@PersistenceContext EntityManager docDatabase;
public void save() {
document.setCreatedBy(currentUser);
docDatabase.persist(document);
}
}
Hopefully, this example gives a flavor of the Web Bean programming model. In the next chapter, we'll explore Web Beans dependency injection in greater depth.
The Web Beans Reference Implementation is being developed at the Seam project. You can download the latest developer release of Web Beans from the the downloads page.
The Web Beans RI comes with a two deployable example applications:
webbeans-numberguess, a war example, containing only
simple beans, and webbeans-translator an ear example,
containing enterprise beans. To run the examples you'll need the following:
the latest release of the Web Beans RI,
JBoss AS 5.0.0.GA, and
Ant 1.7.0.
Currently, the Web Beans RI only runs on JBoss Application Server 5. You'll need to download JBoss AS 5.0.0.GA from jboss.org, and unzip it. For example:
$ cd /Applications $ unzip ~/jboss-5.0.0.GA.zip
Next, download the Web Beans RI from seamframework.org, and unzip it. For example
$ cd ~/ $ unzip ~/webbeans-1.0.0.ALPHA1.zip
Next, we need to tell Web Beans where JBoss is located. Edit
jboss-as/build.properties and set the
jboss.home property. For example:
jboss.home=/Applications/jboss-5.0.0.GA
As Web Beans is a new piece of software, you need to update JBoss AS to run the Web Beans RI. Future versions of JBoss AS will include these updates, and this step won't be necessary.
Currently, two updates are needed. Firstly, a new deployer,
webbeans.deployer is added. This adds supports for
Web Bean archives to JBoss AS, and allows the Web Beans RI to query the
EJB3 container and discover which EJBs are installed in your
application. Secondly, an update to JBoss EJB3 is needed.
To install the update, you'll need Ant 1.7.0 installed, and the
ANT_HOME environment variable set. For example:
$ unzip apache-ant-1.7.0.zip $ export ANT_HOME=~/apache-ant-1.7.0
Then, you can install the update. The update script will use Maven to download the Web Beans and EJB3 automatically.
$ cd webbeans-1.0.0.ALPHA1/jboss-as $ ant update
Now, you're ready to deploy your first example!
The build scripts for the examples offer a number of targets, these are:
ant restart - deploy the example in exploded
format
ant explode - update an exploded example, without
restarting the deployment
ant deploy - deploy the example in compressed jar format
ant undeploy - remove the example from the server
ant clean - clean the example
To deploy the numberguess example:
$ cd examples/numberguess ant deploy
Wait for the application to deploy, and enjoy hours of fun at http://localhost:8080/webbeans-numberguess!
The Web Beans RI includes a second simple example that will translate your text into Latin. The numberguess example is a war example, and uses only simple beans; the translator example is an ear example, and includes enterprise beans, packaged in an EJB module. To try it out:
$ cd examples/translator ant deploy
Wait for the application to deploy, and visit http://localhost:8080/webbeans-translator!
In the numberguess application you get given 10 attempts to guess a number between 1 and 100. After each attempt, you will be told whether you are too high, or too low.
The numberguess example is comprised of a number of Web Beans, configuration files, and Facelet JSF pages, packaged as a war. Let's start with the configuration files.
All the configuration files for this example are located in
WEB-INF/, which is stored in
WebContent in the source tree. First, we have
faces-config.xml, in which we tell JSF to use
Facelets:
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config>
There is an empty web-beans.xml file, which marks
this application as a Web Beans application.
Finally there is web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Web Beans Numbergues example</display-name>
<!-- JSF -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-ma
pping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-pa
ram>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<session-co
nfig>
<session-timeout>10</session-timeout>
</session-config>
<listener>
<listener-class>org.jboss.webbeans.servlet.WebBeansListener</listener-class>
</listener>
</web-app>![]() | Enable and load the JSF servlet |
![]() |
Configure requests to |
![]() |
Tell JSF that we will be giving our source files (facelets) an
extension of |
![]() | Configure a session timeout of 10 minutes |
![]() | Configure the Web Beans listener, so that Web Beans services can be used in the servlet request |
The only configuration required by the Web Beans RI in
web.xml is to add the Web Beans listener.
Whilst this demo is a JSF demo, you can use the Web Beans RI with any Servlet based web framework; just configure the Web Beans listener.
Let's take a look at the Facelet view:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.com/products/seam/taglib">
<ui:composit
ion template="template.xhtml">
<ui:define name="content">
<h1>Guess a number...</h1>
<h:form id="NumberGuessMain">
<div
style="color: red">
<h:messages id="messages" globalOnly="false"/>
<h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess}"/>
<h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess}"/>
</div>
<div>
I
'm thinking of a number between #{game.smallest} and #{game.biggest}.
You have #{game.remainingGuesses} guesses.
</div>
<div>
Your guess:
<
h:inputText id="inputGuess"
value="#{game.guess}"
required="true"
size="3">
<f:validateLongRange maximum="#{game.biggest}"
minimum="#{game.smallest}"/>
</h:inputText>
<h
:commandButton id="GuessButton"
value="Guess"
action="#{game.check}"/>
</div>
</h:form>
</ui:define>
</ui:composition>
</html>![]() | Facelets is a templating language for JSF, here we are wrapping our page in a template which defines the header. |
![]() | There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!" |
![]() | As the user guesses, the range of numbers they can guess gets smaller - this sentance changes to make sure they know what range to guess in. |
![]() | This input field is bound to a Web Bean, using the value expression. |
![]() | A range validator is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of range number. |
![]() | And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the Web Bean. |
The example exists of 4 classes, the first two of which are binding
types. First, there is the @Random binding type,
used for injecting a random number:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface Random {}
There is also the @MaxNumber binding type, used for
injecting the maximum number that can be injected:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface MaxNumber {}
The Generator class is responsible for creating the
random number, via a producer method. It also exposes the maximum
possible number via a producer method:
@ApplicationScoped
public class Generator {
private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
private int maxNumber = 100;
java.util.Random getRandom()
{
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber);
}
@Produces @MaxNumber int getMaxNumber()
{
return maxNumber;
}
}
You'll notice that the Generator is application
scoped; therefore we don't get a different random each time.
The final Web Bean in the application is the session scoped
Game. By making Game session
scoped, you can only play the game once per browser session. You could
easily add a reset button - a good exercise for the reader :-)
You'll also note that we've used the @Named
annotation, so that we can use the bean through EL in the JSF page.
Finally, we've used constructor injection to initialize the game with
a random number. And of course, we need to tell the player when they've
won, so we give feedback with a FacesMessage.
@Named
@SessionScoped
public class Game {
private int number;
private int guess;
private int smallest;
private int biggest;
private int remainingGuesses;
public Game() {}
@Initializer
Game(@Random int number, @MaxNumber int maxNumber) {
this.number = number;
this.smallest = 1;
this.biggest = maxNumber;
this.remainingGuesses = 10;
}
// Getters and setters for fields
public String check() {
if (guess>number) {
biggest = guess - 1;
}
if (guess<number) {
smallest = guess + 1;
}
if (guess == number) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
}
remainingGuesses--;
return null;
}
}
The translator example will take any sentences you enter, and translate them to Latin.
The translator example is built as an ear, and contains EJBs and enterprise beans. As a result, it's structure is more complex than the numberguess example.
EJB 3.1 and Jave EE 6 allow you to package EJBs in a war, which will make this structure much simpler!
First, let's take a look at the ear aggregator, which is located in
webbeans-translator-ear module. Maven automatically
generates the application.xml and
jboss-app.xml for us:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<modules>
<webModule>
<groupId>org.jboss.webbeans.examples.translator</groupId>
<artifactId>webbeans-translator-war</artifactId>
<contextRoot>/webbeans-translator</contextRoot>
</webModule>
</modules>
<jboss>
<loader-repository>webbeans.jboss.org:loader=webbeans-translator</loader-repository>
</jboss>
</configuration>
</plugin>
We're doing a couple of things here - firstly we set the context path, which gives us a nice url (http://localhost:8080/webbeans-translator) and we also enable class loader isolation for JBoss AS.
If you aren't using Maven to generate these files, you would need
META-INF/jboss-app.xml: