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

Java Data Access—JDBC, JNDI, and JAXP phần 6 doc

38 305 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 38
Dung lượng 241,44 KB

Nội dung

a single source. Parameterize the Factory class to create different product objects. Clients can supply different parameters to the factory to retrieve different products. This option enables you to change the factory method dynamically based on your application’s current need. 2. Define an interface for the Factory and let the client reference it in order to change factories as needed. 3. In my next example, I build a connection manager that uses a factory that incorporates the enhancement listed above. The following list identifies some of the features: The ConnectionManager and Factory objects are implemented as a Singleton.• You can supply usernames, passwords and database IDs as parameters to control what database you connect to and which database user account you connect with. • I define an abstract factory class and build specific factory classes that provide connections to either an Oracle or an Access database. • I also remove the client’s reliance on concrete classes in the following example. The product and factory class names appear only in the connection manager, not in the client’s code base. This architecture creates a framework in which you can add your own database connection factory for your system. Remember, the authors of Design Patterns suggest that you program to interfaces rather than to implementations. Listing 11−2 provides the code for an enhanced version of the Factory Method pattern in which I show you how to do this. Listing 11−2: EnhancedFactory.java package Chapter11; import java.sql.*; //Abstract class that defines interface for factory objects abstract class AbstractConnFactory { //Protected variables that hold database specific information protected static Connection conn; protected String dbType = null; protected String user = null; protected String password = null; protected String driver = null; protected String jdbcUrl = null; protected String database = null; //Close the database connection public void close() throws SQLException { //Check if conn is null, if not close it and set to null if (conn!=null){ System.out.println("Closing connection"); System.out.println(); conn.close(); conn = null; } } Chapter 11: Producing Objects with the Factory Method Pattern 180 //Access method to return a reference to a Connection object public Connection connect() throws Exception{ if(conn!=null){ System.out.println("Connection exists. Returning instance "); }else{ System.out.println("Connection not created. Opening connection phase "); openConnection(); }//end if return conn; } //Private method to create connection. private void openConnection() throws Exception{ //Register a driver Class.forName(driver).newInstance(); //Obtain a Connection object System.out.println("Connecting to " + dbType + " database "); conn = DriverManager.getConnection(jdbcUrl, user, password); System.out.println("Connection successful "); } }//end AbstractConnFactory //Subclass of the AbstractConnFactory for connecting to an ODBC database. class OdbcConnFactory extends AbstractConnFactory{ //Private variables private static OdbcConnFactory ocf= null; //Private constructor private OdbcConnFactory() { jdbcUrl ="jdbc:odbc:"; driver = "sun.jdbc.odbc.JdbcOdbcDriver"; } //Public method used to get the only instance of OdbcConnFactory. public static synchronized AbstractConnFactory getInstance(){ //If not initialized, do it here. Otherwise return existing object. if(ocf==null) ocf = new OdbcConnFactory(); return ocf; } //Overridden method to open a database connection public Connection connect() throws Exception{ Chapter 11: Producing Objects with the Factory Method Pattern 181 //Configure the JDBC URL jdbcUrl = jdbcUrl + database; //Call the base class method to provide the connection return super.connect(); } }//end OdbcConnFactory // Subclass of the AbstractConnFactory for connecting to an Oracle database. class OracleConnFactory extends AbstractConnFactory{ //Private variables private static OracleConnFactory ocf= null; //Private constructor private OracleConnFactory() { jdbcUrl = "jdbc:oracle:thin:@localhost:1521:"; driver = "oracle.jdbc.driver.OracleDriver"; } //Public method used to get the only instance of OracleConnFactory. public static synchronized AbstractConnFactory getInstance(){ //If not initialized, do it here. Otherwise just return existing object. if(ocf==null) ocf = new OracleConnFactory(); return ocf; } //Overridden method to open a database connection public Connection connect() throws Exception{ //Configure the JDBC URL jdbcUrl = jdbcUrl + database; //Call the base class method to provide the connection return super.connect(); } }//end OracleFactory //Class to demonstrate the enhanced Factory Method public class EnhancedFactory { //Only reference to ConnectionManager static public ConnectionManager cm = null; //Main method public static void main(String[] args){ try{ Chapter 11: Producing Objects with the Factory Method Pattern 182 //Retrieve the only instance of ConnectionManager cm = cm.getInstance(); //Create and close a connection to the Oracle database to //demonstrate that it works. Connection conn = cm.connect(cm.ORACLE, "toddt", "mypwd", "ORCL"); cm.close(); //Open a connection to an Access database using ODBC conn = cm.connect(cm.ODBC, null, null, "employees"); cm.close(); //Catch all the relevant errors }catch(ConnectionManagerException cme){ cme.printStackTrace(); }catch(SQLException se){ se.printStackTrace(); }catch(Exception e){ e.printStackTrace(); //Use finally block to ensure database resources are closed }finally{ if(cm!=null) try{ cm.close(); }catch(SQLException se){ se.printStackTrace(); } } }//end main() }//end EnhancedFactory //Class that manages database connections class ConnectionManager { //Constants to represent database types public static final int ORACLE = 100; public static final int ODBC = 200; //Variables to hold only instance of ConnectionManager class private static ConnectionManager connMgr = null; //Holds reference to the specific connection factory private static AbstractConnFactory acf =null;; //Private constructor private ConnectionManager() {} //Method that provides connection logic public Connection connect (int dbType, String user, String password, String db) throws Exception{ //Examine the dbType parameter and assign the appropriate //factory to the //acf, which is the base class type. switch(dbType){ //Specific factories are Singletons so get the only Chapter 11: Producing Objects with the Factory Method Pattern 183 //instance and set the appropriate connection values. case ORACLE: acf = OracleConnFactory.getInstance(); acf.dbType = "Oracle"; break; case ODBC: acf = OdbcConnFactory.getInstance(); acf.dbType="ODBC"; break; //Error handling for unsupported database types. default: throw new SQLException("Type not supported"); }//end switch acf.database=db; acf.user=user; acf.password=password; //Connect to the database and return reference. Connection conn = acf.connect(); return conn; } //Close the database connection. public void close() throws SQLException{ acf.close(); } //Public method used to get the only instance of ConnectionManager. public static synchronized ConnectionManager getInstance(){ if(connMgr==null) connMgr = new ConnectionManager(); return connMgr; } }//end ConnectionManager //Used to handle ConnectionManager specific errors class ConnectionManagerException extends SQLException { //default constructor public ConnectionManagerException(){ super(); } //Constructor that allows you to specify your own error messages. public ConnectionManagerException(String msg){ Chapter 11: Producing Objects with the Factory Method Pattern 184 super(msg); } }// end ConnectionManagerException The output from Listing 11−2 is as follows: Connection not created. Beginning connection phase Connecting to Oracle database Connection successful Closing connection Connection not created. Beginning connection phase Connecting to ODBC database Connection successful Closing connection Listing 11−2 uses numerous objects. Figure 11−3 provides a UML class diagram showing the relationships of the classes used in the example. To further help understand the classes, Table 11−2 maps the Factory Method components to the classes in the example. In the code listing, I create the AbstractConnFactory to represent the FactoryInterface. I make the class abstract for two reasons. First, I do not want the class to be directly instantiated. Rather, I want clients to use one of the connection factories, either Oracle or ODBC. Secondly, the two factories share implementations of the openConnection() and the close() methods. If the methods need to be different, I can always override them in a subclass. Figure 11−3: UML class diagram of the enhanced Factory Method example Table 11−2: EnhancedFactory Example Classes Factory Method Components EnhancedFactory Components FactoryInterface AbstractConnFactory class Factory OracleConnFactory class OdbcConnFactory class ProductInterface java.sql.Connection interface Product java.sql.Connection interface Chapter 11: Producing Objects with the Factory Method Pattern 185 Client ConnectionManager Interfaces versus Abstract Classes Sometimes it is not obvious when you should use an interface or abstract class. Both provide similar functionality in that neither can be instantiated and each defines a common interface for subclasses. An interface is an abstract class without any method implementations. As a result, no storage is associated with an interface. In Java, combining interfaces in a class definition enables you to mimic multiple inheritance. This in turn enables you to upcast the class to any interface type included in the definition. The advantage of an abstract class is that you can provide common implementation code without requiring subclasses to rewrite the same code. When deciding which one to use, you should consider if you need multiple inheritance, or if you have numerous methods with identical implementations, that you can share among subclasses. In Listing 11−2 the two factories, OracleConnFactory and OdbcConnFactory, extend the AbstractConnFactory class. This allows the subclass access to the protected properties and methods of the base class, and ensures that they share the same interface. I override the connect() method of the base class in order to configure the jdbcUrl property. However, I still call the base class’s implementation to take advantage of how it manages the Connection object. You can easily add additional functionality in these factory subclasses. For example, Oracle has numerous extensions to the JDBC API that enables you to take advantage of specific Oracle characteristics. You can use those extensions in this class. You may notice the getInstance() method implemented in each subclass. Instantiated subclass objects behave as Singletons to divvy out a Connection object specific to each database. The AbstractConnFactory class is the workhorse of the example. As I mentioned earlier, it implements all the database’s connection−related methods: connect(), openConnection(), and close(). I let the subclasses handle the chores relevant to the specific database. In this example, they set specific driver information and configure the jdbcUrl variable. This class is also a Singleton, so it can control access to the connection logic. XRef Chapter 10, “Building the Singleton Pattern,” provides details on implementing the Singleton pattern. The ConnectionManager object, also a Singleton, controls access to the factories. The connect() method returns a Connection object. It also accepts parameters in order to allow a client to specify which type of database to connect to, and the username and password to connect with. The heart of the method is the following code: switch(dbType){ //Specific factories are Singletons so get the only //instance and set the appropriate connection values. case ORACLE: acf = OracleConnFactory.getInstance(); acf.dbType = "Oracle"; break; case ODBC: acf = OdbcConnFactory.getInstance(); Chapter 11: Producing Objects with the Factory Method Pattern 186 acf.dbType="ODBC"; break; //Error handling for unsupported database types. default: throw new ConnectionManagerException("Type not supported"); }//end switch The switch block contains the logic used to create the correct factory based on the input parameter dbType, which maps to two int constants, ORACLE and ODBC, defined in the class. The variable acf is of type AbstractConnFactory. Depending on the value of the parameter dbType, it is assigned a reference to either the OracleConnFactory or the OdbcConnFactory class. Depending upon the database type, information is propagated up to the base class to populate the variables that hold the connection parameters. In this example, the variable dbType in the base class is only used to identify the factory type. The example also has some supporting classes. The java.sql.Connection interface provides the ProductInterface component for my example, and the two factories create Connection objects as the Product. You may have noticed that I create my own SQLException class called ConnectionManagerException to handle ConnectionManager−related issues. In the preceding example I trap the error that occurs if you supply an unsupported database type to the connect() method. Summary The Factory Method pattern is likely one that you will often implement. It enables you to create consistent objects while abstracting the details of their creation from the client. You can also enhance the basic Factory Method pattern to separate specific implementations from your application. Clients can refer to the base class interface for the factory and products to allow them to use the objects they need when they need them. To summarize, you will find the Factory Method useful if: You need to abstract object creation from the client.• You want subclasses to decide how to create objects and what objects to create.• You cannot anticipate the type of object you must create at runtime.• Chapter 11: Producing Objects with the Factory Method Pattern 187 Chapter 12: Creating a Façade Pattern In This Chapter Understanding the purpose of the Façade pattern• Introducing the structure of the Façade pattern• Applying the Façade pattern to JDBC programming• Implementing the Façade pattern• The previous chapters focused on creational patterns. In this chapter, I switch gears and cover a structural pattern, the Façade. This category of design patterns focuses on combining objects and classes to create larger, more feature−rich, structures. Class patterns in this category, such as the Adapter, use inheritance, while object patterns, like the Façade, use composition to create the new structures. The Façade pattern provides a front−end to a complex object subsystem. Clients use the Façade object to interact with the subsystem. This minimizes the number of methods and objects a client needs to know about. It also allows the subsystem to change without affecting the client. I begin the chapter with a discussion on the details on the Façade pattern. Next I present its structure, and finally provide an implementation example that hides the details of making JDBC database connections and SQL queries. Unlike the previous chapters, this one places more emphasis on the example. What Is the Façade Pattern? The word façade means “an artificial or deceptive front” and that is exactly what this pattern is. The Façade pattern puts an “artificial” front, or interface, onto an object subsystem to simplify a client’s use of it. Instead of having to know about methods from all the objects in the subsystem, the client only needs to understand the methods defined by the Façade object. The only object in the pattern, the Façade object, provides the common interface with an object subsystem. Many different objects can exist in the subsystem, and the interactions among them can be highly complex. However, the Façade pattern wraps the complexity into one object. From the client’s point of view, the Façade object is the subsystem. Façades occur everywhere in the physical world. Consider your microwave, for example. The control panel, or the Façade for the microwave, has numerous buttons, and each of which controls some complex functionality that in turn requires that many components or subsystems work together. Setting the microwave to run on HIGH power for one minute requires only a few control−panel steps, but it sets off a flurry of activity among subsystems inside the microwave. You know nothing about how the microwave completes its task, only that it runs on HIGH for one minute. The same scenario occurs in JDBC programming. For example, a lot of background activity occurs to return a Connection object when you call the Connection.getConnection() method. What happens behind the scenes doesn’t matter, because all you need is a database connection, not the details of what the driver does to make the connection. 188 Nonetheless, the JDBC API is an example of an object subsystem that you can wrap with the Façade pattern. Although using the API is not complex, a lot of redundant method calls occur. For instance, opening a database connection requires the same method calls every time. Executing queries is equally repetitive. You can create a Façade object to hide these details so a client only needs to know one or two methods to access and interact with a database. In fact, this is what I do in this chapter’s example. Introducing the Structure of the Façade Pattern The Façade pattern has the simplest pattern structure I have covered yet. It has only one object, which provides the gateway into a subsystem of objects. Figure 12−1 shows the general structure. The Façade object needs intimate knowledge of the classes in the subsystem. When a client sends a request to the object, the Façade object must know exactly which subsystem object to send the request for execution. The client only needs to know the correct Façade method to call and nothing about the subsystem. However, the subsystem objects have no knowledge of the Façade object. As indicated in Figure 12−1, there is an unidirectional relationship between the Façade object and the subsystem components. That is, they operate independently of the Façade and treat it as their client. Figure 12−1: Façade pattern structure Implementing the Façade Pattern Although you may find the Façade pattern conceptually simple, you will probably find it the most difficult to implement. Reducing a complex subsystem to an interface with a few methods for a client to use is challenging. You need to spend a significant portion of your design time identifying the interface that will best meet the client’s needs. Apart from designing the interface, you have a couple of options available when implementing the pattern. First, you can make the Façade object a Singleton to ensure that only one access point into the subsystem Chapter 12: Creating a Façade Pattern 189 [...]... Package javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi Description Defines classes and interfaces that enable you to interact with naming services Defines classes and interfaces that enable you to interact with directory services Defines classes and interfaces that handle event notifications when you’re working with naming and directory services Defines classes and. .. interact with the database 202 Part IV: Taking It to the Enterprise Chapter List Chapter 13: Accessing Enterprise Data with JNDI Chapter 14: Using Data Sources and Connection Pooling Chapter 15: Understanding Distributed Transactions Chapter 16: Working with JDBC Rowsets Chapter 17: Building Data centric Web Applications Chapter 18: Using XML with JAXP Chapter 19: Accessing Data with Enterprise JavaBeans 203... Name: Todd, Hiredate: 1995−09− 16, Salary: $5000.55 Parameterized UPDATE with execute() to update my salary and hire date Verify updates Row Number=1, SSN: 111111111, Name: Todd, Hiredate: 1989−09− 16, Salary: $100000.75 Add new employee with INSERT and execute() then verify results Row Number=1, SSN: 5 866 69377, Name: Andy, Hiredate: 2001−04−23, Salary: $1400.51 Close and open database connection then verify... Data with JNDI In This Chapter • Introducing naming and directory services • Understanding the Java Naming and Directory Interface (JNDI) • Using JNDI to access data in naming and directory services • Working with LDAP • Using the JNDI LDAP service−provider interface • Searching an LDAP−enabled directory service As enterprise applications grow larger and more complex, finding application services and. .. Closing Database Connection! Connection has not been opened Begin connection phase Connecting to database Connection successful Row Number=1, SSN: 5 866 69377, Name: Andy, Hiredate: 2001−04−23, Salary: $1400.51 Exiting program Closing SqlStatement! Closing Database Connection! Goodbye! 201 Chapter 12: Creating a Façade Pattern In Listing 12−1, I first retrieve a reference to the DbFacade object and use... a driver and open a connection to the data source before you can access a data store Working with the Context and DirContext interfaces The Context and DirContext interfaces play a central role in JNDI programming The first defines methods for interacting with naming services It defines the bind(), rebind(), and unbind() methods that you use to bind and 211 Chapter 13: Accessing Enterprise Data with... PreparedStatement setDate() DbFacade() Private constructor init() Retrieves a reference to the ConnectionMgr object and creates the SqlStatement object Also causes a database connection to be created Listing 12−1: Facade .java package Chapter12; import import import import import java. io.*; java. util.*; java. sql.*; java. sql.Date; Chapter5.MakeEmpDb;//REMOVE public class Facade { //Set a ResultSet object to hold results... cornerstone of the J2EE platform Clients, and business components like Enterprise Java Beans (EJBs), use it to find and retrieve resources such as JDBC DataSource objects from well−known data stores within an organization I begin this chapter by introducing the concepts associated with naming and directory services Next I provide the details of JNDI’s architecture and show you how to use it to access LDAP−enabled... contains the API and the LDAP, COS, RMI, and NIS service providers Sun also provides, as separate downloads, a File System, Domain Name System (DNS), and Directory Service Markup Language (DMSL) service provider The JNDI Web site provides more information on obtaining the software JNDI clients use the API to access naming and directory services The API calls are standard, regardless of the data store you... primarily use the javax.naming and javax.naming.directory packages The following list describes the packages: • javax.naming: This package provides the methods that enable you to access naming services and defines the Context interface, the primary interface for interacting with a naming service It also defines the methods for you to look up, retrieve, bind, and unbind objects • javax.naming.directory: Just . ConnectionManager and Factory objects are implemented as a Singleton.• You can supply usernames, passwords and database IDs as parameters to control what database you connect to and which database user. ConnectionMgr object and creates the SqlStatement object. Also causes a database connection to be created. void Listing 12−1: Facade .java package Chapter12; import java. io.*; import java. util.*; import java. sql.*; import. Supports basic and parameterized queries using the PreparedStatement object. ConnectionMgr Manages database connections. Only shares one connection to the database. DbFacadeException Handles DbFacade−specific

Ngày đăng: 14/08/2014, 06:21

TỪ KHÓA LIÊN QUAN