C H A P T E R  6

Scenario: J2EE Application Client and J2EE Application

FIGURE 6-1 shows another J2EE application. Like the applications in the other scenarios, this one has significant business logic in an EJB module. But, where the earlier examples used web module front ends, this one uses a front end provided by a J2EE client application.

 FIGURE 6-1 J2EE Application With an Application Client

Diagram of the J2EE application covered in this chapter, which contains a J2EE application client and a separate J2EE application.[ D ]

In other scenarios (see Chapter 4 and Chapter 5), a web module front end and an EJB module with substantial business logic are assembled into a J2EE application, and the application is deployed as a unit. End users use web browsers to access the web pages defined in the web modules.

A J2EE application client also provides a user interface, but it is programmed, deployed, and executed differently than a web module. An application client is a separate Java program with its own main method. The application client is deployed separately from the server-side J2EE application. In most cases it is deployed to an end user's machine. Since it is a separate program with its own main method, an end user can start and stop the application client separately from the server-side J2EE application.

The application client runs in a J2EE client container, which means that even though the application client is deployed and executed separately from the server-side J2EE application, it can use Java RMI to invoke the business methods of the server-side application. And, when it does, it can participate in J2EE container-managed transactions and container-managed security.


The Interactions in This Application

This scenario looks at a J2EE application that includes the type of interaction shown in FIGURE 6-1. This application shows you how an application client is used and how it participates in J2EE transactions and security. It is also an example of the kinds of application design problems you can solve with an application client.

In most of the previous scenarios, the application has been an online shopping catalog, and the end users have been online shoppers who access the online catalog through web module front ends.

The online catalog application, however, has other end users besides the shoppers. Items in the online catalog change frequently. Items are added, removed, put on sale, and so on. These tasks aren't performed by the shoppers, but by an application administrator who is an employee of the online vendor.

The work performed by the administrator is more complicated than what the online shoppers do. For example, adding a new item to the catalog requires setting up a product record that is keyed by SKU, setting up the mixture of image and text that appears in the online catalog, and setting up the keywords that online shoppers use to search for products.

Shoppers typically interact rapidly with the application, requesting new pages from the catalog, requesting more detailed information on a particular item, and so on. The application administrator interacts differently with the application, typically spending long periods of time working on a catalog entry before saving it. Only when saving a catalog entry does the application client need the services of the server-side application. So, the application administrator could make use of business logic that executes independently of the server-slide logic.

After considering the work that is performed by the application administrator, you decide that an application client with its own business logic is a more appropriate tool for administering the online catalog than a web interface provided by a web module. The main interactions that will take place when this application runs are:

1. The server side of the application, which performs the actual database inserts, updates, and deletes, is a J2EE application with session and entity enterprise beans. It accesses the same databases that the online shoppers do. This application is typically managed by system administration and is up and running before the application administrator starts the application client.

2. The application administrator starts the application client to perform some catalog management tasks. The application client runs in its own process, on the administrator's machine. Since it was deployed as a J2EE application client, it runs in a J2EE client container. The application administrator logs in and establishes a security identity.

3. The application administrator works with text and images to build a new catalog entry. When the administrator completes a new catalog entry and clicks a Save button, the application client uses JNDI lookup to obtain a remote reference to the session bean in the server-side application, and uses Java RMI to invoke the business method that inserts the new entry into the online catalog database. This may lead to several inserts in different tables.

When the business method is invoked, the application administrator's security identity is passed to the server-side J2EE application. After the server-side EJB container verifies that administrator is an authorized user, the business method executes and inserts the new catalog entry. This enterprise bean business method is transactional, so the EJB container starts a new transaction and commits it after all the database insert operations are successfully completed.

There are other programming issues in this application, such as programming the interactions between the session and entity enterprise beans. These are covered in other scenarios that focus on those issues.


Programming This Application

TABLE 6-1 summarizes the programming required to create the J2EE application and application client illustrated in FIGURE 6-1.

TABLE 6-1 Programming Required for This Scenario

Application Element

Programming Required

Application Server

None.

J2EE Application Client

First write a stand-alone Java program (a program with a main method) that provides the necessary user interface and business logic. At those points in the program flow where server-side business methods are invoked, write JNDI lookups to obtain the remote references for home and remote objects, then write the remote invocations.

After writing the Java client program, transform it into a Java application client. Set up declared references for the enterprise beans named in the JDNI lookups. Identify the stub classes needed for the JNDI lookup.

J2EE Application (server side)

No special programming is required to make the application accessible to an application client.

The server-side application must be deployed before the client is completed, because deployment generates the stub classes needed by the client.


The sections that follow use a simple example to demonstrate each of these programming tasks.

Programming the J2EE Client Application

In this scenario, the application client uses Java RMI to communicate with an enterprise bean in the server-side application. The instructions that follow show you how to write a very simple program that fits this scenario.

The instructions are divided into two main parts. The first explains how to write the Java code for the client program. The second explains how to transform that program into an application client that can be deployed to a J2EE application server.

Writing the Client Code

What distinguishes an application client from other stand-alone Java programs is its use of J2EE services, such as EJB references, to interact with other J2EE applications running in other containers. CODE EXAMPLE 6-1 shows a simple way to implement the JNDI lookup code in a Swing program.

Like other types of J2EE references, the EJB references in this application client consist of the lookup code and corresponding declared references. The next section, which transforms the program into a J2EE application client, explains how to set up the reference declarations. The significant feature in this section is the lookup code.

Notice that the lookup code is similar to the lookup code used when web modules invoke business methods of enterprise beans. The code that is needed for the J2EE interactions has been commented and highlighted.

CODE EXAMPLE 6-1 A JFrame Class With JNDI Lookup Code
/*
 * helloClient.java
 *
 * Created on January 29, 2002, 4:56 PM
 */
 
package HelloClient;
 
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
// Add an import statement for the enterprise bean
// home and remote interfaces.
import HelloBean.*;
 
/**
 *
 * @author J2EE Client Developer
 */
public class helloClient extends javax.swing.JFrame {
    
    // Declare the variables that will be used in the JNDI
    // lookup and the remote method invocation.
    HelloHome hHome = null;
    Hello hRemote = null;
    String returnedText = null;
    
    /** Creates new form helloClient */
    public helloClient() {
        initComponents();
        try {
        // Perform JNDI lookup, get remote reference to
        // enterprise bean's home object:
            Context ic = new InitialContext();
            Object o = ic.lookup("java:comp/env/ejb/Hello");
            System.out.println("get the home");
            hHome = (HelloHome) PortableRemoteObject.narrow(o, HelloHome.class);
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }
       
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        invokeBeanButton = new javax.swing.JButton();
        returnTextField = new javax.swing.JTextField();
 
        getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
 
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });
 
        invokeBeanButton.setText("Click Me");
        invokeBeanButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                invokeBeanButtonActionPerformed(evt);
            }
        });
 
        getContentPane().add(invokeBeanButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(150, 130, -1, -1));
 
        returnTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                returnTextFieldActionPerformed(evt);
            }
        });
 
        getContentPane().add(returnTextField, new org.netbeans.lib.awtextra.AbsoluteConstraints(110, 190, 160, -1));
 
        pack();
    }
 
    private void returnTextFieldActionPerformed(java.awt.event.ActionEvent evt) {
        // Add your handling code here:
    }
 
    private void invokeBeanButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // Add your handling code here:
        // Perform the remote method invocation and display
        // the return value in the text window.
        try {
            System.out.println("inside invokeBeanButtonActionPerformed");
            hRemote = hHome.create();
            System.out.println("performed create");
            returnedText = hRemote.sayHello();         
            System.out.println("invoked sayHello");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        returnTextField.setText(returnedText);
        
    }
    
    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        new helloClient().show();
    }
    
    
    // Variables declaration - do not modify
    private javax.swing.JTextField returnTextField;
    private javax.swing.JButton invokeBeanButton;
    // End of variables declaration
 }

Your real-world application client will be more complex than this, so you may want to test it at this point, before you deploy it to a J2EE application server. You can run your program by executing its main method, either from the IDE or from the command line. But, since it won't be running in a J2EE client container yet, your JNDI lookup calls and remote method invocations will fail. To test execute, you need to comment the JNDI calls, and replace the remote invocations with code that returns dummy values that will allow you to test your program's logic. You can still test your windowing code and business logic.

In this simple example, the JNDI lookup was added to the JFrame's constructor. The create method that returned an instance of the enterprise bean and the remote invocation of sayHello were added to the button's action performed method. This is a simple way of adding J2EE code to a small program. A later section will consider other strategies for adding J2EE code to a client program. The next step in the scenario is transforming your Swing program into a J2EE application client.

Transforming the Program Into a J2EE Client Application

You have written a Java program that provides the functionality you need in an application client. The procedures that follow explain how to use the Sun ONE Studio 4 IDE to turn it into a J2EE application client.

Creating the Client Application Node and Adding the Client Code

To create a client application node and associate it with your client program:

1. Right-click on the folder or package in which you want to create you application client. Choose New right arrow J2EE right arrow Application Client.

This creates an application client node in the explorer.

2. Right-click the application client node. Choose Set Main Class. Use the browser to select your client class. Click OK.

 FIGURE 6-2 Application Client Node With Subnode for the Java Client Program.

Screenshot of a section of the Explorer window with an application client node and its subnodes.

What you see in the IDE is a new sub node of the application client node for your Java client program. FIGURE 6-2 shows an application node named HelloAppClient. The helloClient program (shown in CODE EXAMPLE 6-1) was designated as the main class for this application client node, and the IDE created a sub node named helloClient. The application client node represents the deployable form of the Java client program. You can use its properties to request specific J2EE services from the client container. In this case, the HelloAppClient node represents the deployable form of the helloClient program.

Declaring the EJB References

After creating an application client and associating a program with it, you need to configure the application client. In this case, you wrote a Java client program that invokes an enterprise bean business method, so you need to set up declared references on the application client node that match the JNDI lookup in the program code.

To set up an EJB Reference for an application client:

1. Right-click the application client node. Choose Properties. Click on the References tab to bring it to the front. Locate the EJB References Property, click on it, and click the ellipsis (...) button that appears. This opens the enterprise bean reference property editor. Click Add to open the Add EJB Reference dialog.

FIGURE 6-3 shows the dialog. The values in the fields are correct for the program in CODE EXAMPLE 6-1.

 FIGURE 6-3 Add EJB Reference Dialog Box

Screenshot of the application client's Add EJB Reference Dialog. [ D ]

2. Click on the tab for the J2EE application server you are using to bring it to the front.

The fields that appear on this tab depend on the application server. FIGURE 6-4 shows the tab for the J2EE Reference Implementation, which has a field for JNDI Name. You use this field to identify the enterprise bean your application client will be interacting with. You need to identify the enterprise bean by the JNDI name that was specified when the enterprise bean was deployed. In this example the server-side enterprise bean was deployed with the name Hello.

 FIGURE 6-4 Add EJB Reference Dialog's J2EE RI-specific Tab

Screenshot of the application client's Add EJB Reference dialog, showing J2EE RI-specific tab. The JNDI Name field has the value Hello.

If you are using a different J2EE application server, click the Help button to access online help for the fields on the tab.

3. Click OK to close the Add EJB Reference dialog, and OK again to close the property editor.

Specifying the Target Application (or the Client Jar Path)

In addition to an enterprise bean reference, your application needs a copy of the stub files that support the remote method invocation on the enterprise bean you identified in the reference. These files are server-specific, and they are generated by the application server's deployment tool when the server-side application is deployed. They are normally found in a JAR file generated when the server-side application is deployed.

Some application servers (including WebLogic) are able to download the stub files to the your application client when you execute it. If you are using one of these servers, you don't need to do anything with the stub files. You can proceed directly from setting up the enterprise bean references to executing your application.

Other application servers require you to supply a copy of the stub JAR file before you execute your application client. The J2EE Reference Implementation is one of these servers, and this section contains procedures for telling the Reference Implementation where to find stub JAR. When you deploy the application client to the RI, a copy of the stub JAR will be included in the deployment.

If you are developing both the server-side application and the application client, you probably have a copy of the server-side application mounted in the Explorer along side your application client. If this is the case, you can simply identify the server-side application as the application client's target application, and the IDE will find the client JAR file for you. FIGURE 6-5 shows HelloAppClient in the same fileystem as the server-side application, which is represented by the HelloApplication node.

 FIGURE 6-5 Application Client and Server-side Application in the IDE

Screenshot of a section of the Explorer window, showing the application client node and the server-side Hello application.

To set the Target Application property:

1. Right-click on the application client. Choose Properties. Locate the Target Application property, click on it and click on the ellipsis (...) button.

2. Use the browser to locate the server-side application's node in you IDE. Select it and click OK.

FIGURE 6-6 shows the HelloAppClient's property sheet after it has been configured to use the HelloApplication as its target application.

 FIGURE 6-6 Application Client Property Sheet

Screenshot of the application client's property sheet. The Target Application property has a value of HelloApplication.

If you are developing your client for a server-side application that has already been deployed on another machine, and you don't have the server-side application on your development machine, you can use a different property to provide the application client with the path to the necessary client JAR. You may need to obtain a copy of the client JAR file from the developer of the server-side application, or from the system administrator who manages the server-side application.

If the server-side application was developed with Sun ONE Studio 4, you (or the server-side developer or system administrator) can use the IDE to create the necessary stub JAR file.

To create a client JAR file for a server-side application that is mounted in the IDE:

single-step bulletRight-click on the J2EE application node. Choose Export Client Support. This opens the Specify location for client jar dialog. Use it to specify a directory in which to place the client JAR.

If the client JAR can't be created this way, because the server-side application can't be mounted in the Sun ONE Studio 4 IDE, the server-side developer (or system administrator) will have to obtain a copy of the client JAR generated by the application server.

Once you have a copy of the client JAR, mount it in your file system, and use the client JAR property to identify it to your application client.

To specify a client JAR for you application client:

single-step bulletRight-click on the application client node. Choose Properties. Click on the tab for the application server you are using to bring it to the front. Locate the property that identifies the client JAR path, click on it and click on the ellipsis (...) button.

Figure FIGURE 6-7 shows the J2EE RI tab for the HelloAppClient node. This tab provides a property named Stub Jar File, which you can use to identify the stub JAR file.

 FIGURE 6-7 Application Client's J2EE RI-Specific Tab

Screenshot of the application client's property sheet with J2EE RI-specific tab selected.

For other application servers that require you to identify a client JAR file, the process should be similar. First, you obtain a copy of the client JAR file. Then, on the server-specific property tab, locate the property you use to identify the path to the stub JAR file. Remember that some application servers, including WebLogic, automatically download the client JAR to your application client when you execute it.

Executing the Application Client

To execute your application client:

1. Make sure that you have chosen an application server for your application client. Right-click the client application node and choose Properties. On the property sheet, locate the Application Server property.

The initial value for this property is Default Application Server. If you execute with this value for the property, your application client will be executed by the application server instance that was selected as the default server instance. (To see the default server, switch to the Explorer Window's Runtime tab, locate the Server Registry node and its Default Servers subnode.)

You can also specify a server instance with this property. Click the Application Server property, then click the ellipsis (...) button. This opens the property editor.

2. Right-click the application client node and choose Execute.

This command runs your application client inside a client container provided by the application server you specified in Step 1.

3. Some application servers (including the J2EE Reference Implementation) will open a login screen at this point. Type in a valid username and password.

FIGURE 6-8 shows the J2EE RI login screen with the default J2EE RI username and password (j2ee/j2ee).

 FIGURE 6-8 J2EE Reference Implementation Login Screen

Screenshot of the J2EE Reference Implementation login screen. Fields show default user name, j2ee, and default password, also j2ee.

4. After you log in successfully, the application server will open execute your client program's main method.

Deploying the Application Client

If you prefer to deploy your application client and run it from the command line, you can create a client JAR file. Executing a client JAR file requires the application server's tool for running clients.

To create a client JAR:

1. Right-click the application client node and choose Export Client Jar. Use the dialog to specify the application server and the location of the client jar file.

2. You can move the client JAR file to another machine, if the application server has been installed on that machine.

3. Run the client with the tool provided by the application server. (For the J2EE Reference Implementation, the tool is named runclient.)

Working With the Server-side J2EE Application

In this scenario, the application client communicates with a server-side J2EE application. The server-side application in FIGURE 6-1 consists of a single EJB module, but this is not required. The server-side application could include several EJB modules; it could even include a web module that provided different end-user functionality than the application client does. (Assembling a web module and an EJB module into a single J2EE application is covered in other scenarios.)

No special programming is required to make the server-side application accessible to an application client. When you program an application client, however, you need some information about the server-side application.

  • You need a JNDI name for every J2EE service that your program will be communicating with. In this example, that was the JNDI name for an enterprise bean in the server-side application. For your real-world application clients you might need JNDI names for more than one enterprise bean, for a JMS queue and queue connection factory, or for other J2EE resources.
  • If your application client is going to use Java RMI to communicate with an enterprise bean on the server side, you need two things:
    • Copies of the enterprise bean's home and remote interfaces.
    • Depending on the application server you are using, you may need copies of the stub files that are generated when the server-side application is deployed. The stub files are server-specific, so they must be generated by the application server (not the IDE), as part of the deploy action. (If the server-side application is mounted in the Sun ONE Studio 4 IDE, you can use the Export Client Support command to generate a stub .jar file.) The stub files must generated by the application server to which you will be deploying your application client.
In a production or managed test environment you may need to get this information from system administration.

Transactions With a J2EE Application Client

Transactions are generally part of the server-side J2EE application, and defining transaction boundaries is part of programming the server-side application. The server-side container will start a transaction when the application client invokes a transactional business method, and commit the transaction when all of the business logic inside the transaction boundary completes successfully.

Varying This Scenario

This scenario explains how to program one type of interaction between an application client and a server-side J2EE application. It shows an application client that uses Java RMI to requests services from a server-side J2EE application. It also show the J2EE code inside the swing class that has the main() method.

Using a Helper Class

The example (CODE EXAMPLE 6-1) showed the J2EE code inside the swing class that provided the interface for the application. Putting all of the code in this class made it easier for you to see everything that is required in a client application, but you may want to program your real-world application clients differently.

One approach, that allows you to isolate your J2EE code from your user interface and business logic, is to put your J2EE code into a helper class. FIGURE 6-9 shows a client application that uses a helper class.

 FIGURE 6-9 Application Client With Helper Class

Diagram of another approach to the J2EE application client.	[ D ]

Assume that this application client provides the functionality described in the scenario (The Interactions in This Application), helping an application administrator set up a new entry for an online catalog. In this version of the client, however, when the end-user clicks the Save button, the windowing class does not perform the JNDI lookup and remote invocation itself. Instead, it passes the new catalog entry to the helper class. The Save button's actionPerformed method would now include code something like this:

CODE EXAMPLE 6-2 Using the Helper Class
...
myHelperClass helper = new myHelperClass();
helper.saveNewEntry(newCatalogEntry);
....

The helper class's saveNewEntry method performs the JNDI lookup and invokes the necessary server-side methods. You set the enterprise bean references up in the same way, on the application client node.

This approach makes it easier to test you Java client program. You can simply replace the helper class with another Java class that returns dummy values.

Including Multiple Remote Method Invocations

Note that application clients are not limited to Java RMI interactions with one enterprise bean in the server-side application. They can invoke the business methods of multiple enterprise beans. To do this, your client needs to import the home and remote interfaces of all the enterprise beans, and you need to add JNDI lookup code for all of the enterprise beans. You also need to add references for all the enterprise beans to the application client node.

Using Java Messaging

An application client can also use Java messaging to communicate with a server-side application. To do this, you need to know the JNDI names that were assigned to the queue and queue connection factory when the server-side application was deployed. Instead of enterprise bean references, your application client needs a resource environment reference for the queue (see The Reference Declaration for the Queue) and a resource reference for the queue connection factory (see The Reference Declaration for the QueueConnectionFactory), Your application code needs JNDI lookups for these two references (see The JNDI Lookup Code).