SeamFramework.orgCommunity Documentation
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-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value> </context-param> <session-config> <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:composition 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
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-app
PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN"
"http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
<jboss-app>
<loader-repository>webbeans.jboss.org:loader=webbeans-translator</loader-repository>
</jboss-app>
and META-INF/application.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<application 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/application_5.xsd"
version="5">
<display-name>webbeans-translator-ear</display-name>
<description>Ear Example for the reference implementation of JSR 299: Web Beans</description>
<module>
<web>
<web-uri>webbeans-translator.war</web-uri>
<context-root>/webbeans-translator</context-root>
</web>
</module>
<module>
<ejb>webbeans-translator.jar</ejb>
</module>
</application>
Next, lets look at the war. Just as in the numberguess example, we have
a faces-config.xml
(to enabled Facelets) and a
web.xml
(to enable JSF and attach Web Beans services
to the servlet container) in WebContent/WEB-INF
.
More intersting is the facelet used to translate text. Just as in the numberguess example we have a template, which surrounds the form (ommitted here for brevity):
<h:form id="NumberGuessMain">
<table>
<tr align="center" style="font-weight: bold" >
<td>
Your text
</td>
<td>
Translation
</td>
</tr>
<tr>
<td>
<h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80" />
</td>
<td>
<h:outputText value="#{translator.translatedText}" />
</td>
</tr>
</table>
<div>
<h:commandButton id="button" value="Translate" action="#{translator.translate}"/>
</div>
</h:form>
The user can enter some text in the lefthand textarea, and hit the translate button to see the result to the right.
Finally, let's look at the ejb module,
webbeans-translator-ejb
.
There are two configuration files in
src/main/resources/META-INF
, an empty
web-beans.xml
, used to mark the archive as
containing Web Beans, and ejb-jar.xml
. Web Beans
provides injection and initializtion services for all EJBs, and uses
ejb-jar.xml
to enable this, you'll need this in any
EJB project which uses Web Beans:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar 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/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>org.jboss.webbeans.ejb.SessionBeanInterceptor</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>org.jboss.webbeans.ejb.SessionBeanInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>
We've saved the most interesting bit to last, the code! The project has
two simple beans, SentanceParser
and
TextTranslator
and two enterprise beans,
TanslatorControllerBean
and
SentenceTranslator
. You should be getting quite
familiar with what a Web Bean looks like by now, so we'll just
highlight the most interesting bits here.
Both SentanceParser
and
TextTranslator
are dependent beans, and
TextTranslator
uses constructor initialization:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator)
{
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
TextTranslator
is a stateless bean (with a local
business interface), where the magic happens - of course, we couldn't
develop a full translator, but we gave it a good go!
Finally, there is UI orientated controller, that collects the text from the user, and dispatches it to the translator. This is a request scoped, named, stateful session bean, which injects the translator.
@Stateful
@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController
{
@Current TextTranslator translator;
The bean also has getters and setters for all the fields on the page.
As this is a stateful session bean, we have to have a remove method:
@Remove
public void remove()
{
}
The Web Beans manager will call the remove method for you when the bean is destroyed; in this case at the end of the request.
That concludes our short tour of the Web Beans RI examples. For more on the RI, or to help out, please visit http://www.seamframework.org/WebBeans/Development.
We need help in all areas - bug fixing, writing new features, writing examples and translating this reference guide.