Version 1.0.0.PREVIEW3 of Web Beans (the implementation for JSR 299 Contexts and Dependency Injection For Java EE) now uses the annotations fromJSR 330(Dependency Injection For Java) and it is available in GlassFish V3. 
In this entry, we'll look at a simple JSF 2 application that uses Web Beans and the JSR 330 annotations. There are other features available in this release of Web Beans which will be discussed in subsequent blog entries. This application is a simple "guess number" application which I'm sure we are probably all familiar with by now.  Let's start by taking a look at the application's UI markup.

Listing 1: User Interface Markup

 

     
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml"
  3.     xmlns:ui="http://java.sun.com/jsf/facelets"
  4.     xmlns:h="http://java.sun.com/jsf/html"
  5.     xmlns:f="http://java.sun.com/jsf/core">
  6.     <h:head>
  7.         <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  8.         <title>JSF 2.0 Web Beans Example</title>
  9.     </h:head>
  10.     <h:body>
  11.        <h:form id="NumberGuessMain">
  12.           <h:panelGrid styleClass="title-panel">
  13.              <h:outputText value="Guess Number" styleClass="title-panel-text"/>
  14.              <h:outputText value="Powered By JavaServer Faces 2.0 and Web Beans" styleClass="title-panel-subtext"/>
  15.           </h:panelGrid>
  16.           <div style="color: black; font-size: 24px;">
  17.              I'm thinking of a number between <span style="color: blue">#{game.smallest}</span> and <span style="color: blue">#{game.biggest}</span>. You have <span style="color: blue">#{game.remainingGuesses}</span> guesses.
  18.           </div>
  19.           <h:panelGrid border="1" columns="5" style="font-size: 18px;">
  20.              Number:
  21.              <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"/>
  22.              <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/>
  23.              <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" />
  24.              <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}"style="color: red"/>
  25.              <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"style="color: red"/>
  26.           </h:panelGrid>
  27.           <div style="color: red; font-size: 14px;">
  28.              <h:messages id="messages" globalOnly="false"/>
  29.           </div>
  30.           <h:outputStylesheet name="stylesheet.css" />
  31.        </h:form>
  32.     </h:body>
  33. </html>


Everything on this page is really just standard JSF 2.0 view markup.  I've emphasized  the  Expression Language  (EL) portions of the view, especially game because it refers to a contextual bean instance also known as a Web Bean.

  • Line 17: Binding to Web Bean properties
  • Line 21: Binding to Web Bean properties and validation method
  • Line 22, 23: Binding to Web Bean action method
  • Line 24, 25: Binding to Web Bean properties

As you can see, in JSF, binding to a Web Bean is no different than binding to a typical managed bean.

Supporting Classes And Annotations For The Applicaton

Let's take a look at some of the utility classes for the application, namely the classes that are used to generate a random number and some of the supporting annotations.

Listing 2: The "Random" Annotation

     
  1. package webbeansguess;
  2.  
  3. import static java.lang.annotation.ElementType.FIELD;
  4. import static java.lang.annotation.ElementType.METHOD;
  5. import static java.lang.annotation.ElementType.PARAMETER;
  6. import static java.lang.annotation.ElementType.TYPE;
  7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  8. import java.lang.annotation.Documented;
  9. import java.lang.annotation.Retention;
  10. import javax.inject.Qualifier;
  11.  
  12. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  13. @Retention(RUNTIME)
  14. @Documented
  15. @Qualifier
  16. public @interface Random {
  17. }


The JSR 330 @Qualifierannotation is used to make Random a binding type.   This will allow us to inject a random number into the application.

Listing 3: The "MaxNumber" Annotation

     
  1. package webbeansguess;
  2.  
  3. import static java.lang.annotation.ElementType.FIELD;
  4. import static java.lang.annotation.ElementType.METHOD;
  5. import static java.lang.annotation.ElementType.PARAMETER;
  6. import static java.lang.annotation.ElementType.TYPE;
  7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  8. import java.lang.annotation.Documented;
  9. import java.lang.annotation.Retention;
  10. import java.lang.annotation.Target;
  11. import javax.inject.Qualifier;
  12.  
  13. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  14. @Retention(RUNTIME)
  15. @Documented
  16. @Qualifier
  17. public @interface MaxNumber {
  18. }


Likewise, the @Qualifier annotation is used to makeMaxNumber a binding type that will allow us to inject the maximum number allowed (for a guess) in the application.

Listing 4: The "Generator" Class

     
  1. package webbeansguess;
  2.  
  3. import java.io.Serializable;
  4. import javax.enterprise.context.ApplicationScoped;
  5. import javax.enterprise.inject.Produces;
  6.  
  7. @ApplicationScoped
  8. public class Generator implements Serializable {
  9.     private static final long serialVersionUID = -7213673465118041882L;
  10.    private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
  11.     private int maxNumber = 100;
  12.     java.util.Random getRandom() {
  13.         return random;
  14.     }
  15.     @Produces @Random int next() {
  16.         return getRandom().nextInt(maxNumber);
  17.     }
  18.     @Produces @MaxNumber int getMaxNumber() {
  19.         return maxNumber;
  20.     }
  21. }

 

  • Line 7: An instance of this class exists for the lifecycle of the application
  • Line 15: next() is a Web Beans producermethod.  It will get called by the Web Beans Manager to obtain an instance of the next random number.
  • Line 18: getMaxNumber() is also a Web Beansproducer method.  It will get called by the Web Beans Manager to obtain an instance ofmaxNumber - essentially returning the maximum number to "guess" in the application (in this case "100").

The Anatomy of a Simple Contextual Bean

Now that we have are utility classes and annotations in place, we can use them in our Web Bean.

Listing 5: The "Game" Contextual Bean

     
  1. package webbeansguess;
  2.  
  3. import java.io.Serializable;
  4. import javax.annotation.PostConstruct;
  5. import javax.enterprise.context.SessionScoped;
  6. import javax.enterprise.inject.Instance;
  7. import javax.inject.Inject;
  8. import javax.inject.Named;
  9. import javax.faces.application.FacesMessage;
  10. import javax.faces.component.UIComponent;
  11. import javax.faces.component.UIInput;
  12. import javax.faces.context.FacesContext;
  13.  
  14. @Named
  15. @SessionScoped
  16. public class Game implements Serializable {
  17.     private static final long serialVersionUID = 1L;
  18.  
  19.     private int number;
  20.     private int guess;
  21.     private int smallest;
  22.   
  23.     @MaxNumber @Inject
  24.     private int maxNumber;
  25.   
  26.     private int biggest;
  27.     private int remainingGuesses;
  28.   
  29.     @Random @Inject Instance<Integer> randomNumber;
  30.   
  31.     public Game() {
  32.     }
  33.  
  34.     public int getNumber() {
  35.          return number;
  36.     }
  37.   
  38.     public int getGuess() {
  39.          return guess;
  40.     }
  41.   
  42.     public void setGuess(int guess) {
  43.          this.guess = guess;
  44.     }
  45.   
  46.     public int getSmallest() {
  47.          return smallest;
  48.     }
  49.   
  50.     public int getBiggest() {
  51.         return biggest;
  52.     }
  53.   
  54.     public int getRemainingGuesses() {
  55.         return remainingGuesses;
  56.     }
  57.   
  58.     public String check() throws InterruptedException {
  59.         if (guess>number) {
  60.             biggest = guess - 1;
  61.         }
  62.         if (guess<number) {
  63.             smallest = guess + 1;
  64.        }
  65.        if (guess == number) {
  66.            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
  67.        }
  68.        remainingGuesses--;
  69.        return null;
  70.     }
  71.   
  72.     @PostConstruct
  73.     public void reset() {
  74.         this.smallest = 0;
  75.         this.guess = 0;
  76.         this.remainingGuesses = 10;
  77.         this.biggest = maxNumber;
  78.         this.number = randomNumber.get();
  79.     }
  80.   
  81.     public void validateNumberRange(FacesContext context,  UIComponent toValidate, Object value) {
  82.         if (remainingGuesses <= 0) {
  83.             FacesMessage message = new FacesMessage("No guesses left!");
  84.             context.addMessage(toValidate.getClientId(context), message);
  85.             ((UIInput)toValidate).setValid(false);
  86.             return;
  87.         }
  88.         int input = (Integer) value;
  89.         if (input < smallest || input > biggest) {
  90.             ((UIInput)toValidate).setValid(false);
  91.             FacesMessage message = new FacesMessage("Invalid guess");
  92.             context.addMessage(toValidate.getClientId(context), message);
  93.         }
  94.     }
  95. }


I've color coded the areas of interest in this class.  Theblue areas are JSR 299 (Web Beans) implementation details.  The red areas are JSR 330 (Dependency Injection For Java) areas.  The purple areas are the binding types.

  • Line 14: We are using the Namedannotation to associate a name with this bean.  Because there is no argument specified with the Named annotation, its name will be the name of the bean itself with the first letter lowercase (game).   This allows us to reference the bean by that name using the Expression Language in the view.
  • Line 15: We declare this bean as a session scoped bean, meaning it's lifecycle is the lifecycle of the session.
  • Line 23: The producer method in the Generator class (line 18) will service this injection point causing maxNumber to have a value of "100".
  • Line 29: The producer method in the Generator class (line 15) will service this injection point making a  randomNumber instance available for this Web Bean.
  • Line 72: We use a standard @PostConstruct annotation causing variable initialization (after this Web Bean is created).
  • Line 78: Our Web Bean has been created, so the randomNumber.get() call will cause theproducer method in theGenerator class (line 15) to get called.

Well, that's a quick overview of a simple JSF2 application that uses the Web Beans (JSR 299 implementation) and the Java Dependency Injection (JSR 330) annotations. You can find this version of Web Beans in any of the GlassFish V3 builds after September 2, 2009.