Download JNDI (Java Naming and Directory Interface) is used as a naming

Document related concepts
no text concepts found
Transcript
JNDI
JNDI (Java Naming and Directory Interface) is used
as a naming and directory service in J2EE/J2SE
components.
A Naming service is a service that provides a mechanism for giving names to objects so that you can
reference and retrieve those objects without knowing the location of the object. Examples are DNS,
NIS.
A Directory service is a naming service but also provides additional information by associating attributes with the objects. Examples are Active Directory and LDAP.
JNDI
22 February 2008
1
JNDI itself is just an API so it relies on an underlying
service provider.
Java program
JNDI API
JNDI Service Provider Interface (SPI)
LDAP/DNS/NIS/CORBA/RMI/NDS/...
The SPI is the place where vendors can plugin service providers.
JNDI
22 February 2008
2
•
You only need to learn a single API
•
Insulates the application from protocols and
implementation details
•
You can read/write whole Java objects from the
directories
•
You can link different services together
•
You can access resource factories such as JDBC
drives or JMS drivers
•
Looking up beans
JNDI
22 February 2008
3
A naming system is an hierarchical connected set of
contexts, such as an LDAP tree or a catalogue hierachy. However there is no universal syntax for different services.
JNDI
22 February 2008
4
A J2EE or Servlet container contains a JDNI server
but there are others, e. g. rmiregistry that is a standanlone RMI nameserver.
Some information that you might need to know to
use a JNDI server:
•
JNDI service classname
•
Servers host name
•
port number
The exact info depends on the server
JNDI is used in JDBC, EJB, RMI-IIOP
JNDI
22 February 2008
5
There are several ways of defining JNDI service
properties for a program, but you need only one of
them.
•
Add the properties to the Java runtime home
directory
•
provide an application resource file for the program
•
Specify command line arguments
•
Hardcode in your program, e. g. a Hashmap of
name/value pairs.
A property is just a name/value pair (in the simplest
case). A property file is a file named jndi.properties
that holds these pairs.
JNDI
22 February 2008
6
Some important properties are
•
java.naming.provider.url, defines the server that
runs your jndi service
•
java.naming.factory.initial, defines the classname
of the SPI
•
java.naming.factory.url.pkgs, defines prefix for
other classes used.
JNDI
22 February 2008
7
JNDI is defined in the javax.naming package.
The environment where you can lookup or add
names is a Context.
The default context can be obtained with
Context ctx = new InitialContext();
Once you have a context you can add (bind) JNDI
objects to it
ctx.bind(“java:comp/env”, xxxx);
and lookup JNDI objects
xxxtype xxx = ctx.lookup(““java:/comp/env”);
or looking up an EJB
Object lookup =
ctk.lookup(“java:comp/env/ejb/Agency”);
AgencyHome home = (AgencyHome)
PortableRemoteObject.narrow(lookup,
AgencyHome.class);
The latter is known as narrowing, the remote object
is not an Object but can be narrowed into one.
JNDI
22 February 2008
8
Contexts are hierarchical eg
Context initContext = new InitialContext();
Context envContext =
(Context) initContext.lookup(
“java:/comp/env”);
JNDI
22 February 2008
9
JNDI
22 February 2008
10
JNDI
22 February 2008
11
The 2.1 Specfication EJB’s
Ordinary Java Beans do have a number of limitations:
They are not integrated in the container. No lifecycle
control, no resourcepooling, no sharing, not possible
to secure the beans.
They cannot easily be distributed.
There is no model for how persistency should be
handled.
JNDI
22 February 2008
12
EJB’s (Enterprise Java Beans) is a J2EE component
that is supposed to overcome some of these shortcomings.
What is an EJB?
It is a serverside Java component that encapsulates
the business logic of an application. In other word it
is a piece of Java under the control of the web container and adheres to a number of protocols.
When to use EJB’s?
•
The application must be scalable. You can distibute components across multiple machines, the
location of the EJB’s will be transparent.
•
Transactions are required to ensure data integrity
•
When there are a variety of clients
JNDI
22 February 2008
13
Types of Enterprise Beans:
Session Beans, perform a task for a user, i. e. implements a service somehow
Entity Beans, implements a business entity object
that exists in persistent storage.
Message-Driven Beans, Acts as a listener for the
Java Message Service (JMS) API, process messages
asynchronously
JNDI
22 February 2008
14
What is a Session Bean?
A session bean represents a single client inside the
J2EE server. To access a session bean, the beans
methods are invoked. It performs work for its client,
shielding the client from the complexity inside the
server.
It is not shared nor persistent. When its session terminates, the association is broken and the bean is
terminated or reused.
JNDI
22 February 2008
15
State Management Modes:
We do have stateful session beans and stateless session beans.
A stateful sessionbean do have instancevariables.
The state of the bean is their values. It is also called
“conversational state”.
The state is retained by the container for the duration of the session.
A stateless session bean does not maintain a state. It
can have instancevariables but their state is only
maintained during an invokation.
They are therefore all identical and can be pooled
and reused by other application at soon as they are
free. There is no need to save them anywhere.
JNDI
22 February 2008
16
When to use a session bean?
•
At any time, only one client has access to the bean
instance
•
The state is not persistent
•
The bean implements a web service
JNDI
22 February 2008
17
Stateful beans are appropriate if any of this is true:
•
The state represents interaction between the bean
and the client
•
The bean need to hold information about the client
across invokations
•
The beans mediates between the client and other
components
•
The bean manages the work flow for several beans
Stateless beans are appropriate if any of this is true:
•
The beans state has no clientspecific data
•
In a single method, the bean performs a generic
task for all clients, like sending a mail
•
The beans fetches from a database a set of readonly data that is often used by clients.
JNDI
22 February 2008
18
What is an Entity Bean?
An entity bean represents a business object in a persinstent storage mechanism. Examples of business
objects are customers, orders and products.
The persistent storage in J2EE is a RDBMS. Typically
an entity bean represents one row in table in the
database.
JNDI
22 February 2008
19
What makes Entity Beans different from Session
Beans?
Persistence:
Because the state of an entity bean is saved, it is persistent. This means that the state exists beyond the
lifetime of the client and the server.
There are two types of persistence: BMP and CMP.
With Bean Managed Persistence, the code that you
write contains the database accesses.
With Container Managed Persistence, the container
issues all database access calls automatically. The
exact statements to use are part of the deployment
data, i. e. configured in the container.
JNDI
22 February 2008
20
Shared access:
Entity beans are shared by multiple clients. Therefore you have to use transactions to maintain a
proper state.
Primary key:
Each entity bean has a unique object identifier. A
customer might for example be identified with a
customer number. The unique identifier, the primary key, is used to locate a particular entity bean.
Relationships:
Entity beans may be related to other entity beans.
You need to take care of relations when you use
BMP.
JNDI
22 February 2008
21
Container-managed Persistance:
When using CMP, there are no SQL-statements in
your bean. Instead there are an associated abstract
schema that defines that layout and the actions. This
means that you are not dependent on a particular
database
Abstract Schema:
This defines the fields in the bean and their relationships. The schema is referenced by queries written
in EJB-QL. There should be one query for each
finder method.
JNDI
22 February 2008
22
When to use Entity Beans?
•
The bean represents a business entity, not a procedure. For example a CreditCard, but not CreditCardValidator.
•
The state must be persistent. If the server or the
bean terminates, the data is still stored in the database.
JNDI
22 February 2008
23
What is a Message Driven Bean?
It is a kind of bean that acts as a listener for messages that are asynchronously processed. The message may be sent by any other J2EE component, or a
JMS application outside J2EE.
They are a kind of session beans but they are
accessed in a different way.
JNDI
22 February 2008
24
Defining Client Access with Interfaces.
You never access an EJB directly. For each bean you
define an interface that specifies the methods you
need.
The interfaces simplifies the bean development
because it is separated from the actual implementation. It means the beans can change internally as
long as it doesn’t affect the interface.
The interfaces are never implemented though.
Instead they are used to map your calls into beanmethods in the server. Thus the server will act as
kind of proxy for you.
This is because the location of the bean isn’t known
to the client, but the server knows.
JNDI
22 February 2008
25
There are two sets of interfaces that are used:
•
the remote and home interfaces. These are used for
the general case where a bean might be running in
another JVM somewhere.
•
the local and localhome interfaces. These are used
if we want to restrict our bean to our local JVM.
Firstly you need to decide whether your client
should be remote to the bean or not. You can always
use remote/home interfaces but there is a performance cost in doing that. All access is done using
RMI-calls.
There are some criterias about how to decide this
but we will leave those to self study.
JNDI
22 February 2008
26
A remote model:
Remote
interface
Remote
client
business
methods
EJB
Home
interface
lifecycle
control
Note that you call the interfaces but they are only
stubs that works as proxies, and that the container
will forward your call into the bean itself.
JNDI
22 February 2008
27
The content of an Enterprise Bean
•
Deployment descriptor, i. e. an XML file that specifies information about the type and other
attributes of the bean
•
The bean class, i. e. the implementation of the bean
itself
•
The interfaces
•
Helper classes, other classes that the bean class
might need
JNDI
22 February 2008
28
You pack this into an EJB-jar. Then you package the
complete application in an EAR-file.
This means that you will probably need some kind
of tools to produce the proper files and to deploy the
bean.
In addition you need an EJB-container. You can use
jboss.
www.jboss.org
or Sun’s reference implementation of the J2EE spec
java.sun.com/j2ee/index.jsp
JNDI
22 February 2008
29
Naming conventions (assuming <name> is our
bean):
Enterprise bean name:
EJB JAR:
Bean class:
Home Interface:
Remote Interface:
Local home interface:
Local interface:
Abstract schema:
JNDI
<name>EJB
<name>JAR
<name>Bean
<name>Home
<name>
<name>LocalHome
<name>Local
<name>
22 February 2008
30
An example, a converter, a stateless session bean.
The remote interface:
package converter;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
import java.math.*;
public interface Converter extends EJBObject {
public BigDecimal dollarToYen(
BigDecimal dollars)
throws RemoteException;
public BigDecimal yenToEuro(
BigDecimal yen)
throws RemoteException;
}
JNDI
22 February 2008
31
And the home interface:
package converter;
import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface ConverterHome extends EJBHome {
Converter create() throws RemoteException,
CreateException;
}
JNDI
22 February 2008
32
And the Bean itself:
package converter;
import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.math.*;
public class ConverterBean implements SessionBean
{
BigDecimal yenRate =
new BigDecimal(“121.6000”);
BigDecimal euroRate =
new BigDecimal(“0.0077”);
public BigDecimal dollarToYen(
BigDecimal dollars) {
BigDecimal result =
dollars.multiply(yenRate);
return result.setScale(2,
BigDecimal.ROUND_UP);
}
public BigDecimal yenToEuro(
BigDecimal yen) {
BigDecimal result =
yen.multiply(euroRate);
return result.setScale(2,
BigDecimal.ROUND_UP);
JNDI
22 February 2008
33
}
public ConverterBean() {}
public void ejbCreate() {}
public void ejbRemove() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext(
SessionContext sc) {}
} // ConverterBean
JNDI
22 February 2008
34
And a client:
import converter.Converter;
import converter.ConverterHome;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import java.math.BigDecimal;
public class ConverterClient {
public static void main(String[] args) {
try {
Context initial = new InitialContext();
Context myEnv =
Context) initial.lookup(“java:comp/env”);
Object objref =
myEnv.lookup(“ejb/SimpleConverter”);
ConverterHome home = (ConverterHome)
PortableRemoteObject.narrow(
objref, ConverterHome.class);
Converter currencyConverter =
home.create();
BigDecimal param =
new BigDecimal(“100.00”);
BigDecimal amount =
currencyConverter.dollarToYen(param);
System.out.println(amount);
amount =
currencyConverter.yenToEuro(param);
JNDI
22 February 2008
35
System.out.println(amount);
System.exit(0);
} catch (Exception ex) {
System.err.println(
“Caught an unexpected exception!”);
ex.printStackTrace();
}
}
}
JNDI
22 February 2008
36
A JSP Client
<%@ page import=”converter.Converter,
converter.ConverterHome, javax.ejb.*,
java.math.*, javax.naming.*,
javax.rmi.PortableRemoteObject,
java.rmi.RemoteException” %>
<%!
private Converter converter = null;
public void jspInit() {
try {
InitialContext ic = new InitialContext();
Object objRef = ic.lookup(“java:comp/env/ejb/TheConverter”);
ConverterHome home =
(ConverterHome)PortableRemoteObject.narrow(
objRef, ConverterHome.class);
converter = home.create();
} catch (RemoteException ex) {
System.out.println(“Couldn’t create converter bean.”+
ex.getMessage());
} catch (CreateException ex) {
System.out.println(“Couldn’t create converter bean.”+
ex.getMessage());
} catch (NamingException ex) {
System.out.println(“Unable to lookup home: “+
“TheConverter “+ ex.getMessage());
}
}
public void jspDestroy() {
converter = null;
}
%>
<html>
<head>
<title>Converter</title>
</head>
JNDI
22 February 2008
37
<body bgcolor=”white”>
<h1><b><center>Converter</center></b></h1>
<hr>
<p>Enter an amount to convert:</p>
<form method=”get”>
<input type=”text” name=”amount” size=”25”>
<br>
<p>
<input type=”submit” value=”Submit”>
<input type=”reset” value=”Reset”>
</form>
<%
String amount = request.getParameter(“amount”);
if ( amount != null && amount.length() > 0 ) {
BigDecimal d = new BigDecimal (amount);
%>
<p>
<%= amount %> dollars are <%= converter.dollarToYen(d) %> Yen.
<p>
<%= amount %> Yen are <%= converter.yenToEuro(d) %> Euro.
<%
}
%>
</body>
</html>
JNDI
22 February 2008
38
web.xml will be
<?xml version=”1.0” encoding=”UTF-8”?>
<web-app xmlns=”http://java.sun.com/xml/ns/
j2ee” version=”2.4” xmlns:xsi=”http://
www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/
j2ee http://java.sun.com/xml/ns/j2ee/
web-app_2_4.xsd”>
<display-name xml:lang=”sv”>
ConverterWAR
</display-name>
<servlet>
<display-name xml:lang=”sv”>
index
</display-name>
<servlet-name>
index
</servlet-name>
<jsp-file>
/index.jsp
</jsp-file>
</servlet>
<ejb-ref>
<ejb-ref-name>
ejb/TheConverter
</ejb-ref-name>
<ejb-ref-type>
Session
JNDI
22 February 2008
39
</ejb-ref-type>
<home>
converter.ConverterHome
</home>
<remote>
converter.Converter
</remote>
</ejb-ref>
</web-app>
JNDI
22 February 2008
40
And the additional sun-web.xml
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE sun-web-app PUBLIC “-//Sun
Microsystems, Inc.//DTD Application Server 8.0
Servlet 2.4//EN” “http://www.sun.com/
software/appserver/dtds/
sun-web-app_2_4-0.dtd”>
<sun-web-app>
<context-root>/converter</context-root>
<ejb-ref>
<ejb-ref-name>
ejb/TheConverter
</ejb-ref-name>
<jndi-name>
ConverterEJB
</jndi-name>
</ejb-ref>
</sun-web-app>
JNDI
22 February 2008
41
A BMP entity bean is a bit more complex, but an
example is:
The remote interface:
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
import java.math.BigDecimal;
public interface SavingsAccount extends EJBObject {
public void debit(BigDecimal amount)
throws InsufficientBalanceException,
RemoteException;
public void credit(BigDecimal amount)
throws RemoteException;
public String getFirstName()
throws RemoteException;
public String getLastName()
throws RemoteException;
public BigDecimal getBalance()
throws RemoteException;
}
JNDI
22 February 2008
42
The home interface:
import java.util.Collection;
import java.math.BigDecimal;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface SavingsAccountHome
extends EJBHome {
public SavingsAccount create(String id,
String firstName,
String lastName,
BigDecimal balance)
throws RemoteException,
CreateException;
public SavingsAccount findByPrimaryKey(
String id)
throws FinderException,
RemoteException;
public Collection findByLastName(
String lastName)
throws FinderException,
RemoteException;
public Collection findInRange(
BigDecimal low, BigDecimal high)
throws FinderException,
RemoteException;
JNDI
22 February 2008
43
public void chargeForLowBalance(
BigDecimal minimumBalance,
BigDecimal charge)
throws InsufficientBalanceException,
RemoteException;
}
JNDI
22 February 2008
44
And the bean itself:
import java.sql.*;
import javax.sql.*;
import java.util.*;
import java.math.*;
import javax.ejb.*;
import javax.naming.*;
public class SavingsAccountBean implements EntityBean {
private String id;
private String firstName;
private String lastName;
private BigDecimal balance;
private EntityContext context;
private Connection con;
private final static String dbName =
“java:comp/env/jdbc/SavingsAccountDB”;
public void debit(BigDecimal amount)
throws InsufficientBalanceException {
if (balance.compareTo(amount) == -1) {
throw new InsufficientBalanceException();
}
balance = balance.subtract(amount);
}
public void credit(BigDecimal amount) {
balance = balance.add(amount);
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
JNDI
22 February 2008
45
public BigDecimal getBalance() {
return balance;
}
public void ejbHomeChargeForLowBalance(
BigDecimal minimumBalance,
BigDecimal charge)
throws InsufficientBalanceException {
try {
SavingsAccountHome home = (SavingsAccountHome)
context.getEJBHome();
Collection c = home.findInRange(new BigDecimal(“0.00”),
minimumBalance.subtract(new BigDecimal(“0.01”)));
Iterator i = c.iterator();
while (i.hasNext()) {
SavingsAccount account = (SavingsAccount) i.next();
if (account.getBalance().compareTo(charge) == 1) {
account.debit(charge);
}
}
} catch (Exception ex) {
throw new EJBException(“ejbHomeChargeForLowBalance: “
+ ex.getMessage());
}
}
public String ejbCreate(String id, String firstName,
String lastName, BigDecimal balance)
throws CreateException {
if (balance.signum() == -1) {
throw new CreateException
(“A negative initial balance is not allowed.”);
}
try {
insertRow(id, firstName, lastName, balance);
} catch (Exception ex) {
JNDI
22 February 2008
46
throw new EJBException(“ejbCreate: “ + ex.getMessage());
}
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.balance = balance;
return id;
}
public String ejbFindByPrimaryKey(String primaryKey)
throws FinderException {
boolean result;
try {
result = selectByPrimaryKey(primaryKey);
} catch (Exception ex) {
throw new EJBException(“ejbFindByPrimaryKey: “ +
ex.getMessage());
}
if (result) {
return primaryKey;
} else {
throw new ObjectNotFoundException
(“Row for id “ + primaryKey + “ not found.”);
}
}
public Collection ejbFindByLastName(String lastName)
throws FinderException {
Collection result;
try {
result = selectByLastName(lastName);
} catch (Exception ex) {
throw new EJBException(“ejbFindByLastName “ +
ex.getMessage());
}
return result;
}
JNDI
22 February 2008
47
public Collection ejbFindInRange(BigDecimal low,
BigDecimal high)
throws FinderException {
Collection result;
try {
result = selectInRange(low, high);
} catch (Exception ex) {
throw new EJBException(“ejbFindInRange: “ +
ex.getMessage());
}
return result;
}
public void ejbRemove() {
try {
deleteRow(id);
} catch (Exception ex) {
throw new EJBException(“ejbRemove: “ + ex.getMessage());
}
}
public void setEntityContext(EntityContext context) {
this.context = context;
}
public void unsetEntityContext() {}
public void ejbActivate() {
id = (String) context.getPrimaryKey();
}
public void ejbPassivate() {
id = null;
}
public void ejbLoad() {
JNDI
22 February 2008
48
try {
loadRow();
} catch (Exception ex) {
throw new EJBException(“ejbLoad: “ + ex.getMessage());
}
}
public void ejbStore() {
try {
storeRow();
} catch (Exception ex) {
throw new EJBException(“ejbStore: “ + ex.getMessage());
}
}
public void ejbPostCreate(String id, String firstName,
String lastName, BigDecimal balance) {}
/*********************** Database Routines *************************/
private void makeConnection() {
try {
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup(dbName);
con = ds.getConnection();
} catch (Exception ex) {
throw new EJBException(“Unable to connect to database. “
+ ex.getMessage());
}
}
private void releaseConnection() {
try {
con.close();
} catch (SQLException ex) {
throw new EJBException(“releaseConnection: “ +
ex.getMessage());
}
}
JNDI
22 February 2008
49
private void insertRow(String id, String firstName,
String lastName, BigDecimal balance)
throws SQLException {
makeConnection();
String insertStatement =
“insert into savingsaccount values ( ? , ? , ? , ? )”;
PreparedStatement prepStmt =
con.prepareStatement(insertStatement);
prepStmt.setString(1, id);
prepStmt.setString(2, firstName);
prepStmt.setString(3, lastName);
prepStmt.setBigDecimal(4, balance);
prepStmt.executeUpdate();
prepStmt.close();
releaseConnection();
}
private void deleteRow(String id) throws SQLException {
makeConnection();
String deleteStatement =
“delete from savingsaccount where id = ? “;
PreparedStatement prepStmt =
con.prepareStatement(deleteStatement);
prepStmt.setString(1, id);
prepStmt.executeUpdate();
prepStmt.close();
releaseConnection();
}
private boolean selectByPrimaryKey(String primaryKey)
throws SQLException {
makeConnection();
String selectStatement = “select id “
+ “from savingsaccount where id = ? “;
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, primaryKey);
JNDI
22 February 2008
50
ResultSet rs = prepStmt.executeQuery();
boolean result = rs.next();
prepStmt.close();
releaseConnection();
return result;
}
private Collection selectByLastName(String lastName)
throws SQLException {
makeConnection();
String selectStatement = “select id “
+ “from savingsaccount where lastname = ? “;
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, lastName);
ResultSet rs = prepStmt.executeQuery();
ArrayList a = new ArrayList();
while (rs.next()) {
String id = rs.getString(1);
a.add(id);
}
prepStmt.close();
releaseConnection();
return a;
}
private Collection selectInRange(BigDecimal low, BigDecimal high)
throws SQLException {
makeConnection();
String selectStatement = “select id from savingsaccount “
+ “where balance between ? and ?”;
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setBigDecimal(1, low);
prepStmt.setBigDecimal(2, high);
JNDI
22 February 2008
51
ResultSet rs = prepStmt.executeQuery();
ArrayList a = new ArrayList();
while (rs.next()) {
String id = rs.getString(1);
a.add(id);
}
prepStmt.close();
releaseConnection();
return a;
}
private void loadRow() throws SQLException {
makeConnection();
String selectStatement = “select firstname, lastname, balance “
+ “from savingsaccount where id = ? “;
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, this.id);
ResultSet rs = prepStmt.executeQuery();
if (rs.next()) {
this.firstName = rs.getString(1);
this.lastName = rs.getString(2);
this.balance = rs.getBigDecimal(3);
prepStmt.close();
} else {
prepStmt.close();
throw new NoSuchEntityException(“Row for id “ + id
+ “ not found in database.”);
}
releaseConnection();
}
private void storeRow() throws SQLException {
makeConnection();
String updateStatement =
“update savingsaccount set firstname = ? ,”
+ “lastname = ? , balance = ? “ + “where id = ?”;
JNDI
22 February 2008
52
PreparedStatement prepStmt =
con.prepareStatement(updateStatement);
prepStmt.setString(1, firstName);
prepStmt.setString(2, lastName);
prepStmt.setBigDecimal(3, balance);
prepStmt.setString(4, id);
int rowCount = prepStmt.executeUpdate();
prepStmt.close();
if (rowCount == 0) {
throw new EJBException(
“Storing row for id “ + id + “ failed.”);
}
releaseConnection();
}
} // SavingsAccountBean
JNDI
22 February 2008
53
And a client:
import java.util.*;
import java.math.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public class SavingsAccountClient {
public static void main(String[] args) {
try {
Context initial = new InitialContext();
Object objref =
initial.lookup(“java:comp/env/ejb/SimpleSavingsAccount”);
SavingsAccountHome home =
(SavingsAccountHome) PortableRemoteObject.narrow(
objref.SavingsAccountHome.class);
BigDecimal zeroAmount = new BigDecimal(“0.00”);
SavingsAccount duke =
home.create(“123”, “Duke”, “Earl”, zeroAmount);
duke.credit(new BigDecimal(“88.50”));
duke.debit(new BigDecimal(“20.25”));
BigDecimal balance = duke.getBalance();
System.out.println(“balance = “ + balance);
duke.remove();
SavingsAccount joe =
home.create(“836”, “Joe”, “Jones”, zeroAmount);
joe.credit(new BigDecimal(“34.55”));
SavingsAccount jones = home.findByPrimaryKey(“836”);
jones.debit(new BigDecimal(“2.00”));
balance = jones.getBalance();
System.out.println(“balance = “ + balance);
SavingsAccount pat =
home.create(“456”, “Pat”, “Smith”, zeroAmount);
JNDI
22 February 2008
54
pat.credit(new BigDecimal(“44.77”));
SavingsAccount john =
home.create(“730”, “John”, “Smith”, zeroAmount);
john.credit(new BigDecimal(“19.54”));
SavingsAccount mary =
home.create(“268”, “Mary”, “Smith”, zeroAmount);
mary.credit(new BigDecimal(“100.07”));
Collection c = home.findByLastName(“Smith”);
Iterator i = c.iterator();
while (i.hasNext()) {
SavingsAccount account = (SavingsAccount) i.next();
String id = (String) account.getPrimaryKey();
BigDecimal amount = account.getBalance();
System.out.println(id + “: “ + amount);
}
c = home.findInRange(new BigDecimal(“20.00”),
new BigDecimal(“99.00”));
i = c.iterator();
while (i.hasNext()) {
SavingsAccount account = (SavingsAccount) i.next();
String id = (String) account.getPrimaryKey();j
BigDecimal amount = account.getBalance();
System.out.println(id + “: “ + amount);
}
SavingsAccount pete = home.create(
“904”, “Pete”, “Carlson”, new BigDecimal(“5.00”));
SavingsAccount sally = home.create(
“905”, “Sally”, “Fortney”, new BigDecimal(“8.00”));
home.chargeForLowBalance(new BigDecimal(“10.00”),
new BigDecimal(“1.00”));
BigDecimal reducedAmount = pete.getBalance();
JNDI
22 February 2008
55
System.out.println(reducedAmount);
reducedAmount = sally.getBalance();
System.out.println(reducedAmount);
System.exit(0);
} catch (InsufficientBalanceException ex) {
System.err.println(“Caught an InsufficientBalanceException: “
+ ex.getMessage());
} catch (Exception ex) {
System.err.println(“Caught an exception.”);
ex.printStackTrace();
}
}
}
JNDI
22 February 2008
56
create.sql:
drop table savingsaccount;
create table savingsaccount (
id varchar(3) constraint pk_savings_account primary key,
firstname varchar(24), lastname varchar(24),
balance numeric(10,2));
JNDI
22 February 2008
57
And web.xml
<?xml version=”1.0” encoding=”UTF-8”?><ejb-jar version=”2.1”
xmlns=”http://java.sun.com/xml/ns/j2ee” xmlns:xsi=
”http:/www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://
java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”>
<display-name>SavingsAccountJAR</display-name>
<enterprise-beans>
<entity>
<ejb-name>SavingsAccountEJB</ejb-name>
<home>SavingsAccountHome</home>
<remote>SavingsAccount</remote>
<ejb-class>SavingsAccountBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.Object</prim-key-class>
<reentrant>false</reentrant>
<resource-ref>
<res-ref-name>jdbc/SavingsAccountDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<security-identity>
<use-caller-identity/>
</security-identity>
</entity>
</enterprise-beans>
</ejb-jar>
JNDI
22 February 2008
58
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE sun-ejb-jar PUBLIC “-//Sun Microsystems, Inc.//DTD
Sun ONE Application Server 8.0 EJB 2.1//EN”
“http://www.sun.com/software/sunone/appserver
/dtds/sun-ejb-jar_2_1-0.dtd”>
<sun-ejb-jar>
<enterprise-beans>
<name>SavingsAccountJAR</name>
<unique-id>1489827553</unique-id>
<ejb>
<ejb-name>SavingsAccountEJB</ejb-name>
<jndi-name>SavingsAccountEJB</jndi-name>
<resource-ref>
<res-ref-name>jdbc/SavingsAccountDB</res-ref-name>
<jndi-name>jdbc/ejbTutorialDB</jndi-name>
</resource-ref>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
JNDI
22 February 2008
59