Tech Tip Blogs

by Ed Burns

Michael Jouravlev, in his influential August 2004 article Redirect After Post, described a problem that many web applications present. He described the problem as follows:

All interactive programs provide two basic functions: obtaining user input and displaying the results. Web applications implement this behavior using two HTTP methods: POST and GET respectively. This simple protocol gets broken when an application returns a web page in response to a POST request. Peculiarities of the POST method combined with idiosyncrasies of different browsers often lead to an unpleasant user experience and may produce an incorrect state of the server application.

To address the problem, Jouravlev described a technique that he called POST-REDIRECT-GET, or the PRG pattern for short. The rules of the pattern are as follows:

  • Never show pages in response to POST
  • Always load pages using GET
  • Navigate from POST to GET using REDIRECT

Previous versions of JavaServer Faces (JSF) technology violated the first of these rules by using POST for every page navigation. In navigating from one page to another in a JSF-enabled application, the JSF framework forwarded a POST request through the Servlet API's RequestDispatcher.forward( ) method. This caused a new Faces page to be rendered and returned to the browser in response to the postback request.

Indeed, most popular Java Servlet-based web frameworks, including Struts, use this approach for navigation. HTTP purists rightly point out that this approach violates the first rule in the PRG pattern. Not only did JSF violate the first rule, but until JavaServer Faces 2.0, it was very difficult to do it any other way. Thanks to a JSF contribution from the Seam team at JBoss, it is now much easier to do PRG with JSF.

This Tech Tip shows how to implement the PRG pattern in JSF 2.0. The content of the tip is an adaptation of a section on PRG and JSF 2.0 in my upcoming book, with Neil Griffin, JavaServer Faces 2.0: The Complete Reference.

A Non-PRG Example

Let's start by examining a simple JSF 2.0 application that handles user registration. In this first example, the application does not implement the PRG pattern. The initial page for the application is coded in file register.xhtml, as follows:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Form</h4>
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:inputText label="First Name"
                          id="fname" value="#{userBean.firstName}"
                          required="true"/>
             <h:message for="fname" />
           </td>
         </tr>
         <tr>
           <td>Last Name:</td>
           <td>
             <h:inputText label="Last Name"
                          id="lname" value="#{userBean.lastName}"
                          required="true"/>
             <h:message for="lname" />
           </td>
           </tr>
   ... additional table rows not shown.
       </table>
       <p><h:commandButton value="Register" action="confirm" /></p>
     </h:form>
   </h:body>
   </html>

The page presents text fields for the user to enter a first name and a last name. It also displays a Register button. When the user presses the Register button, the JSF navigation rule system looks for a page within the application whose extension is the same as the current page and whose filename is confirm. If confirm.xhtml exists, JSF uses the navigation components in that file to navigate to the next page. Here is the confirm.xhtml file:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Confirmation</h4>
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:outputText value="First Name" value="#{userBean.firstName}"
           </td>
         </tr>
         <tr>
           <td>Last Name:</td>
           <td>
             <h:outputText label="Last Name" value="#{userBean.lastName}"
           </td>
           </tr>
   ... additional table rows not shown.
       </table>
       <p><h:commandButton value="Edit" action="register" /></p>
       <p><h:commandButton value="Confirm" action="#{userBean.addConfirmedUser}" /></p>
     </h:form>
   </h:body>
   </html>

The confirm.xhtml file includes markup for an Edit button and a Confirm button. If the user clicks the Edit button, he or she is taken back to the register.xhtml page. If the user clicks the Confirm button, an action is invoked. The Confirm button specifies an action method, addConfirmedUser( ), that determines the outcome programmatically in the logic of the method. Here is the UserBean.java file, which contains the addConfirmedUser( ) method:

   package com.jsfcompref.model;

   ...  imports

   @ManagedBean
   @SessionScoped
   public class UserBean {

   ...  properties and methods

      public String addConfirmedUser() {
        boolean added = true; // actual application may fail to add user
        FacesMessage doneMessage = null;
        String outcome = null;
        if (added) {
            doneMessage = new FacesMessage("Successfully added new user");
            outcome = "done";
        } else {
            doneMessage = new FacesMessage("Failed to add new user");
            outcome = "register";
        }
          FacesContext.getCurrentInstance().addMessage(null, doneMessage);
          return outcome;
   }

For this simple case, addConfirmedUser( ) causes a message stating Successfully added new user to be displayed on the page and returns "done" as the outcome. When the addConfirmedUser( ) method returns "done" as the outcome, it takes the user to the done.xhtml page. This is an example of implicit navigation, a new feature in JSF 2.0. If no matching navigation case is found after checking all available rules, the navigation handler checks to see whether the action outcome corresponds to a view id. If a view matching the action outcome is found, an implicit navigation to the matching view occurs. Here the outcome is "done" and the matching view is done.xhtml, so the user is taken to the done.xhtml page. Implicit navigation saves you the effort of adding navigation rules in the faces-config.xml file.

Here is the done.xhtml page:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Confirmation</h4>
       <h:messages />
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:outputText value="First Name" value="#{userBean.firstName}"
           </td>
         </tr>
       </table>
     </h:form>
   </h:body>
   </html>

POST-REDIRECT-GET Using View Parameters

View Parameters is a simple, declarative way to map incoming request parameter values to special components within the view. These mappings are specified using the new <f:viewParam> component, within the new <f:metadata> section of the view. Consider the following example:

   <f:metadata>
      <f:viewParam name="foo" value="#{bean.foo}"/>
   </f:metadata>

This example specifies that the value of the request parameter with the name "foo" is automatically assigned to the property at #{bean.foo}. So for a GET request as follows:

   page1.jspx?foo=bar

The value of the #{bean.foo} property will be set to bar when JSF starts processing the request.

View Parameters is similar in spirit to the page parameters feature found in JBoss Seam, but the JSF 2.0 incarnation of the feature is tightly integrated with the core JSF specification, making the feature easier to use and more powerful. Let’s look at another simple example.

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <h:head>
     <title>A Simple JavaServer Faces 2.0 View</title>
   </h:head>
   <h:body>
     <h:form>

         <p>First Name:< <h:inputText id="fname"
              value="#{userBean.firstName}" /> </p>
       <p><h:commandButton value="submit"
    action="page02?faces-redirect=true&amp;includeViewParams=true" /></p>

     </h:form>
   </h:body>
   </html>

The <h:commandButton> element has action="page02?faces-redirect=true". In the Internet standard that defines URLs, the presence of a ? character indicates the remainder of the URL will be an & or &amp;-separated list of name=value pairs that should be submitted to the server along with the request for the URL. This is known as a query string. JSF borrows the meaning of the ? character here, and the meaning is exactly the same as in the Internet standard for URLs. There are two special query strings parameters recognized by JSF when it parses the outcome on the server side. The faces-redirectquery string tells the navigation system that this implicit navigation case must be treated as if it were a real <navigation-case> element that includes a <redirect/> element. The other special query string parameter, includeViewParams, tells the navigation handler to include the view parameters when performing the navigation. But what view parameters should be included? The view parameters to be included when performing the navigation are declared on the to-view-id page. In this case, we are using implicit navigation, so the implicit to-view-id is page02.xhtml, shown below.

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <f:metadata>
        <f:viewParam name="fname> value="#userBean.firstName}"/>
       </f:metadata> 
   <h:head>
     <title>A Simple JavaServer Faces 2.0 View</title>
   </h:head>
   <h:body>
     <h:form>
         <p> Hello #{userBean.firstName}.</p>
     </h:form>
   </h:body>
   </html>

When the navigation handler encounters the matching navigation-case (implicit or explicit) that declares that view parameters should be included, it looks at the view parameters of the from-view-id and to-view-id pages and performs a match-and-copy algorithm to convey the view parameters to the new page. In this case, the navigation-case also requested a redirect.

Now let’s look at the registration example, this time implemented to do PRG with view parameters. The register.xhtml page looks like this:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <f:metadata>
       <f:viewParam name="fname" value="#{userBean.firstName}" />
       <f:viewParam name="lname" value="#{userBean.lastName}" />
       <f:viewParam name="sex" value="#{userBean.sex}" />
       <f:viewParam name="dob" value="#{userBean.dob}">
          <f:convertDateTime pattern="MM-dd-yy" />
       </f:viewParam>
       <f:viewParam name="mail" value="#{userBean.email}" />
       <f:viewParam name="sLevel" value="#{userBean.serviceLevel}" />
       </f:metadata>
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Form</h4>
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:inputText label="First Name"
                          id="fname" value="#{userBean.firstName}"
                          required="true"/>
             <h:message for="fname" />
           </td>
         </tr>
       ... remaining table rows omitted, they are the same as the original
       </table>

       <!-- The query parameters on the action attribute cause JSF to do the
               POST REDIRECT GET pattern -->
       <p><h:commandButton value="Register"
          action="confirm?faces-redirect=true&amp;includeViewParams=true" /></p>
     </h:form>
   </h:body>
   </html>

In the previous View Parameters example, we stated that elements only appear on the to-view-id page. That is still true in this example, even though this is the first page the user sees. This particular application allows the user to go back and forth between the register.xhtml page and the confirm.xhtml page. Therefore, when the user is on the confirm.xhtml page, the to-view-id is the register.xhtml page and vice versa. Thus, <f:viewParams> is on both pages. You will need an <f:viewParam> for every input component on the from page that you wish to carry forward to the to page. Also note the <f:convertDateTime> within the <f:viewParam> for the dob property. This is necessary because, when the navigation is performed, the converter needs to be invoked to carry the value forward. If there is an explicit converter defined on the input field, then there must also be one on the corresponding <f:viewParam>. Finally, you can see the now familiar extra query parameters on the implicit navigation: confirm?faces-redirect=true&amp;includeViewParams=true.

Let’s examine the changes to the UserBean.java file.

   package com.jsfcompref.model;

   ... omits imports

   @ManagedBean
   @RequestScoped
   public class UserBean {

   ...  additional properties omitted

      public String addConfirmedUser() {
        boolean added = true; // actual application may fail to add user
        FacesMessage doneMessage = null;
        String outcome = null;
        if (added) {
            doneMessage = new FacesMessage("Successfully added new user");
            outcome = "done?faces-redirect=true&amp;includeViewParams=true";
        } else {
            doneMessage = new FacesMessage("Failed to add new user");
            outcome = "register?faces-redirect=true&amp;includeViewParams=true";
        }
          FacesContext.getCurrentInstance().addMessage(null, doneMessage);
          return outcome;
   }

The only changes to this code are to make the bean be request-scoped and to add the query parameters to the implicit navigation string. In this case, the includeViewParams=true parameter is added, causing whatever view parameters declared on the to-view-id page to be included in the navigation.

The confirm.xhtml page follows:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <f:metadata>
          <f:viewParam name="fname" value="#{userBean.firstName}" />
          <f:viewParam name="lname" value="#{userBean.lastName}" />
          <f:viewParam name="sex" value="#{userBean.sex}" />
          <f:viewParam name="dob" value="#{userBean.dob}">
             <f:convertDateTime pattern="MM-dd-yy" />
          </f:viewParam>
          <f:viewParam name="mail" value="#{userBean.email}" />
          <f:viewParam name="sLevel" value="#{userBean.serviceLevel}" />
       </f:metadata>
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Confirmation</h4>
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:outputText value="First Name" value="#{userBean.firstName}"
           </td>
         </tr>

   ... additional rows omitted, they are the same as the original.
       </table>

       <p><h:commandButton value="Edit"
     action="register?faces-redirect=true&amp;includeViewParams=true" /></p>
      </h:form>

      <h:form>
	     <h:inputHidden value="#{userBean.firstName}" />
	     <h:inputHidden value="#{userBean.lastName}"/>
	     <h:inputHidden value="#{userBean.sex}" />
	     <h:inputHidden value="#{userBean.dob}">
	        <f:convertDateTime pattern="MM-dd-yy" />
	     </h:inputHidden>
	     <h:inputHidden value="#{userBean.email}" />
	     <h:inputHidden value="#{userBean.serviceLevel}" />

	     <p><h:commandButton value="Confirm"
          action="#{userBean.addConfirmedUser}" /></p>
            </h:form>

   </h:body>
   </html>

As in the register.xhtml page, we need the <f:metadata> section at the top of the page and the additional query parameters on the action string. What is new here are the additional <h:form> element and <h:inputHidden> elements, and the fact that the Confirm button has been moved into this new form. This is necessary because we need to carry forward to the next page as regular form submit parameters the values passed to this page as view parameters. But there are no regular input fields as there are on the register.xhtml page. Therefore, we use hidden fields to carry the values forward. Note also the continued necessity for the <f:convertDateTime> on the dob field.

Finally, here is the done.xhtml page:

   <!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:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core">
   <f:metadata>
             <f:viewParam name="fname" value="#{userBean.firstName}" />
             <f:viewParam name="lname" value="#{userBean.lastName}" />
             <f:viewParam name="sex" value="#{userBean.sex}" />
             <f:viewParam name="dob" value="#{userBean.dob}">
                <f:convertDateTime pattern="MM-dd-yy" />
             </f:viewParam>
             <f:viewParam name="email" value="#{userBean.email}" />
             <f:viewParam name="sLevel" value="#{userBean.serviceLevel}" />
       </f:metadata>
   <h:head>
     <title>A Simple JavaServer Faces Registration Application</title>
   </h:head>
   <h:body>
     <h:form>
       <h2>JSF Registration App</h2>
       <h4>Registration Confirmation</h4>
       <h:messages />
       <table>
         <tr>
           <td>First Name:</td>
           <td>
             <h:outputText value="First Name" value="#{userBean.firstName}"
           </td>
         </tr>
   ... additional rows omitted
       </table>
     </h:form>
   </h:body>
   </html>

The only difference between this done.xhtml and the original one is the now familiar <f:metadata> section.

Running the Sample Code

A sample application that implements PRG accompanies this tip. These instructions use the Maven 2 software project management tool to build the sample application and then deploy it in the GlassFish v3 Preview application server.

  1. If you haven't already done so, download a recent promoted build or nightly build of the GlassFish v3 Preview application server.
  2. If you haven't already done so, download Maven 2.
  3. Download the sample application package, PostRedirectGet.zip
  4. Extract the contents of the sample application package. You should see the folders prgViewParams, which contains the code for the PRG application that uses View Parameters.
  5. Create the WAR file for the PRG application by changing to the prgViewParams directory and entering the following Maven command:
       mvn install
    
    You should see the file prgViewParams.war in a newly-created target subdirectory under the prgViewParams directory.
  6. Start the GlassFish v3 Preview application server by entering the following command:
       <GFv3_inst>/bin/asadmin start-domain
    
    where <GFv3_inst> is where you installed the GlassFish v3 Preview application server.
  7. Deploy the sample application. One way to do that is to copy the prgViewParams.war file to the <GFv3inst>/domains/domain1/autodeploy directory.
  8. Execute the application by opening a browser and accessing the URL http://localhost:8080/prgViewParams. You should see the form shown in Figure 1.
    Registration Page
    Figure 1. Registration Page
     
  9. Enter information as appropriate into the form and click the Register button. You should see a page similar the one shown in Figure 2.
    Registering Through the Registration Page
    Figure 2. Registering Through the Registration Page
     
  10. Click the Confirm button. You should see a page similar the one shown in Figure 3.
    Confirmation Page
    Figure 3. Confirmation Page
     

Further Reading

For more information, see the following resources:

About the Author

Ed Burns is a senior staff engineer at Sun Microsystems. Ed has worked on a wide variety of client and server-side web technologies since 1994, including NCSA Mosaic, Mozilla, the Sun Java Plugin, Jakarta Tomcat and, most recently JavaServer Faces. Ed is currently the co-spec lead for JavaServer Faces. He is the coauthor of JavaServer Faces: The Complete Reference and the author of Secrets of the Rockstar Programmers. He is also the coauthor of the upcoming book JavaServer Faces 2.0: The Complete Reference. Read Ed Burns's blog.

By Johan Karlsson

You have just developed your new cool MIDlet, the one that is going to rule the world. It runs like a well oiled machine on the emulator. But when you download and install it on your target device, the MIDlet seems to take ages to start up. Finally, you see the splash screen. Oh no! The MIDlet crashes and you get an error pop-up saying "Application Error," and the MIDlet shuts down. What happened? This is not the way you pictured it. Is there something that shows what really happened behind the scenes?

Have you been in a situation like this? Have you ever wanted to log from your MIDlet? Read on, and I will teach how to add powerful logging to your MIDlets.

You may have considered doing your own logging facility. But why not use an existing solution: The Microlog open-source logging library. It is based on the well known Log4j API or logging library, but has been created from the ground up with Java ME limitations in mind.

Read the full article.

by Roger Kitain

This Tech Tip covers the intersection of three powerful technologies that are part of the Java EE 6 platform: JSR 299: Contexts and Dependency Injection, JSR 330: Dependency Injection For Java, and JSR 314: JavaServer Faces 2.0.

JSR 299: Contexts and Dependency Injection (CDI) defines a set of services for the Java EE environment that makes applications much easier to develop. It provides an architecture that allows Java EE components such as servlets, enterprise beans, and JavaBeans to exist within the lifecycle of an application with well-defined scopes. In addition, CDI services allow Java EE components, including EJB session beans and JavaServer Faces (JSF) managed beans to be injected and to interact in a loosely coupled way by firing and observing events. Perhaps most significantly, CDI unifies and simplifies the EJB and JSF programming models. It allows enterprise beans to act as managed beans in a JSF application. Through its services, CDI brings transactional support to the web tier. This can make it a lot easier to access transactional resources in web applications. For example, CDI services makes it a lot easier to build a Java EE web application that accesses a database with persistence provided by the Java Persistence API.

JSR 330: Dependency Injection For Java introduces a standard set of annotations that can be used for dependency injection. Dependency injection is a popular technique in developing enterprise Java applications. Unfortunately, there has not been a standard approach for annotation-based dependency injection. Dependency Injection For Java changes that by providing a standardized and extensible API for dependency injection. The API comprises a set of annotations for use on injectable classes.

JavaServer Faces technology provides a server-side component framework that is designed to simplify the development of user interfaces (UIs) for Java EE applications. The latest release of the technology, JSR 314: JavaServer Faces 2.0, makes UI development for Java EE applications even easier through support for annotations and the addition of new features such as Facelets and composite components.

This Tech Tip illustrates the use of CDI and Dependency Injection for Java in a JSF 2.0 application.

An Example Application

Let's look at some key parts of a JSF 2.0 application that uses CDI and Dependency Injection for Java. You can find the source code for the application in the sample application package that accompanies this tip. See Running the Sample Code for instructions on how to install and run the application.

Figure 1 shows the UI for the application. The UI prompts a user to guess a number that the system has randomly selected. The prompt is as follows: I am thinking of a number between min to max, where min and max represent the minimum and maximum values allowable as a guess, respectively. The UI displays a text field for the user to enter the number, a Guess button to submit the number, and a Reset button to restart the game. If the user enters a number that is lower than the correct number, the UI responds with the message Higher! It also changes the min value in the prompt message to one more than the guessed number. If the user's entry is too high, the UI responds with the message Lower! and changes the max value in the prompt message to one less than the guessed number. The system sets a limit for the number of guesses, and with each incorrect guess, the UI displays a message that tells the user how many guesses remain. The game ends when the user correctly guesses the number or when the user reaches the limit of guesses.

The UI for the Guess Number JSF 2.0 Application
Figure 1. The UI for the Guess Number JSF 2.0 Application
 

Here is the code for the application's UI:

   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 Weld 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 Weld" 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>

The code for the UI should look familiar to you if you develop applications with JSF. In fact, everything on the page is standard JSF 2.0 view markup. Notice the highlighted expression language (EL) expressions. These expressions refer to a contextual bean instance named game. A contextual bean instance is also known as a managed bean or simply a bean.

Actually, the concept of managed beans goes beyond CDI. Managed beans, which is introduced in Java EE 6, is designed to unify all of the various types of beans in Java EE, including JSF managed beans, enterprise beans, and CDI beans. A managed bean is a Java class that is treated as a managed component by the Java EE container. Optionally, you can give it a name in the same namespace as that used by EJB components. A managed bean can also rely on a small number of container-provided services, mostly related to lifecycle management and resource injection. Other Java EE technologies such as JSF, EJB, and CDI build on this basic definition of a managed bean by adding services. So, for example, a JSF managed bean adds lifecycle scopes, an EJB session bean adds services such as support for transactions, and a CDI bean adds services such as dependency injection.

Returning to the highlighted EL expressions in the code for the UI, the EL expressions bind to various bean properties and methods, as follows:

  • The EL expressions in line 17, 24, and 25 bind to bean properties.
  • The EL expressions in line 21 bind to bean properties and to a bean validation method.
  • The EL expressions in lines 22 and 23 bind to bean action methods.

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

The Anatomy of a Simple Contextual Bean

As mentioned previously, beans can be bound to a lifecycle context, can be injected, and can interact with other beans in a loosely coupled way by firing and observing events. In addition, a bean may be called directly from Java code, or as you've seen in the UI for the example application, it may be invoked in an EL expression. This enables a JSF page to directly access a bean.

Let's examine the game bean used in the application. Here is its source code:

   1. package weldguess;
   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. }

Notice especially the following highlighted annotations in the bean.

  • The @Named annotation in Line 14. This is a Dependency Injection For Java annotation that is used to associate a name with the bean. Because there is no name specified as an argument to the annotation, the name of the bean will be the name of the JavaBean with its first letter made lowercase, that is, game. The annotation enables the application to reference the bean by that name using the EL expressions in the view.
  • The @SessionScoped annotation in Line 15. This is a CDI annotation that specifies a scope for the bean. All beans have a scope that determines the lifecycle of their instances and which instances of the beans are visible to instances of other beans. The @SessionScoped annotation declares that this bean is a session scoped bean, meaning that its lifecycle is the lifecycle of the session.
  • The @Inject annotation in Line 23 and line 29. This is a CDI annotation that is used to identify a dependency injection point, that is, a point at which a dependency on a Java class or interface can be injected. In line 23, the annotation identifies a dependency injection point for the maxNumber field. Line 23 also specifies a qualifier annotation, @MaxNumber, that identifies the implementation to inject. Qualifiers are strongly-typed keys that help distinguish different uses of objects of the same type. Later in this tip, you'll learn more about qualifiers. Defining @MaxNumber as a qualifier annotation enables the injection of the limit value for the maximum number of guesses. In line 29, the @Inject annotation identifies a dependency injection point for the randomNumber field. Line 29 also specifies a qualifier annotation, @Random, that identifies the implementation to inject. Defining @Random as a qualifier annotation enables the injection of a random number that the user needs to guess.
  • The @PostConstruct annotation in line 72. This annotation is defined in JSR 250, Common Annotations for the Java Platform. The annotation is used to identify a method that will perform initialization after a component is created. Here, the reset()method is marked with a @PostConstruct annotation. After the bean is created, the reset()method initializes a number of variables such as remainingGuesses, which tracks the remaining number of guesses; biggest, which holds the value for the maximum number of guesses; and number, which holds the randomly generated number that the user needs to guess.

Supporting Annotations

You've seen that the bean uses the @Random and @MaxNumber annotations as qualifier annotations. Now let's see how those annotations are defined.

Here is the definition of the @Random annotation:

   1. package weldguess;
   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 @Qualifier annotation in line 15 is a Dependency Injection For Java annotation that is used to identify an annotation as a qualifier annotation. A qualifier identifies a specific implementation of a Java class or interface to be injected. In order to use a qualifier annotation, you first need to define its type as a qualifier. You use the @Qualifier annotation to do that. Defining @Random as a qualifier annotation enables a random number to be injected into the application.

The @Qualifier annotation is also used in the definition of the @MaxNumber annotation, as shown below:

   1. package weldguess;
   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. }

The @Qualifier annotation in line 16 defines @MaxNumber as a qualifier annotation. Defining @MaxNumber as a qualifier annotation enables the injection of the maximum number of allowed guesses into the application.

The Utility Bean

There is one more important component of the application, a utility bean named Generator. Here is what the Generator bean looks like:

   1. package weldguess;
   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. }

Here are what the highlighted annotations in the bean do:

  • The @ApplicationScoped annotation in line 7 is a CDI annotation that specifies a scope for the class. The annotation declares that an instance of the Generator class exists for the lifecycle of the application.
  • The @Produces annotation in line 15 and line 18 is a CDI annotation that is used to identify a method as a producer method. A producer method is called whenever another bean in the application needs an injected object. In line 15, the producer method is next(). The method is called by the Beans Manager when the Game bean needs to obtain an instance of the next random number. In line 18, the producer method is getMaxNumber(). The method is called by the Beans Manager when the Game bean needs to obtain the maximum number of allowed guesses — in this case, 100.

How the Components Work Together

Let's return to the UI discussed earlier. When a user responds to the prompt and clicks the Guess button, CDI technology goes into action. The Java EE container automatically instantiates a contextual instance of the Game bean and the Generator bean. After the Game bean is created, its reset() method is called to initialize a number of variables such as biggest, which holds the value for the maximum number of guesses, and number, which holds the randomly generated number that the user needs to guess.

The Game bean gets the maximum number of guesses from its maxNumber field. Recall that a dependency injection point with the qualifier annotation, @MaxNumber, is specified for the maxNumber field. Recall too that a producer method, getMaxNumber(), in the Generator bean is associated with the @MaxNumber qualifier annotation. As a result, when the Game bean accesses the @MaxNumber field, it calls the getMaxNumber() method in the Generator bean. The getMaxNumber() method returns the value of the maxNumber field, that is, 100.

The Game bean takes a similar route to provide a random number for the user to guess. The bean calls the randomNumber.get() method as part of its post-construct initialization. Recall that a dependency injection point with the qualifier annotation, @Random, is specified for the randomNumber field, and a producer method, getRandom(), in the Generator bean is associated with the @Random qualifier annotation. As a result, when the Game bean calls the randomNumber.get() method, it invokes the getRandom() method in the Generator bean. The randomNumber.get() method uses the getRandom() method of the java.util.Random class to generate a random number within the range 0 to 100.

Running the Sample Code

A sample application accompanies this tip. To run the sample application, do the following:

  1. If you haven't already done so, download a recent promoted build or nightly build of the GlassFish v3 Preview application server.
  2. Download the sample application package, weld-guess.zip
  3. Extract the contents of the sample application package. You should see the WAR file for the application, weld-guess.war, as well as folders for the application source code. The source code for the UI is in the web folder. The source code for the beans and annotations are in the src folder.
  4. Start the GlassFish v3 Preview application server by entering the following command:
       <GFv3_inst>/bin/asadmin start-domain
    
    where <GFv3_inst> is where you installed the GlassFish v3 Preview application server.
  5. Deploy the sample application by copying the weld-guess.war file to the <GFv3inst>/domains/domain1/autodeploy directory.
  6. Execute the application by opening a browser and accessing the URL http://localhost:8080/weld-guess

Further Reading

For more information, see the following resources:

About the Author

Roger Kitain is the JavaServer Faces co-specification lead. He has been extensively involved with server-side web technologies and products since 1997. Roger started working on JavaServer Faces technology in 2001, as a member of the reference implementation team. He has experience with Servlet and JSP technologies. Most recently, Roger has been involved with the CDI specification and integration of CDI with the GlassFish container. Read Roger Kitain's blog.

By Vikram Goyal

Logging and monitoring your MIDlet in development is easy. Just print some lines on the console around critical events, and you know what is happening within your MIDlet. Integrated development environments (IDEs) such as the NetBeans IDE make this even easier by allowing you to do on-device debugging. But this is of no use to you when your MIDlet is actually being run on a client's phone.

How do you monitor your killer MIDlet? Can you receive notification if something critical happens? Can you get an SMS to attend to notifications? Of course, you can. Several APIs make this possible, and this tech tip will show you how to combine them into a single interface.

Simulate Logging Events

To simulate the various events in an actual MIDlet, I have created a simple MIDlet with a random-event generator. The random-event generator simulates activity within the MIDlet and does nothing for normal events. Because informational events in any MIDlet are more likely to occur than warning, error, or critical events, this random MIDlet takes a sliding-scale approach to generating these events. The scale is implemented in the following code:

    // now try and simulate an event within this application
    int rand = random.nextInt(19);

    if (rand > 8) { // no event that needs logging if random no < 9
      if (rand <= 13) { // info
        form.append(midlet.getInfo());
        midlet.doInfoLog("This is an information message.");
      } else if (rand <= 15) { // warn
        form.append(midlet.getWarn());
        midlet.doWarnLog("This is a warning!");
      } else if (rand <= 17) { // error
        form.append(midlet.getError());
        midlet.doErrorLog("Oh, no, an error occurred!");
      } else { // critical
        form.append(midlet.getCritical());
        midlet.doCriticalLog("The sky is falling!");
      }
  }

When you run the MIDlet and start the activity, it will cycle through a clock going from 1 to 15. This is a timer that shows the user that some activity is happening within the MIDlet. During each activity cycle, a random number is generated. As shown in the previous code, if the random number is within the prescribed ranges, it triggers the corresponding logging event. The simple events, and the ones most likely to occur, are the informational messages. The most dire events are the ones that are marked as critical, and they occur only if the random number is exactly equal to 18.

What to Log Where

I have made the assumption that informational messages are to be recorded only, perhaps, as a way for a technical team to audit if they can get their hands on the actual device if something more critical happens. Similarly, I have assumed that warning messages are to be logged to a nearby Bluetooth device, error messages to an Internet server, and critical messages to be sent by way of SMS.

Create a Logging Interface

To keep things simple, the MIDlet makes decisions on the severity of the logging messages and creates loggers based on that assumption (described in the previous section). The following code shows how these decisions are implemented:

    private void createLoggers() {
      infoLog = new RMSLogger();
      warnLog = new BluetoothLogger();
      errorLog = new InternetLogger();
      criticalLog = new SMSLogger();
  }

Each logger is an implementation of the simple Logger interface. This interface is shown in the following code:

    public interface Logger {

      public void doLog(String msg);
    }

With a single method called doLog, the interface defines a minimum contract for the implementations to follow. The actual implementations must then figure out how they will make the logging calls.

Create the Logging Implementations

Now, it is a simple method to figure out what the actual implementations will do. For example, the following code shows what the RMSLogger will do:

    package logger.impl;

    import javax.microedition.rms.RecordStore;
    import logger.Logger;

    public class RMSLogger implements Logger {

      private RecordStore rs;

      public RMSLogger() {
        try {
          rs = RecordStore.openRecordStore("Log_Store", true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      public void doLog(String msg) {
        byte[] rec = msg.getBytes();
        try {
          rs.addRecord(rec, 0, rec.length);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

As you can see, the constructor does the background work of creating or opening the record store. The doLog() method then does the heavy lifting, by writing the message to the record store.

Similarly, here is the InternetLogger code:

    package logger.impl;

    import java.io.IOException;
    import java.io.OutputStream;
    import javax.microedition.io.Connector;
    import javax.microedition.io.HttpConnection;
    import logger.Logger;

    public class InternetLogger implements Logger {

      // set your destination URL here
      private String destURL = "";

      private HttpConnection conn;

      public InternetLogger() {

        try {
          conn = (HttpConnection) Connector.open(destURL);
          conn.setRequestMethod(HttpConnection.POST);
          conn.setRequestProperty(
            "Content-Type", "application/x-www-form-urlencoded");
        } catch (Exception e) {
          e.printStackTrace();
        }

      }

      public void doLog(String msg) {
        try {
          // The destination URL must be set before doLog is called.

          if(conn == null) {
            System.err.println("DEST URL is not valid.");
            return;
          }
          conn.setRequestProperty("Content-length", "" +
            ("msg=" + msg).getBytes().length);

          OutputStream os = conn.openOutputStream();
          os.write(("msg=" + msg).getBytes());
          os.flush();

        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }

The code here is just a placeholder, and you will need to fill in the destination URL where you want the message to be posted, along with some sort of identification of the sender of the message.

BluetoothLogger and SMSLogger follow similar patterns, and the source code contains the implementations for these.

Resources

By Vikram Goyal

This tip is in response to a recent discussion on the Sun forums about the thread-safety of RecordStore operations. Although the discussion goes in several different directions, the core question remains: How do you protect yourself from unsafe operations of third-party libraries?

The answer is not simple, but this tech tip will try to answer the specific example raised at the start of this discussion. Perhaps that will help provide general directions for handling such things in the real world.

RecordStore Safety

The problem boils down to individual record entry safety. The record entry method itself is atomic, recordStore.addRecord(), and therefore guaranteed to be thread-safe. However, as pointed out in the forums discussion, if consistency is measured in terms of two records being written to the record store, and if only one is entered and the second entry is interrupted because the application management software (AMS) has called destroyApp() between the two calls, have you lost a way to manage your data? Is the data now inconsistent?

Of course not.

This is where the real reason for the destroyApp() method comes into the picture, even if it is called by third-party software.

In the following code, I present the destroyApp() method that would handle this scenario consistently.

  public void destroyApp(boolean unconditional)
    throws MIDletStateChangeException {

    if(!unconditional) {
      if(!recordsWritten) { // Records have not been written yet -- wait!
        throw new MIDletStateChangeException();
      } else { // Records written -- MIDlet can be destroyed!
      }
    } else { // must destroy
      if(!recordsWritten) {
        // Roll back the record that was written.
        if(storage != null) { // Was the store ever opened?
          try {
            storage.deleteRecord(recordId1);
          } catch (Exception ex) {
            ex.printStackTrace();
          }
        }
      }
    }
  }

The destroyApp() method gives you a way to complete unfinished items before it actually closes the MIDlet. The AMS may want to close the MIDlet unconditionally, in which case, you have no choice but to close the MIDlet. But if the closing is not unconditional, and if in the middle of the writing process, you can throw the MIDletStateChangeException to finish the writing process.

Because the data is considered to be consistent only if all of it is written (in this case, two record items), you use the flag of recordsWritten to indicate this. Then you use this flag to monitor the state of the data.

If this flag is set as false, you have not finished the writing process, so you must roll back any data that has been written. It is possible that the destroyApp() method may be called before either of the records has been written. This is fair enough, and trying to delete the first record will raise an exception, which is silently ignored.

The process of writing -- and deleting -- data is itself atomic, so you can be fairly confident that data is not corrupted in between the writing processes. To further insulate from such corruption, you can synchronize on the storage object while writing or deleting.

I hope that this simple example has given you an idea on how to handle the effects of third-party libraries better. Concurrency and data safety are complex subjects, and the developer should understand the problem domain in detail before attempting specific solutions.

Resources

by Carol McDonald

The Java Persistence API (informally referred to as JPA) provides a plain old Java object (POJO)-based persistence model for Java EE and Java SE applications. It handles the details of how relational data is mapped to Java objects, and it standardizes Object/Relational (O/R) mapping. The latest update to JPA, Java Persistence 2.0, adds a number of new features such as additional O/R mapping functionality and new query language capabilities. Another area that has been enhanced in JPA 2.0 is locking and concurrency.

This Tech Tip highlights the new locking and concurrency features in JPA 2.0 and provides an application that demonstrates these capabilities.

Locking and Concurrency

Locking is a technique for handling database transaction concurrency. When two or more database transactions concurrently access the same data, locking is used to ensure that only one transaction at a time can change the data.

There are generally two locking approaches: optimistic and pessimistic. Optimistic locking assumes that there will be infrequent conflicts between concurrent transactions, that is, they won't often try to read and change the same data at the same time. In optimistic locking, the objective is to give concurrent transactions a lot of freedom to process simultaneously, but to detect and prevent collisions. Two transactions can access the same data simultaneously. However, to prevent collisions, a check is made to detect any changes made to the data since the data was last read.

Pessimistic locking assumes that transactions will frequently collide. In pessimistic locking, a transaction that reads the data locks it. Another transaction cannot change the data until the first transaction commits the read.

Optimistic locking works best for applications where concurrent transactions do not conflict. Pessimistic locking works best where concurrent transactions do conflict.

With JPA it is possible to lock an entity. This allows you to control when, where, and which kind of locking to use for an entity. Recall that in JPA, an entity is a lightweight persistence domain object. Typically, an entity represents a table in a relational database, with each entity instance corresponding to a row in that table.

Locking Support in JPA 1.0

JPA 1.0 only supports optimistic read or optimistic write locking. In this support, any transaction can read and update an entity. However, when a transaction commits, JPA checks the version attribute of the entity to determine if it was updated since the entity was last read. If the version attribute was updated since the entity was last read, JPA throws an exception. The advantage of this approach is that no database locks are held. This can result in better scalability than for pessimistic locking. The disadvantage of this approach is that the user or application must refresh and retry failed updates.

A versioned entity is marked with the @Version annotation, as illustrated in the following code snippet:

   public class User {
       @ID int id;
       @Version int version;

and its corresponding database schema has a version column, such as that created by the following SQL statement:

   CREATE TABLE USER
   (ID NUMBER NOT NULL, VERSION NUMBER),
      PRIMARY KEY (ID));

The version attribute can be an int, short, long, or timestamp. It is incremented when a transaction successfully commits. This results in an SQL operation such as the following:

   UPDATE User SET ..., version = version + 1
     WHERE id = ? AND version = readVersion

Figure 1 illustrates optimistic locking.

Optimistic Locking
Figure 1. Optimistic Locking

Here, two concurrent transactions attempt to update Part p. Transaction 1 commits first. In response, JPA increments the version attribute for the p entity. When Transaction 2 commits, JPA throws an OptimisticLockException because the version attribute for the p entity is higher than it was when Transaction 2 last read the p entity. As a result, Transaction 2 is rolled back.

You can further control the way JPA manages locking on a versioned entity by specifying a lock mode. You do this through the lock() method of the EntityManager class. Here is the method signature:

    public void lock(Object entity, LockModeType lockMode);

The first method parameter is the entity instance that needs to be locked in the transaction. The second method parameter is the lock mode.

In JPA 1.0, the lock mode value could only be one of the following:

  • READ. In this case, the JPA entity manager performs the optimistic locking operations as previously described. It locks the entity and before a transaction commits, checks the entity's version attribute to determine if it has been updated since the entity was last read. If the version attribute has been updated, the entity manager throws an OptimisticLockException and rolls back the transaction.
  • WRITE. In this case, the entity manager performs the same optimistic locking operations as for the READ lock mode. However, it also updates the entity's version column.

Additional Locking Support in JPA 2.0

JPA 2.0 adds five new lock modes. Two of these are used for optimistic locking. JPA 2.0 also adds support for pessimistic locking and provides three lock modes for pessimistic locking. The two new optimistic lock modes are:

  • OPTIMISTIC. This is the same as the READ lock mode. The READ lock mode is still supported in JPA 2.0, but specifying OPTIMISTIC is recommended for new applications.
  • OPTIMISTIC_FORCE_INCREMENT. This is the same as the WRITE lock mode. The WRITE lock mode is still supported in JPA 2.0, but specifying OPTIMISTIC_FORCE_INCREMENT is recommended for new applications.

The three new pessimistic lock modes are:

  • PESSIMISTIC_READ. The entity manager locks the entity as soon as a transaction reads it. The lock is held until the transaction completes. This lock mode is used when you want to query data using repeatable-read semantics. In other words, you want to ensure that the data is not updated between successive reads. This lock mode does not block other transactions from reading the data.
  • PESSIMISTIC_WRITE. The entity manager locks the entity as soon as a transaction updates it. This lock mode forces serialization among transactions attempting to update the entity data. This lock mode is often used when there is a high likelihood of update failure among concurrent updating transactions.
  • PESSIMISTIC_FORCE_INCREMENT. The entity manager locks the entity when a transaction reads it. It also increments the entity's version attribute when the transaction ends, even if the entity is not modified.

JPA 2.0 also provides multiple ways to specify the lock mode for an entity. You can specify the lock mode in the lock() and find() methods of the EntityManager. In addition, if you call the EntityManager.refresh() method, it refreshes the state of the entity instance from the database and locks it based on the entity's lock mode.

You can also set the lock mode for a query through the setLockMode() method of the Query interface. And you can specify a lock mode for the results returned by a named query through the setLockMode element of the @NamedQuery annotation.

Let's look at some examples of the new locking support in JPA 2.0.

OPTIMISTIC Lock Mode

The typical use case for OPTIMISTIC lock mode is where an entity has an intrinsic dependency on one or more entities to ensure consistency, for example, when there is a relationship between two entities. In the example shown in Figure 2, Transaction 1 on the left updates the price for part p1. This increments p1's version attribute. Transaction 2 on the right submits a bid for a user, u1. If the part price is lower than the user's current bid, Transaction 2 increases the bid.

Using OPTIMISTIC Lock Mode
Figure 2. Using OPTIMISTIC Lock Mode

In this scenario, you don't want Transaction 2 to commit if Transaction T1 changes the price for the part after Transaction T2 reads the price. So OPTIMISTIC lock mode is a good choice:

    em.lock(p1, OPTIMISTIC);

Before committing Transaction 2, the entity manager checks the version attribute for the p1 entity. The p1 version attribute is higher than when p1 was last read, so the entity manager throws an OptimisticLockException and rolls back Transaction2. Note that checking u1's version attribute for an update would not throw an exception. That's because Transaction 1 updates p1's version attribute — it does not increment u1's version attribute.

OPTIMISTIC_FORCE_INCREMENT Lock Mode

OPTIMISTIC_FORCE_INCREMENT lock mode causes an optimistic lock failure if another transaction tries to modify the locked entity. The common use for this lock is to guarantee consistency among entities in a relationship.

Figure 3 shows an example of OPTIMISTIC_FORCE_INCREMENT lock mode.

Using OPTIMISTIC_FORCE_INCREMENT Lock Mode
Figure 3. Using OPTIMISTIC_FORCE_INCREMENT Lock Mode

Transaction 2 on the right wants to ensure that the price for a part p1 does not change during the transaction, so it locks the p1 entity as follows:

    em.lock(p1, OPTIMISTIC_FORCE_INCREMENT);

Transaction 2 then calls em.flush()— this increments p1's version attribute in the database. Any parallel attempt to update p1 will throw an OptimisticLockException and roll back. As you can see, Transaction 1 attempts to update p1's price after Transaction 2 calls em.flush(). When Transaction T1 attempts to commit, the entity manager checks the p1 version attribute. Because the attribute has been updated since the last read, the entity manager throws an OptimisticLockException and rolls back Transaction T1.

PESSIMISTIC Lock Modes

The pessimistic lock modes lock a database row when data is read. This is the equivalent to the action taken in response to the SQL statement SELECT . . . FOR UPDATE [NOWAIT]. Pessimistic locking ensures that transactions do not update the same entity at the same time. This can simplify application code, but it limits concurrent access to the data, something that can cause poor scalability and may cause deadlocks. Pessimistic locking is better for applications with a higher risk of contention among concurrent transactions.

The following figures show various examples of PESSIMISTIC lock modes:

  • Figure 4 shows an example of reading an entity and in a later step setting it in PESSIMISTIC_READ lock mode.
  • Figure 5 shows an example of reading an entity and at the same time setting it in PESSIMISTIC_WRITE lock mode.
  • Figure 6 shows an example of reading an entity and in a later step setting it in PESSIMISTIC_WRITE lock mode.
Setting PESSIMISTIC_READ Lock Mode After Reading an Entity
Figure 4. Setting PESSIMISTIC_READ Lock Mode After Reading an Entity

Setting PESSIMISTIC_WRITE Lock Mode While Reading an Entity
Figure 5. Setting PESSIMISTIC_WRITE Lock Mode While Reading an Entity

Setting PESSIMISTIC_WRITE Lock Mode After Reading an Entity
Figure 6. Setting PESSIMISTIC_WRITE Lock Mode After Reading an Entity

The right locking approach to use depends on your application. Some questions you might want to ask to help make the decision are:

  • What is the risk of contention among concurrent transactions?
  • What are the requirements for scalability?
  • What are the requirements for user retrying after a failure?

Sample Application

Accompanying this tip is a sample application that demonstrates some of the locking support in JPA 2.0. The application is also available in the Java EE 6 SDK Preview release — look for "The Java Persistence API Locking Sample Application" in the samples directory of the Java EE 6 SDK Preview release download package.

The application consists of a client, a servlet, entity classes for part and user data, and stateless session beans that provide the logic for accessing and updating the data. The client calls the servlet to initialize the data. The client then makes multiple requests to the servlet that simulate parallel read and update operations. These operations are performed by the beans. Some of the operations are performed using optimistic locking, some using pessimistic locking. For example, the following method, updateWithOptimisticReadLock() demonstrates parallel operations performed using optimistic locking.

   public boolean updateWithOptimisticReadLock(int uID, int s) {
        boolean updateSuccessfull = true;
        // find part update price
        partEJB.updatePrice(uID, s);
        simulateThinkTimeForSecond(s);
        // find user and part, lock part OPTIMISTIC, update user
        userEJB.updateBid(uID, s);

        try {
            em.flush();
        } catch (OptimisticLockException e) {
            System.out.println("updateWithOptimisticReadLock OptimisticLockException while updating with Optimistic Lock. "
            + "The transaction will be rolled back");
            updateSuccessfull = false;
        } catch (PersistenceException e) {
            System.out.println("Got Exception while updating with optimstic lock" + e);
            updateSuccessfull = false;
        }
        System.out.println("updateWithOptimisticReadLock " + " updateSuccessful? " + updateSuccessfull);
        return updateSuccessfull;
    }

The updateWithOptimisticReadLock() method calls the updatePrice() method in the partEJB bean to find a user and then update the price of a part. The updateWithOptimisticReadLock() method then waits to allow parallel method calls to find other users before calling the updateBid() method in the userEJB bean. The updateBid() method sets an optimistic lock for the part and then submits a user bid that is based on the part price, as shown below:

   public void updateBid(int uID, int s) {

       User u = em.find(User.class, uID);
       int pID = u.getPart().getId();
       Part p = em.find(Part.class, pID);
       em.lock(p, LockModeType.OPTIMISTIC);

       System.out.println("UserManagmentBean updateBid " + " for userId " + uID);
       if (p.getPrice() <= u.getBid() && ! (p.isSold())) {
           u.setBid(u.getBid() +10);
       }

    }

The updateWithOptimisticReadLock() method then calls em.flush(). At that point, the entity manager performs a version check on the part entity. If any transaction submitted by any of the other users updates the part while it is locked, the entity manager increments the part's version attribute. If the version attribute for the part is higher than it was when the part was last read by the set bid transaction, the updateWithOptimisticReadLock() method throws an OptimisticLockException and rolls back that transaction.

You can find the source code for the application in the /samples/javaee6/jpa/locking directory.

To run the sample application, do the following:

  1. If you haven't already done so, download the Java EE 6 SDK Preview release. Also be sure to have an installed version of the Java Platform Standard Edition (Java SE) 6 SDK.
  2. Download the sample application.
  3. Set up your build environment and configure the application server by following the common build instructions.
  4. Change to the samples_install_dir/javaee6/jpa/locking directory, where samples_install_dir is where you installed the sample application.
  5. Build, deploy, and run the sample application by entering the following command on the command line:
       ant all
    

    You can replace the ant all command with the following set of commands:

    ant default — compiles and packages the application.

    ant dir — deploys the application to the application server.

    ant run — runs the test Java client.

  6. In response, you should see output similar to the following:

            [java] LockingJavaClient: Test is starting
            [java] Calling URL:http://localhost:8080/locking/test/?tc=initData&nc=6
            &ns=3&np=3
            [java]
            [java] Starting parallel updates with 9 users for operation: updateWOL
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=1
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=2
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=7
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=9
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=5
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=3
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=8
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=6
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=4
            [java] Result for operation updateWOL for userId 1 is Success
            [java] Result for operation updateWOL for userId 2 is Success
            [java] Result for operation updateWOL for userId 5 is Failure
            [java] Result for operation updateWOL for userId 6 is Failure
            [java] Result for operation updateWOL for userId 7 is Failure
            [java] Result for operation updateWOL for userId 8 is Success
            [java] Result for operation updateWOL for userId 9 is Success
            [java] Result for operation updateWOL for userId 3 is Success
            [java] Result for operation updateWOL for userId 4 is Failure
            [java] Parallel updates executed with 9 users for operation: updateWOL Time
        taken:6146 miliseconds
            [java] ...
            [java]
            [java] Starting parallel updates with 9 users for operation: updateWPL
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=2
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=5
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=3
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=9
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=1
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=4
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=7
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=6
            [java] Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=8
            [java] Result for operation updateWPL for userId 5 is Success
            [java] Result for operation updateWPL for userId 3 is Success
            [java] Result for operation updateWPL for userId 9 is Success
            [java] Result for operation updateWPL for userId 2 is Success
            [java] Result for operation updateWPL for userId 1 is Success
            [java] Result for operation updateWPL for userId 8 is Success
            [java] Result for operation updateWPL for userId 4 is Success
            [java] Result for operation updateWPL for userId 6 is Success
            [java] Result for operation updateWPL for userId 7 is Success
            [java] Parallel updates executed with 9 users for operation: updateWPL Time
        taken:15054 miliseconds
            [java] LockingJavaClient: Test is ended
    

    The operations, which are identified in the tc parameter values in the URL calls, are as follows:

    • updateWOL. Finds a part. Simulates think time to allow parallel threads to find users in parallel. Updates the part using optimistic locking.
    • updateWOR. Finds a part and a user. Simulates think time to allow parallel threads to find users in parallel. Locks the part using optimistic locking. Updates the user.
    • updateWOW. Finds a part and a user. Simulates think time to allow parallel threads to find users in parallel. Locks the part using an OPTIMISTIC_FORCE_INCREMENT lock. Updates the user.
    • updateWRP. Finds a part. Simulates think time to allow parallel threads to find users in parallel. Locks the part using a PESSIMISTIC_READ lock. Updates the part.
    • updateWRR. Finds a part. Simulates think time to allow parallel threads to find users in parallel. Refreshes using a PESSIMISTIC_WRITE lock. Updates the part.
    • updateWPL. Finds a part using a PESSIMISTIC_WRITE lock. Simulates think time to allow parallel threads to find users in parallel. Updates the part.

    Notice that some update operations that use optimistic locking, such as updateWOL, fail, while all update operations that use pessimistic locking, such as updateWPL, are successful. However, the time it takes to update using pessimistic locking is much higher than that taken using optimistic locking.

    Use the command ant clean to undeploy the sample application and to remove temporary directories.

Further Reading

For more information, see the following resources:

About the Author

Carol McDonald is a Java Technology Evangelist at Sun Microsystems. As a software developer since 1986, Carol's experience has been in the technology areas of distributed network applications and protocols, including Java EE technology, XML, Internet/Intranet applications, LDAP, Distributed Network Management (CMIP,SNMP) and Email (X.400,X.500). Besides Java, Carol is also fluent in French and German. Read Carol McDonald's blog.

By Bruce Hopkins

My article Three Reasons Why Your Next Java ME Mobile Application Should Include JavaFX Mobile introduced the overall Java FX architecture and, specifically, the Java FX Mobile 1.1 APIs. Well, the JavaFX 1.2 APIs have been released since then, with tons of new features that were requested by you, the developer community.

The purpose of this tech tip is to briefly answer the questions that were submitted in the Comments section of the original article (on JavaFX 1.1), and to simultaneously point to some of the capabilities of JavaFX 1.2.

Question 1: When will development tools for JavaFX for Linux be available?

Answer: The newly released JavaFX 1.2 SDK is now available for the following four platforms:

  • Windows
  • Mac OS X
  • Linux
  • Open Solaris

Question 2: How can I load my JavaFX applications on a mobile device?

Answer: Applications created with the JavaFX 1.1 SDK were not supported on mobile devices for deployments, so it was not possible to get your JavaFX 1.1 Mobile application running on a real handset (unless you did some real hacking). However, the JavaFX 1.2 SDK is capable of creating mobile applications that can be deployed to Windows Mobile 6.0 and 6.1 devices. Terrence Barr has created a screencast with detailed instructions that show developers how to get started.

Question 3: How can I learn about all the new features in JavaFX 1.2?

Answer: You can learn about all the new features in JavaFX 1.2 in an Features and Enhancements article written by Inyoung Cho. Additionally, it’s always good to have the JavaFX APIs handy whenever you learn how to use a particular class.

Final Thoughts

The JavaFX 1.2 APIs include many new features that allow desktop, mobile, and web developers to create compelling, dynamic, and feature-rich applications. Check them out.

NFC is a radio-communication standard that enables wireless data transfer between two devices at a very short distance -- less than 10 centimeters. NFC devices include a certain class of radio-frequency identification (RFID) tags and contactless smart cards. NFC devices operate within the 13.56 MHz frequency range, and they support extremely low data rates -- a maximum of 0.42 Mb per second.

Compared to Bluetooth and Wi-Fi, NFC technology operates at drastically reduced transfer rates and only within a very small proximity. If that's the case, why use NFC technology? Three reasons:

  • Setup time. NFC devices communicate instantly -- in less than 100 milliseconds -- when placed within range.
  • Power consumption. NFC tags and cards do not consume power, so their lifespan can be unlimited.
  • Cost. NFC tags and cards are inexpensive to manufacture compared to other wireless technologies.

This article shows you how to get Bluetooth applications to completely bypass the device-discovery and service-searching processes simply by using Near-Field Communication (NFC) technology and JSR 257: Contactless Communication API.

Read the full article

Check out the MAC applet blog entry regarding the new security warning on Macs. It's directed to Mac users who access javafx.com pages with embedded applets and who now see this warning:

Access dialog box

To prevent the message from appearing, check Allow all applets from "javafx.com" access.

It happens because Apple has changed to a site/URL-based security model in one of its recent Java updates. In previous updates of Java for Mac OS X, unless the applet was cached a Trust dialog box appeared with different text and unrestricted access information in the fine print: This applet was signed by "JavaFX Runtime," but Java cannot verify the authenticity of the signature's certificate. Click Trust to run this applet and allow it unrestricted access to your computer.

For more technical information about Java for Mac OS X v10.5 Update 4, see the Apple support documentation.

This article demonstrates that Java ME developers have a wide array of choices -- in addition to the full-featured Java ME SDK (which replaces the well-known Wireless Toolkit) -- to create and test applications.

The Sun Java ME SDK 3.0, considered the de facto standard SDK when it comes to mobile application development, integrates the very popular Java Wireless Toolkit for CLDC and the Java Toolkit for CDC as a single product. It lets developers create Java ME applications for the following JVM platforms:

  • CLDC/MIDP: The common JVM configuration for hundreds of millions of mobile phones
  • CDC/FP/PBP/AGUI: The JVM configuration for high-end smart phones and other devices
  • CDC/FP/PBP/BD-J: The JVM configuration for Blu-ray Disc players

In addition to the Sun Java ME SDK 3.0, this article include details on the following offerings and then summarizes them in a handy comparison table:

  • NetBeans 6.5 IDE
  • MOTODEV Studio for Java ME
  • Nokia S60, S40, and NFC SDKs
  • BlackBerry JDE 4.7
  • Sony Ericsson SDK 2.5 for Java ME
  • LG SDK 1.2 for Java ME

The Java ME SDK Comparison Matrix table shows a list of all Java ME SDKs and tools that are evaluated in this article, with an entry for API support for each one. (Note: The NetBeans IDE supports multiple Java configurations, so its entries in this matrix apply to when it is configured with the Java ME SDK 3.0.)

Read the full article

by Ken Saks

The latest update to Enterprise JavaBeans (EJB) technology, EJB 3.1, is nearing completion. A Proposed Final Draft of the EJB 3.1 specification is now available. The main goals of this new specification are to further simplify development using EJB technology and to add a number of long-requested features such as singleton beans.

EJB 3.1 will be included in Java Platform, Enterprise Edition (Java EE) 6. A preview version of Java EE 6 is currently available for download. The preview version includes a nearly complete implementation of EJB 3.1 and a sample application that takes advantage of some of the new features in EJB 3.1.

This Tech Tip introduces a few of these exciting new EJB 3.1 capabilities. It also includes instructions on how to run the EJB 3.1 sample application in the Java EE 6 preview.

Ease of Development

EJB 3.1 builds on the ease-of-use enhancements in EJB 3.0 by providing many new ways to improve developer productivity. Chief among these are the ability to implement session beans using only a bean class and the ability to package enterprise bean classes directly in a .war file, without the need for an ejb-jar file.

No-interface View

The EJB 3.0 local client view is based on a plain old java interface (POJI) called a local business interface. A local interface defines the business methods that are exposed to the client and that are implemented on the bean class. Although this separation of interface and implementation is a well-accepted approach to application design, the separation sometimes is unnecessarily cumbersome and adds little value. This is especially true for very fine-grained components with closely coupled clients that are collocated in the same module.

Developers have asked for a way to get the same enterprise bean functionality without having to write a separate business interface. The EJB 3.1 specification addresses this by making local business interfaces optional. The result is the no-interface local view.

The no-interface view has the same behavior as the EJB 3.0 local view, for example, it supports features such as pass-by-reference calling semantics and transaction and security propagation. However, a no-interface view does not require a separate interface, that is, all public methods of the bean class are automatically exposed to the caller. By default, any session bean that has an empty implements clause and does not define any other local or remote client views, exposes a no-interface client view.

For example, the following session bean exposes a no-interface view:

   @Stateless
      public class HelloBean {

          public String sayHello() {
              String message = propertiesBean.getProperty("hello.message");
              return message;
          }

      }

As is the case for a local view, the client of a no-interface view always acquires an EJB reference -- either through injection or JNDI lookup. The only difference is that the Java type of the EJB reference is the bean class type rather than the type of a local interface. This is shown in the following bean client:

   @EJB
   private HelloBean helloBean;

   ...

   String msg = helloBean.sayHello();

Note that even though there is no interface, the client cannot use the new() operator to explicitly instantiate the bean class. That's because all bean invocations are made through a special EJB reference, or proxy, provided by the container. This allows the container to provide all the additional bean services such as pooling, container-managed transactions, and concurrency management.

Simplified Packaging

The EJB specification has always required that enterprise beans be packaged in an enterprise module called an ejb-jar file. Since it is common for Java EE web applications to use enterprise beans, this packaging requirement can be burdensome. These applications are forced to use a web application archive (.war file) for the web application, an ejb-jar file for the enterprise beans, and an enterprise archive (.ear file) that encompasses the other packages. This packaging approach is further complicated by the special handling required for any classes or resources that must be shared between the modules.

The EJB 3.1 specification addresses this problem by removing the restriction that enterprise bean classes must be packaged in an ejb-jar file. You now have the option of placing EJB classes directly in the .war file, using the same packaging guidelines that apply to web application classes. This means that you can place EJB classes under the WEB-INF/classes directory or in a .jar file within the WEB-INF/lib directory. The EJB deployment descriptor is also optional. If it's needed, you can package it as a WEB-INF/ejb-jar.xml file.

New EJB 3.1 Features

Because of the concentrated focus on ease of use in EJB 3.0, there was not enough time to add many of the other features that developers have requested. The EJB 3.1 specification adds a number of these features to the EJB API. Four of the new features are singleton session beans, application initialization/shutdown callbacks, asynchronous session bean invocations, and automatic EJB timers. This section describes singleton session beans and application initialization/shutdown callbacks.

Singletons

A long-standing omission in the EJB API has been the ability to easily share state between multiple instances of an enterprise bean component or between multiple enterprise bean components in the application. By contrast, the Java EE web application programming model has always provided this type of capability through a ServletConfig object. In EJB 3.1, this omission has been addressed with the introduction of singleton beans, also known as singletons.

A singleton is a new kind of session bean that is guaranteed to be instantiated once for an application in a particular Java Virtual Machine (JVM)*. A singleton is defined using the @Singleton annotation, as shown in the following code example:

   @Singleton
   public class PropertiesBean {

    private Properties props;
    private int accessCount = 0;

    public String getProperty(String name) { ... }

    public int getAccessCount() { ... }

  }

Because it's just another flavor of session bean, a singleton can define the same local and remote client views as stateless and stateful beans. Clients access singletons in the same way as they access stateless and stateful beans, that is, through an EJB reference. For example, a client can access the above PropertiesBean singleton as follows:

   @EJB
   private PropertiesBean propsBean;

   ...

   String msg = propsBean.getProperty("hello.message");

Here, the container ensures that all invocations to all PropertiesBean references in the same JVM are serviced by the same instance of the PropertiesBean. By default, the container enforces the same threading guarantee as for other component types. Specifically, no more than one invocation is allowed to access a particular bean instance at any one time. For singletons, that means blocking any concurrent invocations. However, this is just the default concurrency behavior. There are additional concurrency options that allow more efficient concurrent access to the singleton instance.

Application Startup/Shutdown Callbacks

The introduction of singletons also provides a convenient way for EJB applications to receive callbacks during application initialization or shutdown. By default, the container decides when to instantiate the singleton instance. However, you can force the container to instantiate the singleton instance during application initialization by using the @Startup annotation. This allows the bean to define a @PostConstruct method that is guaranteed to be called at startup time. In addition, any @PreDestroy method for a singleton is guaranteed to be called when the application is shutting down, regardless of whether the singleton was instantiated using lazy instantiation or eager instantiation. In lazy instantiation, the singleton isn't instantiated until it's method's are first needed. In eager instantiation, the singleton is instantiated at startup time whether or not it gets used.

Here is an example that shows part of a singleton that includes a @Startup annotation as well as @PostConstruct and @PreDestroy methods:

   @Singleton
   @Startup
   public class PropertiesBean {

     @PostConstruct
     private void startup() { ... }

     @PreDestroy
     private void shutdown() { ... }

      ...

   }

Sample Application

The Java EE 6 SDK Preview release includes an application that uses each of the EJB 3.1 features covered in this tip. The application is composed of a servlet, a singleton session bean, and a stateless session bean. Each session bean exposes a no-interface view. The singleton defines a callback that is called by the container during application initialization. Both the servlet and stateless bean use the singleton to access common application configuration information. When the servlet is accessed, it invokes both session beans and prints some messages containing the return values. The entire application is packaged within a .war file, without any .xml file.

To run the sample application, do the following:

  1. If you haven't already done so, download the Java EE 6 SDK Preview. Also be sure to have an installed version of the Java Platform Standard Edition (Java SE) 6 SDK.
  2. Download the sample application, ejb31-war.war
  3. Start the GlassFish V3 Prelude application server that is packaged with the Java EE 6 SDK by entering the following command:
       <javaee_home>/bin/asadmin start-domain
    
    where <javaee_home> is where you installed the Java EE 6 SDK.
  4. Deploy the sample application by copying it to the <javaee_home>/domains/domain1/autodeploy directory.
  5. Execute the application by opening a browser and accessing the URL http://localhost:8080/ejb-ejb31-war

    You should see the following output appear in a browser window:

       ejb31-war Servlet
       HelloBean says : Hello, world
       Singleton property access count = 2
    

You can view the source code for the application in the <javaee_home>/samples/javaee6/ejb/ejb31-war/src directory.

Further Reading

For more information, see the following resources:

About the Author

Ken Saks is the Specification Lead for EJB 3.1 and a Senior Staff Engineer in the Java EE team at Sun. Read his blog.

* As used on this web site, the terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform.

by Harold Carr

Metro is a high performance, extensible, easy to use web service stack. It combines the JAX-WS reference implementation with Web Services Interoperability Technologies (WSIT), formerly known as Project Tango. WSIT includes features that enable advanced web service interoperability with the .NET Windows Communication Foundation (WCF), a set of technologies for building and running connected systems. Metro is bundled as part of the GlassFish Server, and runs in other containers such as Tomcat.

An earlier Tech Tip, Testing Interoperability Between Metro and .NET, described an interoperability test in which a Metro-based client communicates with a WCF-based service. In using Metro-based services for these tests, I sometimes start with a Web Service Definition Language (WSDL) file. Sometimes I build Metro-based services from Java classes. Sometimes I deploy the services to containers. Sometimes I don't deploy to a container. To simplify the task of using Metro-based services for these tests, I have a common ant build.xml file. The file handles all these combinations of web service sources and deployment approaches. This Tech Tip describes the contents and operation of the build.xml file.

A .tar file, CommonAntBuild.tar, accompanies this tip. The tar file contains the code and build files referenced in the tip. Note that the directory structure of the code uses symbolic links that work on UNIX and LINUX platforms. The tip assumes that you are running on a UNIX or LINUX platform. If you are running on a Windows platform, you will need to use other techniques for sharing common files -- these techniques are not covered in this tip.

Top-Level Targets

To get started, let's see what the build.xml file advertises by entering the following commands. Note that the commands in this tip assume that you have connected to the root directory of the source code associated with this tip.

   cd examples/from-java-container
   ant

In response, you should see the following build file targets:

   help:
        [echo] service-from-wsdl-container : Builds, wars, deploys service
        [echo] service-from-java-container : Builds, wars, deploys service
        [echo] service-from-wsdl-publish   : Builds, wars, publishes service
        [echo] service-from-java-publish   : Builds, wars, publishes service
        [echo] service-undeploy            : Undeploys the service WAR from the container
        [echo] client                      : Builds and runs the client
        [echo] clean                       : Delete all generated code

Each of the targets that begin with service-from- either builds a service from a WSDL description or from a Java class annotated with @WebService. It then either creates a WAR file and deploys the war file to a container or it invokes the Endpoint.publish() method to publish the web service endpoint using the HTTP server built into the Java platform.

General Project Layout

Here is the general layout of a project that uses the common build file.

   cd examples/from-java-container
   ls -alF
   -rw-r--r--  1 carr  staff   74 May 27 09:21 .README
   lrwxr-xr-x  1 carr  staff    5 May 27 09:00 build-common@ -> ../..
   -rw-r--r--  1 carr  staff  436 May 27 09:06 build.properties
   lrwxr-xr-x  1 carr  staff   29 May 27 09:00 build.xml@ -> build-common/build-common.xml
   drwxr-xr-x  4 carr  staff  136 May 27 09:07 etc/
   drwxr-xr-x  3 carr  staff  102 May 27 08:44 src/

To avoid duplicating files, I use symbolic links. The common build file is located in the root directory. It is named build-common.xml and linked in the current directory as build.xml. The following lines in the file import property files:

   <project basedir="." default="help" name="tango/code/build-common">

       <property file="build.properties"/>
       <property file="${tools.properties}"/>
       <property file="${container.properties}"/>

The first import is for the build.properties file in the current directory. The first two lines of the build.properties file define the other two property files to be imported. As shown below, the two other files to be imported are tools.properties and tomcat-container.properties:

   tools.properties=build-common/tools.properties
   container.properties=build-common/tomcat-container.properties

The tools.properties file defines settings for the wsgen and wsimport commands. The wsgen command generates Java API for XML Web Services (JAX-WS) portable artifacts for a web service. The wsimport command generates JAX-WS portable artifacts for a web service client. Here are the contents of the tools.properties file:

   # WSGEN options
   wsgen.verbose=true
   wsgen.keep=true

   # WSIMPORT options
   wsimport.debug=false
   wsimport.verbose=false
   wsimport.keep=true
   wsimport.extension=
   wsimport.xendorsed=true

You can either globally control settings for all the code that uses this property file or you can define a property file specifically for a particular project.

The tomcat-container.properties file sets up ant constants that are used to build and deploy a service in a Tomcat container. Here are the contents of the tomcat-container.properties file:

   catalina.home=/usr/local/hc/java/apache/apache-tomcat-5.5.26
   lib.home=${catalina.home}/shared/lib
   lib.endorsed=${catalina.home}/common/endorsed
   lib.glassfishv3=${catalina.home}
   deploy.dir=${catalina.home}/webapps

Note that if you use Tomcat with the common build file, you need to have Metro already installed into Tomcat.

There are two other properties files of interest in the root directory: glassfish-container.properties and no-container.properties. The glassfish-container.properties file sets up ant constants that are used to build and deploy a service in a GlassFish container. Here are the contents of the glassfish-container.properties file:

   #as.home=/Applications/NetBeans/glassfish-v2.1
   as.home=C:/ProgramFiles/glassfish-v2.1
   lib.home=${as.home}/lib"
   lib.endorsed=${as.home}/lib/endorsed"
   lib.glassfishv3=${as.home}/modules
   domain=domain1
   deploy.dir=${as.home}/domains/${domain}/autodeploy

Here are the contents of the no-container.properties file:

   metro.home=/Users/carr/ws/wsit/wsit/dist/image/metro/lib
   lib.home=${metro.home}
   lib.endorsed=${metro.home}
   lib.glassfishv3=${metro.home}
   deploy.dir=/tmp

The no-container.properties file points directly to the image created when building Metro. This allows users to test the latest bits. In general, most people will not want to download Metro source, but they will want to try building a service without deploying it to a container, that is, simply publishing the service endpoint using the Endpoint.publish() method. In that case, use the GlassFish or Tomcat settings to get the Metro code -- the deploy.dir assignment will be ignored.

Building a Service From Java Classes and Deploying To a Container

Let's take a closer look at what's in the build.xml file and see how it's used. Let's begin by examining the project that builds a Metro web service from a Java class and deploys the service to a container.

First change to the from-java-container directory:

   cd examples/from-java-container

The .README file in this directory shows the ant tasks necessary to build and deploy the service, to run the client, to do cleanup, and to undeploy the service. Here are the contents of the .README file:

   ant service-from-java-container
   ant client
   ant clean
   ant service-undeploy

Building and Deploying the Service

The first ant task in the .README file runs the service-from-java-container target. Here is the definition of that target in the build.xml file:

   <target name="service-from-java-container"
	    depends="clean, setup, setup-war, service-compile, service-wsgen, service-war, service-deploy"/>

The service-from-java-container target initially runs the following targets:

  • clean - Removes any previously generated and/or compiled code.
  • setup - Creates a build/classes directory.
  • setup-war - Creates a build/war directory.
  • service-compile - Compiles the pertinent Java classes.
  • service-wsgen - Runs the wsgen command to generate portable artifacts for the web service.
  • service-war - Creates a WAR file for the compiled and generated code.
  • service-deploy - Deploys the WAR file to the deploy directory of the container.

Here is what the service-compile target looks like:

    <target name="service-compile" depends="setup">
        <javac
            fork="true"
            srcdir="${basedir}/src"
            destdir="${build.classes.home}"
            includes="**/service/**,**/common/**">
            <classpath refid="wsit.classpath"/>
        </javac>
       </target>

The service-compile target runs the javac compiler on all Java classes found in directories named service and common (note that common is not used in this example). A Java class annotated with @WebService is found and compiled (not shown).

Here is what the service-wsgen target looks like:

    <target name="service-wsgen" depends="setup">
        <wsgen
            verbose="${wsgen.verbose}"
            keep="${wsgen.keep}"
            destdir="${build.classes.home}"
            sei="${service.wsgen.sei}"
	       >
            <classpath path="${build.classes.home}"/>
        </wsgen>
    </target>

The service-wsgen target invokes the wsgen command to generate server-side artifacts, such as JAXB marshaling code, for the web service. The target uses wsgen settings from the tools.properties and service.wsgen.sei variables defined in the build.properties file of the current directory. For example, here is the service.wsgen.sei setting in the build.properties file in the from-java-container directory:

    service.wsgen.sei=fromjava.service.AddNumbersImpl

The service.wsgen.sei setting is the service endpoint interface (SEI) for the web service, that is, a Java class that contains a @WebService annotation.

Here are the contents of the service-war target:

    <target name="service-war">
	     <war warfile="${service.war.file}" webxml="etc/web.xml">
	         <webinf dir="${etc.dir}" includes="sun-jaxws.xml"/>

	         <zipfileset
	             dir="${etc.dir}"
	             includes="*.wsdl, *.xsd"
	             prefix="WEB-INF/wsdl"/>

	         <classes dir="${build.classes.home}"/>
	     </war>
    </target>

The service-war target creates a WAR file that contains the compiled and generated code. It also includes *.xml files (and *.wsdl and *.xsd files - not used in this example). The name of the WAR file is defined in build.properties of the current directory, as follows:

    service.war.filename=wsit-enabled-fromjava.war

Here is what the service-deploy target looks like:

    <target name="service-deploy">
	        <copy file="${service.war.file}" todir="${deploy.dir}"/>
    </target>

The service-deploy target copies the WAR file to the deploy directory of the container.

Creating the Client

The second ant task in the from-java-container .README file runs the client target. The client target builds the client and then runs it. Building the client runs the client-wsimport, client-compile, and client-cp-config targets in the build.xml file.

Here is the definition of the client-wsimport target:

   <target name="client-wsimport" depends="setup">
        <wsimport
           debug="${wsimport.debug}"
           verbose="${wsimport.verbose}"
           keep="${wsimport.keep}"
           extension="${wsimport.extension}"
           xendorsed="${wsimport.xendorsed}"
           destdir="${build.classes.home}"
           wsdl="${client.wsimport.wsdl}"
   	    package="${client.wsimport.package}"
   	   >
            <binding dir="${etc.dir}" includes="${client.wsimport.binding}"/>
        </wsimport>
    </target>

The client-wsimport target invokes the wsimport command. The target picks up client.wsimport.wsdl, client.wsimport.package, and client.wsimport.binding settings in the build.properties file in the current directory (client.wsimport.binding is not used in this example). Here are the settings in the build.properties file:

   address=http://localhost:8080/wsit-enabled-fromjava/addnumbers
   client.wsimport.wsdl=${address}?wsdl
   client.wsimport.package=fromwsdl.client

The target action retrieves the WSDL file of the deployed service and places the generated code in the fromwsdl.client package. You can implement finer-grained control of JAXB bindings by supplying a client.wsimport.binding file.

Here is the definition of the client-compile target:

   <target name="client-compile" depends="setup">
       <javac
           fork="true"
           srcdir="${basedir}/src"
           destdir="${build.classes.home}"
           includes="**/client/**,**/common/**">
           <classpath>
               <path refid="wsit.classpath"/>
               <pathelement path="${client.compile.classpath.extra}"/>
           </classpath>
       </javac>
   </target>

The client-compile target runs the javac compiler on all the Java source code for the project that it finds in the client and common directories under src.

Here is the definition of the client-cp-config target:

   <target name="client-cp-config" depends="setup">
       <copy todir="${build.classes.home}">
           <fileset dir="${etc.dir}" includes="client-*.xml"/>
       </copy>
   </target>

The client-cp-config target copies any files to the build directory. This is useful for configuration files such as those used in JAX-WS handler configuration (not used in this example).

Here is the target that runs the client:

   <target name="client-run">
       <java fork="true" classname="${client.main}">
           <jvmarg value="${client.http.dump.do}"/>
           <classpath>
               <path refid="wsit.classpath"/>
               <pathelement location="${build.classes.home}"/>
               <pathelement location="${etc.dir}"/>
           </classpath>
           <arg value="${client.main.arg1}"/>
           <arg value="${client.main.arg2}"/>
       </java>
   </target>

The client-cp-config target defines the main class and optionally defines a switch to control whether Metro dumps the HTTP messages that are sent and received. It also optionally passes values to the main class. The target uses the following settings from the build.properties file:

   client.main=fromjava.client.AddNumbersClient
   #client.http.dump=true

The following ant tasks do final clean up by deleting the build directory and undeploying the service from the container.

   ant clean
   ant service-undeploy

Building a Service From a WSDL File and Deploying To a Container

Now let's examine the project that builds a Metro web service from a WSDL file and deploys the service to a container.

Change to the from-wsdl-container directory:

   cd examples/from-wsdl-container

The ant tasks for building a service from WSDL are similar to those for building a service from a Java class. The difference is that the service-wsimport target runs before the service-compile target, and the service-wsgen target does not run at all.

The service-wsimport target generates code from a WSDL file similarly to the way the client-wsimport target does on the client-side in building a service from a Java class. However, in the service-wsimport case, the WSDL file is located in the file system as defined in the build.properties file, rather than accessed from the network. Here are the settings in the build.properties file in the from-wsdl-container directory:

   service.wsimport.wsdl=etc/AddNumbers.wsdl
   service.wsimport.package=fromwsdl.service

The .README file in the from-wsdl-container directory shows the ant tasks to build a service from a WSDL file and deploy it to a container. With the exception of the initial task, the tasks are the same as for building a service from a Java class and deploying it to a container. The client tasks are exactly the same because the client should know nothing about the implementation of the web service.

Here are the contents of the .README file:

   ant service-from-wsdl-container
   ant client
   ant clean
   ant service-undeploy

Building a Service From a Java Class and Publishing It

So far we've examined projects that build a web service and deploy it to a container. Now let's examine projects that build a service and publish the web service endpoint.

Change to the from-java-publish directory:

   cd examples/from-java-publish

The .README file shows the ant tasks to build and publish the service. Here is the initial task:

   ant service-from-java-publish &

The & at the and of the command is the way to run a UNIX or LINUX process in the background. (Running the process in the background allows me to use the same shell for further commands. However, spawning another shell works well too.)

Here is the definition of the service-from-java-publish target in the build.xml file:

   <target name="service-from-java-publish"
	    depends="clean, setup, service-compile, service-wsgen, service-cp-config, service-publish"/>

As is the case for building a service from a Java class and deploying it to a container, the service-compile target compiles the user-written source code for the web service. The service-wsgen target then runs the wsgen command on the SEI. The service-cp-config target copies service-*.xml files from the etc directory. Those files are useful for configuration files such as JAX-WS handlers. However, they are not used here.

The service-publish target is where this project differs from service-from-java-container. Here is the definition of the service-publish target:

   <target name="service-publish">
       <java fork="true" classname="${service.main}">
           <jvmarg value="${service.http.dump.do}"/>
           <classpath>
               <path refid="wsit.classpath"/>
               <pathelement location="${build.classes.home}"/>
           </classpath>
           <arg value="${service.main.arg1}"/>
           <arg value="${service.main.arg2}"/>
       </java>
    </target>
The service-publish target runs service.main and passes it jvmargs and main args. The values for these variables are specified in the build.properties file in the from-java-publish directory as follows:

   address=http://localhost:8888/echo

   service.wsgen.sei=foo.service.Echo
   service.main=common.GenericPublisher
   service.main.arg1=${address}
   service.main.arg2=${service.wsgen.sei}

Notice that the service.main class is GenericPublisher. Most of the code to publish an endpoint is the same for the various projects in this example. Because of this, I use a GenericPublisher to do the publishing. I share this class, using symbolic links, will all the projects that publish. The GenericPublisher is given the address at which to publish the service and the SEI to be published. The class uses reflection to instantiate the SEI.

Here are the contents of the GenericPublisher class:

   package common;

   import javax.xml.ws.Endpoint;

   public class GenericPublisher {
       public static void main(String[] av) {
           final String address = av[0];
           final String serviceImplementationBeanClass = av[1];
           try {
               final Object serviceImplementationBean =
                   Class.forName(serviceImplementationBeanClass).newInstance();
               Endpoint.publish(address, serviceImplementationBean);
           } catch (Throwable t) {
               t.printStackTrace();
           }
       }
   }

The steps to run the client are identical to those in the other projects in this example.

Building a Service From a WSDL File and Publishing It

Change to the from-java-publish directory:

   cd examples/from-wsdl-publish

The .README file shows the ant tasks to build and publish the service. Here is the initial task:

   ant service-from-wsdl-publish &

Here is the definition of the service-from-wsdl-publish target in the build.xml file:

   <target name="service-from-wsdl-publish"
	    depends="clean, setup, service-wsimport, service-compile, service-cp-config, service-publish"/>

The first steps in this process are similar to the service-from-java-container. The main differences are the last steps. Instead of creating a WAR file and deploying it in a container, this process publishes the endpoint using the GenericPublisher, as specified in the following build.properties file settings:

   tools.properties=build-common/tools.properties
   container.properties=build-common/no-container.properties

   service.wsimport.wsdl=etc/AddNumbers.wsdl
   service.wsimport.package=fromwsdl.service

   address=http://localhost:8080/fromwsdl/addnumbers
   service.main=common.GenericPublisher
   service.main.arg1=${address}
   service.main.arg2=fromwsdl.service.AddNumbersImpl

   client.wsimport.wsdl=${address}?wsdl
   client.wsimport.package=fromwsdl.client
   client.main=fromwsdl.client.AddNumbersClient

   client.http.dump=true

Again, the client steps are identical.

Summary

This Tech Tip showed a build.xml file that can be used with Metro to create a web service from a Java class or from a WSDL file and deploy the service in a web container or standalone using the Endpoint.publish method.

It is also possible to create dynamic clients using the JAX-WS Dispatch API and dynamic services using the JAX-WS Provider API. Much of the ant build file described in this tip should work for those cases, but I have not tested it or extended it.

I also use NetBeans in combination with GlassFish to create and deploy Metro-based services and clients. But it is often useful to have some test cases handy that can be used quickly from the command line in different configurations. And that's the value of the ant build file covered in this tip.

Further Reading

For more information, see the following resources:

About the Author

Harold Carr is the engineering lead for enterprise web services interoperability at Sun Microsystems. Previous to this role, Harold was responsible for RMI-IIOP load-balancing and fail-over in the Sun Java System Application Server. He designed the core architecture used in Sun's CORBA ORB and in the JAX-RPC 2.0 reference implementation and the scalable socket communications architecture used in SJSAS HTTP and IIOP remoting. Harold helped write the OMG Portable Object Adapter specification and was chairperson of the OMG Portable Interceptor specification. Previous to Sun, he did distributed computing research at Hewlett-Packard Research Laboratories and Schlumberger Research Laboratories, was Chief Architect of Visual Lisp technology at Autodesk, and was a logic simulation consultant for Cirrus Logic. He holds a Ph.D., in Computer Science from the University of Utah. Read Harold Carr's blog.

By Bruce Hopkins

After reading both Part 1 and Part 2 of the “Working with Bluetooth and GPS” series of articles, you were given a clear explanation of the example code that shows you how to do the following:


    1. Use the JSR-82 Bluetooth API to access the data from a Bluetooth-enabled GPS receiver
    2. Parse the data streams in NMEA format and obtain the coordinates of your current location
    3. Formulate an HTTP request to access an external mapping service
    4. Use the JSR-172 XML Parsing and Web Services API to parse an XML result
    5. Make a request in order to display a map image

Therefore, the purpose of this tech tip is to provide answers to the questions that were submitted by the readers of both articles in the series.

Question 1: Hi Bruce, I have a problem when I start the Mpowerplayer tool with any MIDlet that uses Bluetooth and the JSR-82 API. When the application tries to execute my MIDet, it immediately displays a java.lang.NoClassDefFoundError: javax/bluetooth/DiscoveryListener. What could be the problem?

Answer 1: The MPowerplayer made a change on how it handles JSR-82 libraries between releases #1127 and #1185. Unfortunately, it not explicitly stated in the documentation, but you need to make two simple changes in order to run MIDlets that require the JSR-82 API:


    1. Place any JSR-82 implementation in the /mpp-sdk folder. I’ve tested with the following JSR-82 implementations: Avetana (requires a license) and BlueCove (free open-source alternative).
    2. Rename that file to be called bt.jar.

After you make those two changes, you will be able to run any application requires the JSR-82 APIs.

Question 2: Hi Bruce, this is a nice article. I would like to know how to get GPS data from a mobile phone that already has a GPS receiver built-in.

Answer 2: If your mobile phone is MSA-compliant and already has a GPS radio built-in, then you don’t need to use the JSR-82 API to connect to a remote GPS receiver. All you need to do is use the JSR-179 Location APIs in order to retrieve your location data from an embedded GPS receiver. If you’d like to get started with the JSR-179 API, then Qusay Mahmoud has written a great article, Java ME and Location-Based Services, on that topic.

Question 3: I have a Bluetooth-enabled GPS receiver: the Holux Slim 236. I also have a Bluetooth-enabled computer. Can I run this example with what I have?

Answer 3: Yes, you should have no problem running the example code using the tools that you have. If you plan to use the current version of Mpowerplayer, then be sure to follow the instructions in the answer to Q1 first.

Question 4: Hi Bruce, thanks for creating this meaningful guide for developers. Your original article shows developers how to use the Avetana Bluetooth JSR-82 implementation with the Mpowerplayer SDK. The problem, however is that Aventana implementation only provides a free 14-day trial, and afterwards requires a license fee. Is there any way to configure the Mpowerplayer with the BlueCove JSR-82 implementation which is open source?

Answer 4: Yes, please refer to the answer provided to Q1 listed above in order to find out how to use the BlueCove library with the MPowerplayer SDK.

Question 5: Hi, I am having problem with this example with WTK 2.5.2 and NetBeans IDE 6.1 which are both installed in my PC. When I run this application on my PC, I’m not able to get any data from the remote Bluetooth devices.

Answer 5: Actually, the whole point of Part 1 in the two-part series was to show developers how to debug and test their JSR-82 applications on their PCs using the Mpowerplayer. Neither the WTK, the NetBeans IDE, nor the Java ME SDK have the ability to leverage the Bluetooth hardware of your PC in order to discover or search for services on remote Bluetooth devices.

Question 6: I have a Bluetooth-enabled phone with a built-in GPS receiver. I want to send NMEA data from the phone to a Bluetooth-enabled PC. I have a desktop application (Streets & Trips) that can consume GPS data. Since my phone support GPS and Bluetooth, is there a Java ME application that will enable my mobile phone to do this?

Answer 6: I don’t know of any Java ME applications that do this, however this sounds like the basis for another article!

Final Thoughts

Thanks to all the readers who took the time to provide feedback to this article series! Your input, thoughts, questions, and ideas are always welcome and appreciated.

By Xueming Shen

It's well known that creating a Jar file can be a "little" slow. How slow? On my aged SunBlad1000, it takes about 1 minute and 40 seconds to jar the whole rt.jar in cf0M mode (no compress, no manifest) -- and it costs you a little more if done in compress mode.

But then we figured we were talking about creating jars for ten of thousands of classes with a total size of over 50M. Given the number of files and the total size, it seemed a reasonable amount of time. So, until now, we assumed it really needed that time — until someone accidentally noticed that "the CPU went to 100% busy for quite some time, perhaps a minute or more on my laptop, before starting to hit the disk to create the Jar archive."

That sounds strange, as the main job the Jar is supposed to do is to copy and compress the files (into the Jar). Thus it should hit the disk from the very beginning to the end.

So I peeked into the Jar source code (after many years), and it turned out we had a very embarassing bug in the jar code: We were doing a O(n) look-up on a Hashtable (via the contains() method) for each and every file we were jarring, where it really should be a O(1) look-up operation with a HashSet. Given the number of files the command is working on, this simple mistake caused us to spend the majority of the time (that 1 min 40+ seconds) in collecting the list of files that need to jar, instead of the real "jarring" work. Sigh:-(

With that fixed (in JDK 7 build44 and later), the Jar is now much faster.

Following are the quick time-measure numbers of 10 runs of jarring/zipping the rt.jar/zip, in Store Only mode and Zip Compression mode.

  • b43: the JDK 7/build43, which does not have the fix.
  • b47: the JDK 7/build47, which does have the fix.
  • zip: the default zip installed on my Solaris, which is zip2.3/1999

jar cf0M / zip -r0q (store, no zip compression)
Build 43 Build 471 Zip
1:43.7 20.6 10.2
1:40.3 20.2 9.2
1:40.1 21.0 9.0
1:40.5 19.6 10.4
1:40.9 19.6 8.7
1:40.2 19.6 9.1
1:40.0 18.6 10.0
1:39.1 20.0 8.6
1:41.3 18.5 9.0
1:42.1 19.6 9.6
jar cfM/zip -rq (with zip compression)
Build 43 Build 471
Zip
1:47.0 25.3 15.7
1:45.9 23.4 14.2
1:44.7 23.3 14.9
1:45.4 23.7 14.3
1:45.6 23.3 14.3
1:44.9 23.6 14.0
1:45.9 23.2 14.6
1:44.0 23.0 14.2
1:44.9 23.3 14.8
1:45.8 23.5 14.2
1 The fix is in JDK 7 only, for now.

This page contains details of the fix.

We are making much progress on the Jar tool, and it is performing much better, though it is still slower compared to the Zip command. So we will continue our efforts going forward. I have to admit I do have some code that make Jar processing time much closer to Zip, but it will take time to make it into the product. Stay tuned!

Xueming Shen is an engineer at Sun Microsystems, working in the Java core technologies group.

By Vikram Goyal

Developing location-aware applications seems like a lot of work, especially since getting started seems to be the hardest part. In this tech tip, I will show you how to get started using the Location API (JSR 179) to get over the initial hurdle, and build a small location-aware application that you can use to tag your favorite spots.

I have tested and verified that the MIDlet works on a Nokia N95 device. When testing this on your device, make sure that it supports the Location API (JSR 179).

There are three steps in this tech tip

  1. Find and initialize a location provider
  2. Listen and act on location updates given by this provider
  3. Store and list favorite spots
The following paragraphs elaborate on these steps. It may help to have the entire source code of this MIDlet available for review while following the code snippets in these steps.

Step 1: Find and initialize a location provider

The process of discovery of a suitable location provider is broken down into two further steps. First, you need to create a set of criteria for the location provider. Second, you need to create an instance of this provider using these criteria.

The Location API provides two classes for these two steps: Criteria and LocationProvider.

To create a valid criteria, you create an instance of this class, set various parameters of the criteria. The code below, taken from the source code, creates a criteria that is suitable for our purposes.


  // create a very basic criteria for the provider
  Criteria criteria = new Criteria();
  criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setPreferredResponseTime(Criteria.NO_REQUIREMENT);
  criteria.setCostAllowed(false);

As you can see, this is a very relaxed criteria. There are no specific requirements for horizontal or vertical accuracy or for response times. The only restriction is that there should not be a cost involved in using the Location API (possibly linked to the network provider).

We should be allowed to proceed only if the Location API built into your device can provide a provider based on these criteria. We do so, by asking the LocationProvider class for a provider using these criteria as the guiding set.


  // get the provider based on this criteria
  LocationProvider provider = LocationProvider.getInstance(criteria);

  // provider found
  if (provider != null) {
    provider.setLocationListener(this, -1, 0, 0);
  } else {
    display.setCurrent(
      new Alert("Error!",
      "Phone does not support Location Provider with the given criteria",
      null, AlertType.ERROR));
  }

If a provider with the given criteria cannot be found, a message is given to the user, and the MIDlet cannot proceed. But if the device can provide a valid location provider, the MIDlet sets up a location listener to listen to all the updates given by the location provider. In this case, the listener is the MIDlet itself.

Step 2: Listen and act on location updates

In the previous step, the location listener is set to the MIDlet itself. This means that the MIDlet must implement two methods provided by the LocationListener class. These two methods are locationUpdated(LocationProvider lp, Location l) and providerStateChanged(LocationProvider lp, int newState). The code below shows the implementation of the locationUpdated method.


  // if valid location is found, update the coords and status
  if(location != null && location.isValid()) {
    QualifiedCoordinates coords = location.getQualifiedCoordinates();
    coordsDisplay.setText(
      truncate(coords.getLatitude()) + ", " +
      truncate(coords.getLongitude()));
    statusDisplay.setText("Available");
    currentLocation = location;
  } else {
    coordsDisplay.setText("--, --");
    statusDisplay.setText("Unavailable");
    currentLocation = null;
  }

Each time the location of the device is updated, the location provider sends out the new location using the Location parameter in the locationUpdated method. The new location's coordinates can be picked using the getQualifiedCoordinates method.

Of course, if the device is out of range of the GPS satellites, then the provider will not be able to get the correct coordinates and, therefore, the actual location will be either null or invalid. The method checks for this before updating the status and the current location of the device.

The providerStateChanged method accepts updates when the location provider goes in and out of range of the GPS satellites. However, I found that my implementation on the Nokia N95 did not reliably send out updates for the providerStateChanged method. I therefore used the locationUpdated method to find out the status of the provider, However, I have kept the code in the providerStateChanged in case it works on other devices.

NOTE

To be on the safe side, the code in the locationUpdated method (and the corresponding providerStateChanged method) should be in its own thread to make sure that it doesn't block the normal MIDlet thread.

Step 3: Store and list favorite spots

Once the current location using the latitude and longitude have been found, it is a simple method to store this location with a tag as your favorite spot. The Location API makes it ridiculously simple by providing the Landmark store. You can either create your own Landmark store, or use the default one.

The default Landmark store is shared by all the MIDlets within the device. You create a Landmark store by using the static method provided by the LandmarkStore class. By passing in null, as shown in the following code, you are asking for the default store from this instance.

  store = LandmarkStore.getInstance(null);

The Landmark store contains the details of a location using the Landmark class. As shown in the following code, you can create a landmark by giving it a name (provide by you as a name for your favorite spot), a description (this is empty in the code below), and of course, the all important coordinates. The last parameter that is accepted by this constructor is an AddressInfo object that can be used to store actual address information, if supported by the provider. In this case, I have kept these details as simple as possible.


    // create the landmark
    Landmark landmark =
      new Landmark(name, "", currentLocation.getQualifiedCoordinates(), null);

    // and save it
    try {
      store.addLandmark(landmark, null);

      display.setCurrent(
        new Alert("Message", "Done", null, AlertType.INFO), displayForm);

      return;

    } catch(Exception ex) {
      handleError(ex);
    }

Once you have created the landmark, you can store it in the store using the addLandmark method. The second parameter specifies a category for that landmark, but I have kept it simple by putting it in the default category.

The list of existing landmarks can be retrieved using the getLandmarks method. This returns an enumeration that can be iterated over to display to the user in a list. This is shown in the following code.


  Enumeration en = store.getLandmarks();
  while(en.hasMoreElements()) {
    Landmark landmark = (Landmark)en.nextElement();
    landmarkList.append(
      landmark.getName() +
      " - " +
      truncate(landmark.getQualifiedCoordinates().getLatitude()) + ", " +
      truncate(landmark.getQualifiedCoordinates().getLongitude()), null);

Resources

by Paul Sandoz

Jersey is an open-source, production-ready reference implementation of JAX-RS, the Java API for RESTful Web Services (JSR-311). JAX-RS is an annotation-driven API that makes it easy to build Java-based RESTful web services that adhere to the REST architectural style. The JAX-RS API is standardized by the Java Community Process. The JAX-RS API is currently at version 1.0 and Jersey is at version 1.0.2.

Jersey provides additional value beyond the JAX-RS API. It provides its own APIs that support Atom's XML format, MIME MultiPart message format , JavaScript Object Notation (JSON), Web Application Description Language (WADL), as well as Spring framework integration. Jersey is shipped with GlassFish and is available from the GlassFish version 2 and version 3 update centers.

An earlier Tech Tip, Implementing RESTful Web Services in Java, introduced RESTful Web Services, JAX-RS, and Jersey. It also showed how you can write RESTful web services that conform to the JAX-RS specification. Other tips on Jersey-related topics described how to configure JSON for RESTful web services in Jersey 1.0 and how to consume RESTful web services with the Jersey client API.

In this tip, you will learn how to use Jersey's integrated support for Spring, a framework for building and running enterprise Java applications. You'll learn how to configure Spring with Jersey and use Jersey's Spring-related features. The tip assumes that you are familiar with Spring concepts. If not, refer to the Spring Tutorial.

Creating a Basic Web Application

To demonstrate Jersey's Spring-related features, you'll first create a simple web application, one that does not use Spring and then change it to use Spring. Let's use the Maven 2 software project management tool to build the simple web application. If you're not familiar with Maven, see Welcome to Maven and Building Web Applications with Maven 2.

First, create a Maven 2 project by running the following Maven 2 archetype plugin in a command line:

   mvn archetype:generate -DarchetypeCatalog=http://download.java.net/maven/2

In response, Maven 2 will prompt you to choose an archetype, that is, a Maven 2 project template, from the archetypes listed in the archetype catalog, archetype-catalog.xml, at URL http://download.java.net/maven/2:

   Choose archetype:
   1: http://download.java.net/maven/2 -> jersey-quickstart-grizzly (Archetype for creating a RESTful web application with Jersey and Grizzly)
   2: http://download.java.net/maven/2 -> jersey-quickstart-webapp (Archetype for creating a Jersey based RESTful web application WAR packaging)
   Choose a number:  (1/2):

Choose 2, jersey-quickstart-webapp. You will then be prompted for a group ID and an artifact ID. Enter example.jersey.spring for the group ID and example-spring-jersey for the artifact ID. Accept the default values for the other prompts.

After you confirm the inputs, Maven 2 creates a new subdirectory called example-spring-jersey, which contains a template for the new Jersey-based web application. Figure 1 shows the expanded structure of the example-spring-jersey directory.

Expanded Structure of the example-spring-jersey directory

Figure 1. Expanded Structure of the example-spring-jersey directory

Maven 2 also creates a Project Object Model (POM) file, pom.xml, which contains an XML representation of the Maven project. You can find the pom.xml file in the example-spring-jersey directory. If you navigate below the example-spring-jersey directory to src/main/java/example/jersey/spring, you'll see a Java class named MyResource that represents a resource used in the application. You'll also find a web.xml file for the web application in the src/main/webapp/WEB-INF directory.

Let's build, deploy, and test the web application to see if it works. To build the application, go to the example-spring-jersey directory and enter the following command:

   mvn clean install

In response, Maven 2 compiles the source code and creates an example-spring-jersey.war file for the application.

To deploy the application, GlassFish V3 Prelude must be running. Start GlassFish V3 Prelude if it isn't already running. To start GlassFish V3 Prelude, enter the following command:

   <GF_install_dir/bin>asadmin start-domain domain1

where <GF_install_dir/bin> is the directory where you installed GlassFish v3 Prelude.

Deploy the application to GlassFish v3 Prelude using the following command:

   asadmin deploy --force=true target/example-spring-jersey.war

Finally, you can verify that the deployed application runs by using the command line tool, curl, as follows:

   curl -v http://localhost:8080/example-spring-jersey/webresources/myresource

In response, you should see the following output in the command window:

   * About to connect() to localhost port 8080 (#0)
   *   Trying 127.0.0.1... connected
   * Connected to localhost (127.0.0.1) port 8080 (#0)
   > GET /example-spring-jersey/webresources/myresource HTTP/1.1
   > User-Agent: curl/7.17.1 (i586-pc-mingw32msvc) libcurl/7.17.1 OpenSSL/0.9.7c zib/1.2.3
   > Host: localhost:8080
   > Accept: */*
   >
   < HTTP/1.1 200 OK
   < X-Powered-By: Servlet/2.5
   < Server: Sun Java System Application Server 9.1_02
   < Content-Type: text/plain
   < Transfer-Encoding: chunked
   < Date: Thu, 02 Apr 2009 22:18:29 GMT
   <
   Hi there!* Connection #0 to host localhost left intact
   * Closing connection #0

You can also verify the application by pointing your browser to the URL http://localhost:8080/example-spring-jersey/webresources/myresource. You should see the following text displayed on the page: Hi there!

Transforming the Web Application to Use Spring

Now let's change the web application to use Spring. To do that, you need to take the following actions:

Modify the pom.xml File: Recall that one of the files generated when you created the Maven 2 project for the web application is a pom.xml file that represents the Maven project. Replace the contents of the pom.xml file with the content shown here.

The replacing code simplifies the Maven configuration to only use the required dependencies for this example. Note especially the following code, which adds the Jersey Spring dependency, using the jersey-spring module:

   <dependency>
       <groupId>com.sun.jersey.contribs</groupId>
       <artifactId>jersey-spring</artifactId>
       <version>${jersey-version}</version>
   </dependency>

Create a Spring Application Context Configuration: The Spring application context configuration file specifies an application's configuration for initialization by Spring. You need to create a Spring application context configuration file for the web application. Create a file applicationContext.xml and put it in the src/main/resources directory. The file should have the following content:

   <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
       <context:component-scan base-package="example.jersey.spring"/>
   </beans>

This configuration directs Spring to use autowiring with Spring-based annotations and to scan for Spring-based resources in the Java package example.spring.jersey. Autowiring is a feature in Spring that allows it to introspect bean classes for dependencies so that you do not have to explicitly specify bean properties or constructor arguments.

Modify the web.xml File: Replace the contents of the web.xml file with the content shown here.

The following code in the updated web.xml file declares the Spring application context configuration, created earlier as a servlet context parameter:

   <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:applicationContext.xml</param-value>
   </context-param>

The updated content also declares two listeners. The first configures Spring and the second configures Spring for use with the request scope for Spring beans.

   <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>
   <listener>
          <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
   </listener>

Then, the file declares the Jersey Spring servlet, which supports the Jersey integration with Spring.

   <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
   </servlet>

Modify the Root Resource Class: Modify the MyResource.java file in the src/main/java/example/jersey/spring directory with the following content:

   package example.jersey.spring;

   import javax.ws.rs.GET;
   import javax.ws.rs.Path;
   import javax.ws.rs.Produces;
   import org.springframework.context.annotation.Scope;
   import org.springframework.stereotype.Component;

   // The Java class will be hosted at the URI path "/myresource"
   @Path("/myresource")
   @Component
   @Scope("request")

   public class MyResource {

       // The Java method will process HTTP GET requests
       @GET
       // The Java method will produce content identified by the MIME Media
       // type "text/plain"
       @Produces("text/plain")
       public String getIt() {
           return "Hi there!";
       }
   }

The @Component annotation declares that the class is a Spring bean class. The @Scope("request") annotation declares that instances of this class will be instantiated within the scope of the HTTP request. This highlights a difference between the default scopes for JAX-RS or Jersey and Spring. The default scope for JAX-RS is per request. By comparison, the default scope for Spring is a singleton, that is, one instance per web application. See Supported Scopes for more information about the scopes that Jersey supports.

The MyResource root resource class is functionally equivalent to the root resource class that you originally created, but it's now Spring-enabled.

Verify that the Spring-enabled web application deploys and executes by entering the following commands in a command line:

   mvn clean install
   asadmin deploy --force=true target/example-spring-jersey.war
   curl -v http://localhost:8080/example-spring-jersey/webresources/myresource

After the Spring-enabled web application is successfully deployed, you should see output similar to the following in the server.log (<GF_install_dir>/glassfish/domains/domain1/logs/server.txt):

   [PWC1412: WebModule[/example-spring-jersey] ServletContext.log():Initializing Spring root WebApplicationContext|#]
   [INFO| Root WebApplicationContext: initialization started|]
   [INFO| Refreshing org.springframework.web.context.support.XmlWebApplicationContext@53ecec: display name [Root WebApplicationContext]; startup date [Mon Apr 06 14:37:02 PDT 2009]; root of context hierarchy|#]
   [INFO| Loading XML bean definitions from class path resource [applicationContext.xml]|#]
   [INFO| Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@53ecec]: org.springframework.beans.factory.support.DefaultListableBeanFactory@c0267a|#]
   [INFO| Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c0267a: defining beans [myResource,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor]; root of factory hierarchy|#]
   [INFO| Root WebApplicationContext: initialization completed in 891 ms|#]
   [INFO| Loading application example-spring-jersey at /example-spring-jersey|#]
   [INFO| Deployment of example-spring-jersey done is 4500 ms|#]
   [INFO| Registering Spring bean, myResource, of type example.jersey.spring.MyResource as a root resource class|#]

Notice the final line that begins "Registering Spring bean". This is output from Jersey. Jersey knows that the class MyResource is a root resource class and also a Spring bean class. No Jersey-specific configuration was required to register root resource classes, as was the case in the web.xml for the original version of the web application.

Because Spring is used to register Spring beans, in this case using autowiring, Jersey leverages Spring to perform registration rather that requiring duplicate registration. It is possible to intermix Spring-managed and Jersey-managed root resource classes by using Jersey's registration mechanism. It does not matter if both Spring and Jersey find the same class -- only one reference to the class will be managed appropriately.

Supported Scopes

Jersey supports the following Spring scopes:

  • Request. Scopes a single Spring bean definition to the lifecycle of a single HTTP request, that is, each HTTP request has its own instance of a Spring bean created from a single Spring bean definition. This scope requires that you declare the Spring RequestContextListener servlet context in the web.xml file for the web application.
  • Singleton. Scopes a single Spring bean definition to a single object instance per web application.
  • Prototype. Scopes a single Spring bean definition to multiple object instances. A new Spring bean instance is created for each request for that specific bean.

You can inject Jersey artifacts into fields of Spring bean instances according to the scoping rules. If the scope is prototype, then the scoping rules for request apply. If Jersey does not recognize the scope, then it assumes a scope of singleton for the purpose of injection.

For example, you can modify the MyResource class in the Spring-enabled Web application to include an @QueryParam for injection. Here is what the modified class looks like:

   package example.jersey.spring;

   import javax.ws.rs.GET;
   import javax.ws.rs.Path;
   import javax.ws.rs.Produces;
   import javax.ws.rs.QueryParam;
   import org.springframework.context.annotation.Scope;
   import org.springframework.stereotype.Component;

   // The Java class will be hosted at the URI path "/myresource"
   @Path("/myresource")
   @Component
   @Scope("request")
   public class MyResource {
       @QueryParam("x") String x;

       // The Java method will process HTTP GET requests
       @GET
       // The Java method will produce content identified by the MIME Media
       // type "text/plain"
       @Produces("text/plain")
       public String getIt() {
           return "Hi there! " + x;
       }
   }

In response, Jersey should inject the information into the Spring bean in request scope, that is, per request. To test that, you can redeploy and execute the updated application by entering the following commands in a command line window:

   mvn clean install
   asadmin deploy --force=true target/example-spring-jersey.war
   curl -v http://localhost:8080/example-spring-jersey/webresources/myresource?x=curl

The application should return "Hi there! curl" in the output. If it does, this verifies that Jersey can correctly inject information into the Spring bean per request.

Summary

This tip showed you how to use some of Jersey's Spring-related features. But there are other useful elements to Jersey's support for Spring. Some of the these are:

  • You can take advantage of the JAX-RS support for hierarchical URI path matching to further match a URI path that was not already matched by a root resource. This means that you can include a subresource locator method in a resource to return an instance of a newly created Spring bean class. You use the Jersey ResourceContext class to obtain the instance.
  • You can inject Spring beans into JAX-RS-based methods. You do this with the Jersey @Inject annotation.
  • You can use Jersey Spring-based Aspect-Oriented Programming (AOP).
  • You can have Spring instantiate a resource class, but have Jersey manage the resource class's lifecycle.

Further Reading

For more information on Jersey and Spring, see the following resources:

About the Author

Paul Sandoz is the co-spec lead and implementation lead for JSR 311: Java API for RESTful Web Services. He has participated in the W3C, ISO, and ITU-T standards organizations and contributed various performance-related technologies and improvements to the GlassFish web services stack, particularly in standardization, implementation, integration, and interoperability of Fast Infoset.


2009 JavaOne Conference, June 2-5, San Francisco ** Register Now**

Stay on top of everything new and different, both inside and around Java technology. Register by April 22, 2009, and save $200 off a Conference Pass or Conference Plus Pass. Register now at http://java.sun.com/javaone.

By Bruce Hopkins

Java technology is an integral part of the new high-definition video standard: the Blu-ray Disc standard. In the past year, Sun published a two-part series to lower the learning curve for Java developers who want to get started using the Blu-ray Disc for Java (BD-J) platform.

In Part 1: Creating Your First Application, I provided an introduction to the BD-J platform and provided information on the various APIs that are required by BD-J, including GEM/MHP (Globally Executable Multi Home Platform) and Java TV. In Part 2: Responding to User Input, I showed you how to use the Java ME SDK to create an application that can respond to the user via the remote.

Among the thousands of readers of this series, several readers submitted the following questions in the Comments section of the articles.

Question: Is it really a good idea to use org.havi and org.dvb classes? Will this work on all Blu-ray players?

Answer: Yes, it is perfectly fine to use any of the use org.havi and org.dvb classes that are a part of the BD-J specification. Specifically, those classes originate from the GEM/MHP layer of the BD-J software stack, and all Blu-ray players must support them. Please refer to Part 1, where I provide a complete list of all the Java packages that must be supported in all Blu-ray players on the market (including PC-based Blu-ray players).

Question: I have following the problem when I compile the source file:

Fatal Error: Unable to find package java.lang in classpath or bootclasspath
Details message: target="${javac.target}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
debug="${javac.debug}"
srcdir="${buildsystem.baton}" destdir="${build.classes.dir}"
bootclasspath="${platform.bootclasspath}"
includes="${javac.includes}"
encoding="${javac.encoding}">

Answer: If you’re using the Java ME SDK 3.0 platform and you’re having a compilation error, then please refer to the instructions provided in Part 2: I list step-by-step instructions on how to set up the Java ME SDK 3.0 to compile BD-J applications. Note that the Java ME SDK 3.0 cannot compile BD-J applications in its default state after you install the SDK. It must be configured with the BD-J libraries to compile BD-J applications.

Final Thoughts

Thanks to all the readers who took the time to provide feedback to this article series! Your input, thoughts, questions, and ideas are always welcome and appreciated.

Over the years, the Enterprise Java Technologies Tech Tips have covered a wide variety of enterprise Java technology topics. Here's a short quiz that tests your knowledge of some topics covered in recent Tech Tips. You can find the answers at the end of the quiz.

  1. You are developing an application that uses the Jersey 1.0.2 Client API to consume a RESTful web service. You create a Client object for the RESTful web service client. What do you need to create next so that the Client object can be used to issue web service requests?

    a. A ClientPipe object.
    b. A WebResource object.
    c. A ServiceRequest object.
    d. A ClientFactory object.
    e. None of the above.

  2. The following code snippet appears in a program that uses JAXB 2.0 to marshal an XML document:
       import javax.xml.bind.*;
       import a.JustAType;
       import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
    
          NamespacePrefixMapper m = new PreferredMapper();
                         marshal(jc, e, m);
    
             public static class PreferredMapper extends NamespacePrefixMapper {
                    @Override
                    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                      return "mappedNamespace" + namespaceUri;
                    }
              }
    
    

    What does the getPreferredPrefix() method in the PreferredMapper class do?

    a. Returns the preferred prefix, mappedNamespace to be declared at the root element of the marshalled XML.
    b. Returns the preferred namespace prefix, jc, and namespace URI, mappedNamespacee, to be declared at the root element of the marshalled XML.
    c. Returns the preferred prefix, mappedNamespacea, to be declared at the root element of the marshalled XML.
    d. Returns a list of preferred namespace prefixes, jc, e, and m, to be declared in elements of the marshalled XML.
    e. None of the above.

  3. The javafx.servlet.sip.SipFactory interface provides utility methods to create a Session Initiation Protocol (SIP) request in an enterprise application. Which of the following statements about the SipFactory interface is true?

    a. A SipFactory instance can be injected into a Java EE component such as an EJB or MJB using the @SIP annotation.
    b. A SipFactory instance cannot be used in a Converged Enterprise Application.
    c. SipFactory instances that belong to multiple SIP applications can be injected into a Java EE component, whether the applications are co-located in the same .ear file or not.
    d. A SipFactory is specific to a SIP application and there can be only one SipFactory instance for each SIP application.

  4. Metro supports the WS-Trust specification. Which of the following is not true about the WS-Trust support in Metro:

    a. Supports token refactoring.
    b. Supports token issuance and token validation protocols.
    c. Supports the Security Token Service (STS) framework
    d. Supports issuing SAML 1.0, SAML 1.1 and SAML 2.0 tokens, by default.
    e. Supports the issuing of symmetric proof keys, public proof keys, and no proof keys.

  5. Fill in the blank: When SOAP attachments are used in a SOAP message, the SOAP message is accompanied by a MIME header and possibly ________ _________.

    a. Cipher references
    b. STS tokens
    c. Boundary parts
    d. User profiles
    e. Signature values

Answers

  1. You are developing an application that uses the Jersey 1.0.2 Client API to consume a RESTful web service. You create a Client object for the RESTful web service client. What do you need to create next so that the Client object can be used to issue web service requests?

    a. A ClientPipe object.
    b. A WebResource object.
    c. A ServiceRequest object.
    d. A ClientFactory object.
    e. None of the above.

  2. b. A WebResource object. After you create a Client instance, you can start using it. However, to issue requests, you need to create a WebResource object, which encapsulates a web resource for the client. You use the WebResource object to build requests to send to the web resource and to process responses returned from the web resource. For example, you can use the WebResource object for HTTP GET, PUT, POST, and DELETE requests. For more information about using the Jersey 1.0.2 Client API, see the February 26, 2009 Tech Tip, Consuming RESTful Web Services With the Jersey Client API.

  3. The following code snippet appears in a program that uses JAXB 2.0 to marshal an XML document:
       import javax.xml.bind.*;
       import a.JustAType;
       import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
    
          NamespacePrefixMapper m = new PreferredMapper();
                         marshal(jc, e, m);
    
             public static class PreferredMapper extends NamespacePrefixMapper {
                    @Override
                    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                      return "mappedNamespace" + namespaceUri;
                    }
              }
    
    

    What does the getPreferredPrefix() method in the PreferredMapper class do?

    a. Returns the preferred prefix, mappedNamespace to be declared at the root element of the marshalled XML.
    b. Returns the preferred namespace prefix, jc, and namespace URI, mappedNamespacee, to be declared at the root element of the marshalled XML.
    c. Returns the preferred prefix, mappedNamespacea, to be declared at the root element of the marshalled XML.
    d. Returns a list of preferred namespace prefixes, jc, e, and m, to be declared in elements of the marshalled XML.
    e. None of the above.

    c. Returns the preferred prefix, mappedNamespacea, to be declared at the root element of the marshalled XML. JAXB 2.0 (or later) provides a service provider interface (SPI) named com.sun.xml.bind.marshaller.NamespacePrefixMapper that you can use to specify helpful namespace prefixes for marshalling. You implement the SPI and pass it to the Marshaller. One of the methods in the NamespacePrefixMapper class is getPreferredPrefix(), which returns a list of namespace URIs that should be declared at the root element. In the code snippet, the getPreferredPrefix() method in the PreferredMapper class returns the preferred prefix, in this case, mappedNamespacea to be declared at the root element of the marshalled XML, as follows:

       <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
       <mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
           <foo>true</foo>
       </mappedNamespacea:JustAnElement>
    
    
    To learn more about customizing namespace prefixes during marshalling, see the December 2, 2008 Tech Tip Customizing JAXB.

  4. The javafx.servlet.sip.SipFactory interface provides utility methods to create a Session Initiation Protocol (SIP) request in an enterprise application. Which of the following statements about the SipFactory interface is true?

    a. A SipFactory instance can be injected into a Java EE component such as an EJB or MJB using the @SIP annotation.
    b. A SipFactory instance cannot be used in a Converged Enterprise Application.
    c. SipFactory instances that belong to multiple SIP applications can be injected into a Java EE component, whether the applications are co-located in the same .ear file or not.
    d. A SipFactory is specific to a SIP application and there can be only one SipFactory instance for each SIP application.

  5. d. A SipFactory is specific to a SIP application and there can be only one SipFactory instance for each SIP application. The SipFactory instance is available in the servlet context of a SIP Application as an attribute of javax.servlet.sip.SipFactory. The servlet specification defines specific context attributes that are used to store and retrieve information specific to SIP servlets and interfaces from the context. In the case of Java EE components such as EJBs and MDBs, which are outside the scope of the servlet context, the SipFactory is available as a resource. You can inject the resource into a Java EE component such as an EJB or MJB using the @Resource annotation. For more information about the SipFactory interface, SIP requests, and their use in converged enterprise applications, see the March 13, 2009 Tech Tip, Converged Enterprise Applications.

  6. Metro supports the WS-Trust specification. Which of the following is not true about the WS-Trust support in Metro:

    a. Supports token refactoring.
    b. Supports token issuance and token validation protocols.
    c. Supports the Security Token Service (STS) framework
    d. Supports issuing SAML 1.0, SAML 1.1 and SAML 2.0 tokens, by default.
    e. Supports the issuing of symmetric proof keys, public proof keys, and no proof keys.

    a. Supports token refactoring. Metro is a high performance, extensible, easy-to-use web services stack. It combines the JAX-WS reference implementation with Project Tango. Project Tango, also called Web Services Interoperability Technology or WSIT, implements numerous WS-* standards to enable interoperability with other implementations and to provide Quality of Service (QOS) features such as security, reliability, and transaction support. WS-Trust is a WS-* specification that provides extensions to the WS-Security specification. Metro supports the WS-Trust specification. In supporting WS-Trust, Metro:

    • Supports token issuance and token validation protocols.
    • Supports the STS framework.
    • Supports building an STS as an independent web service.
    • Supports client and service authentication and security with issued tokens from an STS within the general framework of WS-Security and WS-SecurityPolicy.
    • Provides a general framework for building an STS as a web service for issuing security tokens.
    • Supports authentication and secure communication between a client and an STS in the same way as for a regular web service.
    • Supports issuing SAML 1.0, SAML 1.1 and SAML2.0 tokens, by default.
    • Supports the issuing of symmetric proof keys, public proof keys, and no proof keys.
    • Can be extended to support the issuing of other types of tokens.
    • Allows for plugging in additional authorization mechanisms that control the issuing of tokens according to the user's identity and the targeted service.
    • Allows for plugging in user mappings that control the user identity/attributes carried in the SAML token issued by n STS for different services.

    However, it does not support token refactoring. For more information about WS-Trust support in Metro, see the October 14, 2008 Tech Tip Using WS-Trust Support in Metro to Secure Web Services.

  7. Fill in the blank: When SOAP attachments are used in a SOAP message, the SOAP message is accompanied by a MIME header and possibly ________ _________.

    a. Cipher references
    b. STS tokens
    c. Boundary parts
    d. User profiles
    e. Signature values

    c. Boundary parts. When SOAP attachments are used in a SOAP message, the SOAP message is accompanied by a MIME header and possibly multiple boundary parts. This is known as a SOAP message package. The primary SOAP envelope is generally conveyed in the first MIME part. The attachments are carried in other MIME parts and are referenced from the SOAP envelope. Learn more about SOAP message attachments and how they can be secured with Metro in the September 29, 2008 Tech Tip Securing Attachments With Metro 1.3.


2009 JavaOne Conference, June 2-5, San Francisco ** Register Now**

Stay on top of everything new and different, both inside and around Java technology. Register by April 22, 2009, and save $200 off a Conference Pass or Conference Plus Pass. Register now at http://java.sun.com/javaone.

By Vikram Goyal

One of the first steps in implementing Bluetooth applications on Java ME devices is the discovery process. In a nutshell, the discovery process is the process by which Bluetooth-enabled devices find each other, and then handshake to find out the services that they can each support. The next step, invariably, is learning how to send data between these paired devices.

In this tech tip, I will show you how to create a MIDlet that will search for devices and services, and then will allow the user to send a simple note to one of the found devices. I have tested and verified that the MIDlet works on a Nokia N95 device, and that it connects to a computer running Windows Vista, with Bluetooth support enabled.

I have broken down the whole process into the following steps:

  1. Start the discovery process.
  2. Query the devices found in the discovery process for supported services.
  3. Initiate and process an OBEX data exchange using the supported service URL.
The following paragraphs elaborate on these steps. It may help to have the whole source code of this MIDlet available for review while following the code snippets in these steps. The source code is available as a zipped file under Resources.

Step 1: Start the discovery process

The discovery process is used to tell the local Bluetooth stack that it should look within the nearby vicinity for any Bluetooth devices that are available for pairing. In the case of the MIDlet, this stack will be the implementation provided by your device provider for JSR 82.

This process of discovery is initiated by the discovery agent present in the local device, as shown in the following code.


    // get the local discovery agent
    agent = LocalDevice.getLocalDevice().getDiscoveryAgent();

    // start the inquiry for general unlimited inquiry
    agent.startInquiry(DiscoveryAgent.GIAC, this);

Once the discovery agent has started the discovery process, it will call various callback methods on a class that implements the DiscoveryListener interface. In our case, this is our MIDlet class.

Specifically, four methods of this interface must be implemented, two of which are interest to us in the discovery phase: deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) and inquiryCompleted(int discType). These two methods handle the discovery of a device and completion of the discovery process, respectively. As shown in the following code from the MIDlet, we use these methods to append our UI with devices as they are discovered and when the process is completed.


  public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
    try {
      // add the devices using the friendly names
      listofDevices.append(btDevice.getFriendlyName(false), null);
      // add to the devices hashtable
      devices.put(new Long(listofDevices.size()), btDevice);
    } catch(Exception ex) { handleError(ex); }
  }

  public void inquiryCompleted(int discType) {
    // once the inquiry is completed, show the list of devices to the user
    if(listofDevices.size() == 0) {
      display.setCurrent(nothing, noteBox);
    } else {
      display.setCurrent(listofDevices);
    }
  }

Step 2: Start the service discovery on discovered devices

Since our aim in this tip is to allow data transfer from our MIDlet to a compatible device, we need to find services on the discovered devices that enable this goal. To do so, we need to specify the correct attributes and UUIDs in our service discovery process. The following code shows how to do so:


  agent.searchServices(
    null,
    new UUID[] {new UUID(0x1105L)}, // we want the OBEX PUSH Profile
    device,
    this);

As you may guess, the code uses the local agent that we had used earlier to search for devices. We are not after a particular set of attributes, so we pass null as the first parameter, but the UUID must be OBEX PUSH profile, as this is the most open way of transferring data.

We talked about the DiscoveryListener interface which has two other methods that can be used to employ discovered services. These two methods are servicesDiscovered(int transID, ServiceRecord[] servRecord) and serviceSearchCompleted(int transID, int respCode). As the names suggest, the first method is called each time a service is discovered, while the second method is called when the service process has completed.

Each time a service is discovered, we need to find out the connection URL for that particular service on the respective device. This connection URL will be used to make the OBEX connection for putting our data across, and consists of the Bluetooth hardware address of the device, among other things. In the code below, this connection URL is retrieved in the servicesDiscovered method:


String connURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);

With this connection URL, we can now move to the process of transferring our data across to the discovered device.

Step 3: Send data using OBEX PUT

In this MIDlet, we are going to allow the user to type some text as a note, and then send that across using the discovered device/service. To do so, we will need the connection URL we got in the previous step (and of course, the note data as a String).


    // open a client session
    ClientSession clientSession =
      (ClientSession) Connector.open(connURL);

    // connect using no headers
    clientSession.connect(null);

    if(rHeaders.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
      // the connection could not be established
      handleError(
        new Exception("Remote client returned invalid response code: " +
          rHeaders.getResponseCode()));
      return;
    }

    // if we are here, then response code was ok

    // create a new set of headers
    HeaderSet headers = clientSession.createHeaderSet();
    headers.setHeader(
      HeaderSet.LENGTH,
      new Long(noteBox.getString().length()));
    headers.setHeader(HeaderSet.NAME, "myNote.txt");
    headers.setHeader(HeaderSet.TYPE, "text/plain");

    // create an operation using the headers we have just created
    Operation op = clientSession.put(headers);

    // on this operation, create the output stream
    OutputStream out = op.openOutputStream();

    // and send the note
    out.write(noteBox.getString().getBytes());

To send the data, a client session is opened and a connection established with empty headers. At this point, your target device will ask for confirmation of receipt of data from a new device. It may also ask you for a passkey if you have never paired the devices before.

Once the connection is established, some headers that explain the purpose of the data are created, and a new Operation created with these headers. The Operation is then used to send the data via the available OutputStream.

The received note will be available in the default Bluetooth exchange folder on the target device.

Resources

By Xueming Shen

The UTF-8 charset implementation, which is available in all JDK/JRE releases from Sun, has been updated recently to reject non-shortest-form UTF-8 byte sequences. This is because the old implementation might be leveraged in security attacks. Since then I have been asked many times about what this "non-shortest-form" issue is and what the possible impact might be, so here are some answers.

The first question usually goes: "What is the non-shortest-form issue"?

The detailed and official answer is at Unicode Corrigendum #1: UTF-8 Shortest Form. Simply put, the problem is that Unicode characters can be represented in more than one way (form) in the "UTF-8 encoding" than many people think or believe. When asked what UTF-8 encoding looks like, the simplest explanation would be the following bit pattern:

# Bits Bit pattern
1 7 0xxxxxxx      
2 11 110xxxxx 10xxxxxx    
3 16 1110xxxx 10xxxxxx 10xxxxxx  
4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

The pattern is close, but it's actually wrong, based on the latest definition of UTF-8. The preceding pattern has a loophole in that you can actually have more than one form represent a Unicode character.

For ASCII characters from u+0000 to u+007f, for example, the UTF-8 encoding form maintains transparency for all of them, so they keep their ASCII code values of 0x00..0x7f (in one-byte form) in UTF-8. Based on the preceding pattern, however, these characters can also be represented in 2-bytes form as [c0, 80]..[c1, bf], the "non-shortest-form".

The following code shows all of the non-shortest-2-bytes-form for these ASCII characters, if you run code against the "old" version of the JDK and JRE (Java Runtime Environment).


    byte[] bb = new byte[2];
    for (int b1 = 0xc0; b1 < 0xc2; b1++) {
        for (int b2 = 0x80; b2 < 0xc0; b2++) {
            bb[0] = (byte)b1;
            bb[1] = (byte)b2; 
            String cstr = new String(bb, "UTF8");
            char c = cstr.toCharArray()[0];
            System.out.printf("[%02x, %02x] -> U+%04x [%s]%n",
                              b1, b2, c & 0xffff, (c>=0x20)?cstr:"ctrl");
        }
    }

The output would be as follows:


...
[c0, a0] -> U+0020 [ ]
[c0, a1] -> U+0021 [!]
...
[c0, b6] -> U+0036 [6]
[c0, b7] -> U+0037 [7]
[c0, b8] -> U+0038 [8]
[c0, b9] -> U+0039 [9]
...
[c1, 80] -> U+0040 [@]
[c1, 81] -> U+0041 [A]
[c1, 82] -> U+0042 [B]
[c1, 83] -> U+0043 [C]
[c1, 84] -> U+0044 [D]
...

So, for a string like "ABC", you would have two forms of UTF-8 sequences:


"0x41 0x42 0x43" and "0xc1 0x81 0xc1 0x82 0xc1 0x83"

The Unicode Corrigendum #1: UTF-8 Shortest Form specifies explicitly that "The definition of each UTF specifies the illegal code unit sequences in that UTF. For example, the definition of UTF-8 (D36) specifies that code unit sequences such as [C0, AF] are illegal."

Our old implementation accepts those non-shortest-form (while it never generates them when encoding). The new UTF_8 charset now rejects the non-shortest-form byte sequences for all BMP characters. Only the "legal byte sequences" listed below are accepted.


    /*  Legal UTF-8 Byte Sequences
     *
     * #    Code Points      Bits   Bit/Byte pattern
     * 1                     7      0xxxxxxx
     *      U+0000..U+007F          00..7F
     * 2                     11     110xxxxx    10xxxxxx
     *      U+0080..U+07FF          C2..DF      80..BF
     * 3                     16     1110xxxx    10xxxxxx    10xxxxxx
     *      U+0800..U+0FFF          E0          A0..BF      80..BF
     *      U+1000..U+FFFF          E1..EF      80..BF      80..BF
     * 4                     21     11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
     *     U+10000..U+3FFFF         F0          90..BF      80..BF      80..BF
     *     U+40000..U+FFFFF         F1..F3      80..BF      80..BF      80..BF
     *    U+100000..U10FFFF         F4          80..8F      80..BF      80..BF
     */

The next question usually is: "What would be the issue/problem if we keep using the old version of JDK/JRE?"

First, I'm not a lawyer — oops, I meant I'm not a security expert:-) — so my word does not count. We consulted with our security experts instead. Their conclusion is that while "it is not a security vulnerability in Java SE per se, it may be leveraged to attack systems running software that relies on the UTF-8 charset to reject these non-shortest form of UTF-8 sequences".

A simple scenario that might give you an idea about what the above "may be leveraged to attack..." really means:

  1. A Java application would like to filter the incoming UTF-8 input stream to reject certain key words, for example "ABC".
  2. Instead of decoding the input UTF-8 byte sequences into Java char representation and then filter out the keyword string "ABC" at Java "char" level, for example:
    
           String utfStr = new String(bytes, "UTF-8");
           if ("ABC".equals(strUTF)) { ... }
    
    The application might choose to filter the raw UTF-8 byte sequences "0x41 0x42 0x43" (only) directly against the UTF-8 byte input stream and then rely on (assume) the Java UTF-8 charset to reject any other non-shortest-form of the target keyword, if there is any.
  3. The consequence is the non-shortest form input "0xc1 0x81 0xc1 0x82 0xc1 0x83" will penetrate the filter and trigger a possible security vulnerability, if the underlying JDK/JRE runtime is an OLD version.

So the recommendation is: Update to the latest JDK/JRE releases to avoid the potential risk.

Wait, there is another big bonus for updating: performance.

The UTF-8 charset implementation has not been updated or touched for years. UTF-8 encoding is very widely used as the default encoding for XML, and more and more websites use UTF-8 as their page encoding. Given that fact, we have taken the defensive position of "don't change it if it works" during the past years.

So Martin and I decided to take this opportunity to give it a speed boost as well. The following data is from one of my benchmark's run data, which compares the decoding/encoding operations of new implementation and old implementation under -server vm. (This is not an official benchmark: it is provided only to give a rough idea of the performance boost.)

The new implementation is much faster, especially when decoding or encoding single bytes (those ASCIIs). The new decoding and encoding are faster under -client vm as well, but the gap is not as big as in -server vm. I wanted to show you the best:-)


    Method Millis Millis(OLD)
    Decoding 1b UTF-8         :  1786  12689
    Decoding 2b UTF-8         : 21061  30769
    Decoding 3b UTF-8         : 23412  44256
    Decoding 4b UTF-8         : 30732  35909
    Decoding 1b (direct)UTF-8 : 16015  22352
    Decoding 2b (direct)UTF-8 : 63813  82686
    Decoding 3b (direct)UTF-8 : 89999 111579
    Decoding 4b (direct)UTF-8 : 73126  60366
    Encoding 1b UTF-8         :  2528  12713
    Encoding 2b UTF-8         : 14372  33246
    Encoding 3b UTF-8         : 25734  26000
    Encoding 4b UTF-8         : 23293  31629
    Encoding 1b (direct)UTF-8 : 18776  19883
    Encoding 2b (direct)UTF-8 : 50309  59327
    Encoding 3b (direct)UTF-8 : 77006  74286
    Encoding 4b (direct)UTF-8 : 61626  66517

The new UTF-8 charset implementation has been integrated in JDK7, Open JDK 6, JDK 6 update 11 and later, JDK5.0u17, and 1.4.2_19.

If you are interested in what the change looks like, you can take a peek at the webrev of the new UTF_8.java for OpenJDK7.

Xueming Shen is an engineer at Sun Microsystems, working in the Java core technologies group.

by Prasad Subramanian

The February 29, 2008 Tech Tip, Adding Voice to Java EE With SIP Servlets, introduced Session Initiation Protocol (SIP), a signaling protocol that is used to set up, modify, and terminate a session between two endpoints. It also introduced various SIP-related concepts such as a SIP container -- a server-side container of SIP components or services -- and a SIP servlet -- a servlet that runs in a SIP container and that supports the SIP protocol. The tip mentioned that together, SIP and SIP servlets, are behind many popular telecommunications-based applications that provide services such as Voice-over-IP (VoIP), instant messaging, presence and buddy list management, as well as web conferencing. In addition, the tip presented a sample web application that uses SIP servlets and HTTP servlets to provide VoIP phone service.

SIP and SIP servlets are also important in the enterprise. Combined with Java EE technology, SIP servlets can be used to add rich media interactions to enterprise applications. For example, a Java EE-conforming enterprise application that supports SIP could process voice calls or calls in other media. In such an application, an Enterprise JavaBeans (EJB) technology component could set up a SIP-related call and a SIP servlet could invoke an EJB component or a connector resource. The SIP Servlet API v1.1 specification (JSR 289) defines the contract between SIP servlets and a Java EE-conforming enterprise application. JSR 289 makes it easier for application developers to use the Java EE model for developing applications that process SIP requests and responses.

One of the concepts introduced in the earlier tip is that of a converged application, that is, an application that includes both SIP and HTTP servlets. In this tip, you'll learn about converged enterprise applications and how the SIP Servlet API v1.1 specification simplifies the development of converged enterprise applications. You'll also find a sample converged enterprise application that demonstrates the concepts and techniques covered in this tip.

What's a Converged Enterprise Application?

A converged enterprise application is an enterprise application that has a SIP servlet application bundled within it. An enterprise application is typically packaged in an enterprise archive file whose extension is .ear. The package may include an application.xml file, which describes the content of the modules within the enterprise application. Here, the term module refers to the web application and any EJB or connector archive files bundled within the application. Note that including an application.xml in an enterprise application package is optional. However, even if an application.xml file is not included, it is possible to bundle a SIP application within the enterprise application. In this case, the SIP Application is bundled in the same way as other applications such as web applications or the way EJB modules are bundled in a descriptor-less enterprise application.

A converged enterprise application is also packaged in an enterprise archive file with a .ear extension. The bundled SIP application is described as a web module in the application.xml file. The following code snippet is an example of how a bundled SIP application is described in an application.xml file:

   <?xml version="1.0" encoding="UTF-8"?>
   <application version="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/application_5.xsd">
     <display-name>ConvergedEnterprise</display-name>
     <module>
       <web>
         <web-uri>ConvergedSipApplication.war</web-uri>
         <context-root>/ConvergedSipApplication</context-root>
       </web>
     </module>
     <module>
       <ejb>TalkBack.jar</ejb>
     </module>
</application>

Converged Enterprise Applications and SIP

As mentioned earlier, the SIP Servlet API v1.1 specification makes it easier for application developers to use the Java EE model for developing applications that process SIP requests and responses. For example, consider an EJB component such as a Message Driven Bean (MDB). If the MDB receives a message, it could use the APIs defined in SIP Servlet API v1.1 to invoke a SIP request. Similarly, a SIP servlet that receives an INVITE request could invoke an EJB component from the SIP servlet's doInvite() method to do some complex processing logic. Or a connector resource could be invoked from within the SIP Servlet to access an external subsystem such as a Home Subscriber Server (HSS) for authentication or a media server to process media.

Let's examine some aspects of SIP Servlet API v1.1 as it relates to SIP servlets and Java EE components.

SIP Servlet-Java EE Component Interface

The SIP Servlet API v1.1 specification defines the interface between Java EE components and SIP servlet applications. Typically, you invoke a SIP request from a Java EE component such as an EJB MDB or invoke an EJB or connector resource from a SIP servlet.

You use the javax.servlet.sip.SipFactory interface to invoke a SIP request from a Java EE component. This interface provides utility methods to create a SIP request in an enterprise application. The methods are summarized in Table 1. Note that the methods in bold are the ones that are used to create a SIP Request.

Table 1: SipFactory Methods
Method Signature Description
createAddress(java.lang.String addr) Returns an Address object corresponding to the specified string.
createAddress(URI uri) Returns an Address object with the specified URI and no display name.
createAddress(URI uri, java.lang.String displayName) Returns a new Address object with the specified URI and display name.
createApplicationSession() Returns a new SipApplicationSession object.
createApplicationSessionByKey(java.lang.String sipApplicationKey) Returns a new SipApplicationSession object identified by the specified SipApplicationKey.
createAuthInfo() Creates a new AuthInfo object that can be used to provide authentication information on servlet initiated requests.
createParameterable(java.lang.String s) Creates a new Parameterable object parsed from the specified string.
createRequest(SipApplicationSession appSession, java.lang.String method, Address from, Address to) Returns a new request object with the specified request method, From, and To headers.
createRequest(SipApplicationSession appSession, java.lang.String method, java.lang.String from, java.lang.String to) Returns a new request object with the specified request method, From, and To headers.
createRequest(SipApplicationSession appSession, java.lang.String method, URI from, URI to) Returns a new request object with the specified request method, From, and To headers.
createSipURI(java.lang.String user, java.lang.String host) Returns a new SipApplicationSession object identified by the specified SipApplicationKey.
createURI(java.lang.String uri) Returns a URI object corresponding to the specified string, which should represent an escaped SIP, SIPS, or tel URI.
 

A SipFactory instance is specific to a SIP Application and there can only be one SipFactory instance for each SIP Application. The SipFactory instance is available in the servlet context of that SIP Application as an attribute of javax.servlet.sip.SipFactory. Recall that the servlet context as defined in the servlet specification also applies to SIP servlets. The servlet specification defines specific context attributes that are used to store and retrieve information specific to SIP servlets and interfaces from the context. In the case of Java EE components such as EJBs and MDBs, which are outside the scope of the servlet context, the SipFactory is available as a resource. You can inject the resource into a Java EE component such as an EJB or MJB using the @Resource annotation. The syntax of this injection looks like this:

   @Resource(name="sip/app-name/SipFactory") SipFactory sf-app;

where app-name is the name of the SIP application whose SipFactory is being injected. Note that there could be more than one SIP application bundled in the enterprise application. So you need to specify which SipFactory instance to inject into the Java EE component. The app-name is derived based on certain rules. For a description of the rules see the blog Sailfin in detail: Part 1 app-name.

A key constraint here is that only SipFactory instances that belong to SIP applications which are co-located in the .ear file can be injected into a Java EE component.

Let's look at an example. The following code snippet injects the SipFactory instance for the SIP application whose application.xml file was shown earlier. The SipFactory instance is injected as a resource into the EJB component in the TalkBack.jar file.

   @Stateless
   public class TalkBackBeanBean implements TalkBackBeanLocal {

       @Resource(name="sip/ConvergedEnterprise/ConvergedSipApplication/SipFactory")
           SipFactory sf;
       @Resource(name="sip/ConvergedEnterprise/ConvergedSipApplication/SipSessionsUtil")
           SipSessionsUtil ssu;

       public String findWho() {

           SipApplicationSession sas = ssu.getApplicationSessionByKey("CSA", false);
           return (String) sas.getAttribute("newReg");

   }

The app-name in the code snippet above is ConvergedEnterprise/ConvergedSipApplication because there is no explicit app-name defined in the sip.xml deployment descriptor. This follows Case I in the app-name derivation rules.

Accessing a Java EE component from a SIP Servlet

There are two ways to access a Java EE component from a SIP Servlet. The first way is to use annotations. Java EE annotations are supported within a SIP Servlet. For instance, you could use an @EJB annotation to inject an EJB into a SIP Servlet or use a @Resource annotation to inject a connector resource.

The following SIP servlet example demonstrates this approach. Here an @EJB annotation is used to access a bean defined in the TalkBack.jar file. The syntax of the @EJB annotation in the SIP servlet is the same as for HTTP servlets. In this simple example, the SIP servlet invokes the TalkBackBean method in the EJB and returns either a success message or an error message based on the return value from the EJB.

   public class InviteServlet extends SipServlet {


       @EJB(name="TalkBackBean") private TalkBackBeanLocal tbBean;

       //Reference to context - The ctx Map is used as a central storage for this app
       javax.servlet.ServletContext ctx = null;


       /*
        * Processes the INVITE request
        */
       @Override
       protected void doInvite(SipServletRequest req)
               throws ServletException, IOException {

           System.out.println("In the INVITE servlet");
           SipServletResponse resp = null;

           String responseMessage = tbBean.findWho();

           // if the bean returns a non null value, then its a success.
           if(responseMessage != null) {
               resp = req.createResponse(200, "SUCCESS");
           } else {
               resp = req.createResponse(500, "Error");
           }
           resp.send();
    }

The second way to access a Java EE component from a SIP servlet is to specify the to-be-injected EJB in the <ejb-ref> element of a sip.xml or sun-sip.xml file. The sun-sip.xml file is a Sailfin-specific deployment descriptor file, which is functionally equivalent to the sun-web.xml file for web applications. Recall that Sailfin is the SIP servlet container implementation in GlassFish being developed in the SailFin project. You can also specify a connector resource to be injected in the <resource-ref> element of these files. This is made possible through the support provided in the sip.xml and sun-sip.xml files for elements such as <ejb-ref>, <resource-ref>, and <resource-env-ref>.

The following example demonstrates the second approach. Here an EJB is specified in an <ejb-ref> element in a sip.xml file. The EJB can then be looked up using the ejb-ref-name in the JNDI context.

   <ejb-local-ref>
       <ejb-ref-name>TalkBackBean</ejb-ref-name>
       <ejb-ref-type>Session</ejb-ref-type>
       <local>sample.talkback.TalkBackBeanLocal</local>
       <ejb-link>TalkBack.jar#TalkBackBeanBean<

Java EE Annotations in SIP Servlet Classes

The @EJB and @Resource annotations are not the only Java EE annotations that can be specified in SIP servlet API v1.1 classes. Any of the following Java EE annotations:

  • @RunAs
  • @DeclaresRole
  • @Resource
  • @Resources
  • @EJB
  • @WebServiceRef
  • @PostConstruct
  • @PreDestroy

can be specified in any of the following classes:

  • javax.servlet.sip.Servlet
  • javax.servlet.sip.SipApplicationSessionListener
  • javax.servlet.sip.SipApplicationSessionActivationListener
  • javax.servlet.sip.SipSessionAttributeListener
  • javax.servlet.sip.SipSessionListener
  • javax.servlet.sip.SipSessionActivationListener
  • javax.servlet.sip.SipErrorListener
  • javax.servlet.sip.TimerListener

The Sample Converged Enterprise Application

Accompanying this tip is a zip file that contains NetBeans projects for three applications:

  • ConvergedEnterprise - A converged enterprise application.
  • ConvergedSipApplication - A SIP application.
  • TalkBack - An EJB module.

The SIP application, ConvergedSipApplication, is bundled in the converged enterprise application, ConvergedEnterprise. Download the zip file and extract its content. Navigate to the SampleApp/ConvergedEnterprise/src/conf directory. You'll see the application.xml file for the converged enterprise application. Notice that the bundled SIP application and the EJB module, TalkBack, are described in the file. A code snippet of the application.xml is shown here. Also notice the .ear file for the converged enterprise application in the SampleApp/ConvergedEnterprise/dist directory.

Navigate to the SampleApp/TalkBack/src/java/sample/talkback directory, you'll see an EJB component, TalkBackBeanBean. Notice how the SipFactory instance for the SIP application, ConvergedSipApplication, is injected as a resource. A code snippet of the EJB component is shown here.

Navigate to the SampleApp/ConvergedSipApplication/src/java/sample/servlet directory. You'll see a servlet, InviteServlet. Notice how the servlet uses an @EJB annotation to inject the EJB component named TalkBackBean. A code snippet of the servlet is shown here.

Running the Sample Converged Enterprise Application

To run the sample converged enterprise application, do the following:

  1. If you do not have Sailfin 1.0 installed, download and install it.
  2. If you do not have NetBeans IDE 6.1 (or later) installed, download and install it. The instructions presented here are for NetBeans IDE 6.5.
  3. Install the NetBeans SIP development and test plugins as follows:
    • In the NetBeans IDE, select the Tools menu, then Plugins. This opens the Plugins dialog box.
    • Select the Downloaded tab. Then click the Add Plugins button. This opens the Add Plugins dialog box.
    • Navigate to the sailfin-install-dir/lib/tools/netbeans directory, where sailfin-install-dir is the directory where you installed Sailfin 1.0.
    • Select all the files with .nbm extensions and click the Open button.
  4. Ensure that Sailfin is registered in the NetBeans IDE, as follows:
    • Click the Services tab in the NetBeans IDE.
    • Expand the Servers node. You should see Sailfin V1 in the list of servers. If not, register Sailfin V1 as follows:
      • Right-click the Servers node and select Add Server. This opens an Add Server Instance wizard.
      • Select Sailfin V1 in the server list of the wizard and click the Next button.
      • Enter the location information for the server and click the Next button.
      • Enter the admin name and password and click the Finish button.
  5. If you haven't already done so, download the zip file for the sample and extract its contents.
  6. Open the converged enterprise application as follows:
    • Click Open Project in the File menu of the NetBeans IDE. This opens the Open Project dialog box.
    • Navigate to the directory that contains the extracted contents for the sample and select ConvergedEnterprise. Select the Open Required Projects checkbox. This should open all the three projects for the converged enterprise application: ConvergedEnterprise, ConvergedSipApplication, and TalkBack.
    • Click the Open Project button.
  7. Resolve references in the applications as follows.
    • Right click the ConvergedEnterprise project in the Projects window and select Properties. This open the Project Properties dialog box.
    • Select the Libraries node in the Categories window. Then select the Add JAR/Folder button. This open the Add JAR/Folder window.
    • Navigate to the sailfin-install-dir/lib directory and select the ssa-api.jar file.
    • Click the Open button in the Add JAR/Folder window and the O.K. button in the Project Properties window.
    • Perform the same actions for the ConvergedSipApplication and TalkBack projects.
  8. Build and deploy the application as follows:
    • Right-click the ConvergedEnterprise project and select Clean and Build.
    • Right-click the ConvergedEnterprise project and select Deploy. This should start Sailfin and deploy the converged enterprise application in Sailfin. You should also see a SIP Test Agent window open in the NetBeans IDE as shown in Figure 1. This window is a SIP emulator that can be used to send SIP requests and receive responses.

      SIP Test Agent Window
      Figure 1. SIP Test Agent Window
       
  9. Click the New Request button under the Message Creation window. In response, you should see various dialog boxes open for a SIP request as shown in Figure 2.

    SIP Request Dialog Boxes
    Figure 2. SIP Request Dialog Boxes
     
  10. Select INVITE in the Method drop-down in the Request dialog box. Then click the Send button below the Message Preview window. In response, you should see a response message that includes 200 OK as shown in Figure 3. This indicates that the application successfully invoked an EJB from within a SIP servlet.

    SIP Response Message
    Figure 3. SIP Response Message
     

For more information on adding the SIP development and test plugins to NetBeans and adding Sailfin as a server to NetBeans, see the Hands On Lab, Adding Convergence of media to your Java EE Application using NetBeans IDE and Sailfin. The Hands On Lab also has details on how to use the SIP Test Agent.

Summary

The SIP Servlet API 1.1 specification formalizes the interfaces and interactions between the SIP servlets and Java EE applications. It enables users to create converged enterprise applications that can handle voice and data traffic using SIP servlets.

About the Author

Prasad Subramanian is a staff engineer at Sun Microsystems and is the engineering lead for Project Sailfin.


2009 JavaOne Conference, June 2-5, San Francisco ** Register Now**

Stay on top of everything new and different, both inside and around Java technology. Register by April 22, 2009, and save $200 off a Conference Pass or Conference Plus Pass. Register now at http://java.sun.com/javaone.

By Michael McMahon

Complex Java programs, such as application servers, sometimes create their own class loaders using the URLClassLoader type. With URLClassLoader, applications can load classes and resources from a search path of URLs. The following URL types are supported:

  • file: (loads from file-system directories)
  • jar: (loads from JAR files)
  • http: (loads from http servers)

A frequent problem has been how to support updated implementations of the classes and resources loaded from a particular codebase, and in particular from JAR files. In principle, once the application clears all references to a loader object, the garbage collector and finalization mechanisms will eventually ensure that all resources (such as the JarFile objects) are released and closed.

The application can then replace the JAR file, and create a new URLClassLoader instance to load from the same location, but this time using the new implementation of the classes/resources.

However, since it can't be predicted exactly when finalization and garbage collection will occur, this causes problems for applications which need to be able to do this in a predictable and timely fashion. It is a particular problem on Windows, because open files cannot be deleted or replaced.

To alleviate this problem, URLClassLoader has acquired a new method called close(). It has been implemented since Build 48 of JDK7.

The close() method effectively invalidates the loader, so that no new classes can be loaded from it. It also closes any JAR files that were opened by the loader. This allows the application to delete or replace these files and, if necessary, create new loaders using new implementations.

The new method follows the familiar "Closeable" pattern, and URLClassLoader now implements the Closeable interface, which defines URLClassLoader.close(). The following sample code shows how one might use the method.

       //
       // create a class loader loading from "foo.jar"
       //
       URL url = new URL("file:foo.jar");
       URLClassLoader loader = new URLClassLoader (new URL[] {url});
       Class cl = Class.forName ("Foo", true, loader);
       Runnable foo = (Runnable) cl.newInstance();
       foo.run();
       loader.close ();

       // foo.jar gets updated somehow

       loader = new URLClassLoader (new URL[] {url});
       cl = Class.forName ("Foo", true, loader);
       foo = (Runnable) cl.newInstance();
       // run the new implementation of Foo
       foo.run();

Michael McMahon is an engineer at Sun Microsystems. He works in the Java Security, Networking, and Libraries group.

by Jakub Podlesak

Jersey 1.0 is an open-source, production-ready reference implementation of JAX-RS, the Java API for RESTful Web Services (JSR-311). Jersey makes it easy to create RESTful web services using Java technology.

An earlier Tech Tip, Implementing RESTful Web Services in Java, introduced RESTful Web Services, JAX-RS, and Jersey. It also showed how using Java technology you can write RESTful web services that conform to the JAX-RS specification. Another tip, Configuring JSON for RESTful Web Services in Jersey 1.0, showed how to configure data in JSON (JavaScript Object Notation) using Jersey 1.0.

In this tip, you will learn how to use the Jersey 1.0.2 Client API to consume HTTP-based RESTful Web Services. The Jersey 1.0.2 client API is an easy-to-use, high level, Java technology API that can help you write clients for any HTTP-based RESTful web service. The API is built on the uniform interface concept, one of the key principles of REST. The uniform interface concept means that whatever URIs a REST-based application accesses, the interface to those URIs should be the same

Jersey Client API Basics

To start working with the Jersey client API, you need to create an instance of the com.sun.jersey.api.client.Client class. The simplest way to do that is as follows:

   import com.sun.jersey.api.client.Client;

   Client client = Client.create();

The Client class is the main configuration point for building a RESTful web service client. You use it to configure various client properties and features and indicate which resource providers to use. Creating an instance of a Client is an expensive operation, so try to avoid creating an unnecessary number of client instances. A good approach is to reuse an existing instance, when possible.

After you create a Client instance, you can start using it. However, to issue requests, you need to create a WebResource object, which encapsulates a web resource for the client. For example, the following code creates a WebResource object for a web resource whose URI is http://example.com/base:

   import com.sun.jersey.api.client.WebResource;

   WebResource webResource = client.resource("http://example.com/base");

You use the WebResource object to build requests to send to the web resource and to process responses returned from the web resource. For example, you can use the WebResource object for HTTP GET, PUT, POST, and DELETE requests.

GET Request: Use the get() method in the WebResource class to submit an HTTP GET request to the web resource:

   String s = webResource.get(String.class);

This means that if the URI for the WebResource object is http://example.com/base, an HTTP GET request is submitted to the resource whose URI is http://example.com/base. If you're familiar with curl, the command line HTTP tool, you'll see that:

   String s = webResource.get(String.class);

corresponds to the following curl command:

   curl http://example.com/base

You can specify query parameters in the get() request. For example, the following code specifies two query parameters in the get() request:

   MultivaluedMap queryParams = new MultivaluedMapImpl();
   queryParams.add("param1", "val1");
   queryParams.add("param2", "val2");
   String s = webResource.queryParams(queryParams).get(String.class);

This corresponds to the following curl command:

   curl http://example.com/base?param1=val1&param2=val2

You can also specify the acceptable MIME type for the response. For example, the following code specifies an acceptable MIME type of text:

   String s = webResource.accept("text/plain").get(String.class);

This corresponds to the following curl command:

   curl -HAccept:text/plain http://example.com/base

In addition, you can get the HTTP status code for the request. Here, for example, is a request that returns a text entity and a status code:

   ClientResponse response = webResource.accept("text/plain").get(ClientResponse.class);
   int status = response.getStatus();
   String textEntity = response.getEntity(String.class);

The ClientResponse object represents an HTTP response in the client.

PUT Request: Use the put() method in the WebResource class to submit an HTTP PUT request to the web resource. For example, the following request puts a text entity foo:bar into a web resource:

   ClientResponse response = webResource.type("text/plain").put(ClientResponse.class, "foo:bar");

This corresponds to the following curl command:

   curl -XPUT -HContent-type:text/plain --data "foo:bar" http://example.com/base

You can also specify query parameters in the put()request. You do this in a way that is similar to specifying query parameters for a get() request. In the following example, the same query parameters that were used in the previous get() method example are specified in a put() request:

  MultivaluedMap queryParams = new MultivaluedMapImpl();
  queryParams.add("param1", "val1");
  queryParams.add("param2", "val2");
  ClientResponse response = webResource.queryParams(queryParams).put(ClientResponse.class, "foo:bar");

This corresponds to the following curl command:

   curl -XPUT -HContent-type:text/plain --data "foo:bar" http://example.com/base?param1=val1&param2=val2

POST Request: A POST request is a syntactic combination of a GET request and a PUT request, that is, you can use a POST request to send an entity to a web resource and receive another entity. Use the post() method in the WebResource class to submit an HTTP POST request to the web resource. For example, the following code submits a POST request with query parameters and URL-encoded form data:

  MultivaluedMap formData = new MultivaluedMapImpl();
  formData.add("name1", "val1");
  formData.add("name2", "val2");
  ClientResponse response = webResource.type("application/x-www-form-urlencoded").post(ClientResponse.class, formData);

This corresponds to the following curl command:

   curl -d name1=val1 -d name2=val2 http://example.com/base

DELETE Request: Use the delete() method in the WebResource class to submit an HTTP DELETE request to the web resource. For example, the following request deletes the resource whose URI is http://example.com/base/user/123:

  ClientResponse response = webResource.path("user/123").delete(ClientResponse.class);

This corresponds to the following curl command:

   curl -XDELETE http://example.com/base/user/123

Note that the WebResource.path() method, which can also be used in all the HTTP request methods, allows you to specify an additional path for the requested web resource. Another WebResource method, header(), allows you to add an HTTP header to your request.

Configuring the Jersey Client

Before submitting requests, you might need to configure the client. This can involve registering providers. You also have the option of adding filters. See the Jersey 1.0.2 Client API for an overview of all possible options.

Registering Providers: In JAX-RS, a provider is an implementation of a JAX-RS extension. A provider class is marked with a @Provider annotation. The Jersey server presents an infrastructure for providers. In implementing JAX-RS, Jersey includes standard provider classes. The Jersey client API reuses the same provider infrastructure as the Jersey server. However, you need to explicitly register all non-standard providers because no automatic classpath scan takes place on the client side.

To register a provider, you need to add its provider class to the ClientConfig object for the Client instance. The ClientConfig class declares the common property names, features, properties, provider classes, and singleton provider instances that can be used by a Client object. For example, the following code registers a JSON provider class for use by a Client object:

   ClientConfig config = new DefaultClientConfig();
   config.getClasses().add(JSONRootElementProvider.class);
   Client client = Client.create(config);

Notice the use of the DefaultClientConfig class. It declares the default client configuration.

Adding Filters: Another option you have in configuring a client is to add filters to the client instance. A filter dynamically intercepts requests and responses targeted to a resource class and can be used to modify the request or response. The Jersey client API provides a number of classes that implement filters. One of them is LoggingFilter, which implements a logging filter. You can use a logging filter to track communication between the client and a server application, something that can be valuable in debugging. Here is how to add a logging filter to the client:

   import com.sun.jersey.api.client.filter.LoggingFilter

   client.addFilter(new LoggingFilter());

An Example of a Jersey-Based Client

Accompanying this tip is an example application that uses the Jersey client API to access the popular Twitter web service. The example demonstrates the ability of the Jersey Client API to consume real-world, HTTP-based web services. You can download the example application as a Twitter client ZIP archive. If you expand the archive, you can examine the source code for the client. You can also download a runnable Twitter client JAR file to test the application and see how it works. Note that you need Java SE Runtime Environment (JRE) 6 to run the application.

Twitter: Twitter is a service that allows you to exchange short text messages with friends, coworkers, family members, and others. The messages are designed to answer the question, "What are you doing?" Here is an example of some messages displayed through Twitter.

Twitter messages
Twitter Messages
 

Twitter also provides a public Twitter API that you can use to programmatically produce or consume Twitter messages and access other aspects of the service. If you use the Twitter API, one thing you need to take into account is Twitter's authentication and security mechanism and requirements.

Twitter Authentication and Security: Twitter uses a Basic HTTP authentication schema. This means that if you access Twitter through its API, you need to add a special Authorization header to your request. Then you will probably also want to secure the communication using the Secure Sockets Layer (SSL). You can do this simply with the following code:

   ClientConfig config = new DefaultClientConfig();
   SSLContext ctx = SSLContext.getInstance("SSL");
   ctx.init(null, myTrustManager, null);
   config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(hostnameVerifier, ctx));
   Client client = Client.create(config);

Examining the Client: Download the Twitter client ZIP archive and expand it. Navigate to the TwitterClient class in the src\main\java\com\sun\jersey\techtips\twitter directory. This is the Jersey-based client for the application.

As you examine the source code in the TwitterClient class, notice especially the following:

  • Code that creates the Client and WebResource objects:
       import com.sun.jersey.api.client.Client;
       import com.sun.jersey.api.client.WebResource;
    
       private static final String BaseURI = "https://twitter.com";
       private final WebResource wr;
    
       Client client = Client.create(config);
       wr = client.resource(BaseURI);
    
  • Code that configures the client:
       import com.sun.jersey.api.client.config.ClientConfig;
       import com.sun.jersey.api.client.config.DefaultClientConfig;
    
       ClientConfig config = new DefaultClientConfig();
    
       config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(hv, ctx));
       config.getClasses().add(JAXBContextResolver.class);
    
  • Code that issues a get request:
       public List<StatusBean> getFriendsTimelineJson() {
               return wr.path("statuses/friends_timeline.json")
                       .header(AUTHENTICATION_HEADER, authentication)
                       .accept(MediaType.APPLICATION_JSON_TYPE)
                       .get(new GenericType<List<StatusBean>>() {
               });
        }
    
    Notice the addition of an Authentication header to the request.

Running the Example Application

To run the example application, do the following:

  1. If you do not have JRE 6 installed, download and install it .
  2. Download the Twitter client JAR file
  3. Issue the following command from the command line:
       java -jar jersey-twitter-client-1.0-SNAPSHOT-jar-with-dependencies.jar
    

    In response, you will be prompted for your Twitter user name and password. Respond to the prompts as appropriate. You should see then Twitter messages with timestamps. Here is an example:

    Simple Jersey (http://jersey.dev.java.net) based twitter client
    Twitter username:mytwitter
    Password:
    Hello mytwitter!
    Status will get updated every 60 secs.
    Enter !exit to finish the session.
    Arun Gupta (1238705837), at: Mon Feb 23 00:04:40 +0000 2009:
     #slumdog is a favorite ... have not seen the movie yet but would be great if it
    's the first Indian movie to win ... fingers crossed!
    LarryLary (1238103969), at: Mon Feb 23 00:07:33 +0000 2009:
     Gonna go for a walk. Need some fresh air.
    kmollo (1239025876), at: Mon Feb 23 01:43:34 +0000 2009:
     enjoying everyone's '15 Albums That Changed Your Life' lists. I have been so
     bored, it's nice to have some 'new' music to check out!
    iFab @fauntleroy (1239103887), at: Mon Feb 23 02:02:20 +0000 2009:
     It's a beautiful day
    JessicaxG (1239248068), at: Mon Feb 23 02:36:34 +0000 2009:
     Shop. Shop. Shop. Another way to avoid things I need to do.
    DoughJoe (1239571723), at: Mon Feb 23 03:55:39 +0000 2009:
     Slumdog grabs it all
    > Congratulations to Kate Winslet on her best actress Oscar.
    Posted at: Tue Feb 24 16:54:17 +0000 2009
    >!exit
    bye
     

    Notice that you can also enter your own messages in the client.

Further Reading

For more information on Jersey, see the following resources:

About the Author

Jakub Podlesak is a member of the Jersey project team. Previously, he participated in the development of Metro, the GlassFish web services stack, as a member of the WS-Policy team. Read his blog.


2009 JavaOne Conference, June 2-5, San Francisco ** Register Now**

Stay on top of everything new and different, both inside and around Java technology. Register by April 22, 2009, and save $200 off a Conference Pass or Conference Plus Pass. Register now at http://java.sun.com/javaone.

By Bruce Hopkins

Let's assume that you're in the middle of your development cycle, and you realize that your mobile application needs to perform some very important but non-GUI-related operations such as:

  • Discover a local Bluetooth device in the vicinity
  • Communicate with a SIP registrar or proxy
  • Determine your geo-location via a GPS device

So now what do you do? You want to write your killer-app using great declarative syntax of JavaFX, but you also realize that the Java standard specifications for Bluetooth wireless technology (JSR-82), SIP communication (JSR-180), and location-based application development (JSR-179) and are available as Java ME APIs.

Fortunately, the JavaFX runtime is completely dependent upon (and compatible with) the Java virtual machine (JVM). Simply stated, it means the following:

  • Your JavaFX Mobile application has no restrictions on calling any class bundled in the JAR or any JSR API library that's present on the handset.
  • Your JavaFX Desktop application will work seamlessly upon any deployment platform that has the current version of the JRE:
    • For Windows machines, this will be Java 6, update 11 (or later)
    • For Mac OS X machines, this will be Java 5, update 13 (or later)

Independent of the operating system, your JavaFX Desktop application will also be able to call any class that's bundled in the JAR package for your desktop application. Note: On the Windows desktop, JavaFX runs on Java 5 and it degrades gracefully (for example, the Drag2Install feature does not work) — that is, it does not break your application.

Read the full article, with source code.

Enterprise Tech Tips Crossword

Over the years, the Enterprise Java Technologies Tech Tips have covered a wide variety of enterprise Java technology topics. Here's a crossword puzzle that tests your knowledge of some topics covered in recent Tech Tips. Each clue lists a tip that contains the answer.

This crossword was created with EclipseCrossword - www.eclipsecrossword.com

1  234
         
  5               
                   
     
     
   
   
6                       
                         
    7
     
  89 
       
10      1112   
               
             
             
13                         
                           
     
     
  14       
           
15          16   
                 
  17
   
18                   
                     
   
   

Across

  1. JAXB binding compiler [Customizing JAXB]
  2. Session bean type that can implement a web service [Referencing Multiple Web Services From An Application Client]
  3. JPA interface for accessing a database Extended Persistence Context in Stateful Session Beans]
  4. SIP application package extension [Adding Voice to Java EE With SIP Servlets]
  5. SSL certificate objective [Using SSL with GlassFish v2]
  6. The world's most popular database [Combining Groovy, Grails, MySQL, and the Java Persistence API]
  7. Scripting engine used by Phobos [Building An Ajax-Enabled Web Application Using Phobos and jMaki]
  8. SIP-related protocol that specifies end user capabilities [Adding Voice to Java EE With SIP Servlets]
  9. Creating an XML document from a Java object tree [Customizing JAXB]

Down

  1. "Convention over ____________" [True Abstraction: Composite UI Components in JSF 2.0 -- Part 1]
  2. Authority that can be trusted by a client and service that have no direct trust relationship [Using WS-Trust Support in Metro to Secure Web Services]
  3. JAX-RS production-quality Reference Implementation [Configuring JSON for RESTful Web Services in Jersey 1.0]
  4. Yiddish expert or Apache build framework [Using JAX-WS with Maven]
  5. jMaki event handler based on publish/subscribe mechanism [Working with jMaki Events]
  6. WS* security specification provider [Using WS-Trust Support in Metro to Secure Web Services]
  7. SOAP Messages with Attachments (abbrv.) [Securing Attachments With Metro 1.3]
  8. REST resource identifier [Configuring JSON for RESTful Web Services in Jersey 1.0]
  9. Open-source web application framework that leverages Groovy [Combining Groovy, Grails, MySQL, and the Java Persistence API]
  10. GlassFish web services stack [Using WS-Trust Support in Metro to Secure Web Services]
  11. Ticket-granting part of a Key Distribution Center [Building Kerberos-Based Secure Services Using Metro]

Here is the solution to the puzzle.

January 21, 2009, Wednesday. Sun Microsystems campus, Santa Clara, Caifornia.

These are notes from the presentations I attended at the Java Mobile, Media & Embedded Developer Days (M3DD). For more details, please go to the M3DD website and view the specific presentation's slides.

Sun Microsystems Mobile and Embedded community manager Roger Brinkley and evangelist Terrence Barr briefly welcomed the group to the second developer days, sponsored by Sony Ericsson and Sun Microsystems, then launched into the packed agenda. While the numbers rose and fell during the day, there were some 100 participants at the conference and another 150 participating via the live stream.

Marketing VP Eric Klein and Engineering VP Jeet Kaul gave the keynote speech. Eric stressed that the 2009 keywords for Java are "open" and "expressive." Eric noted that customers today consume and create business and personal content 24x7, across the screens of their life (mobile, desktop, television).

Eric spent some minutes reviewing Sun's "open" history, including the open collaboration around Java for over 12 years, resulting in Java being completely open source. Today's focus is on using Java to create a rich, immersive, expressive platform, so that developers can solve complex customer problems, using multiple data sources. The 6.5 million Java developers worldwide can combine with the 8 million content authors/web developers to grow a vibrant mobile platform. Jeet talked about his focus on streamlining the designer-developer workflow, embracing the native tools used by the community.

Jeet and Eric spoke of two current initiatives to address fragmentation issues: Java ODP and JavaFX. Java On Device Portal (ODP) allows the use of mobile widgets across global mobile devices, while JavaFX is positioned as the unifying technology for rich internet applications (RIA), web, and Java development across all screens (desktop, mobile, television). Eric also talked about Project Hydrazine (aka rocket fuel), which is an initiative to develop internet and operator services.

Florian Tournier, Sun senior product line manager, presented an overview of the Java mobility roadmap. First, the numbers:


  • 2.6 billion Java phone base
  • 6 billion Java Cards deployed
  • 840 million Java-enabled desktops
  • 40 million+ Blu-ray and TV devices

Florian stressed Sun's continuing commitment to open source and standards. Open source is exemplified by the regular phoneME releases -- phoneME Feature being the open-source implementation based on CLDC and MIDP, while phoneME Advanced is an open-source implementation of CDC for consumer devices and advanced phones -- and the open-sourcing of the LWUIT interface. LightWeight User Interface Toolkit (LWUIT), a standalone library, creates rich UIs easily for Java apps, which runs on any CLDC 1.1/MIDP 2.0 device. Standards are demonstrated by the Mobile Service Architecture (MSA) platform for Java in wireless, industry initiatives against fragmentation, and popular development/testing tools.

For 2009, Florian foresees the return of the feature (as opposed to smart) phone, with increasingly expressive experiences. He sees more emphasis on the browser, so discussed JSR 290, the mobile browser APIs for Java ME, mobile web servers (such as the Sprint Titan architecture), and Java Card 3. Innovations in Java show up in MSA2/MIDP3 functionality, CDC on phone (Sprint Titan with OSGi), modularization (Java SE first, then Java ME), and testing and tools in the Java ME SDK, with CLDC/CDC and BD-J support.

Phil Bender of CableLabs was the speaker at the next talk I attended. tru2way is Java-based middleware that allows interactivity with the television set, without requiring cable-top boxes. OpenCable project is on java.net, and there will be a developers conference on February 10. CableLabs also has a Visiting Engineer program. Cognizant's visiting engineer did a TeenLocator app, ported from Cognizant's IMS app for mobile, that lets users find a family member's mobile phone and map its location with driving directions.

The new Java TV standard for digital TV in Brazil came next, by Sun's Michael Lagally and Jens Pätzold. Interactive TV (TV plus apps) lets you augment A/V with Java apps, which are synchronized to the A/V content. Brazil has the world's largest dual terrestrial-mobile TV deployment. It has the world's 4th largest TV network (around 80 million viewers a day), so the Brazilian goverment has a standards body (Sistema Brasileiro de Televisao Digital, or SBTVD), which requested Sun to create royalty-free DTV specification. People use television to connect to the internet in Brazil, so it is used for many things as eGovernment apps (such as to obtain a driver's license).

Several lightning talks followed, with each person having 7 minutes to introduce his or her material. Patrick Curran talked about the Java Community Process (JCP). and noted there are 26 active Java ME JSRs. Nokia's Jackson Feijo Filho gave usability testing tips for mobile developers, including a usability checklist. Gail Rahn Frederick talked about multi-modal search in On Device Portals, and Medio Systems' handset-resident mobile search-driven ODP application, requiring JSR 135. SunLabs' Eric Arseneau showed a video on First, which will tie into his Project Squawk presentation on January 22.

Next, Ken Gilmer of Bug Labs talked about mobile Java on the BUG programmable and modular open-source gadget platform, which lets you use electronic building blocks to build personalized hardware devices. The BUG device is a mobile Linux computer in a small metal rectangle, the size of an older clunky mobile phone, with several pluggable modules (e.g., camera, LCD, GPS, and the lovely Von Hippel breakout board). It contains an OSGi runtime on a CDC JVM (Concierge on phoneME) and has an SDK with a virual BUG emulator.

That's it for today's presentation notes. If you'd like to follow the rest of today's or tomorrow's sessions, you can stream the conference. If needed, find the instructions here.

By Vikram Goyal

Mobile Media API (MMAPI) is a protocol- and format-agnostic API for playing and manipulating multimedia content in mobile devices. It is a diverse API and handles several different types of media seamlessly, depending upon device capabilities. In this tech tip, you will learn how to mix and play multiple media content at the same time.

Understanding the issues of mixing in MMAPI

On the face of it, mixing sounds in a mobile applications is a desirable attribute to have, especially for multimedia-rich applications like games. MMAPI provides you the ability to mix different media, but there are pitfalls. The following sections describe some of these issues.

Device fragmentation

MMAPI implementations that return a value of true for supports.mixing system property should, in theory, be able to do the following.

  • Support the playing of at least two tones simultaneously,
  • Use Manager.playTone() when another player instance is playing back audio, and
  • Support the playback of at least two instances of audio players.

In practice, not all MMAPI implementations follow these guidelines. This is due to device fragmentation. You should consult the design guidelines supplied by the device manufacturer to find out the capabilities of the device that you are working with.

Multiple player instances

With multiple player instances active in an application, there is a danger of too many resources being taken up to service these instances. When a player instance is in a prefetched/realized state, it will become a memory liability if kept around for a long time, especially because player instances in this state can request exclusive access to system resources, like the audio hardware. Thus, even if your device's MMAPI implementation allows for more than 2 player instances to be active at any time, it is prudent to keep this number low.

MIDI, tones, and sampled audio

As I said earlier, what can be mixed depends on your device's MMAPI implementation. Generally, most implementations will allow you to mix one instance of sampled audio and one instance of either a simple tone or MIDI sound, or both.

Putting together the code

Mixing sounds is a common feature in games where a background sound plays throughout the game, while various user or application events generate their own short lived sounds. In the following example, I will use a basic sampled audio as a background score, while various events during the game play will be mixed using MIDI and Tone control. The example is created and run using Netbeans 6.5. Make sure that MMAPI is selected as an optional API while creating this application, as MIDIControl is not part of the basic MIDP 2.0 MMAPI package.

When you run this code (supplied as a Netbeans project), you will be able to mix a MIDI sound and a system-generated tone with the continuous background music. This is tested in Sun Wireless Toolkit 2.2 supplied with Netbeans. If you run this in other toolkits, or better still, on an actual device, you will need to make sure that MIDIControl is supported.

Resources


EXAMPLE SOURCE CODE

/*
 * TechnicalTipMIDlet.java
 *
 */

import javax.microedition.media.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.media.control.MIDIControl;

/*
 * TechnicalTipMIDlet mixes audio, MIDI and tone
 * @author  Vikram Goyal
 */
public class TechnicalTipMIDlet extends MIDlet implements CommandListener {

  // define variables

  // the players for background music and MIDI
  private Player backgroundMusic = null;
  private Player aPlayer = null;

  // the MIDIControl extracted from aPlayer
  private MIDIControl mControl = null;

  // display items, the display
  private Display display = null;

  // and an alert
  private Alert alert = null;

  // commands to exit, for aCommand (MIDI) and bCommand (tone)
  private Command exitCommand = null;
  private Command aCommand = null;
  private Command bCommand = null;

  public TechnicalTipMIDlet() {

    // initialize the display
    display = Display.getDisplay(this);

    // a message for the user
    alert = new Alert("Message");
    alert.setString("Press A to play a tone, Press B to play a MIDI");
    alert.setTimeout(Alert.FOREVER);

    // create commands
    exitCommand = new Command("Exit", Command.EXIT, 1);
    aCommand = new Command("A", Command.ITEM, 1);
    bCommand = new Command("B", Command.ITEM, 1);

    // add to alert
    alert.addCommand(exitCommand);
    alert.addCommand(aCommand);
    alert.addCommand(bCommand);

    // set this class as command listener
    alert.setCommandListener(this);

    // and initialize the player instances
    initialize();
  }

  private void initialize() {

    // create and prefetch player instances
    try {

      // for the background music, load a simple wav file and put it on
      // infinite loop
      backgroundMusic =
        Manager.createPlayer(
          getClass().getResourceAsStream("music.wav"), "audio/x-wav");
      backgroundMusic.prefetch();
      backgroundMusic.setLoopCount(-1);

      // create the MIDI player, prefetch
      aPlayer = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
      aPlayer.prefetch();

      // and extract the MIDIControl
      mControl =
        (MIDIControl)aPlayer.getControl(
          "javax.microedition.media.control.MIDIControl");

    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void commandAction(Command cmd, Displayable disp) {

    // handle the exit command
    if(cmd == exitCommand) {
      destroyApp(true);
      notifyDestroyed();
      return;
    }

    try {

      // if it's the aCommand
      if(cmd == aCommand) {

        // play a short MIDI event
        mControl.shortMidiEvent(MIDIControl.NOTE_ON | 11, 60, 100);
      }

      if(cmd == bCommand) {

        // if bCommand, use the Manager class to play a simple tone
        Manager.playTone(61, 1000, 100);
      }
    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void startApp() {

    try {

      // start the background music if it was created successfully
      if(backgroundMusic != null) backgroundMusic.start();
      else handleError(new Exception("Error with background player"));
    } catch(Exception ex) { handleError(ex); }

    display.setCurrent(alert);
  }

  public void pauseApp() {
  }

  public void destroyApp(boolean unconditional) {

    try {

      // close players
      if(backgroundMusic != null) {
        backgroundMusic.close();
        backgroundMusic = null;
      }

      if(aPlayer != null) {
        aPlayer.close();
        aPlayer = null;
      }

    } catch(Exception e) {
      handleError(e);
    }

  }

  // handles errors
  private void handleError(Exception ex) {
    alert.setTitle("Error");
    alert.setString(ex.getMessage());
    display.setCurrent(alert);
    ex.printStackTrace();
  }
}

Vikram Goyal is the author of Pro Java ME MMAPI, published by Apress. This book explains how to add audio, video and other multimedia capabilities to a Java-enabled phone. Vikram is also the author of the Jakarta Commons Online Bookshelf and helps manage a free craft projects website.

Bruce Hopkins serves up Part 2 of his series on Blu-ray Disc Java development.

Part 1 introduces the BD-J platform and discusses the significant differences between the system requirements for developing, compared to playing, Blu-ray content. Additionally, we learn that the BD-J platform comprises various other supporting APIs, including GEM/MHP (Globally Executable Multi Home Platform) and Java TV. We are introduced to the application lifecycle of BD-J Xlets.

In Part 2, Hopkins delves into the Java ME SDK 3.0, which is the perfect tool for all Java ME development — whether you're doing Blu-ray application development or mobile phone application development. The Java ME SDK 3.0 provides substantial enhancements to its predecessor, the Wireless Toolkit for CLDC 2.5, mainly due to the fact that it allows developers the ability to author, edit, and compile all Java ME applications — especially of course, BD-J applications. Using the BD-J APIs, developers can create Java ME applications for all Blu-ray disc players, including the Sony PlayStation 3 gaming console.

Read the full article

by Jennie Hall
Updated Jan. 23, 2009

In this tip, you'll learn how to use Swing's progress indicator support to monitor and report on the progress of long-running operations. It is a good practice to keep users informed as they interact with an application; one way to do this is with a progress bar. A progress bar is an animated image that indicates the degree of completion of a given task. The animation typically looks like a rectangular bar that fills in as the task becomes more complete.

Swing's Progress Monitoring API consists of three classes that enable the use of progress bars. JProgressBar subclasses JComponent and is a graphical component that illustrates the progress of an operation. It can be embedded within other graphical components. ProgressMonitor subclasses Object and is not itself a graphical component. It monitors a task and pops a dialog box with a progress bar in it. ProgressMonitorInputStream is a stream filter with an associated progress monitor. As the stream is read, the progress monitor automatically receives updates on the number of bytes read and displays the percentage of work completed in its dialog box.

The Java Tutorial provides some good rules of thumb that help to determine the appropriate class to use in a given situation. For example, use JProgressBar when you need more than one progress bar or you would like more control over the configuration of the progress bar. If you need a convenient way to cancel the monitored task or to allow the user to dismiss the dialog box while continuing to run the task in the background, ProgressMonitor provides for this. ProgressMonitor also features a modifiable status note in its dialog box that can be updated periodically by your application. The sample application for this tip uses ProgressMonitor.

The Sample Application

The sample application copies files located in a source directory (in) to a destination directory (out). It has a Swing GUI that allows the user to launch the copy operation by clicking the Copy Files button as shown in Figure 1.

Figure 1: Sample Application

Upon the launch of the copy operation, the application creates a progress monitor that keeps track of the amount of work completed and displays this information in a dialog containing a progress bar. The application also writes output regarding the progress of the operation to the console as shown in Figure 2.

Figure 2: Dialog containing progress bar

As shown above, the GUI displays the number of kilobytes copied and the file name of the file currently being copied. The user may cancel the operation at any time by clicking the Cancel button. After the copy operation completes, the GUI appears as shown in Figure 3:

Stepping Through the Sample Application

The sample application consists of a class, ProgressMonitorExample, that extends javax.swing.JPanel and implements java.awt.event.ActionListener and java.beans.PropertyChangeListener. ProgressMonitorExample's main() method tells the event dispatch thread to schedule the execution of a Runnable that creates the application GUI:

	public static void main(String[] args) {
		// tell the event dispatch thread to schedule the execution
		// of this Runnable (which will create the example app GUI) for a later time
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				// create example app window
				JFrame frame = new JFrame("Progress Monitor Example");
				// application will exit on close
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
				
				// create example app content pane
				// ProgressMonitorExample constructor does additional GUI setup
				JComponent contentPane = new ProgressMonitorExample();
				contentPane.setOpaque(true);
				frame.setContentPane(contentPane);					
				...

ProgressMonitorExample contains an inner class, CopyFiles, that extends javax.swing.SwingWorker. When the user clicks the Copy Files button, ProgressMonitorExample's actionPerformed() method receives the event, creates a new ProgressMonitor, and starts the file-copying operation on a background thread. Here's the code that creates the ProgressMonitor:

    public void actionPerformed(ActionEvent event) {
        // make sure there are files to copy
        File srcDir = new File("in");
        if (srcDir.exists() && (srcDir.listFiles() != null && srcDir.listFiles().length > 0)) {
            // set up the destination directory
            File destDir = new File("out");            
            // create the progress monitor
            progressMonitor = new ProgressMonitor(ProgressMonitorExample.this,
                                                  "Operation in progress...",
                                                  "", 0, 100);
            progressMonitor.setProgress(0);
			...

ProgressMonitor has a single constructor. The first argument is the parent component to the progress monitor's dialog box. The second argument, of type Object, is displayed on the dialog box. It should be a string, icon, or component. This example supplies the constructor with a string that lets the user know that the requested operation is underway. The third argument is an optional status note that also appears on the dialog box. This status note can be updated periodically as the monitored task runs. Set this value to null if no status note is necessary. The fourth and fifth arguments are the minimum and maximum values for the progress bar in the progress monitor dialog box.

The code below, also excerpted from actionPerformed(), creates a new instance of CopyFiles, adds ProgressMonitorExample as a property change listener on the instance, and executes the instance:

    // schedule the copy files operation for execution on a background thread
    operation = new CopyFiles(srcDir, destDir);
    // add ProgressMonitorExample as a listener on CopyFiles;
    // of specific interest is the bound property progress
    operation.addPropertyChangeListener(this);
    operation.execute();
    // we're running our operation; disable copy button
    copyButton.setEnabled(false);

CopyFiles subclasses SwingWorker, so the call to inherited method execute() schedules CopyFiles for execution on a background thread and returns immediately. Time-consuming activities should always run on a background thread rather than the event dispatch thread. This way, the GUI remains responsive.

Although the file-copying operation has begun, the progress monitor dialog box doesn't pop up right away. By default, ProgressMonitor waits for 500 ms before making a decision on whether or not to show the dialog box at all. After this time period has elapsed, if ProgressMonitor determines that the monitored operation has already completed or is likely to complete before the dialog box can be displayed, ProgressMonitor does not pop the dialog box. ProgressMonitor's method setMillisToDecideToPopup() controls this setting. setMillisToPopup() sets the estimated amount of time it will take the dialog box to appear; the default value for this property is 2 seconds.

The real work of copying the files occurs in doInBackground(), an abstract method on SwingWorker that CopyFiles overrides. Here's a partial listing:

	// perform time-consuming copy task in the worker thread
	@Override
	public Void doInBackground() {
		int progress = 0;
		// initialize bound property progress (inherited from SwingWorker)
		setProgress(0);
		// get the files to be copied from the source directory
		File[] files = srcDir.listFiles();
		// determine the scope of the task
		long totalBytes = calcTotalBytes(files);
		long bytesCopied = 0;
		
		while (progress < 100 && !isCancelled()) {                 
			// copy the files to the destination directory
			for (File f : files) {
				File destFile = new File(destDir, f.getName());
				long previousLen = 0;
				
				try {
					InputStream in = new FileInputStream(f);
					OutputStream out = new FileOutputStream(destFile);                    
					byte[] buf = new byte[1024];
					int counter = 0;
					int len;
					
					while ((len = in.read(buf)) > 0) {
						out.write(buf, 0, len);
						counter += len;
						bytesCopied += (destFile.length() - previousLen);
						previousLen = destFile.length();
						if (counter > PROGRESS_CHECKPOINT || bytesCopied == totalBytes) {
							// get % complete for the task
							progress = (int)((100 * bytesCopied) / totalBytes);
							counter = 0;
							CopyData current = new CopyData(progress, f.getName(), getTotalKiloBytes(totalBytes), getKiloBytesCopied(bytesCopied));

							// set new value on bound property
							// progress and fire property change event
							setProgress(progress);
							
							// publish current progress data for copy task
							publish(current);
						}
					}
					in.close();
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			...

doInBackground() gets any files located in the in directory and copies them one by one to the out directory. Each time a specified number of bytes have been copied, the application calculates what percentage of the total number of bytes has been copied so far, then creates an instance of the inner class CopyData to hold this information along with the total number of kilobytes, the number of kilobytes copied so far, and the filename of the file currently being copied. The application then updates the bound property progress with the calculated percentage, firing a property change event in the process. The call to publish() makes the copy task's current progress data available for processing in the event dispatch thread.

ProgressMonitorExample's propertyChange() method extracts the progress value from the property change event. It then updates the progress monitor animation by calling its setProgress() and passing the progress value. Here's the code:

    // executes in event dispatch thread
    public void propertyChange(PropertyChangeEvent event) {
        // if the operation is finished or has been canceled by
        // the user, take appropriate action
        if (progressMonitor.isCanceled()) {
            operation.cancel(true);
        } else if (event.getPropertyName().equals("progress")) {            
            // get the % complete from the progress event
            // and set it on the progress monitor
            int progress = ((Integer)event.getNewValue()).intValue();
            progressMonitor.setProgress(progress);            
        }        
    }

Notice that ProgressMonitor provides a convenient way to determine if the dialog has been canceled by the user. The sample application responds to a user cancellation by terminating the monitored activity, but in other situations it might be appropriate to allow the user to dismiss the dialog box while the activity continues to run in the background.

By overriding the SwingWorker method process(), CopyFiles can use the progress data made available by the call to publish() to update the GUI. process() executes in the event dispatch thread, so it is safe to update Swing components in this method. Here's the code:

	// process copy task progress data in the event dispatch thread
	@Override
	public void process(List data) {
		if(isCancelled()) { return; }
		CopyData update  = new CopyData(0, "", 0, 0);
		for (CopyData d : data) {
		    // progress updates may be batched, so get the most recent
			if (d.getKiloBytesCopied() > update.getKiloBytesCopied()) {
				update = d;
			}
		}
		
		// update the progress monitor's status note with the
		// latest progress data from the copy operation, and
		// additionally append the note to the console
		String progressNote = update.getKiloBytesCopied() + " of " 
							  + update.getTotalKiloBytes() + " kb copied.";
		String fileNameNote = "Now copying " + update.getFileName();
		
		if (update.getProgress() < 100) {
			progressMonitor.setNote(progressNote + " " + fileNameNote);
			console.append(progressNote + "\n" + fileNameNote + "\n");
		} else {
			progressMonitor.setNote(progressNote);
			console.append(progressNote + "\n");
		}           
	}

As shown above, process() updates the progress monitor's status note with the number of kilobytes copied so far and the filename of the file currently being copied, then appends this information to the console.

When its background operation is finished, CopyFiles sets its own state to done and invokes the done() method in the event dispatch thread. done() invokes the SwingWorker method get(), which returns the final result of the background task. In the case of the sample application, however, there is no final result to be processed. The sample application calls get() to determine whether or not the background task was canceled before completion and responds appropriately:

	// perform final updates in the event dispatch thread
	@Override
	public void done() {
		try {
			// call get() to tell us whether the operation completed or 
			// was canceled; we don't do anything with this result
			Void result = get();
			console.append("Copy operation completed.\n");                
		} catch (InterruptedException e) {
			
		} catch (CancellationException e) {
		    // get() throws CancellationException if background task was canceled
			console.append("Copy operation canceled.\n");
		} catch (ExecutionException e) {
			console.append("Exception occurred: " + e.getCause());
		}
		// reset the example app
		copyButton.setEnabled(true);
		progressMonitor.setProgress(0);
	}


Running the Sample Application

To run the sample application, download the sample code and unzip it. The sample application assumes that there are files to copy in the in directory located under the project root, so add some (preferably large) files of your choice to this directory. Launch NetBeans and select File -> Open Project. In the Open Project dialog box, navigate to the directory where you unzipped the sample code and select the folder progressMonitorExample. Select the Open as Main Project check box. Click Open Project Folder. Right-click the progressMonitorExample project and select Build, then right-click the project again and select Run.

References and Resources

Sample code for this tip
The Java Tutorial

About the Author

Jennie Hall is a lead developer working in the financial sector.

A Java mobile widget is a small chunk of Java ME code installed and operated by the Java On Device Portal (Java ODP) technology.

While other Java ODP solutions force developers to write mobile widgets using a proprietary scripting language, the Java ODP platform leverages Java ME technology. You can write widgets in pure Java and take advantage of Java's full capabilities, such as packages for Personal Information Management (PIM), location-based services (LBS), multimedia, and more.

Register here to join program to receive access to the Early Access SDK.