Sometimes enterprise applications use a standalone client application for handling tasks such as system or application administration. For example, a web-based banking application might use an application client to manually administer customers and accounts. This capability is useful in the event the site becomes inaccessible for any reason or a customer prefers to communicate things like changes to account information by phone.
The Java 2 Enterprise Edition (J2EE) reference implementation provides a way for you to write, test, and deploy application clients. A J2EE application client is a standalone program launched from the command line or desktop, and typically accesses Enterprise JavaBean programs running on the J2EE application server.
This article shows you how to write, deploy, and test a simple
application client. The application client is launched
with the J2EE runclient command to administer
customer information for a web-based banking application. The example
has a Project Swing user interface.
The application client for this article references enterprise bean and utility classes created by a third party and packaged into JAR files. The enterprise beans and classes in those JAR files handle customer, account, and transaction operations for a web-based banking application.
In this example, the application client references the
CustomerControllerEJB bean in the
customerBean JAR file.
CustomerControllerEJB is a session bean that looks up and
communicates with the CustomerEJB entity bean. The data storage
details of the entity bean are hidden from the application client because
the application client calls the session bean methods only. When the user
adds or updates customer data, that data is first handled by the session
bean where it is in a transient state, and passed to the entity bean where
it is in a persistent state for a database read or write operation. If for
any reason a database read or write operation cannot complete, the entire
database transaction is backed out to prevent a condition where only part
of a new record is recorded or only some of the updates for an existing record
are committed. Because the session bean does not have direct access to
the database, no such insurance is needed. Lost data that never made it
to the entity bean can be reentered by the user, and data read from the
database for display in the user interface can be retrieved in its original
state.
To keep the complexity of the user interface code to a minimum,
this application client implements only the three customer functions
shown in Figure 1, which are view customer information, add a new
customer to the database, and update customer information. These
customer functions are implemented as methods available through
the CustomerControllerBean session bean.
Figure 1: Example Application Client
Customer information is stored in the underlying Cloudscape database
that comes with the J2EE installation. To read from and write to this
database, the application client looks up and creates a reference to
the CustomerControllerEJB session bean by way of its
home and remote interfaces. Figure 2 shows how the application client
and session bean work together once they are assembled into a complete
J2EE application and deployed. The container, shown in the box within the
circle is the interface between the session bean and the low-level
platform-specific functionality that supports the session bean.
The container is created during deployment.
Figure 2: Cooperating Classes and Interfaces
The application client does not work directly with the enterprise bean, but
creates an instance of its home interface, CustomerControllerHome.
The home interface extends EJBHome and has a create
method for creating the enterprise bean in its container.
CreateException is thrown if the enterprise bean cannot be
created, and RemoteException is thrown if a communications-related
exception occurs during the execution of a remote method.
When the home interface is created, the J2EE application server creates the
remote interface, CustomerController, and enterprise bean,
CustomerControllerEJB. The remote interface extends
EJBObject and declares methods for creating and managing customer
information. These methods are required to throw
javax.rmi.RemoteException.
The methods declared in the remote interface are implemented in the
enterprise bean class.
The CustomerControllerEJB class provides implementations
for the following methods, some of which are used in the example
code for this article:
createCustomerremoveCustomergetCustomerOfAccountgetDetailsgetCustomerOfLastNamesetNamesetAddressA J2EE application client is written like any other Java programming language application. You write your class or classes using Java 2 Standard Edition (J2SE) and J2EE APIs, and compile as you normally would.
The J2EE application client for this article consists of the following classes: BankApp, EventHandle, and DataModel. You can read a detailed explanation of the code in Code Walkthrough below.
The application client classes are not in a package, so you can
compile the BankApp class
as shown below. The EventHandle and DataModel
classes are compiled at the same time because BankApp
references EventHandle and EventHandle
references DataModel.
javac BankApp.java
To assemble, deploy, and test the J2EE application client, you start the J2EE server, database, and deploy tool as described here. First, download and install the J2SE and J2EE platforms. Once you have these platforms set up, you can start the J2EE server, database, and deploy tool.
In different windows, type the following commands in this order to
start the J2EE server, Deploy tool, and Cloudscape database. Be sure
the J2EE server is completely started before executing the
deploytool and cloudscape commands:
j2ee -verbose deploytool cloudscape -start
If that does not work, supply the fully-qualified pathname.
For example, if your SDK installation
is in a directory called JavaEE type this from the
JavaEE directory:
javadkee/bin/j2ee -verbose javadkee/bin/deploytool javadkee/bin/cloudscape -start
javadkee\bin\j2ee -verbose javadkee\bin\deploytool javadkee\bin\cloudscape -start
The first step is to create a J2EE application to house the application client executables and enterprise bean JAR files.
File menu:
New Application dialog box:
appclient.earappclientappclient.ear file.appclient.ear.Bean JAR files contain the third-party enterprise beans used by the application client.
File menu:
Add EJB JAR dialog box:
txBean.jar and click Add EJB JAR. accountBean.jar and
customerBean.jar the same way.The application client must contain the application client executables and any classes those executables reference.
File menu:
appclientEdit Contents of dialog box:
BankApp.class and click Add. BankApp$1.class and click Add.BankApp$2.class and click AddDataModel.class and click AddEventHandle.class and click AddMessagesBundle_en_US.properties and click Add
Note: Because the files for this example are not in a package, the lower box should display the class names only.
General dialog box:
BankApp.
When an application consists of more than one class, one and only
one of those classes has a main method so the Java
virtual machine1 can launch it.
BankAppEnvironment Entries dialog box:
Enterprise Bean References dialog box:
In this screen, you enter the home and remote interfaces for the
CustomerControllerEJB session bean referenced by the
application client. The coded name is the name defined in the
com.sun.ebank.util.CodedNames class for the
CustomerController remote interface.
ejb/customerControllersessioncom.sun.ebank.ejb.customer.CustomerControllercom.sun.ebank.ejb.customer.CustomerControllerHome
With appclient selected, click the JNDI Names
tab. Fill in the JNDI Name column as shown in Figure 4. The
order may be a
little different on your own display, but make sure you map the
JNDI name you provide opposite the exact Component and
Referenced By column as shown here. An explanation of these
mappings immediately follows.
Figure 4: Specifying JNDI Names
A JNDI name is the name the J2EE server uses to look up
enterprise beans. In your code when you look up an enterprise
bean, you supply statements similar to those shown below.
The actual lookup takes place three lines down where the
getCustomerControllerHome method is called
on the EJBGetter class. The EJBGetter
class is a utility class that retrieves a coded JNDI name
from the src.com.sun.ebank.util.CodedNames class.
In this example, the application client is looking up the coded
name for the CustomerController remote interface.
try {
customerControllerHome =
EJBGetter.getCustomerControllerHome();
customer = customerControllerHome.create();
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
If you look at the last line of the bottom table in the figure
above, you see that BankApp (the display name
for the main class for the application client) references
ejb/customerController, which is
the coded name defined in the CodedNames class for
the CustomerController remote interface. Your job
is to supply a JNDI name in the last column.
The JNDI name that you supply is stored in the J2EE application
deployment descriptor and the J2EE server uses it to look up the
CustomerControllerBean. If you look at the second row
from the top in the top table in the figure above, you see that
CustomerControllerBean is mapped to the same JNDI name as
is ejb/customerController in the last line of the
bottom table. It does not matter what JNDI name you supply, as long as
you use the same name for the remote interface lookup as you use for
its corresponding bean. So, looking at the table, you can say that
the application client (BankApp) looks up the
CustomerController remote interface, which uses the
JNDI name of MyCustomerController, and the J2EE server
uses the MyCustomerController JNDI name to find the
corresponding CustomerControllerBean object.
The other rows in the top table have the mappings for the other enterprise beans. All of these beans are stored in the JAR files you added to the J2EE application during assembly. Their implementations have coded names for looking up either other enterprise beans or the database driver.
The JNDI name for the database driver is mapped in the bottom
table and is jdbc/Cloudscape. This name is the default
coded name supplied in the ~/javadkee/config
file. You can use a different JNDI name for the database driver
if you change the coded name in the ~/javadkee/config file.
Before you deploy the J2EE application, it is a good idea to verify that the bean and application client code is compliant with the J2EE specification.
Tools menu:
Tools Menu:
Introduction dialog box:
appclient.localhost.Client.jar appended
as follows: ~/appclientClient.jar.JNDI Names dialog box:
Review dialog box:
So the enterprise beans can write to and read from the database, you create the appropriate tables. To make things easy, the database tables are created with the following two scripts. These scripts create all the tables used by all the third-party enterprise beans; however, this example as it stands really only needs a database table for customer information. If you take this example and later expand it to use some of the other enterprise beans, the tables will be in the database ready for data.
Shift-click to download:
Put these files in the same directory anywhere on your system, make sure
the Cloudscape database is running, and execute the cloudUtil
script with create-table.sql parameter as follows:
cloudUtil.sh
create-table.sql
Note: Your class path should point toJ2sdkee/lib/system/tools.jar, and you might need to setJ2EE_HOMEto point to your javadkee installation.
To launch and test the example application client,
set the APPCPATH environment variable to
point to the directory where you stored the appclient.ear
file and type the following at the command line:
runclient -client appclient.ear -name BankApp en US
The -client appclient.ear parameter is the
name of the J2EE application EAR file, and the
-name BankApp parameter is the display name
of the application client.
At run time, you'll need to set the APPCPATH environment variable to the client stub JAR, which contains the EJB class files. This is the path specified during deployment when you checked the box Return Client JAR. By default, the pathname for the returned jar file is the location where the EAR file is stored and the application client name with Client.jar appended as follows: ~/appclientClient.jar.
The en and US parameters passed to the
runclient command are the language and country
codes. The language and country codes in this example tell the
application to use the English language (en) from the
United States (US). See Internationalization
below for more information on internationalizing and localizing an
application.
When the login box appears, type in guest for the user
name, and
guest123 for the password, and click OK. The next thing
you see is the application shown in Figure 5.
Figure 5: J2EE Application Client
This section walks you through the code for the three classes that comprise the J2EE application client. Discussions on object-oriented program design and internationalization are included. You can, of course, skip these sections if you are already familiar with this material.
The J2EE application client for this article is broken into the following three classes. Their relationship is depicted in Figure 6.
BankApp builds the initial user interface,
creates the EventHandle object, and provides methods for
the EventHandle and DataModel
objects to call to update the user interface.EventHandle listens for button clicks by the user,
takes action based on which button the user clicks, creates the
DataModel object, calls methods in the DataModel
object to write data to and read data from the underlying database, and
calls methods in the BankApp object to update the user
interface when actions complete.DataModel retrieves data from the user interface, performs
data checks, writes valid data to and reads stored data from the underlying database, and
calls methods in the BankApp object to update the user interface based on the
success of the database read or write operation.
Figure 6: Relationships among Classes
Organizing the application client code into classes according to function is a
modular approach to application design that makes the application code easier
to read, update, and maintain. For example, if you decide to remove the
application client from the J2EE environment and run it as a stand alone
application that accesses customer data in a file instead of a database, you
only have to modify method implementations in the DataModel
class. As long as you do not change the method signatures, you do not have
to modify method signatures or implementations in other classes that call
DataModel methods.
Another name for modularized programming like this is object-oriented programming. If you are new to object-oriented programming with the Java programming language, you might forget to design your application to use a separate class for each function and might not vigilant about making sure each class defines only one kind of function. You end up with one large class that combines functions and is essentially a procedural program wrapped up in one class. If you think you might be guilty of this, you are not alone. I have been guilty of it too.
There are a lot of texts that expound upon the concepts and benefits of object-oriented programming, but what I found to be the most enlightening was seeing a working program that does not use good object-oriented form and then seeing how to change it so it does. In that spirit, here is the BankAppNotOO code all in one class. The following discussions explain how to use a modular object-oriented approach to break this one very large class into three separate, organized, and smaller classes.
The BankApp class creates the user interface,
is the class with the main method and provides
protected methods for the other BankApp
application classes to call.
The main method creates instances of the BankApp
and EventHandle classes. The application is internationalized.
The language and country variables passed to the
BankApp constructor specify the language to use where
en means English and US means United States. These
values mean the application uses United States English as opposed to
Australian or United Kingdom English.
The values for the language and country codes are retrieved from the
args parameter passed to the main method.
The args parameter gets its values when the application
starts from values passed to the runclient command described
in Test the J2EE Application above.
public static void main(String args[]) {
String language, country;
if(args.length != 2) {
language = new String("en");
country = new String("US");
} else {
language = new String(args[0]);
country = new String(args[1]);
}
frame = new BankApp(language, country);
frame.setTitle("Banking Administration Client");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
frame.addWindowListener(l);
frame.pack();
frame.setVisible(true);
//Create event handling object
EventHandle ehandle = new EventHandle(frame,
messages);
}
The BankApp constructor creates the initial user interface, which
consists of three buttons that let the user view customer information, add
a new customer to the database, or update an existing customer's information.
The internationalization code creates a Locale from the
language and country parameters, and uses
the Locale to create a ResourceBundle.
The other parameter to the ResourceBundle is the first
part of the name of the properties file where the translated text is
stored. In this example, that file is
MessagesBundle_en_US.properties, which you added to the
application client during assembly.
public BankApp(String language, String country) {
//Internationalization variables
Locale currentLocale;
currentLocale = new Locale(language, country);
messages = ResourceBundle.getBundle(
"MessagesBundle", currentLocale);
//Create initial UI (Panel 1)
getContentPane().setLayout(new GridLayout(1,2));
p1 = new JPanel();
p1.setLayout(new GridLayout(11,1));
p2 = new JPanel();
p1.setBackground(Color.white);
p2.setBackground(Color.white);
getContentPane().add(p1);
getContentPane().add(p2);
view = new JButton(messages.getString(
"ViewButton"));
add = new JButton(messages.getString(
"AddButton"));
update = new JButton(messages.getString(
"UpdateButton"));
messlab = new JLabel();
messlab2 = new JLabel();
messlab3 = new JLabel();
messlab4 = new JLabel();
messlab5 = new JLabel();
messlab6 = new JLabel();
p1.add(view);
p1.add(add);
p1.add(update);
p1.add(new JLabel());
p1.add(messlab);
p1.add(messlab2);
p1.add(messlab3);
p1.add(messlab4);
p1.add(messlab5);
p1.add(messlab6);
//Create Panel 2 buttons so EventHandle
//constructor can add as action listeners
OK = new JButton(
messages.getString("OKButton"));
cancel = new JButton(messages.getString(
"CancelButton"));
//Add functionality to close window
addWindowListener(new WindowAdapter() {
public void windowClosing(
WindowEvent event) {
System.exit(0);
}
});
}
In an internationalized program, string values are read from
a properties file that contains translations for the language
in use in the form of key and value pairs. So, instead of creating
strings directly in your code, you create a ResourceBundle
that indicates the file where the translations are and read the
translations (values) from that file using the corresponding key.
Here are the key and value pair definitions for the properties file used
in this example:
ViewButton=View Customer Information AddButton=Add New Customer UpdateButton=Update Customer Information OKButton=OK CancelButton=Cancel ViewButtonMess=View Customer Information AddButtonMess=Add New Customer UpdateButtonMess= Update Customer Information EnterCustIDMess=Enter Customer ID: RemoteException=Remote Exception CustomerException=Customer NotFoundException=not found StateLimitException= State has two-letter limit MILimitException=MI has one-letter limit MissingRequiredException= Missing required information FnameLab=First name (Required): LnameLab=Last name (Required): MiLab=MI (Required): StreetLab=Street (Required): CityLab=City (Required): StateLab=State (Required): ZipLab=Zip: PhoneLab=Phone: EmailLab=Email:
So, for example, instead of creating the view button like this:
view = new JButton( "View Customer Information")
you would do it like this:
view = new JButton(
messages.getString("ViewButton")).
In this example, ViewButton is the key in the
MessagesBundle_en_US.properties file with a corresponding
value of View Customer Information.
This approach makes it easy to localize application text to the
language spoken by the majority of its users. For example, if you have
another file named MessagesBundle_fr_FR.properties with
French values for the keys, you could supply fr FR
to the runclient command instead of en US
to launch the application client to read in French from France
instead of United States English.
The BankApp class provides methods that other objects call when
they need to update the user interface. These methods are as follows:
clearMessages() resetPanelTwo() createPanel2Labels(), createROFields(
String first, String last, String mid,
String str, String cty, String st,
String zp, String tel,
String mail) createEditableFields(String first,
String last, String mid,
String str, String cty, String st, String zp, String tel,
String mail. The implementations are very straightforward, so rather than show it all here, you can browse the BankApp class file.
The EventHandle class
implements the ActionListener interface, which provides
a method interface for handling action events. Like all other interfaces
in the Java programming language, ActionListener defines a set of
methods, but does not implement their behavior. Instead, you provide
the implementations because they take application-specific actions.
The ActionListener interface has only one method,
the actionPerformed method. This method handles
action events generated by the BankApp class when
users interact with the user interface by clicking buttons.
Figure 7 illustrates how the EventHandle class interacts
with the BankApp and DataModel classes,
and the following sections detail the illustration.
Figure 7: Class Interactions
Events generated by the BankApp class are handled
in the EventHandle class, so the EventHandle
class not only implements the ActionListener
interface with code to handle the events, but also listens for
the button events generated by the BankApp class.
To set up this connection, the EventHandle
constructor receives an instance of the BankApp class,
assigns it to its private instance variable, calls the
addActionListener methods on the BankApp
buttons, and passes the addActionListener methods an
instance of itself (this) to add the EventHandle
action listener to the buttons.
public EventHandle(BankApp frame,
ResourceBundle messages) {
this.frame = frame;
this.messages = messages;
this.dataModel = dataModel;
frame.view.addActionListener(this);
frame.add.addActionListener(this);
frame.update.addActionListener(this);
frame.OK.addActionListener(this);
frame.cancel.addActionListener(this);
dataModel = new DataModel(frame, messages);
}
The constructor also receives an instance of the ResourceBundle
class and assigns it to its private instance variable so the
EventHandle object has access to the application client's
localized text.
The actionPerformed method handles the button events
generated by the BankApp class. Its implementation
uses a series of if statements to find out which
button generated the event and takes the appropriate action.
The bodies of the if statements change message
text and the Panel 2 display in BankApp, and call
methods in the DataModel class when data needs to be
written to or read from the database, or when the Panel 2 display
in BankApp needs to be updated in preparation for
an add, view, or update operation.
public void actionPerformed(
ActionEvent event) {
Object source = event.getSource();
//View customer data
if(source == frame.view) {
frame.clearMessages()
String vbutton =
messages.getString( "viewButton");
frame.messlab5.setText(" " + vbutton);
mess = new String(messages.getString(
"EnterCustIDMess"));
returned = JOptionPane.showInputDialog(frame,
mess);
if(returned != null) {
which = 3;
dataModel.createCustInf(
which, returned);
}
}
//Add new customer
if(source == frame.add){
frame.clearMessages();
String abutton =
messages.getString("AddButton");
frame.messlab5.setText(" " + abutton);
which = 1;
dataModel.createCustInf(which, returned);
}
//Update customer data
if(source == frame.update){
frame.clearMessages();
String ubutton = messages.getString(
"UpdateButton");
frame.messlab5.setText(" " + ubutton);
mess = new String(messages.getString(
"EnterCustIDMess"));
returned = JOptionPane.showInputDialog(frame,
mess);
if(returned != null) {
which = 2;
dataModel.createCustInf(which, returned);
}
}
//Process data
if(source == frame.OK) {
if(which == 3) { //view data
frame.resetPanelTwo();
//add or update data
} else if((which == 1) || (which == 2)) {
//Test data and write to database
int complete = dataModel.checkData(returned,
which);
//If data okay, clear Panel 2
if(complete == 0) {
if(which == 1) {
JOptionPane.showMessageDialog(frame,
dataModel.custID, "Customer ID",
JOptionPane.PLAIN_MESSAGE);
}
frame.resetPanelTwo();
}
//If errors, redisplay data to user
//and leave error messages on display
if(complete == 1) {
frame.createEditableFields(dataModel.first,
dataModel.last, dataModel.mid,
dataModel.str, dataModel.cty,
dataModel.st, dataModel.zp,
dataModel.tel, dataModel.mail);
}
}
}
//Clear data on cancel button press
if(source == frame.cancel) {
frame.resetPanelTwo();
}
}
The DataModel class provides methods for reading data from the database, writing data to the database, retrieving data from the user interface, and checking that data before it is written to the database.
Figure 8 illustrates how the DataModel class interacts
with the BankApp and EventHandle classes,
and the following sections detail the illustration.
Figure 8: Class Interactions
The constructor receives an instance of the BankApp class
and assigns it to its private instance variable so the DataModel
object can display error messages in the user interface when its
checkData or writeData method detects errors.
It also receives an instance of the ResourceBundle
class and assigns it to its private instance variable so the
DataModel object has access to the application client's
localized text.
Because the DataModel class interacts with the database, the
constructor also has the code to establish a connection with the
remote interface for the CustomerController enterprise
bean and use the remote interface to create an instance of the
CustomerControllerEJB enterprise bean.
public DataModel(BankApp frame,
ResourceBundle messages) {
this.frame = frame;
this.messages = messages;
//Look up and create CustomerController bean
try {
customerControllerHome =
EJBGetter.getCustomerControllerHome(
);
customer = customerControllerHome.create();
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
}
The getData method retrieves data from the user interface
text fields and uses the String.trim method to remove extra
control characters such as spaces and returns.
Its one parameter is a JTextfield so any instance of
the JTextfield class can be passed in for processing.
This polymorphic approach saves the series of if statements
used in the BankAppNotOO version.
private String getData(JTextField component) {
String text, trimmed;
if(component.getText().length() > 0) {
text = component.getText();
trimmed = text.trim();
return trimmed;
} else {
text = null;
return text;
}
}
The checkData method
stores data retrieved by the getData method
and checks the data to be sure all required fields have data,
the middle initial is no longer than one character, and the state is no
longer than two characters. If everything checks out, the writeData
method is called. If there are errors, they are printed to the user interface
in the BankApp object.
protected int checkData(
String returned, int which) {
int i, j, k;
this.which = which;
this.returned=returned;
last = getData(frame.lname);
first = getData(frame.fname);
mid = getData(frame.mi);
str = getData(frame.street);
cty = getData(frame.city);
st = getData(frame.state);
zp = getData(frame.zip);
tel = getData(frame.phone);
mail = getData(frame.e);
frame.messlab.setText(null);
frame.messlab2.setText(null);
frame.messlab3.setText(null);
frame.messlab4.setText(null);
frame.messlab6.setText(null);
//Check for data in required fields
if((last != null) && (first != null)
&& (str != null) && (cty != null)
&& (st != null)) {
i = 0;
} else {
frame.messlab6.setText(" " +
messages.getString(
"MissingRequiredException"));
i = 1;
}
//Check middle initial length
if(frame.mi.getText().length() > 1) {
frame.messlab2.setText(" " +
messages.getString("MILimitException"));
j = 1;
} else {
j = 0;
}
//Check state length
if(frame.state.getText().length() > 2) {
frame.messlab3.setText(" " +
messages.getString("StateLimitException"));
k = 1;
} else {
k = 0;
}
if((i == 0) && (j == 0) && (k == 0)) {
//Write data to database
int success = writeData();
return success;
} else {
return 1;
}
}
The writeData method determines whether the operation
is an add or an update and calls methods on the CustomerControlerEJB
enterprise bean as appropriate.
If the add or update operation fails, it writes error messages to the
BankApp user interface.
private int writeData() {
if(which == 2){ //Update customer information
try {
customer.setName(last, first, mid, returned);
customer.setAddress(str, cty, st, zp, tel,
mail, returned);
return 0;
} catch (RemoteException ex) {
frame.messlab.setText(" " +
messages.getString(
"RemoteException"));
return 1;
} catch (CustomerNotFoundException ex) {
frame.messlab4.setText(" " +
messages.getString(
"CustomerException") +
" " + returned + " " +
messages.getString(
"NotFoundException"));
return 1;
}
}
if(which == 1) { //Add new customer information
try {
custID = customer.createCustomer(
last, first, mid,
str, cty, st, zp, tel, mail);
return 0;
} catch (RemoteException ex) {
frame.messlab.setText(" " +
messages.getString(
"RemoteException"));
return 1;
}
}
return 0;
}
The createCustInf method is called by the EventHandle
class to refresh the Panel 2 display in the event of a view, update, or
add action event.
createROFields method in the BankApp
class for display in read-only fields.createEditableFields method in the BankApp
class for display in editable fields.createEditableFields method in the BankApp
with null data to create empty editable fields for the user to enter
customer data.
protected void createCustInf(int which,
String returned) {
CustomerDetails details = null;
//View Data
if((which == 3) && (returned.length() > 0)) {
try {
details = customer.getDetails(returned);
frame.createROFields(details.getFirstName(),
details.getLastName(),
details.getMiddleInitial(),
details.getStreet(
), details.getCity(),
details.getState(), details.getZip(),
details.getPhone(),
details.getEmail());
} catch (RemoteException ex) {
frame.messlab.setText(" Remote Exception");
} catch (CustomerNotFoundException ex) {
frame.messlab4.setText(" " +
messages.getString("CustomerException") +
" " + returned + " " +
messages.getString("NotFoundException"));
frame.resetPanelTwo();
}
}
//Update Data
if((which == 2) && (returned.length() > 0)) {
try {
details = customer.getDetails(returned);
frame.createEditableFields(
details.getFirstName(),
details.getLastName(),
details.getMiddleInitial(),
details.getStreet(), details.getCity(),
details.getState(), details.getZip(),
details.getPhone(),
details.getEmail());
} catch (RemoteException ex) {
frame.messlab.setText(" Remote Exception");
} catch (CustomerNotFoundException ex) {
frame.messlab4.setText(" " +
messages.getString("CustomerException") +
" " +
returned + " " +
messages.getString("NotFoundException"));
frame.resetPanelTwo();
}
}
//Add Data
if(which == 1) {
frame.createEditableFields(
null, null, null, null,
null, null, null, null, null);
}
}
You might want to include an application client with your J2EE application for handling system or application administration. Deploying and running an application client is slightly different from deploying and running other J2EE components, but the code to connect to the enterprise beans running on the J2EE server is the same for all J2EE components.
The enterprise beans used for this article are part of a larger banking application, which is part of the J2EE Tutorial. The J2EE Tutorial is an excellent resource for the J2EE platform, tools, and APIs. For information on the banking application, please see Duke's Bank Application.
1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.
© 1994-2005 Sun Microsystems, Inc.