1. Trang chủ
  2. » Công Nghệ Thông Tin

Art of Java Web Development STRUTS, TAPESTRY, COMMONS, VELOCITY, JUNIT, AXIS, COCOON, INTERNETBEANS, WEBWORK phần 7 potx

62 359 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 62
Dung lượng 779,62 KB

Nội dung

342 CHAPTER 12 Separating concerns import javax.sql.*; import java.sql.*; import com.nealford.art.ejbsched.model.ScheduleItem; import javax.rmi.PortableRemoteObject; public class EventDbBean implements SessionBean { private SessionContext sessionContext; private static final String SQL_SELECT = "SELECT * FROM event"; private static final String COLS[] = {"EVENT_KEY", "START", "DURATION", "DESCRIPTION", "EVENT_TYPE"}; public void ejbCreate() { } public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { } public void setSessionContext(SessionContext sessionContext) { this.sessionContext = sessionContext; } private DataSource getDataSource() throws RemoteException { DataSource ds = null; try { Context c = new InitialContext(); Object o = c.lookup("java:/MySQLDS"); ds = (DataSource) PortableRemoteObject.narrow(o, DataSource.class); } catch (ClassCastException ex) { throw new RemoteException("Cast exception", ex.getMessage()); }catch (NamingException ex) { throw new RemoteException("Naming exception", ex.getMessage()); } return ds; } The class EventDbBean implements SessionBean , which resides in the J2EE specifi- cation. Note that this is an interface, meaning that the EJB infrastructure relies on interfaces (as opposed to concrete classes) to ensure flexibility. The SessionBean interface defines a handful of methods, most of which are left blank for this bean. These methods represent callback hooks for the application server to manage the Using Enterprise JavaBeans 343 lifecycle of the bean. For example, the pair of methods for ejbActivate() and ebjPassivate() allow the developer to write code for a situation in which the application server needs to move the object out of memory temporarily. In this case, you can leave them blank but they must be present because of the interface. The next method accepts a SessionContext object. SessionContext is analogous to ServletContext —it is an object passed to this bean by the application server upon creation. It provides a connection to the application server’s facilities. The remaining method in this snippet returns a DataSource that allows the bean to connect to the database. The application server keeps the database connections in a pool. To access any resource of the application server, you create a Java Nam- ing and Directory Interface ( JNDI) context and ask for the resource by name. The lookup() method of Context returns an object reference to the requested resource (or null if the resource doesn’t exist). This object is cast to the appropriate type via the narrow() method and returned. The method for establishing the database connection pool within the applica- tion server is different with each application server. To create the named connec- tion for JBoss, you edit the jboss.jcml configuration file and add the entries shown in listing 12.2. <mbean code="org.jboss.jdbc.JdbcProvider" name="DefaultDomain:service=JdbcProvider"> <attribute name="Drivers"> org.hsqldb.jdbcDriver,org.gjt.mm.mysql.Driver </attribute> </mbean> <mbean code="org.jboss.jdbc.XADataSourceLoader" name="DefaultDomain:service=XADataSource,name=MySQLDS"> <attribute name="PoolName">MySQLDS</attribute> <attribute name="DataSourceClass"> org.jboss.pool.jdbc.xa.wrapper.XADataSourceImpl </attribute> <attribute name="URL"> jdbc:mysql://localhost/schedule </attribute> <attribute name="JDBCUser">root</attribute> <attribute name="Password">marathon</attribute> <attribute name="MinSize">0</attribute> <attribute name="MaxSize">5</attribute> </mbean> Listing 12.2 Jboss.jcml entries that establish a named connection pool 344 CHAPTER 12 Separating concerns The next order of business is to retrieve the schedule items from the connection delivered via the DataSource in the getDataSource() method. This code appears in listing 12.3. private ResultSet getResultSet() throws RemoteException, SQLException { return getDataSource().getConnection().createStatement(). executeQuery(SQL_SELECT); } public List getScheduleItems() throws RemoteException { ResultSet rs = null; List list = new ArrayList(10); Map eventTypes = getEventTypes(); try { rs = getResultSet(); addItemsToList(rs, list, eventTypes); } catch (SQLException sqlx) { throw new RemoteException(sqlx.getMessage()); } finally { try { rs.close(); rs.getStatement().getConnection().close(); } catch (SQLException ignored) { } } return list; } private void addItemsToList(ResultSet rs, List list, Map eventTypes) throws SQLException { while (rs.next()) { ScheduleItem si = new ScheduleItem(); si.setStart(rs.getString(COLS[1])); si.setDuration(rs.getInt(COLS[2])); si.setText(rs.getString(COLS[3])); si.setEventTypeKey(rs.getInt(COLS[4])); si.setEventType((String) eventTypes.get( new Integer(si.getEventTypeKey()))); list.add(si); } } The getResultSet() method simply returns a result set from the SQL query defined in a constant at the top of the class. This method is used by the getScheduleItems() method to execute the query. It creates the necessary data structures and in turn Listing 12.3 Retrieving the schedule items and returning them as a List Using Enterprise JavaBeans 345 calls the addItemsToList() method to populate the individual ScheduleItem s into the list. This code is similar to the non- EJB code that appears in chapter 4 (listing 4.2) in the original version of this application. To use an EJB, you must first create it. To create a bean, you must look up the name of the home interface for the bean from JNDI. The home interface returns an object that implements the remote interface defined with the bean. In other words, the home interface is a factory for creating instances of EJBs. Listing 12.4 contains the code that creates an EventDb reference. Object o = context.lookup("EventDb"); EventDbHome home = (EventDbHome) PortableRemoteObject.narrow(o, EventDbHome.class); EventDb eventDb = home.create(); One technique used by application servers for scalability involves indirection. The application server manages the actual objects and returns to the user a remote ref- erence to the object. If the developer doesn’t have a direct link to the object, the application server can manage the resources for the EJB much more effectively behind the scenes. When you get a reference to an EJB, you invoke the create() method on the home interface. The home interface returns a remote reference, which the application server attaches to a “real” object. In the code in listing 12.4, we look up the home interface for the EventDb bean, create an instance of the bean through its home interface, and return the EventDb reference. The home interface for EventDbBean is shown in listing 12.5. package com.nealford.art.ejbsched.ejb; import java.rmi.*; import javax.ejb.*; public interface EventDbHome extends EJBHome { public EventDb create() throws RemoteException, CreateException; } The home interface includes only a single method, which returns an EventDb ref- erence. The EventDb reference is a Remote Method Invocation (RMI) interface Listing 12.4 Creating an EventDb reference so that you can call its methods Listing 12.5 The home interface for EventDbBean 346 CHAPTER 12 Separating concerns that exposes the methods available through this object to the caller. It appears in listing 12.6. package com.nealford.art.ejbsched.ejb; import java.rmi.*; import javax.ejb.*; import java.util.List; public interface EventDb extends EJBObject { public List getScheduleItems() throws RemoteException; } The public interface for EventDbBean exposes only one method, which returns a List of schedule items. Thus, this is the only method that is callable from the EJB. This remote reference represents the “outside world’s” link to the code written inside the EJB. Once you have created a home reference and used it to create this remote reference, you call this method of the remote reference, which in turn calls the corresponding method of the bean: scheduleItems = eventDb.getScheduleItems(); The EventTypeDbBean EJB The other table whose items appear in the web application is the event_types table. The EventTypeDbBean stateless session bean encapsulates the application’s access to this resource. The source for the EventTypeDbBean is shown in listing 12.7. package com.nealford.art.ejbsched.ejb; import java.rmi.*; import java.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; import javax.rmi.*; import javax.sql.*; public class EventTypeDBBean implements SessionBean { private SessionContext sessionContext; private static final String SQL_EVENT_TYPES = "SELECT event_type_key, event_text FROM event_types"; public void ejbCreate() { Listing 12.6 The remote interface for EventDbBean Listing 12.7 The EventTypeDBBean encapsulates the event_types table values. Using Enterprise JavaBeans 347 } public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { } public void setSessionContext(SessionContext sessionContext) { this.sessionContext = sessionContext; } public Map getEventTypes() throws RemoteException { Map eventTypes = new HashMap(); Connection con = null; Statement s = null; ResultSet rs = null; try { con = getDataSource().getConnection(); s = con.createStatement(); rs = s.executeQuery(SQL_EVENT_TYPES); eventTypes = new HashMap(); while (rs.next()) eventTypes.put(rs.getObject("event_type_key"), rs.getString("event_text")); } catch (SQLException sqlx) { throw new RemoteException(sqlx.getMessage()); } finally { try { rs.close(); s.close(); con.close(); } catch (Exception ignored) { } } return eventTypes; } private DataSource getDataSource() throws RemoteException { DataSource ds = null; try { Context c = new InitialContext(); Object o = c.lookup("java:/MySQLDS"); ds = (DataSource) PortableRemoteObject.narrow(o, DataSource.class); } catch (ClassCastException ex) { throw new RemoteException(ex.getMessage()); }catch (NamingException ex) { 348 CHAPTER 12 Separating concerns throw new RemoteException(ex.getMessage()); } return ds; } } The EventTypeDbBean class is similar to the EventDbBean class. The primary differ- ence lies in the return type of the getEventTypes() method, which returns a Map instead of a List . The home and remote interfaces also resemble the ones from EventDbBean and don’t appear here. Both EventDbBean and EventDbTypeBean are stateless session beans that return collections of items from the database. These EJBs populate the views of the appli- cation but don’t provide a way of modifying one of the items they encapsulate. Entity beans are used for that purpose. The event entity EJB The only updatable item in the application is a schedule item. To update records in a database in an EJB application, entity beans are used. Like session beans, entity beans implement a standard J2EE interface. Two types of entity beans exist: container-managed persistence ( CMP) and bean-managed persistence (BMP). Container-managed entity beans use code generated by the application server to interact with the database. Each application server includes mapping tools that generate the appropriate JDBC code for creating, updating, deleting, and finding records. Container-managed beans offer ease of use—the developer doesn’t have to write any JDBC code. However, these beans can work only in generic circum- stances. For example, if the entity modeled spans multiple tables, most applica- tion servers cannot generate code to handle this contingency. In these cases, bean-managed persistence is the alternative. In bean-managed persistence, the developer of the bean writes the necessary JDBC code to create, update, delete, and find objects inside the bean. While this approach involves much more work (and debugging), it offers infinite flexibility. In the case of the schedule application, it would seem that we could use container- managed persistence. After all, we’re accessing a very simple table. However, the database server generates the keys for the records upon insert, which frees us from coming up with a scheme to ensure unique keys. Most database servers offer an auto-increment facility, and the MySQL database used in this application is no exception. Because the database server generates the key (and not the devel- oper), we cannot use container-managed persistence and must rely on bean-man- aged persistence instead. Using Enterprise JavaBeans 349 Another requirement for entity beans is a primary key class. Because they model database entities, each record must have a primary key. Generally, these key classes are simple encapsulated single values, but the infrastructure exists for com- plex compound keys. Listing 12.8 shows the primary key class for the event bean. package com.nealford.art.ejbsched.ejb; import java.io.*; public class EventPk implements Serializable { public int key; public EventPk() { } public EventPk(int key) { this.key = key; } public boolean equals(Object obj) { if (this.getClass().equals(obj.getClass())) { EventPk that = (EventPk) obj; return this.key == that.key; } return false; } public int hashCode() { return key; } } The EventPk class is a serializable class with a single public member variable, which is typical for EJB primary key classes. It contains two constructors, including a parameterless one. It also contains overridden equals() and hashCode() meth- ods. Including the equals() and hashCode() methods is a requirement for EJB and is critical to ensure that the application server can correctly compare two pri- mary keys via the equals() method and can place them into hashtables via hash- Code() . Listing 12.9 contains the prelude for EventBean . package com.nealford.art.ejbsched.ejb; import java.rmi.*; import javax.ejb.*; Listing 12.8 EventPk, the primary key class for EventBean Listing 12.9 The prelude for EventBean 350 CHAPTER 12 Separating concerns import javax.sql.DataSource; import java.sql.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import javax.naming.NamingException; public class EventBean implements EntityBean { private EntityContext entityContext; private static final String SQL_SELECT = "SELECT * FROM event" + " where event_key = ?"; private static final String SQL_INSERT = "INSERT INTO event (start, duration, description, " + "event_type) VALUES(?, ?, ?, ?)"; private static final String SQL_EVENT_TYPES = "SELECT event_type_key, event_text FROM event_types"; private static final String SQL_UPDATE = "UPDATE event SET start = ?, duration = ?, " + "description = ?, event_type = ? WHERE event_key = ?"; private static final String SQL_DELETE = "DELETE FROM event WHERE event_key = ?"; private static final String SQL_LAST_INSERT_ID = "SELECT distinct last_insert_id() k from event"; public String start; public int duration; public String text; public int eventType; public int eventKey; The EventBean class implements the EntityBean interface from J2EE. It contains a large number of constants that handle the SQL needed to perform its work. It also includes public member variables for the fields of the entity. It is common in entity beans for the fields to be public, which seems like a violation of encapsula- tion. However, the application server code itself is the only code that has access to these public fields. Remember that the user always accesses the bean through the remote interface. The ejbCreate() method (listing 12.10) creates a new record in the database. public EventPk ejbCreate(String start, int duration, String text, int eventType) throws CreateException { this.start = start; this.duration = duration; this.text = text; this.eventType = eventType; Listing 12.10 ejbCreate() creates a new Event entity. Using Enterprise JavaBeans 351 Connection con = null; PreparedStatement ps = null; Statement s = null; ResultSet rs = null; int newKey = -1; try { con = getDataSource().getConnection(); ps = con.prepareStatement(SQL_INSERT); ps.setString(1, start); ps.setInt(2, duration); ps.setString(3, text); ps.setInt(4, eventType); if (ps.executeUpdate() != 1) { throw new CreateException("Insert failed"); } // get the generated id s = con.createStatement(); rs = s.executeQuery(SQL_LAST_INSERT_ID); rs.next(); newKey = rs.getInt("k"); } catch (SQLException sqlx) { throw new CreateException(sqlx.getMessage()); } finally { try { if (rs != null) rs.close(); if (ps != null) ps.close(); if (s != null) s.close(); if (con != null) con.close(); } catch (Exception ignored) { } } EventPk eventPk = new EventPk(); eventPk.key = newKey; return eventPk; } public void ejbPostCreate(String start, int duration, String text, int eventType) throws CreateException { } The ejbCreate() method accepts parameters for all the fields except the key field, which comes from the database. The getDataSource() method of this bean is identical to the one in listing 12.1. This code performs a SQL INSERT command Pulls the key from the database [...]... behavior of the model objects themselves 12.3.3 Using EJBs in web frameworks Most of the frameworks featured in part 2 of Art of Java Web Development adhere to the Model 2 architecture As such, a similar transformation to EJB is possible In fact, that is why we chose the generic Model 2 application as the base The only framework we cover that prevents an easy porting to EJB is the sole Rapid Application Development. .. parts of some core concepts makes communication easier Design patterns, UML, and advanced Java language concepts (such as the way interfaces are used in enterprise systems) have become the lingua franca of Java web developers Changing fundamental infrastructure parts of your application is easy—if you have designed it to be extensible Otherwise, doing so is a nightmare This chapter provides the payoff... either the controller or the views—which illustrates the advantage of the clean separation of responsibilities in a Model 2 architecture Because the original application used Model 2 to separate the parts of the application, it enabled us to change the infrastructure of one of the key parts (the model) without affecting the other parts The model now acts as a proxy for the EJBs, which handle both persistence... database connection pool version of eMotherEarth.com is organized into four packages, and the shopping cart each with different For the sake of brevity, we show only the code that responsibilities is unique to this application The entire application is available with the source code archive as art_ emotherearth_base So, we won’t show listings of classes that consist primarily of accessors and mutators and... application’s quality 13.1.1 Building the base: eMotherEarth.com To illustrate these requests, an application must be in place This and subsequent chapters use a simulated toy e-commerce site named eMotherEarth The beginnings of this application appeared in chapter 2 to illustrate the evolution of web development from servlets and JSP However, this version of the application is reorganized into a Model 2... Understanding where to put things is more than half the battle The trend in software engineering decouples applications as much as possible The use of design patterns is an example of this trend, as is the use of business component technologies like EJBs It helps to see applications that successfully manage this separation That is one of the goals of this chapter Understanding the terminology and best practices... is shown in listing 12.15 Listing 12.15 The remote interface for the entity EJB EventBean package com.nealford .art. ejbsched.ejb; import java. rmi.*; import javax.ejb.*; public interface Event extends EJBObject { public void setStart(String start) throws RemoteException; public String getStart() throws RemoteException; public void setDuration(int duration) throws RemoteException; public int getDuration()... user interface of the application using Model 2 Handling flow This chapter covers I I I Application usability options Building undo operations Handling exceptions 371 372 CHAPTER 13 Handling flow In this chapter, we take a look at the usability and flow of a web application from a design standpoint The greatest application in the world won’t be used much if its flow doesn’t meet the needs of its users,... client-side validation The updated version of the Model 2 schedule application now incorporates JavaScript to perform input validation Note that this section is not meant to be an introduction to JavaScript; many books are available that cover JavaScript thoroughly This sample appears in the source code archive as art_ sched_js A common practice when including JavaScript places the code in a separate... validation This version of the schedule application uses client-side validation in JavaScript generated from the model objects First, place the JavaScript in the model objects as constants with an accessor This is demonstrated in listing 12.23 Figure 12 .7 Using JavaScript allows the user to get instant feedback whenever invalid data is entered 366 CHAPTER 12 Separating concerns Listing 12.23 JavaScript validations . lies in the encapsulated behavior of the model objects themselves. 12.3.3 Using EJBs in web frameworks Most of the frameworks featured in part 2 of Art of Java Web Development adhere to the Model. listing 12 .7. package com.nealford .art. ejbsched.ejb; import java. rmi.*; import java. sql.*; import java. util.*; import javax.ejb.*; import javax.naming.*; import javax.rmi.*; import javax.sql.*; public. com.nealford .art. ejbsched.ejb; import java. rmi.*; import javax.ejb.*; public interface Event extends EJBObject { public void setStart(String start) throws RemoteException; public String getStart()

Ngày đăng: 09/08/2014, 12:22

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN