Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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