1 2 Previous Next

rogerk

20 posts

Recently I had the privilege of writing an article for Java Tech Journal about using HTML5 Server Sent Events in a JSF 2 User Interface.  I've made that article available here.

One of the features that had been lacking in JSF has been the ability to use the JSR 330 @Inject annotation for injecting object instances into JSF managed beans.  The feature now has been enabled in GlassFish 3.1 - starting with the latest July 22 nightly builds, or a current source build.  So now, you should be able to use it in a JSF managed bean as follows:

                                   
           

import javax.inject.Inject;

           

....

           

@ManagedBean
            @SessionScoped
             

           

public class UserNumberBean implements Serializable {

           

    @Inject
                private Count count;

            ...

           

    public String getCount() {
                    if (null != count) {
                        return count.getCount();
                    } else {
                        return "";
                    }
                }
            ...

           

}

           

 

 

 

Cheers...

 

My slides for "Exploring HTML5 With JavaServer Faces 2.0" slides are  available at Slideshare: Available at: http://www.slideshare.net/rkitain/jsf2-html5jazoon

The ongoing HTML5 specification offers many features to promote a "rich"   web user experience.  If you've worked wth HTML5, you know that some   features are available in some browsers and not available in others.    Here's a handy tool to tell you the HTML5 features that are available in   your favorite browser.  All you need to do is fire up a browser and  visit: http://html5test.com  .  With this,  you'll see a nice breakdown of the features that are  available in the  current browser version.  It will also tell you, the  strengh of support  for each feature.  For example, for the current  version of Firefox I'm  using (3.6.3), it says it has a total score of  101 out of 160.  Here's a breakdown for each of the current browsers I'm using:

                                                                                                                                                                       
Firefox 3.6.3101/160
Safari 4.0.3115/160
Opera 10.10  38/160
Chrome 5.0.375.55 beta142/160

Of course if you really like an HTML5 feaure that is not available in your favorite browser, you can always check the "development" versions for the browser - as HTML5 support is still a work in progress. 

 

 

I've had questions about how to inject Web Beans into servlets and whether that is supported.  In this entry I'll outline a method of accomplishing just that.
This is a simple login application that communicates to a servlet using Ajax calls from a JSP view.  I'm not going to focus on the view or the protocol (Ajax) that  is used to communicate with the servlet.  If you are interested in that, you can check out the source (instructions at the end of this post).  I'm going to focus on the servlet code and the supporting classes for the application.  The application just prompts for a user name / pasword, and pressing the submit button sends those values to a servlet.  First, let's take a look at some of the supporting code for the application:

Listing 1: Login Credentials

                                   
           
                   
  1. package webbeansservlet;
  2.                
  3.  
  4.                
  5. import javax.enterprise.context.RequestScoped;
  6.                
  7. import javax.enterprise.inject.Default;
  8.                
  9. import javax.inject.Named;
  10.                
  11.  
  12.                
  13. /**
  14.                
  15.  * This is just a simple container class Web Bean for the username
  16.                
  17.  *  and password entry values.
  18.                
  19.  */
  20.                
  21. @Named
  22.                
  23. @RequestScoped
  24.                
  25. @Default
  26.                
  27. public class Credentials {
  28.                
  29.     private String username = null;
  30.                
  31.     private String password = null;
  32.                
  33.     public String getUsername() {
  34.                
  35.         return username;
  36.                
  37.     }
  38.                
  39.     public void setUsername(String username) {
  40.                
  41.         this.username = username;
  42.                
  43.     }
  44.                
  45.     public String getPassword() {
  46.                
  47.         return password;
  48.                
  49.     }
  50.                
  51.     public void setPassword(String password) {
  52.                
  53.         this.password = password;
  54.                
  55.     }
  56.                
  57. }
  58.            
           

 

       
  • Line 11: The name of this Web Bean will be credentials since we don't supply an argument to the Named annotation.
  •    
  • Line 12: For the purposes of this simple application this Web Bean scope will be for the current request.
  •    
  • Line 13: Specifies the default qualifier type for this Web Bean.  Note that you should not have to specify this if it's the only qualifier type being used.  In future implementations of Web Beans this should be fixed.

Listing 2: Login

                                   
           
                   
  1. package webbeansservlet;
  2.                
  3.  
  4.                
  5. import java.io.Serializable;
  6.                
  7. import javax.enterprise.context.SessionScoped;
  8.                
  9. import javax.enterprise.inject.Default;
  10.                
  11. import javax.inject.Inject;
  12.                
  13. import javax.inject.Named;
  14.                
  15.  
  16.                
  17. /**
  18.                
  19.  * A simple Web Bean that performs a login operation with user's
  20.                
  21.  * credentials.
  22.                
  23.  */
  24.                
  25. @Named
  26.                
  27. @SessionScoped
  28.                
  29. @Default
  30.                
  31. public class Login implements Serializable {
  32.                
  33.  
  34.                
  35.     @Inject Credentials credentials;
  36.                
  37.  
  38.                
  39.     private boolean loggedIn = false;
  40.                
  41.  
  42.                
  43.     /**
  44.                
  45.      * This is where you could potentially access a database.
  46.                
  47.      */
  48.                
  49.     public void login() {
  50.                
  51.         if ((credentials.getUsername() != null &&
  52.                
  53.             credentials.getUsername().trim().length() > 0) &&
  54.                
  55.             (credentials.getPassword() != null &&
  56.                
  57.             credentials.getPassword().trim().length() > 0)) {
  58.                
  59.             loggedIn = true;
  60.                
  61.         }
  62.                
  63.     }
  64.                
  65.  
  66.                
  67.     public boolean isLoggedIn() {
  68.                
  69.         return loggedIn;
  70.                
  71.     }
  72.                
  73.  
  74.                
  75. }
  76.            
           
       
  • Line 13: The name of this Web Bean will be login
  •    
  • Line 14: This Web Bean will exist for the session
  •    
  • Line 15: Specifies the default qualifier type for this Web Bean.
  •    
  • Line 18: We're injecting an instance of Credentials so we can check the validity of the user name and password entries

Listing 3: Login Servlet

                                   
           
                   
  1. package webbeansservlet;
  2.                
  3. import java.io.IOException;
  4.                
  5. import java.io.PrintWriter;
  6.                
  7. import javax.enterprise.inject.spi.BeanManager;
  8.                
  9. import javax.inject.Inject;
  10.                
  11. import javax.servlet.ServletException;
  12.                
  13. import javax.servlet.annotation.WebServlet;
  14.                
  15. import javax.servlet.http.HttpServlet;
  16.                
  17. import javax.servlet.http.HttpServletRequest;
  18.                
  19. import javax.servlet.http.HttpServletResponse;
  20.                
  21.  
  22.                
  23. /**
  24.                
  25.  * This Servlet class demonstrates Web Beans injection.
  26.                
  27.  */
  28.                
  29. @WebServlet(name="LoginServlet", urlPatterns={"/LoginServlet"})
  30.                
  31. public class LoginServlet extends HttpServlet {
  32.                
  33.  
  34.                
  35.     // Inject Web Beans Bean Manager.
  36.                
  37.     @Inject BeanManager m;
  38.                
  39.  
  40.                
  41.     // Inject The Credentials Web Bean.
  42.                
  43.     @Inject Credentials credentials;
  44.                
  45.  
  46.                
  47.     // Inject the Login Web Bean.
  48.                
  49.     @Inject Login login;
  50.                
  51.  
  52.                
  53.     /**
  54.                
  55.      * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
  56.                
  57.      * @param request servlet request
  58.                
  59.      * @param response servlet response
  60.                
  61.      * @throws ServletException if a servlet-specific error occurs
  62.                
  63.      * @throws IOException if an I/O error occurs
  64.                
  65.      */
  66.                
  67.     protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  68.                
  69.         throws ServletException, IOException {
  70.                
  71.         response.setContentType("text/html;charset=UTF-8");
  72.                
  73.         PrintWriter out = response.getWriter();
  74.                
  75.         credentials.setUsername(request.getParameter("username"));
  76.                
  77.         credentials.setPassword(request.getParameter("password"));
  78.                
  79.         login.login();
  80.                
  81.         try {
  82.                
  83.             if (login.isLoggedIn()) {
  84.                
  85.                 out.println("Successfully Logged In As: " + credentials.getUsername());
  86.                
  87.             } else {
  88.                
  89.                 out.println("Login Failed: Check username and/or password.");
  90.                
  91.             }
  92.                
  93.         } finally {
  94.                
  95.             out.close();
  96.                
  97.         }
  98.                
  99.     }
  100.                
  101.    .......
  102.                
  103. }
  104.            
           
       
  • Line 15: New for Servlet 3.0 - eliminates servlet entry in web.xml! Not relevant to this example, but worth mentioning.
  •    
  • Line 19: The Web Beans Bean Manager can also be injected.  The Bean Manager api provides some useful methods for interrogating portions of a Web Beans application.
  •    
  • Line 22: The Credentials Web Bean is injected making it available to the servlet.
  •    
  • Line 38: Now we can access the Credentials Web Bean.
  •    
  • Line 40: We can also use the injected Login Web Bean instance.

This is just one example of Web Bean injection into a servlet.  There are more areas in the JavaEE6 platform that can be used as Web Bean injection points - topics that will certainly be covered in future posts.  The sample for this blog can be found under the glassfish-samples project.  You can check out the code following these instructions.  Once the workspace is checked out, you can find this sample under glassfish-samples/ws/javaee6/webbeans/webbeans-servlet.  You can find documentation for the sample under glassfish-samples/ws/javaee6/webbeans/webbeans-servlet/docs.  As with all the Web Beans samples now, you should run with GlassFish V3 - any build after September 2 2009.

Version 1.0.0.PREVIEW3 of Web Beans (the implementation for JSR 299 Contexts and Dependency Injection For Java EE) now uses the annotations from JSR 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.                
  3. <html xmlns="http://www.w3.org/1999/xhtml"
  4.                
  5.     xmlns:ui="http://java.sun.com/jsf/facelets"
  6.                
  7.     xmlns:h="http://java.sun.com/jsf/html"
  8.                
  9.     xmlns:f="http://java.sun.com/jsf/core">
  10.                
  11.     <h:head>
  12.                
  13.         <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  14.                
  15.         <title>JSF 2.0 Web Beans Example</title>
  16.                
  17.     </h:head>
  18.                
  19.     <h:body>
  20.                
  21.        <h:form id="NumberGuessMain">
  22.                
  23.           <h:panelGrid styleClass="title-panel">
  24.                
  25.              <h:outputText value="Guess Number" styleClass="title-panel-text"/>
  26.                
  27.              <h:outputText value="Powered By JavaServer Faces 2.0 and Web Beans" styleClass="title-panel-subtext"/>
  28.                
  29.           </h:panelGrid>
  30.                
  31.           <div style="color: black; font-size: 24px;">
  32.                
  33.              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.
  34.                
  35.           </div>
  36.                
  37.           <h:panelGrid border="1" columns="5" style="font-size: 18px;">
  38.                
  39.              Number:
  40.                
  41.              <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"/>
  42.                
  43.              <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/>
  44.                
  45.              <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" />
  46.                
  47.              <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}" style="color: red"/>
  48.                
  49.              <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}" style="color: red"/>
  50.                
  51.           </h:panelGrid>
  52.                
  53.           <div style="color: red; font-size: 14px;">
  54.                
  55.              <h:messages id="messages" globalOnly="false"/>
  56.                
  57.           </div>
  58.                
  59.           <h:outputStylesheet name="stylesheet.css" />
  60.                
  61.        </h:form>
  62.                
  63.     </h:body>
  64.                
  65. </html>
  66.            
           


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.  
  4.                
  5. import static java.lang.annotation.ElementType.FIELD;
  6.                
  7. import static java.lang.annotation.ElementType.METHOD;
  8.                
  9. import static java.lang.annotation.ElementType.PARAMETER;
  10.                
  11. import static java.lang.annotation.ElementType.TYPE;
  12.                
  13. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  14.                
  15. import java.lang.annotation.Documented;
  16.                
  17. import java.lang.annotation.Retention;
  18.                
  19. import javax.inject.Qualifier;
  20.                
  21.  
  22.                
  23. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  24.                
  25. @Retention(RUNTIME)
  26.                
  27. @Documented
  28.                
  29. @Qualifier
  30.                
  31. public @interface Random {
  32.                
  33. }
  34.            
           


The JSR 330 @Qualifier annotation 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.  
  4.                
  5. import static java.lang.annotation.ElementType.FIELD;
  6.                
  7. import static java.lang.annotation.ElementType.METHOD;
  8.                
  9. import static java.lang.annotation.ElementType.PARAMETER;
  10.                
  11. import static java.lang.annotation.ElementType.TYPE;
  12.                
  13. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  14.                
  15. import java.lang.annotation.Documented;
  16.                
  17. import java.lang.annotation.Retention;
  18.                
  19. import java.lang.annotation.Target;
  20.                
  21. import javax.inject.Qualifier;
  22.                
  23.  
  24.                
  25. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  26.                
  27. @Retention(RUNTIME)
  28.                
  29. @Documented
  30.                
  31. @Qualifier
  32.                
  33. public @interface MaxNumber {
  34.                
  35. }
  36.            
           


Likewise, the @Qualifier annotation is used to make MaxNumber 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.  
  4.                
  5. import java.io.Serializable;
  6.                
  7. import javax.enterprise.context.ApplicationScoped;
  8.                
  9. import javax.enterprise.inject.Produces;
  10.                
  11.  
  12.                
  13. @ApplicationScoped
  14.                
  15. public class Generator implements Serializable {
  16.                
  17.     private static final long serialVersionUID = -7213673465118041882L;
  18.                
  19.    private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
  20.                
  21.     private int maxNumber = 100;
  22.                
  23.     java.util.Random getRandom() {
  24.                
  25.         return random;
  26.                
  27.     }
  28.                
  29.     @Produces @Random int next() {
  30.                
  31.         return getRandom().nextInt(maxNumber);
  32.                
  33.     }
  34.                
  35.     @Produces @MaxNumber int getMaxNumber() {
  36.                
  37.         return maxNumber;
  38.                
  39.     }
  40.                
  41. }
  42.            
           

 

       
  • Line 7: An instance of this class exists for the lifecycle of the application
  •    
  • Line 15: next() is a Web Beans producer method.  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 Beans producer method.  It will get called by the Web Beans Manager to obtain an instance of maxNumber - 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.  
  4.                
  5. import java.io.Serializable;
  6.                
  7. import javax.annotation.PostConstruct;
  8.                
  9. import javax.enterprise.context.SessionScoped;
  10.                
  11. import javax.enterprise.inject.Instance;
  12.                
  13. import javax.inject.Inject;
  14.                
  15. import javax.inject.Named;
  16.                
  17. import javax.faces.application.FacesMessage;
  18.                
  19. import javax.faces.component.UIComponent;
  20.                
  21. import javax.faces.component.UIInput;
  22.                
  23. import javax.faces.context.FacesContext;
  24.                
  25.  
  26.                
  27. @Named
  28.                
  29. @SessionScoped
  30.                
  31. public class Game implements Serializable {
  32.                
  33.     private static final long serialVersionUID = 1L;
  34.                
  35.  
  36.                
  37.     private int number;
  38.                
  39.     private int guess;
  40.                
  41.     private int smallest;
  42.                
  43.   
  44.                
  45.     @MaxNumber @Inject
  46.                
  47.     private int maxNumber;
  48.                
  49.   
  50.                
  51.     private int biggest;
  52.                
  53.     private int remainingGuesses;
  54.                
  55.   
  56.                
  57.     @Random @Inject Instance<Integer> randomNumber;
  58.                
  59.   
  60.                
  61.     public Game() {
  62.                
  63.     }
  64.                
  65.  
  66.                
  67.     public int getNumber() {
  68.                
  69.          return number;
  70.                
  71.     }
  72.                
  73.   
  74.                
  75.     public int getGuess() {
  76.                
  77.          return guess;
  78.                
  79.     }
  80.                
  81.   
  82.                
  83.     public void setGuess(int guess) {
  84.                
  85.          this.guess = guess;
  86.                
  87.     }
  88.                
  89.   
  90.                
  91.     public int getSmallest() {
  92.                
  93.          return smallest;
  94.                
  95.     }
  96.                
  97.   
  98.                
  99.     public int getBiggest() {
  100.                
  101.         return biggest;
  102.                
  103.     }
  104.                
  105.   
  106.                
  107.     public int getRemainingGuesses() {
  108.                
  109.         return remainingGuesses;
  110.                
  111.     }
  112.                
  113.   
  114.                
  115.     public String check() throws InterruptedException {
  116.                
  117.         if (guess>number) {
  118.                
  119.             biggest = guess - 1;
  120.                
  121.         }
  122.                
  123.         if (guess<number) {
  124.                
  125.             smallest = guess + 1;
  126.                
  127.        }
  128.                
  129.        if (guess == number) {
  130.                
  131.            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
  132.                
  133.        }
  134.                
  135.        remainingGuesses--;
  136.                
  137.        return null;
  138.                
  139.     }
  140.                
  141.   
  142.                
  143.     @PostConstruct
  144.                
  145.     public void reset() {
  146.                
  147.         this.smallest = 0;
  148.                
  149.         this.guess = 0;
  150.                
  151.         this.remainingGuesses = 10;
  152.                
  153.         this.biggest = maxNumber;
  154.                
  155.         this.number = randomNumber.get();
  156.                
  157.     }
  158.                
  159.   
  160.                
  161.     public void validateNumberRange(FacesContext context,  UIComponent toValidate, Object value) {
  162.                
  163.         if (remainingGuesses <= 0) {
  164.                
  165.             FacesMessage message = new FacesMessage("No guesses left!");
  166.                
  167.             context.addMessage(toValidate.getClientId(context), message);
  168.                
  169.             ((UIInput)toValidate).setValid(false);
  170.                
  171.             return;
  172.                
  173.         }
  174.                
  175.         int input = (Integer) value;
  176.                
  177.         if (input < smallest || input > biggest) {
  178.                
  179.             ((UIInput)toValidate).setValid(false);
  180.                
  181.             FacesMessage message = new FacesMessage("Invalid guess");
  182.                
  183.             context.addMessage(toValidate.getClientId(context), message);
  184.                
  185.         }
  186.                
  187.     }
  188.                
  189. }
  190.            
           


I've color coded the areas of interest in this class.  The blue 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 Named annotation 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 the producer method in the Generator 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.

Andy Schwartz (Oracle Corp/JSF 2.0 EG member) and I will be speaking at Ajax World next week on JSF and Ajax Past, Present and Future.

The session will explore the variety of JSF Ajax frameworks available today.  Then you will get a preview of the Ajax work that is being standardized in the JSF 2.0 specification.

The JavaScript public API is the beginnings of the client side portion of the JavaServer Faces / Ajax standard.  The JavaServer Faces 2.0 Expert Group includes members representing other JavaServer Faces / Ajax frameworks such as RichFaces, ADF Faces (Trinidad) and ICEfaces.

       

We're definitely exploring new territory here, as this is the first time that a public JavaScript API has been introduced with JavaServer Faces to  the JCP.  It may be the first time a public JavaScript API has been introduced to the JCP, period.

Often when you are "heads down" developing a technology, you forget about who might be using that technology.  And in the course of giving a presentation about the technology, you may hear a question or two like "yeah... great....  but who is using this out there in the real world?"..  Well.. we've compiled an initial list of companies/sites out there that use JSF....  That list can be found here.  Enjoy!

Filter Blog

By date: