domingo, 27 de mayo de 2007

¡ rápido con groovy ! Un esquema de conectividad JDBC completo

En el blog anterior propuse encapsular la conectividad, primero para esconder algún nivel de complejidad, y segundo con el propósito de construir una estructura reutilizable para más de un sistema de base de datos

La estructura propuesta (gráfico) tiene que ver con una clase abstracta que contine la lógica pre-elaborada y normalizada para lograr un punto de comunicación con cualquier sistemas de base de datos RDBMS que "hable" JDBC. El usuario de esta clase utilizará el método connect(...) para logar una conexión activa, internamente se llama al método setServer(..) a ser definido en una subclase concreta orientada a un RDBMS específico, en nuestro caso las clases concretas son SQLSERVERConnection y MySqlConnection, para SqlServer y MySql respectivamente.

  1  ...
  2  // Conectividad abstracta
  3  abstract class Connection {
  4 
  5    abstract void setServer(server,DB)
  6 
  7    boolean connect(erver,DB,user,password) {
  8      ...
  9      setServer(server,DB)  
 10      ...
 11    }
 12    ...
 13  }
 14 
 15 
 16  // Conectividad MS-SqlServer
 17  class SQLSERVERConnection extends Connection {
 18 
 19    void setServer(server,DB) {
 20      ...
 21    }
 22 
 23  }
 24 
 25 
 26  // Conectividad MySQL
 27  class MySqlConnection extends Connection {
 28 
 29    void setServer(server,DB) {
 30      ...
 31    }
 32 
 33  }

Como se vió en el blog anterior las subclases concretas se limitan a definir los campos driver y url de acuerdo a cada RDBMS. Si desea conectarse a Oracle, primero deberá encontrar e instalar las librerías de conectividad JDBC, agregar a CLASSPATH la localización de los archivos JAR y luego crear la clase concreta que la podriamos llamar OracleConnection.

Para lograr un buen nivel de adaptabilidad, una "factoría" parece lo más indicado. Esta no es otra cosa que una clase con un método estático, en este caso getConnection(...), que retorna una instancia de una conexión específica.

  1  class ConnectionFactory {
  2 
  3    static Connection getConnection(dbType) {
  4      if(dbType == 'MySQL')
  5          return new MySqlConnection()
  6      else
  7      if(dbType == 'MS-SqlServer')
  8          return new SQLSERVERConnection()
  9      else
 10          return null ;
 11    }
 12 
 13  }

Honestamente ésta es una factoría bastante simple. La idea es que en base al argumento el método retorne una instancia de conexión específica

  1  // recupera una conexión para MySql
  2  Connection cn = ConnectionFactory.getConnection('MySql')
  3 
  4  // recupera una conexión para SqlServer
  5  Connection cn = ConnectionFactory.getConnection('MS-SqlServer')

A continuación se presenta el código completo, al final hay un código de prueba, que deberá ser comentado o eliminado luego de las respectivas pruebas. Este código lo he guardado en un archivo de nombre DBConection.groovy.

  1  import groovy.sql.Sql                                    
  2                                                           
  3                 
  4  // == Abstract connection ==        
  5                 
  6  abstract class Connection {         
  7                 
  8  def db              
  9                 
 10  def driver             
 11                 
 12  def url              
 13                 
 14  abstract void setServer(strServer,strDB)     
 15                 
 16  boolean connected = false         
 17                 
 18  boolean connect(strServer,strDB,strUser,strPassword) {  
 19    try {              
 20      if(connected)           
 21        disconnect()           
 22      setServer(strServer,strDB)        
 23      db = Sql.newInstance(url,strUser,strPassword,driver) 
 24      connected = true          
 25                 
 26    } catch(Exception ex) {         
 27      db = null            
 28      connected = false          
 29    }               
 30                 
 31      return connected          
 32    }               
 33                 
 34                 
 35    void disconnect() {          
 36      db.close()            
 37      db = null            
 38    }               
 39                 
 40  }               
 41                 
 42                 
 43  // == MS-SqlServer connection ==       
 44                 
 45  class SQLSERVERConnection extends Connection {    
 46                 
 47    void setServer(strServer,strDB) {                          
 48      driver = 'com.microsoft.jdbc.sqlserver.SQLServerDriver'                 
 49      url = "jdbc:microsoft:sqlserver://$strServer:1433;databaseName=$strDB"  
 40    }                                  
 51                 
 52  }               
 53                 
 54                 
 55  // == MySQL connection ==         
 56                 
 57  class MySqlConnection extends Connection {     
 58                 
 59    void setServer(strServer,strDB) {       
 60      driver = 'com.mysql.jdbc.Driver'      
 71      url = "jdbc:mysql://$strServer:3306/$strDB"    
 72    }               
 73                 
 74  }               
 75                 
 76                 
 77  // === Factory Class ===         
 78                 
 79  class ConnectionFactory {         
 80                 
 81    static Connection getConnection(dbType) {     
 82      if(dbType == 'MySQL')         
 83        return new MySqlConnection()       
 84      else             
 85      if(dbType == 'MS-SqlServer')       
 86        return new SQLSERVERConnection()      
 87      else             
 88        return null ;           
 89    }               
 90                 
 91  }               
 92                 
 93                 
 94                 
 95  // - código de prueba : inicio
 96 
 97  def myServer = 'localhost'
 98  def myDBType = 'MySQL'
 99  def myUser = 'root'
100  def myPassword = 'admin'
101 
102  Connection myConection = ConnectionFactory.getConnection(myDBType)  
103 
104  if(myConection.connect(myServer,myDBType,myUser,myPassword)) {
105    println '¡ Bacán ! me conecté a $myDBType en $myServer !!!'
106    myConection.disconnect()
107  }
108  else
109    println 'uff... no pude Conectarme a $myDBType en $myServer '
110 
111  return true // - código de prueba : fin

Para compilar estas clases almacenadas en el archivo "DBConection.groovy", procedo desde la línea de comandos:

   groobyc DBConection.groovy

que genera un archivo *.class por cada clase

Para "los iniciados"...

...estoy totalmente de acuerdo que:

  • es posible evitar la herencia si leemos parámetros de un archivo de configuración
  • es necesario declarar una interface con el contrato de implementación
  • es posible y necesario parametrizar los puertos IP
  • si se soporta en Hibernate, IBatis, etc. puede que Ud. esté haciendo las cosas de otra manera