SeamFramework.orgCommunity Documentation
The Web Beans is being developed at the Seam project. You can download the latest developer release of Web Beans from the the downloads page.
Web Beans 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. There are also two variations on the
numberguess example, the tomcat example (suitable for deployment to
Tomcat) and the jsf2 example, which you can use if you are running JSF2.
To run the examples you'll need the following:
the latest release of Web Beans,
JBoss AS 5.0.1.GA, or
Apache Tomcat 6.0.x, and
Ant 1.7.0.
You'll need to download JBoss AS 5.0.1.GA from jboss.org, and unzip it. For example:
$ cd /Applications $ unzip ~/jboss-5.0.1.GA.zip
Next, download Web Beans from seamframework.org, and unzip it. For example
$ cd ~/ $ unzip ~/webbeans-$VERSION.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.1.GA
To install Web Beans, you'll need Ant 1.7.0 installed, and the
ANT_HOME
environment variable set. For example:
JBoss 5.1.0 comes with Web Beans built in, so there is no need to update the server.
$ 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 Web Beans automatically.
$ cd webbeans-$VERSION/jboss-as $ ant update
Now, you're ready to deploy your first example!
The build scripts for the examples offer a number of targets for JBoss AS, 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
Start JBoss AS:
$ /Application/jboss-5.0.0.GA/bin/run.sh
If you use Windows, use the run.bat
script.
Wait for the application to deploy, and enjoy hours of fun at http://localhost:8080/webbeans-numberguess!
Web Beans 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!
You'll need to download Tomcat 6.0.18 or later from tomcat.apache.org, and unzip it. For example:
$ cd /Applications $ unzip ~/apache-tomcat-6.0.18.zip
Next, download Web Beans from seamframework.org, and unzip it. For example
$ cd ~/ $ unzip ~/webbeans-$VERSION.zip
Next, we need to tell Web Beans where Tomcat is located. Edit
jboss-as/build.properties
and set the
tomcat.home
property. For example:
tomcat.home=/Applications/apache-tomcat-6.0.18
The build scripts for the examples offer a number of targets for Tomcat, these are:
ant tomcat.restart
- deploy the example in exploded
format
ant tomcat.explode
- update an exploded example, without
restarting the deployment
ant tomcat.deploy
- deploy the example in compressed jar format
ant tomcat.undeploy
- remove the example from the server
ant tomcat.clean
- clean the example
To deploy the numberguess example for tomcat:
$ cd examples/tomcat ant tomcat.deploy
Start Tomcat:
$ /Applications/apache-tomcat-6.0.18/bin/startup.sh
If you use Windows, use the startup.bat
script.
Wait for the application to deploy, and enjoy hours of fun at http://localhost:8080/webbeans-numberguess!
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> </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 |
Whilst this demo is a JSF demo, you can use Web Beans with any Servlet based web framework.
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 and game.guess ne 0}"/> <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"/> </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" disabled="#{game.number eq game.guess}">
<f:validateLongRange maximum="#{game.biggest}" minimum="#{game.smallest}"/> </h:inputText> <h
:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/> </div> <div> <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" /> </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
.
You'll 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
.
package org.jboss.webbeans.examples.numberguess;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.webbeans.AnnotationLiteral;
import javax.webbeans.Current;
import javax.webbeans.Initializer;
import javax.webbeans.Named;
import javax.webbeans.SessionScoped;
import javax.webbeans.manager.Manager;
@Named
@SessionScoped
public class Game
{
private int number;
private int guess;
private int smallest;
private int biggest;
private int remainingGuesses;
@Current Manager manager;
public Game()
{
}
@Initializer
Game(@MaxNumber int maxNumber)
{
this.biggest = maxNumber;
}
public int getNumber()
{
return number;
}
public int getGuess()
{
return guess;
}
public void setGuess(int guess)
{
this.guess = guess;
}
public int getSmallest()
{
return smallest;
}
public int getBiggest()
{
return biggest;
}
public int getRemainingGuesses()
{
return remainingGuesses;
}
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;
}
@PostConstruct
public void reset()
{
this.smallest = 0;
this.guess = 0;
this.remainingGuesses = 10;
this.number = manager.getInstanceByType(Integer.class, new AnnotationLiteral<Random>(){});
}
}
The numberguess for Tomcat differs in a couple of ways. Firstly,
Web Beans should be deployed as a Web Application library in
WEB-INF/lib
. For your convenience we provide a
single jar suitable for running Web Beans in any servlet container
webbeans-servlet.jar
.
Of course, you must also include JSF and EL, as well common
annotations (jsr250-api.jar
) which a JEE server
includes by default.
Secondly, we need to explicitly specify the servlet listener
(used to boot Web Beans, and control it's interaction with requests)
in web.xml
:
<listener> <listener-class>org.jboss.webbeans.environment.servlet.Listener</listener-class> </listener>
Whilst JSR-299 specifies integration with Java ServerFaces, Web Beans allows you to inject into Wicket components, and also allows you to use a conversation context with Wicket. In this section, we'll walk you through the Wicket version of the numberguess example.
You may want to review the Wicket documentation at http://wicket.apache.org/.
Like the previous example, the Wicket WebBeans examples make use of
the webbeans-servlet
module. The use of the
Jetty servlet container
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.
These examples make use of the Eclipse IDE; instructions are also given to deploy the application from the command line.
To generate an Eclipse project from the example:
cd examples/wicket/numberguess mvn -Pjetty eclipse:eclipse
Then, from eclipse, choose File -> Import -> General -> Existing Projects into Workspace,
select the root directory of the numberguess example, and click
finish. Note that if you do not intend to run the example with jetty from
within eclipse, omit the "-Pjetty." This will create a project in your
workspace called webbeans-wicket-numberguess
This project follows the wicket-quickstart
approach of creating an instance of Jetty in the
Start
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
see console output related to Jetty starting up; then visit able
http://localhost:8080
to view the app. To
debug choose Debug as Java Application.
This example can also be deployed from the command line in a
(similar to the other examples). Assuming you have set up the
build.properties
file in the
examples
directory to specify the location of
JBoss AS or Tomcat, as previously described, you can run
ant deploy
from the
examples/wicket/numberguess
directory, and
access the application at
http://localhost:8080/webbeans-numberguess-wicket
.
JSF uses Unified EL expressions to bind view layer components in JSP or Facelet views to beans, Wicket defines it's components in Java. The markup is plain html with a one-to-one mapping between html elements and the view components. All view logic, including binding of components to models and controlling the response of view actions, is handled in Java. The integration of Web Beans with Wicket takes advantage of the same binding annotations used in your business layer to provide injection into your WebPage subclass (or into other custom wicket component subclasses).
The code in the wicket numberguess example is very similar to the JSF-based numberguess example. The business layer is identical!
Differences are:
Each wicket application must have a
WebApplication
subclass, In our case,
our application class is
SampleApplication
:
public class SampleApplication extends WebBeansApplication { @Override public Class getHomePage() { return HomePage.class; } }
This class specifies which page wicket should treat as our
home page, in our case, HomePage.class
In HomePage
we see typical wicket code
to set up page elements. The bit that is interesting is
the injection of the Game
bean:
@Current Game game;
The Game
bean is can then be used, for
example, by the code for submitting a guess:
final Component guessButton = new AjaxButton("GuessButton") { protected void onSubmit(AjaxRequestTarget target, Form form) { if (game.check()) {
All injections may be serialized; actual storage of the bean is managed by JSR-299. Note that Wicket components, like the HomePage and it subcomponents, are not JSR-299 beans.
Wicket components allow injection, but they
cannot use interceptors, decorators
and lifecycle callbacks such as
@PostConstruct
or
@Initializer
methods.
The example uses AJAX for processing of button events, and dynamically hides buttons that are no longer relevant, for example when the user has won the game.
In order to activate wicket for this webapp, the Wicket filter is added to web.xml, and our application class is specified:
<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>
Note that the servlet listener is also added, as in the Tomcat example, in order to boostrap Web Beans when Jetty starts, and to hook Web Beans into the Jetty servlet request and session lifecycles.
This example can be found in the
examples/se/numberguess
folder of the Web
Beans distribution.
To run this example:
Open a command line/terminal window in the
examples/se/numberguess
directory
Ensure that Maven 2 is installed and in your PATH
Ensure that the JAVA_HOME
environment
variable is pointing to your JDK installation
execute the following command
mvn -Drun
There is an empty beans.xml
file in the root
package (src/main/resources/beans.xml
), which
marks this application as a Web Beans application.
The game's main logic is located in Game.java
.
Here is the code for that class, highlighting the changes made
from the web application version:
@ApplicationScoped
public class Game implements Serializable
{
private int number;
private int guess;
private int smallest;
@MaxNumber
private int maxNumber;
private int biggest;
private int remainingGuesses;
private boolean validNumberRange = true;
@Current Generator rndGenerator;
...
public boolean isValidNumberRange()
{
return validNumberRange;
}
public boolean isGameWon(){
return guess == number;
}
public boolean isGameLost()
{
return guess != number && remainingGuesses <= 0;
}
public boolean check()
{
boolean result = false;if ( checkNewNumberRangeIsValid() )
{
if ( guess > number )
{
biggest = guess - 1;
}
if ( guess < number )
{
smallest = guess + 1;
}
if ( guess == number )
{
result = true;
}
remainingGuesses--;
}
return result;
}
private boolean checkNewNumberRangeIsValid()
{
return validNumberRange = ( ( guess >= smallest ) && ( guess <= biggest ) );
}
@PostConstructpublic void reset()
{
this.smallest = 0;
...
this.number = rndGenerator.next();
}
}
![]() | The bean is application scoped instead of session scoped, since an instance of the application represents a single 'session'. |
![]() | The bean is not named, since it doesn't need to be accessed via EL |
![]() |
There is no JSF
This allows the Swing UI to query the state of the game,
which it does indirectly via a class called
|
![]() |
Validation of user input is performed during the
|
![]() |
The |
The MessageGenerator
class depends on the
current instance of Game
, and queries its
state in order to determine the appropriate messages to provide
as the prompt for the user's next guess and the response to the
previous guess. The code for MessageGenerator
is as follows:
public class MessageGenerator
{@Current Game game;
public String getChallengeMessage()
{
StringBuilder challengeMsg = new StringBuilder( "I'm thinking of a number between " );
challengeMsg.append( game.getSmallest() );
challengeMsg.append( " and " );
challengeMsg.append( game.getBiggest() );
challengeMsg.append( ". Can you guess what it is?" );
return challengeMsg.toString();
}public String getResultMessage()
{
if ( game.isGameWon() )
{
return "You guess it! The number was " + game.getNumber();
} else if ( game.isGameLost() )
{
return "You are fail! The number was " + game.getNumber();
} else if ( ! game.isValidNumberRange() )
{
return "Invalid number range!";
} else if ( game.getRemainingGuesses() == Game.MAX_NUM_GUESSES )
{
return "What is your first guess?";
} else
{
String direction = null;
if ( game.getGuess() < game.getNumber() )
{
direction = "Higher";
} else
{
direction = "Lower";
}
return direction + "! You have " + game.getRemainingGuesses() + " guesses left.";
}
}
}
![]() |
The instance of |
![]() |
The |
![]() | And again to determine whether to congratulate, console or encourage the user to continue. |
Finally we come to the NumberGuessFrame
class
which provides the Swing front end to our guessing game.
public class NumberGuessFrame extends javax.swing.JFrame
{private @Current Game game;
private @Current MessageGenerator msgGenerator;
public void start( @Observes @Deployed Manager manager )
{
java.awt.EventQueue.invokeLater( new Runnable()
{
public void run()
{
initComponents();
setVisible( true );
}
} );
}private void initComponents() {
buttonPanel = new javax.swing.JPanel();
mainMsgPanel = new javax.swing.JPanel();
mainLabel = new javax.swing.JLabel();
messageLabel = new javax.swing.JLabel();
guessText = new javax.swing.JTextField();
...
mainLabel.setText(msgGenerator.getChallengeMessage());
mainMsgPanel.add(mainLabel);
messageLabel.setText(msgGenerator.getResultMessage());
mainMsgPanel.add(messageLabel);
...
}private void guessButtonActionPerformed( java.awt.event.ActionEvent evt )
{
int guess = Integer.parseInt(guessText.getText());
game.setGuess( guess );
game.check();
refreshUI();
}private void replayBtnActionPerformed( java.awt.event.ActionEvent evt )
{
game.reset();
refreshUI();
}private void refreshUI()
{
mainLabel.setText( msgGenerator.getChallengeMessage() );
messageLabel.setText( msgGenerator.getResultMessage() );
guessText.setText( "" );
guessesLeftBar.setValue( game.getRemainingGuesses() );
guessText.requestFocus();
}
// swing components
private javax.swing.JPanel borderPanel;
...
private javax.swing.JButton replayBtn;
}
![]() | The injected instance of the game (logic and state). |
![]() | The injected message generator for UI messages. |
![]() |
This application is started in the usual Web Beans SE way,
by observing the |
![]() |
This method initialises all of the Swing components. Note
the use of the |
![]() |
|
![]() |
|
![]() |
|
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. 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
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>
</configuration>
</plugin>
Here we set the context path, which gives us a nice url (http://localhost:8080/webbeans-translator).
If you aren't using Maven to generate these files, you would need
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 enable Facelets) and a
web.xml
(to enable JSF) 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
.
In src/main/resources/META-INF
there is just an
empty web-beans.xml
, used to mark the archive as
containing Web Beans.
We've saved the most interesting bit to last, the code! The project has
two simple beans, SentenceParser
and
TextTranslator
and two enterprise beans,
TranslatorControllerBean
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 SentenceParser
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 examples. For more on Web Beans , 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.