Connect the enterprise with the JCA, Part 2

In "Connect the Enterprise with the JCA, Part 1," I introduced JCA (J2EE Connector Architecture), explained how it compares to EAI (enterprise application integration) products, and offered details on JCA interfaces.

JCA, an important new Java standard addressing enterprise integration, provides a framework, much like JDBC (Java Database Connectivity), to read and write data to different enterprise systems such as SAP, PeopleSoft, or Siebel. Reflecting its importance, the latest releases of most J2EE (Java 2 Platform, Enterprise Edition) application servers support JCA.

Read the whole series on the JCA:



In this article, the second of two, I demonstrate how to implement a JCA adapter -- a set of classes with which a J2EE application server targets a particular enterprise system. A JCA adapter functions similarly to how a JDBC driver connects to databases. However, because developing a full-featured JCA adapter is a complex task, I can only scratch the surface in this article. Nevertheless, by the end, you will understand a basic JCA adapter's construction, and grasp the effort required to build your own.

To accomplish those goals, I first describe the sample adapter's capabilities, as well as how to deploy and run it. I then introduce the implementation classes, followed by what occurs when the adapter executes in the container. Finally, I discuss the lessons learned from creating the sample adapter.

Note: To download the myjca.rar source code that accompanies this article, see Resources.

What the sample JCA adapter implementation does (and doesn't) contain

First, it's important to frame the sample-adapter discussion by describing its functionality. This article's sample adapter doesn't actually hook up to an enterprise system; it merely implements the interfaces required to deploy the adapter and look up a connection.

Moreover, the sample adapter implements only those classes required for the JCA specification's connection management section. Further, most of the adapter's method implementations contain print statements that let you see the method calls' order, without hooking up a debugger. The sample adapter does not, however, address transaction and security contacts.

This article's sample adapter does not use the CCI (Common Client Interface) interfaces. It strictly demonstrates the classes necessary to connect to an enterprise system.

What you need to deploy the sample adapter

To use the adapter (or any JCA adapter for that matter), you need a J2EE application server with JCA 1.0 specification support. I used BEA's WebLogic 6.1 server to test the sample adapter; however, other application servers should work.

To deploy the sample adapter with BEA's WebLogic 6.1, you must:

  1. Navigate to the connector tree in the Administration Console
  2. Click on the "Install new connector" link
  3. Navigate to the myjca.rar file, then upload it  http://www.javaworld.com/javaworld/jw-02-2002/jca/jw-0201-jca2.zip

In a later section, you'll find instructions on how to compile and build myjca.rar.

The sample class files

Next, let's delve into the Java classes required to implement the sample JCA adapter. The adapter includes two class categories:

  • Managed classes: The application server calls managed classes to perform the connection management. They're needed only if the application server is managing the connection (via a connection pool), a likely situation.
  • Physical connection classes: These required classes, which the aforementioned managed classes may call, establish the connection to the EIS (enterprise information systems).



MyManagedConnectionFactory

With the MyManagedConnectionFactory class, which implements the ManagedConnectionFacytory interface, you create the MyConnectionFactory and MyManagedConnection classes. The MyManagedConnectionFactory class acts as the main entry point for the application server to call into the adapter:

 

None.gif  
None.gif
package  myjca;
None.gif
import  java.io.PrintWriter;
None.gif
import  java.io.Serializable;
None.gif
import  java.sql.DriverManager;
None.gif
import  java.util.Iterator;
None.gif
import  java.util.Set;
None.gif
import  javax.resource.ResourceException;
None.gif
import  javax.resource.spi. * ;
None.gif
import  javax.security.auth.Subject;
None.gif
public   class  MyManagedConnectionFactory
None.gif    
implements  ManagedConnectionFactory, Serializable
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public MyManagedConnectionFactory() dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.constructor");
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.createConnectionFactory,1");
InBlock.gif        
return new MyDataSource(this, cxManager);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public Object createConnectionFactory() throws ResourceException dot.gif{
InBlock.gif              System.out.println(
"In MyManagedConnectionFactory.createManagedFactory,2");
InBlock.gif        
return new MyDataSource(thisnull);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo info) dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.createManagedConnection");
InBlock.gif        
return new MyManagedConnection(this"test");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo info)
InBlock.gif        
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.matchManagedConnections");
InBlock.gif        
return null;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public void setLogWriter(PrintWriter out) throws ResourceException dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.setLogWriter");
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public PrintWriter getLogWriter() throws ResourceException dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnectionFactory.getLogWriter");
InBlock.gif        
return DriverManager.getLogWriter();
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public boolean equals(Object obj) dot.gif{
InBlock.gif        
if(obj == null)
InBlock.gif            
return false;
InBlock.gif        
if(obj instanceof MyManagedConnectionFactory)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
int hash1 = ((MyManagedConnectionFactory)obj).hashCode();
InBlock.gif            
int hash2 = hashCode();
InBlock.gif            
return hash1 == hash2;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return false;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
public int hashCode()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif              
return 1;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
MyManagedConnection

The MyManagedConnection class implements the ManagedConnection interface. MyManagedConnection encapsulates the adapter's physical connection, in this case the MyConnection class:

 
  
None.gif package  myjca;
None.gif
import  java.io.PrintWriter;
None.gif
import  java.sql.Connection;
None.gif
import  java.sql.SQLException;
None.gif
import  java.util. * ;
None.gif
import  javax.resource.NotSupportedException;
None.gif
import  javax.resource.ResourceException;
None.gif
import  javax.resource.spi. * ;
None.gif
import  javax.security.auth.Subject;
None.gif
import  javax.transaction.xa.XAResource;
None.gif
public   class  MyManagedConnection
None.gif  
implements  ManagedConnection
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif     
private MyConnectionEventListener myListener;
InBlock.gif     
private String user;
InBlock.gif     
private ManagedConnectionFactory mcf;
InBlock.gif     
private PrintWriter logWriter;
InBlock.gif     
private boolean destroyed;
InBlock.gif     
private Set connectionSet;
InBlock.gif  MyManagedConnection(ManagedConnectionFactory mcf, String user)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    System.out.println(
"In MyManagedConnection");
InBlock.gif    
this.mcf = mcf;
InBlock.gif    
this.user = user;
InBlock.gif    connectionSet 
= new HashSet();
InBlock.gif    myListener 
= new MyConnectionEventListener(this);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
private void throwResourceException(SQLException ex)
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    ResourceException re 
= new ResourceException("SQLException: " +
InBlock.gifex.getMessage());
InBlock.gif    re.setLinkedException(ex);
InBlock.gif    
throw re;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public Object getConnection(Subject subject, ConnectionRequestInfo
InBlock.gifconnectionRequestInfo)
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    System.out.println(
"In MyManagedConnection.getConnection");
InBlock.gif    MyConnection myCon 
= new MyConnection(this);
InBlock.gif    addMyConnection(myCon);
InBlock.gif    
return myCon;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void destroy()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.destroy");
InBlock.gif        destroyed 
= true;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void cleanup()
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.cleanup");
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void associateConnection(Object connection)
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.associateConnection");
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void addConnectionEventListener(ConnectionEventListener listener)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.addConnectionEventListener");
InBlock.gif    myListener.addConnectorListener(listener);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void removeConnectionEventListener(ConnectionEventListener listener)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.removeConnectionEventListener");
InBlock.gif    myListener.removeConnectorListener(listener);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public XAResource getXAResource()
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.getXAResource");
InBlock.gif    
return null;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public LocalTransaction getLocalTransaction()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif           System.out.println(
"In MyManagedConnection.getLocalTransaction");
InBlock.gif      
return null;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public ManagedConnectionMetaData getMetaData()
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    System.out.println(
"In MyManagedConnection.getMetaData");
InBlock.gif    
return new MyConnectionMetaData(this);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public void setLogWriter(PrintWriter out)
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.setLogWriter");
InBlock.gif    logWriter 
= out;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
public PrintWriter getLogWriter()
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.getLogWriter");
InBlock.gif    
return logWriter;
ExpandedSubBlockEnd.gif  }

InBlock.gif  Connection getMyConnection()
InBlock.gif    
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.getMyConnection");
InBlock.gif    
return null;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
boolean isDestroyed()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.isDestroyed");
InBlock.gif    
return destroyed;
ExpandedSubBlockEnd.gif  }

InBlock.gif  String getUserName()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.getUserName");
InBlock.gif    
return user;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
void sendEvent(int eventType, Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.sendEvent,1");
InBlock.gif    myListener.sendEvent(eventType, ex, 
null);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
void sendEvent(int eventType, Exception ex, Object connectionHandle)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.sendEvent,2 ");
InBlock.gif    myListener.sendEvent(eventType, ex, connectionHandle);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
void removeMyConnection(MyConnection myCon)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.removeMyConnection");
InBlock.gif    connectionSet.remove(myCon);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
void addMyConnection(MyConnection myCon)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.addMyConnection");
InBlock.gif    connectionSet.add(myCon);
ExpandedSubBlockEnd.gif  }

InBlock.gif  ManagedConnectionFactory getManagedConnectionFactory()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif        System.out.println(
"In MyManagedConnection.getManagedConnectionFactory");
InBlock.gif    
return mcf;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}
MyConnectionEventListener

For its part, the MyConnectionEventListener class allows the application server to register callbacks for the adapter. The application server can then perform operations, connection-pool maintenance, for example, based on the connection state:

 

None.gif package  myjca;
None.gif
import  java.util.Vector;
None.gif
import  javax.resource.spi.ConnectionEvent;
None.gif
import  javax.resource.spi.ConnectionEventListener;
None.gif
import  javax.resource.spi.ManagedConnection;
None.gif
public   class  MyConnectionEventListener
None.gif    
implements  javax.sql.ConnectionEventListener
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private Vector listeners;
InBlock.gif    
private ManagedConnection mcon;
InBlock.gif    
public MyConnectionEventListener(ManagedConnection mcon)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener");
InBlock.gif        
this.mcon = mcon;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void sendEvent(int eventType, Exception ex, Object connectionHandle)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener.sendEvent");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void addConnectorListener(ConnectionEventListener l)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener.addConnectorListener");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void removeConnectorListener(ConnectionEventListener l)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener.removeConnectorListener");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void connectionClosed(javax.sql.ConnectionEvent connectionevent)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener.connectorClosed");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void connectionErrorOccurred(javax.sql.ConnectionEvent event)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionEventListener.connectorErrorOccurred");
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
MyConnectionMetaData

The MyConnectionMetaData class provides meta information -- product name, the maximum number of connections allowed, and so on -- regarding the managed connection and the underlying physical connection class:

 

None.gif package  myjca;
None.gif
import  javax.resource.ResourceException;
None.gif
import  javax.resource.spi. * ;
None.gif
public   class  MyConnectionMetaData
None.gif    
implements  ManagedConnectionMetaData
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private MyManagedConnection mc;
InBlock.gif    
public MyConnectionMetaData(MyManagedConnection mc)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionMetaData.constructor");
InBlock.gif        
this.mc = mc;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getEISProductName()
InBlock.gif        
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionMetaData.getEISProductName");
InBlock.gif        
return "myJCA";
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getEISProductVersion()
InBlock.gif        
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionMetaData.getEISProductVersion");
InBlock.gif        
return "1.0";
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public int getMaxConnections()
InBlock.gif        
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif            System.out.println(
"In MyConnectionMetaData.getMaxConnections");
InBlock.gif            
return 5;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getUserName()
InBlock.gif        
throws ResourceException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif           
return mc.getUserName();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
MyConnection

Next up: the MyConnection class, which represents the underlying physical connection to the EIS. MyConnection is one of the few classes that does not implement an interface in the JCA specification. The implementation below is simplistic, but a working implementation might contain connectivity code using sockets, as well as other functionality:

 

None.gif package  myjca;
None.gif
public   class  MyConnection
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private MyManagedConnection mc;
InBlock.gif    
public MyConnection(MyManagedConnection mc)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnection");
InBlock.gif        
this.mc = mc;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


MyConnectionRequestInfo

The MyConnectionRequestInfo class contains the data (such as the user name, password, and other information) necessary to establish a connection:

None.gif package  myjca;
None.gif
import  javax.resource.spi.ConnectionRequestInfo;
None.gif
public   class  MyConnectionRequestInfo
None.gif    
implements  ConnectionRequestInfo
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private String user;
InBlock.gif    
private String password;
InBlock.gif    
public MyConnectionRequestInfo(String user, String password)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo");
InBlock.gif        
this.user = user;
InBlock.gif        
this.password = password;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getUser()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo.getUser");
InBlock.gif        
return user;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getPassword()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo.getPassword");
InBlock.gif        
return password;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public boolean equals(Object obj)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo.equals");
InBlock.gif        
if(obj == null)
InBlock.gif            
return false;
InBlock.gif        
if(obj instanceof MyConnectionRequestInfo)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            MyConnectionRequestInfo other 
= (MyConnectionRequestInfo)obj;
InBlock.gif            
return isEqual(user, other.user) && isEqual(password, other.password);
ExpandedSubBlockEnd.gif        }
 else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return false;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
public int hashCode()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo.hashCode");
InBlock.gif        String result 
= "" + user + password;
InBlock.gif        
return result.hashCode();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
private boolean isEqual(Object o1, Object o2)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyConnectionRequestInfo.isEqual");
InBlock.gif        
if(o1 == null)
InBlock.gif            
return o2 == null;
InBlock.gif        
else
InBlock.gif            
return o1.equals(o2);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


MyDataSource

The MyDataSource class serves as a connection factory for the underlying connections. Because the sample adapter does not implement the CCI interfaces, it implements the DataSource interface in the javax.sql package:

None.gif package  myjca;
None.gif
import  java.io.PrintWriter;
None.gif
import  java.io.Serializable;
None.gif
import  java.sql. * ;
None.gif
import  javax.naming.Reference;
None.gif
import  javax.resource.Referenceable;
None.gif
import  javax.resource.ResourceException;
None.gif
import  javax.resource.spi.ConnectionManager;
None.gif
import  javax.resource.spi.ManagedConnectionFactory;
None.gif
import  javax.sql.DataSource;
None.gif
public   class  MyDataSource
None.gif    
implements  DataSource, Serializable, Referenceable
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private String desc;
InBlock.gif    
private ManagedConnectionFactory mcf;
InBlock.gif    
private ConnectionManager cm;
InBlock.gif    
private Reference reference;
InBlock.gif    
public MyDataSource(ManagedConnectionFactory mcf, ConnectionManager cm)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyDataSource");
InBlock.gif        
this.mcf = mcf;
InBlock.gif        
if(cm == null)
InBlock.gif            
this.cm = new MyConnectionManager();
InBlock.gif        
else
InBlock.gif            
this.cm = cm;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public Connection getConnection()
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyDataSource.getConnection,1");
InBlock.gif        
try
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return (Connection)cm.allocateConnection(mcf, null);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
catch(ResourceException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new SQLException(ex.getMessage());
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
public Connection getConnection(String username, String password)
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.out.println(
"In MyDataSource.getConnection,2");
InBlock.gif        
try
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            javax.resource.spi.ConnectionRequestInfo info 
= new MyConnectionRequestInfo(username, password);
InBlock.gif            
return (Connection)cm.allocateConnection(mcf, info);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
catch(ResourceException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new SQLException(ex.getMessage());
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
public int getLoginTimeout()
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return DriverManager.getLoginTimeout();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void setLoginTimeout(int seconds)
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        DriverManager.setLoginTimeout(seconds);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public PrintWriter getLogWriter()
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return DriverManager.getLogWriter();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void setLogWriter(PrintWriter out)
InBlock.gif        
throws SQLException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        DriverManager.setLogWriter(out);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public String getDescription()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return desc;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void setDescription(String desc)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
this.desc = desc;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public void setReference(Reference reference)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
this.reference = reference;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public Reference getReference()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return reference;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

Compile and build myjca.rar

Now that you've seen the adapter' source code, it's time to build the myjca.rar file. First, I assume you have a source directory containing two subdirectories: myjca containing the .java files, and META-INF containing the configuration files.

To compile and build the rar file:

  1. Compile the class files by typing javac *.java in the myjca directory
  2. Build the myjca.jar from the source directory by entering jar cvf myjca.jar myjca
  3. Create the rar file using the myjca.jar and the META-INF directory by typing jar cvf myjca.rar myjca.jar META-INF


Deployment output

Once you deploy the adapter rar file (using the steps outlined in the beginning of the article), you should see the output of the println statements contained in most of the adapter's methods. You should see output similar to the following as the adapter deploys:

In MyManagedConnectionFactory.constructor
In MyManagedConnectionFactory.createManagedConnection
In MyManagedConnection
In MyConnectionEventListener
In MyManagedConnection.getMetaData
In MyConnectionMetaData.constructor
In MyConnectionMetaData.getEISProductName
In MyConnectionMetaData.getEISProductVersion
In MyConnectionMetaData.getMaxConnections
 
 

The output above shows the ManagedConnectionFactory's creation, which then invoked the ManagedConnection, which in turn created the ConnectionEventListener. Finally, you see that the application server called the ConnectionMetaData.

Get a connection

Now that you've deployed the adapter successfully, let's use the adapter to obtain a connection. The following JSP (JavaServer Pages) file does just that, by looking up the connection using JNDI (Java Naming and Directory Interface), then calling the getConnection() method on the DataSource:

None.gif < html >
None.gif
< head >
None.gif       
< title > Connector example </ title >
None.gif
</ head >
None.gif
< body  bgcolor =#ffffff >
ExpandedBlockStart.gifContractedBlock.gif
<% dot.gif @ page import="javax.naming.*, java.sql.*, javax.sql.*"  %>
ExpandedBlockStart.gifContractedBlock.gif
<% dot.gif  
InBlock.gif    InitialContext initCtx 
= null;
InBlock.gif    
Object obj = null;
InBlock.gif    try {
InBlock.gif      initCtx 
= new InitialContext();
InBlock.gif      DataSource ds 
= (javax.sql.DataSource)
InBlock.gif      initCtx.lookup(
"MyConnector");      
InBlock.gif      obj 
= ds.getConnection();
InBlock.gif    } catch(NamingException ne) {
InBlock.gif        System.out.println(
"Error with context: " + ne);    
ExpandedBlockEnd.gif    }
None.gif
%>
None.gif
< h2 > Performed a lookup and got a connection </ h2 >
None.gif
</ body >
None.gif
</ html >  

You'll see the following output when the adapter acquires the connection:
 
 
In MyManagedConnectionFactory.createConnectionFactory,1
In MyDataSource
In MyDataSource.getConnection,1
In MyManagedConnectionFactory.matchManagedConnections
In MyManagedConnectionFactory.createManagedConnection
In MyManagedConnection
In MyConnectionEventListener
In MyManagedConnection.getMetaData
In MyConnectionMetaData.constructor
In MyConnectionMetaData.getEISProductName
In MyConnectionMetaData.getEISProductVersion
In MyConnectionMetaData.getMaxConnections
In MyManagedConnection.getUserName
In MyManagedConnection.getConnection
In MyConnection
In MyManagedConnection.addMyConnection
In MyManagedConnection.addConnectionEventListener
 
 
 

As you can see, many classes help obtain the connection.

Lessons learned

As you've likely figured out, the JCA specification's complexity makes implementing even a basic adapter a large undertaking. Moreover, the task grows larger when you add the transaction and security contracts (not implemented for this sample adapter), as well as the CCI interfaces.

The complexity shows that the JCA specification is really oriented towards commercial software vendors implementing adapters and their consulting/IT customers using them. In this context, the JCA interfaces' complexity makes sense, although a less flexible, simpler interface version would be nice.

Therefore, if you are considering using JCA to connect to a legacy system in your enterprise, you'd benefit from leveraging an off-the-shelf adapter rather than developing your own. If the system to which you need connectivity does not have a JCA adapter (that is, for a homegrown system), consider an alternative approach. Using Web services to connect to such a system may offer the best solution.

For its part, while JCA is still a new standard, it shows promise for making the task of integrating with an EIS less daunting.

Author Bio

Dirk Reinshagen, an architect at Zaplet, Inc., a commercial software vendor in the San Francisco Bay Area, has more than eight years of software architecture and development experience. He holds a B.S. in computer science from Tufts University.
 
摘自:http://www.javaworld.com/javaworld/jw-02-2002/jw-0201-jca2.html?page=1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值