• No results found

Using a JNDI DataSource

In document Java Programming with Oracle JDBC pdf (Page 103-106)

Cancel( ) and setQueryTimeout( ) are not supported by the server-side Thin driver.

Chapter 7. JNDI and Connection Pooling

7.1.3 Using a JNDI DataSource

Let's take a look at a couple of sample applications that illustrate the power and utility of using data sources that are accessed via JNDI. The examples use Sun's file-based JNDI

implementation. You can download the class files for Sun's JNDI filesystem implementation at http://java.sun.com/products/jndi/index.html.

First, the program in Example 7-2, TestDSBind, creates a logical entry in a JNDI directory to store our DataSource. It uses Sun's JNDI filesystem implementation as the directory. After that, we'll look at another program that uses the DataSource created by the first.

My DataSource bind program, TestDSBind, starts by creating a Context variable named

ctx. Next, it creates a Properties object to use in initializing an initial context. In layman's terms, that means it creates a reference to the point in the local filesystem where our program should store its bindings. The program proceeds by creating an initial Context and storing its reference in ctx. Next, it creates an OracleDataSource and initializes its properties. Why an

OracleDataSource and not a DataSource? You can't really use a DataSource for binding; you have to use an OracleDataSource, because the setter/getter methods for the properties are implementation- or vendor-specific and are not part of the DataSource interface. Last, the program binds our OracleDataSource with the name joe by calling the Context.bind( )

method.

Example 7-2. An application that binds a JNDI DataSource

import java.util.*; import javax.naming.*; import oracle.jdbc.pool.*;

public class TestDSBind {

public static void main (String args []) throws SQLException, NamingException {

// For this to work you need to create the

// directory /JNDI/JDBC on your filesystem first Context ctx = null;

try {

Properties prop = new Properties( ); prop.setProperty( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); prop.setProperty( Context.PROVIDER_URL, "file:/JNDI/JDBC"); ctx = new InitialContext(prop); }

catch (NamingException ne) {

System.err.println(ne.getMessage( )); }

OracleDataSource ds = new OracleDataSource( ); ds.setDriverType("thin"); ds.setServerName("dssw2k01"); ds.setPortNumber(1521); ds.setDatabaseName("orcl"); ds.setUser("scott"); ds.setPassword("tiger"); ctx.bind("joe", ds); } }

Create a directory, JNDI, on your hard drive, and then create a subdirectory, JDBC, in your JNDI directory. Compile Example 7-2 and execute it. Assuming you get no error messages, you should find a bindings file in your new JDBC subdirectory. This file holds the values for a

serialized form of your DataSource logically named joe. This means that we can later retrieve a new connection by referencing a resource named joe.

Now that we have a directory entry, let's test it with our next program, TestDSLookup, in

Example 7-3. First, TestDSLookUp creates an initial context just like TestDSBind did. Next, it uses the Context.lookup( ) method to look up and instantiate a new DataSource from our serialized version of joe. Finally, the program queries the database and closes the connection. Pretty cool huh? When using DriverManager, you typically must specify the JDBC driver and database URL in your source code. By using a DataSource together with JNDI, you can write code that is independent of a JDBC driver and of a database URL.

Example 7-3. An application that uses a JNDI DataSource

import java.sql.*; import javax.sql.*; import javax.naming.*;

import java.util.*;

public class TestDSLookUp {

public static void main (String[] args) throws SQLException, NamingException {

Context ctx = null; try {

Properties prop = new Properties( ); prop.setProperty( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); prop.setProperty( Context.PROVIDER_URL, "file:/JNDI/JDBC"); ctx = new InitialContext(prop); }

catch (NamingException ne) {

System.err.println(ne.getMessage( )); }

DataSource ds = (DataSource)ctx.lookup("joe"); Connection conn = ds.getConnection( );

Statement stmt = conn.createStatement( ); ResultSet rset = stmt.executeQuery(

"select 'Hello Thin driver data source tester '||" + "initcap(USER)||'!' result from dual");

if (rset.next( )) System.out.println(rset.getString(1)); rset.close( ); stmt.close( ); conn.close( ); } }

7.1.4 Caveats

I hope you can appreciate the long-term gain of using DataSources with JNDI rather than embedding connections in your code:

• It makes your code independent of a JDBC driver. • It makes your code independent of a database URL.

• It allows you to look up the driver and URL in one operation from anywhere on the network.

DataSource objects do, however, have a few drawbacks. One is that you can't use Oracle Advanced Security with the Thin driver, because there is no way to set the oracle.net

properties for data encryption and integrity. This is because oracle.net properties are not a part of the standard, nor are they part of Oracle's implementation-specific set of DataSource

properties. Another drawback to using DataSources is that you have to make the investment in an LDAP directory to truly leverage the use of JNDI, and that can be quite costly.

In addition to the drawbacks I've mentioned, there are a few DataSource behaviors you should be aware of. One concerns the logging feature. There are two methods you can use to set and

get the log writer for a DataSource. A log writer is a PrintWriter object used by the driver to write its activities to a log file. They are:

public synchronized void setLogWriter(PrintWriter pw) throws SQLException

public synchronized PrintWriter getLogWriter( ) throws SQLException

As with the DriverManager facility, logging is disabled by default. You will always need to call the setLogWriter( ) method after a DataSource has been instantiated, even if you set the log writer before you bind it to a directory. Why? Because the PrintWriter you specify in the

setLogWriter( ) method is transient and therefore cannot be serialized. A second behavior you should be aware of is that when DataSource logging is enabled, it bypasses

DriverManager's logging facility.

There are also two methods you can use to set and get the login timeout, which is the amount of time that an idle connection should be kept open. The methods are:

public synchronized void setLoginTimeout(int seconds) throws SQLException

public synchronized int getLoginTimeout( ) throws SQLException

Now that you have a firm grasp of how and when to use a DataSource object, let's continue our investigation of the JDBC 2.0 Extension API with a look at the connection pooling interface

ConnectionPoolDataSource.

In document Java Programming with Oracle JDBC pdf (Page 103-106)