D.S

www.adam-bien.com

A Simple Transactional File JCA 1.5 Connector (4 Classes / 2 Reusable) : Adam Bien's Weblog

A Simple Transactional File JCA 1.5 Connector (4 Classes / 2 Reusable) : Adam Bien's Weblog Adam Bien's Weblog « JavaOne Sessions... | Main | Service s = new... » A Simple Transactional File JCA 1.5 Connector (4 Classes / 2 Reusable) There is a common prejudice that JCA connectors have to be too complicated for day to day use. "Custom & lightweight" solutions are built instead, which are usually orders of magnitudes more complex, than a pragmatic JCA implementation. So, how to built one: JCA connectors are deployed as .rar archives with internal structure similar to ejb-jar archives. You can reuse your existing packaging and just change the ending from .jar to .rar Start with the ra.xml deployment descriptor. You "only" have to implement the elements listed in this deployment descriptor: <connector 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/connector_1_5.xsd"            version="1.5">     <display-name>Generic JCA</display-name>     <vendor-name>adam-bien.com</vendor-name>     <eis-type>Generic JCA</eis-type>     <resourceadapter-version>1.0</resourceadapter-version>     <resourceadapter>         <outbound-resourceadapter>             <connection-definition>                 <managedconnectionfactory-class>...genericjca.GenericManagedConnectionFactory</managedconnectionfactory-class>                 <connectionfactory-interface>...genericjca.DataSource</connectionfactory-interface>                 <connectionfactory-impl-class>...genericjca.FileDataSource</connectionfactory-impl-class>                 <connection-interface>...genericjca.Connection</connection-interface>                 <connection-impl-class>...genericjca.FileConnection</connection-impl-class>             </connection-definition>             <transaction-support>LocalTransaction</transaction-support>             <authentication-mechanism>                 <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>                 <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>             </authentication-mechanism>             <reauthentication-support>false</reauthentication-support>         </outbound-resourceadapter>     </resourceadapter> </connector>    GenericManagedConnectionFactory and GenericManagedConnection are mostly reusable. These classes care about connection management. You will be able to manage a connector through e.g. the Glassfish admin console. The code is surprisingly simple - its mainly book keeping and logging. See  http://kenai.com/projects/javaee-patterns/ , project GenericJCA. The "core" business logic resides in the FileConnection: public class FileConnection implements Connection, LocalTransaction{     private String buffer;     private FileOutputStream fileOutputStream;     private ConnectionRequestInfo connectionRequestInfo;     public final static String FILE_NAME = "/temp/jcafile.txt";     private GenericManagedConnection genericManagedConnection;     private PrintWriter out;     public FileConnection(PrintWriter out,GenericManagedConnection genericManagedConnection,ConnectionRequestInfo connectionRequestInfo) {         this.out = out;         this.genericManagedConnection = genericManagedConnection;         this.connectionRequestInfo = connectionRequestInfo;         this.initialize();     }     private void initialize(){         try {             this.buffer = null;             this.fileOutputStream = new FileOutputStream(FILE_NAME,true);         } catch (FileNotFoundException ex) {             Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex);             throw new IllegalStateException("Cannot initialize OutputStream: " + FILE_NAME);         }     }     public void write(String content) {         this.buffer = content;     }     public void close() {             this.genericManagedConnection.close();     }     public void destroy(){         try {             if(this.fileOutputStream != null)                 this.fileOutputStream.close();           this.fileOutputStream = null;           this.buffer = null;          } catch (IOException ex) {             Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex);             throw new IllegalStateException("Cannot close stream: " +ex,ex);         }     }     public void begin() throws ResourceException {         this.initialize();     }     public void commit() throws ResourceException {         out.println("#FileConnection.commit "  +toString());         try {          this.fileOutputStream.write(this.buffer.getBytes());          this.fileOutputStream.flush();          this.fileOutputStream.close();         } catch (IOException ex) {             Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex);             throw new ResourceException(ex);         }     }     p