You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ba...@apache.org on 2003/03/08 21:35:05 UTC

cvs commit: jakarta-commons-sandbox/dbutils/src/test/org/apache/commons/dbutils Demo.java ProcedureUtilsTest.java

baliuka     2003/03/08 12:35:05

  Modified:    dbutils/src/java/org/apache/commons/dbutils DbUtils.java
                        ProcedureUtils.java
  Added:       dbutils/src/java/org/apache/commons/dbutils
                        ResultSetHandler.java ScalarHandler.java
               dbutils/src/test connection.properties
               dbutils/src/test/org/apache/commons/dbutils Demo.java
                        ProcedureUtilsTest.java
  Log:
  added dependancy on Qdox
  
  Revision  Changes    Path
  1.11      +1 -5      jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/DbUtils.java
  
  Index: DbUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/DbUtils.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- DbUtils.java	6 Mar 2003 18:47:35 -0000	1.10
  +++ DbUtils.java	8 Mar 2003 20:35:05 -0000	1.11
  @@ -64,11 +64,7 @@
   
   public final class DbUtils {
       
  -    public static interface ResultSetHandler{
  -        
  -        public Object handle(ResultSet rs)throws SQLException;
  -        
  -    }
  +   
       public static abstract class ListAdapter extends ArrayList implements ResultSetHandler{
           
           final public Object handle(ResultSet rs)throws SQLException{
  
  
  
  1.2       +261 -145  jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/ProcedureUtils.java
  
  Index: ProcedureUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/ProcedureUtils.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ProcedureUtils.java	6 Mar 2003 18:47:35 -0000	1.1
  +++ ProcedureUtils.java	8 Mar 2003 20:35:05 -0000	1.2
  @@ -60,31 +60,36 @@
   import java.util.*;
   import java.lang.reflect.*;
   import java.sql.*;
  +import java.io.*;
  +
  +import com.thoughtworks.qdox.JavaDocBuilder;
  +import com.thoughtworks.qdox.model.*;
  +
   /**
    * sample:
    * class DAO {
    *
    * static interface Procedure{
  - *     int execute(int p1); 
  + *     int execute(int p1);
    *  }
    *
    * static interface Procedure2{
  - *     int execute2(int p1, int p2); 
  + *     int execute2(int p1, int p2);
    *  }
    *
    * static private scalarProc(Class cls, String sql){
    *    ProcedureUtils.register(cls, sql, new ScalarHandlerImpl() );
  - *  
  + *
    * }
    * static{
    *
    *  scalarProc(Procedure.class,
  - *                          "SELECT COUNT(*) FROM MY_TABLE WHERE VALUE < $1" 
  + *                          "SELECT COUNT(*) FROM MY_TABLE WHERE VALUE < $1"
    *                     );
  - *     
  + *
    *  salarProc(Procedure.class,
  - *                          "SELECT SUM(VALUE) - $2 FROM MY_TABLE WHERE VALUE > $1" 
  - *                    
  + *                          "SELECT SUM(VALUE) - $2 FROM MY_TABLE WHERE VALUE > $1"
  + *
    *                   );
    * }
    *
  @@ -98,38 +103,40 @@
    *                                                       currentConnection());
    *  }
    *
  - * 
  + *
    *  public static int main( String args ){
  - *  
  + *
    *   System.out.println(getProcedure().execute(0) + getProcedure2().execute(1,3));
  - *   
  + *
    * }
    * }
  - * 
  + *
    * TODO:
    *
    * interface MyDAO{
    *
  - *     @sql SELECT MAX(VALUE) FROM MY_TABLE WHERE VALUE < $1 
  - *     int getMaxLesThan(int p1); 
  + *     @sql SELECT MAX(VALUE) FROM MY_TABLE WHERE VALUE < $1
  + *     int getMaxLesThan(int p1);
    *
  - *     @sql SELECT COUNT(*) FROM MY_TABLE  WHERE VALUE < $1 and VALUE >= $2  
  - *     int getCount(int p1, int p2); 
  + *     @sql SELECT COUNT(*) FROM MY_TABLE  WHERE VALUE < $1 and VALUE >= $2
  + *     int getCount(int p1, int p2);
    *  }
  - * 
  + *
    *
    * @author  baliuka
    */
   public final class ProcedureUtils {
       
       private static final Map PROCEDURES = new HashMap();
  +    private static final Map PREDEFINED_HANDLERS = new HashMap();
  +    private static final ResultSetHandler SCALAR_HANDLER = new ScalarHandler();
       
       
       static class ProcedureDescriptor{
           
           String jdbcSQL;
           int indexMap[];
  -        DbUtils.ResultSetHandler handler;
  +        ResultSetHandler handler;
           boolean update;
           //TODO:
           boolean cached;
  @@ -142,9 +149,8 @@
           
       }
       
  -    private static ProcedureDescriptor compile(Class procInterface, String sqlStr,
  -    DbUtils.ResultSetHandler handler,boolean update){
  -        
  +    private static ProcedureDescriptor compile(Method proc, String sqlStr,
  +    ResultSetHandler handler,boolean update){
           
           java.util.ArrayList indexes = new java.util.ArrayList();
           char sql[] = sqlStr.toCharArray();
  @@ -156,26 +162,13 @@
           
           for (int i = 0; i < sql.length; i++ ){
               
  -            if(sql[i] == '\''){
  -                
  -                escape = false;
  -                arg = false;
  -                
  -                while( true ){
  -                   try{ 
  -                    sb.append(sql[i++]);
  -                    if(sql[i] == '\'' && sql[i - 1] != '\\'){
  -                        sb.append('\'');
  -                        break;
  -                    }
  -                   }catch(ArrayIndexOutOfBoundsException aie){
  -                       throw new IllegalArgumentException("unterminated string in query");
  -                   }
  -                }
  -                continue;
  -            }
               
               if(sql[i] == '$'){
  +                if(escape && !arg){
  +                    escape = false;
  +                    arg = false;
  +                    continue;
  +                }
                   escape = true;
                   arg = false;
                   continue;
  @@ -184,8 +177,11 @@
               if (Character.isDigit(sql[i]) && escape){
                   digit.append(sql[i]);
                   arg = true;
  -                if( i != sql.length - 1 )
  +                if( i != sql.length - 1 ){
                       continue;
  +                }else {
  +                   i++;
  +                }    
               }
               
               if(arg){
  @@ -193,52 +189,53 @@
                   sb.append('?');
                   digit.delete(0, digit.length() );
               }
  -            
  -            sb.append(sql[i]);
  +            if( i < sql.length ){    
  +                  sb.append(sql[i]);
  +            }
               escape = false;
               arg    = false;
               
           }
  -    
  -    
  -    
  -     Method methods[] =  procInterface.getDeclaredMethods();
  -       
  -       if(methods.length != 1 ){
  -         throw new IllegalArgumentException( procInterface.getName() + 
  -                                " must declare singe method" );
  -       }
  -       
  -      if(update && ( methods[0].getReturnType() != Void.TYPE || methods[0].getReturnType() != Integer.TYPE   )){
  -       
  -            throw new IllegalArgumentException( "update method " + methods[0] + 
  -                                   " must return int or void " );
  -       
  -      
  -      }
  -     
  -       for( int i = 0; i < methods[0].getParameterTypes().length; i++   ){
  -         if(!indexes.contains(new Integer( i + 1))){
  -           throw new IllegalArgumentException( "missing prameter " + 
  -                     methods[0].getParameterTypes() +  " $" + (i + 1 ) );
  -          }
  +        
  +        if( update &&  proc.getReturnType() != Void.TYPE && proc.getReturnType() != Integer.TYPE  ){
  +            
  +            throw new IllegalArgumentException( "update method " + proc +
  +            " must return int or void " );
  +            
  +            
  +        }
  +        
  +        for( int i = 0; i < proc.getParameterTypes().length; i++   ){
  +            if(!indexes.contains(new Integer( i + 1))){
  +                
  +                throw new IllegalArgumentException( "missing prameter " +
  +                proc.getParameterTypes()[i] +  " $" + (i + 1 ) + " in " + proc );
  +            }
           }
  -     
  -       
  -       ProcedureDescriptor descriptor = new ProcedureDescriptor();
  -       if(indexes.size() > 0){ 
  -           
           
  -        int indexMap[] = new int[indexes.size()];
  +        for( Iterator i = indexes.iterator(); i.hasNext(); ){
  +             int param = ((Number)i.next()).intValue();
  +             if(param == 0 || param > proc.getParameterTypes().length ){
  +                throw new IllegalArgumentException( "extra prameter " + 
  +                                                        i + " in " + proc);
  +            }
           
  -        for( int i = 0 ; i < indexMap.length; i++ ){
  -          indexMap[i] = ((Integer)indexes.get(i)).intValue() - 1;
           }
  -        descriptor.indexMap = indexMap;
           
  -       }else {
  -         descriptor.indexMap = new int[0];
  -       }
  +        ProcedureDescriptor descriptor = new ProcedureDescriptor();
  +        if(indexes.size() > 0){
  +            
  +            
  +            int indexMap[] = new int[indexes.size()];
  +            
  +            for( int i = 0 ; i < indexMap.length; i++ ){
  +                indexMap[i] = ((Integer)indexes.get(i)).intValue() - 1;
  +            }
  +            descriptor.indexMap = indexMap;
  +            
  +        }else {
  +            descriptor.indexMap = new int[0];
  +        }
           
           descriptor.handler = handler;
           descriptor.jdbcSQL = sb.toString();
  @@ -247,86 +244,205 @@
           return descriptor;
       }
       
  -    private static void register( Class procInterface, String sql,
  -                              DbUtils.ResultSetHandler handler){
  -           if(handler == null){
  -             throw new NullPointerException("handler is null");
  -           }                       
  -           register( procInterface, sql, handler, false);                         
  +    private static void register( Method proc, String sql,
  +     ResultSetHandler handler){
  +        if(handler == null){
  +            throw new NullPointerException("handler is null");
  +        }
  +        register( proc, sql, handler, false);
       }
       
  -   private static void register( Class procInterface, String sql){
  -           register( procInterface, sql, null, false);                         
  +    private static void register(Method proc, String sql){
  +        register( proc, sql, null, false);
       }
  - 
       
  -    private static void register( Class procInterface, String sql,
  -    DbUtils.ResultSetHandler handler, boolean update ){
  -       if(!procInterface.isInterface()){
  -         throw new IllegalArgumentException(procInterface.getName() + " is not an interface");
  -       } 
  -       ProcedureDescriptor des = compile(procInterface,sql, handler, update ); 
  -       PROCEDURES.put(procInterface,des); 
  +    
  +    private static void register( Method proc, String sql,
  +     ResultSetHandler handler, boolean update ){
  +        if(!proc.getDeclaringClass().isInterface()){
  +            throw new IllegalArgumentException(proc.getDeclaringClass().getName() + " is not an interface");
  +        }
  +        ProcedureDescriptor des = compile(proc,sql, handler, update );
  +        PROCEDURES.put(proc,des);
           
       }
       
  -   
  -  public static Object getInstance(Class cls,Connection connection){
  -   
  -      ProcedureDescriptor descriptor = (ProcedureDescriptor)PROCEDURES.get(cls);
  -      
  -      if(descriptor == null){
  -          
  -        throw new IllegalStateException("no procedure registred for " + cls.getName() );
  +    private static Method findMethod(Class cls, JavaMethod jmethod){
           
  -      }
  -      
  -      return Proxy.newProxyInstance(cls.getClassLoader(), 
  -                                    new Class[]{cls},
  -                                    new Invocation(connection, descriptor)
  -                );
  +        Method methods[] = cls.getDeclaredMethods();
  +        for(int i=0; i< methods.length; i++ ){
  +            
  +            if(methods[i].getName().equals(jmethod.getName()) ){
  +                
  +                JavaParameter jparams[] = jmethod.getParameters();
  +                Class params[] = methods[i].getParameterTypes();
  +                
  +                if( params.length == jparams.length ){
  +                    
  +                    for( int j = 0; j < params.length; j++ ){
  +                        
  +                        if(!params[j].getName().equals(jparams[j].getType().getValue()) ){
  +                            continue;
  +                        }
  +                        
  +                    }
  +                    
  +                    return methods[i];
  +                }
  +                
  +            }
  +        }
  +        
  +        throw new IllegalStateException("metadata not found for " + jmethod);
  +    }
  +    
  +    private static ResultSetHandler findHandler(Method method, 
  +                                         JavaMethod jmethod){
  +    
    
  -  }
  - static class Invocation implements InvocationHandler{
  -     
  -      Connection connection;
  -      ProcedureDescriptor descriptor;
  -      
  -      Invocation(Connection connection,ProcedureDescriptor descriptor){
  -        this.connection = connection;
  -        this.descriptor = descriptor;
  -      }
  +   ResultSetHandler handler = null;                                             
  +                                              
  +   String name = null;
        
  -      private Object[] prepareArgs(Object[] args){
  -       int len = descriptor.indexMap.length;  
  -       Object pargs[] = new Object[ len ];
  -        for(int i = 0; i < len; i++ ){
  -          pargs[i] = args[ descriptor.indexMap[i] ];
  -        }   
  -       return pargs;
  +    DocletTag tag = jmethod.getTagByName("handler");
  +    if(tag != null ){
  +      name = tag.getValue(); 
  +      if(name != null){
  +        return (ResultSetHandler)PREDEFINED_HANDLERS.get(name);                                        
         }
  -   //TODO: some way to handle SQLException     
  -      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  -          if(!descriptor.update){
  -             return DbUtils.executeQuery(  connection,
  -                                        descriptor.jdbcSQL,
  -                                        prepareArgs(args),
  -                                        descriptor.handler
  -                                        );
  -          }else{
  -            int updateCount = DbUtils.executeUpdate(  connection,
  -                                                      descriptor.jdbcSQL,
  -                                                      prepareArgs(args)
  -                                                    );
  -          
  -            if(method.getReturnType() == Void.TYPE ){
  -                return null;
  -            }else {
  -              return new Integer(updateCount);
  +    }
  +    
  +    if( name == null && method.getReturnType().isPrimitive() ){
  +     return SCALAR_HANDLER;
  +    }
  +    
  +    if(name != null){
  +     try{   
  +      handler = (ResultSetHandler)method.getDeclaringClass().
  +                          getClassLoader().loadClass(name).newInstance();
  +     }catch(Exception e){
  +       throw new IllegalStateException( e.getMessage() + ":" + handler + " " + name + 
  +                       " not found in " + method  );
  +     }
  +    }
  +    
  +     return  handler;  
  +   }
  +    
  +    private static Map buildProcedures(Class cls){
  +        
  +        String res = cls.getName().replace('.','/') + ".java";
  +        InputStream is = cls.getClassLoader().getResourceAsStream(res);
  +        Map desctiptors = new HashMap();
  +        
  +        if( is == null ){
  +            throw new IllegalStateException( "resource " + res + " not found" );
  +        }
  +        
  +        JavaDocBuilder builder = new JavaDocBuilder();
  +        builder.addSource( new InputStreamReader(is) );
  +        JavaClass jclass = builder.getClassByName(cls.getName());
  +        JavaMethod [] jmethods = jclass.getMethods();
  +        
  +        for( int i = 0; i< jmethods.length; i++  ){
  +            
  +            DocletTag tag = jmethods[i].getTagByName("sql");
  +            if(tag == null){
  +                throw new IllegalStateException("no @sql attribute in " + res + " " + jmethods[i]);
               }
  -          } 
  -      }
  -      
  -  }  
  +            String sql = tag.getValue();
  +            Method method = findMethod(cls, jmethods[i] );
  +            boolean update = jmethods[i].getTagByName("update") != null;
  +            ResultSetHandler handler = null;
  +            if( !update ){
  +              handler = findHandler(method,jmethods[i] );
  +            }
  +        
  +            desctiptors.put( method, 
  +                compile(  method, sql, handler, update  ));
  +        }
  +        
  +       return desctiptors;
  +        
  +    }
  +  //TODO:
  +    private static Object convert( Class convertTo, Object obj ){
  +       return obj;
  +    }
  +    
  +    public static Object getInstance(Class cls, Connection connection){
  +        
  +        Map descriptors = (Map)PROCEDURES.get(cls);
  +        
  +        if(descriptors == null){
  +            
  +          descriptors =  buildProcedures(cls);  
  +          PROCEDURES.put(cls, descriptors);
  +            
  +        }
  +        
  +        return Proxy.newProxyInstance(cls.getClassLoader(),
  +        new Class[]{cls},
  +        new Invocation(connection, descriptors)
  +        );
  +        
  +    }
  +    
  +    static class Invocation implements InvocationHandler{
  +        
  +        Connection connection;
  +        Map descriptors;
  +        
  +        Invocation(Connection connection,Map descriptors){
  +            this.connection = connection;
  +            this.descriptors = descriptors;
  +        }
  +        
  +        private Object[] prepareArgs(ProcedureDescriptor descriptor, Object[] args){
  +            int len = descriptor.indexMap.length;
  +            Object pargs[] = new Object[ len ];
  +            for(int i = 0; i < len; i++ ){
  +                pargs[i] = args[ descriptor.indexMap[i] ];
  +            }
  +            return pargs;
  +        }
  +        //TODO: some way to handle SQLException
  +        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  +            
  +            if(method.getDeclaringClass() == Object.class ){
  +               return null;
  +            }
  +            
  +            ProcedureDescriptor descriptor = (ProcedureDescriptor)descriptors.get(method);
  +            
  +            if(descriptor == null){
  +                
  +                throw new IllegalStateException("no descriptor found for " + method);
  +                
  +            }
  +            
  +            if(!descriptor.update){
  +                return convert( method.getReturnType(), DbUtils.executeQuery(  connection,
  +                descriptor.jdbcSQL,
  +                prepareArgs(descriptor,args),
  +                descriptor.handler
  +                ));
  +            }else{
  +                int updateCount = DbUtils.executeUpdate(  connection,
  +                descriptor.jdbcSQL,
  +                prepareArgs(descriptor,args)
  +                );
  +                
  +                if(method.getReturnType() == Void.TYPE ){
  +                    return null;
  +                }else {
  +                    return new Integer(updateCount);
  +                }
  +            }
  +        }
  +        
  +        
  +        
  +    }
       
   }
  
  
  
  1.1                  jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/ResultSetHandler.java
  
  Index: ResultSetHandler.java
  ===================================================================
  
  package org.apache.commons.dbutils;
  
  /**
   *
   * @author  baliuka
   */
   public  interface ResultSetHandler{
          
          public Object handle(java.sql.ResultSet rs)throws java.sql.SQLException;
          
   }
  
  
  1.1                  jakarta-commons-sandbox/dbutils/src/java/org/apache/commons/dbutils/ScalarHandler.java
  
  Index: ScalarHandler.java
  ===================================================================
  package org.apache.commons.dbutils;
  
  import java.sql.*;
  /**
   *
   * @author  user
   */
  public class ScalarHandler implements ResultSetHandler {
      
      /** Creates a new instance of ScalarHandler */
      public ScalarHandler() {
      }
      
      public Object handle(ResultSet rs)throws SQLException{
                 
                  if (rs.next()) {
                      Object result = rs.getObject(1);
                      return result;
                  }
                 throw new SQLException();
              }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/dbutils/src/test/connection.properties
  
  Index: connection.properties
  ===================================================================
  driver=org.postgresql.Driver
  url=jdbc:postgresql:test
  user=test
  password=test
  
  
  1.1                  jakarta-commons-sandbox/dbutils/src/test/org/apache/commons/dbutils/Demo.java
  
  Index: Demo.java
  ===================================================================
  
  package org.apache.commons.dbutils;
  
  /**
   *
   * @author  baliuka
   */
  public interface Demo {
  
      /**
       *@sql CREATE TABLE  TBL (ID INT NOT NULL PRIMARY KEY, NAME VARCHAR(128))
       *@update
       */
      
      void create();
      
       /**
       *@sql DROP TABLE  TBL 
       *@update
       */
      
      void drop();
     
      
      /**
       *@sql SELECT  COUNT(1) > 0 FROM TBL WHERE ID=$1
       */
      public boolean exists(int id);
      
      /**
       *@sql INSERT INTO TBL (ID) VALUES($1)
       *@update
       */
      public int addId(int id);
      
      /**
       *@sql DELETE FROM TBL 
       *@update
       */
      public void clear();
      
      
      
  }
  
  
  
  1.1                  jakarta-commons-sandbox/dbutils/src/test/org/apache/commons/dbutils/ProcedureUtilsTest.java
  
  Index: ProcedureUtilsTest.java
  ===================================================================
  
  package org.apache.commons.dbutils;
  
  import java.util.*;
  import java.lang.reflect.*;
  import java.sql.*;
  import java.io.*;
  import com.thoughtworks.qdox.JavaDocBuilder;
  import com.thoughtworks.qdox.model.*;
  import junit.framework.*;
  
  /**
   *
   * @author baliuka
   */
  public class ProcedureUtilsTest extends TestCase {
      
     static java.sql.Connection connection;
      
      public ProcedureUtilsTest(java.lang.String testName) {
          super(testName);
      }
      
      public static void main(java.lang.String[] args) throws Exception{
          
          
          junit.textui.TestRunner.run(suite());
      }
      
      public static Test suite() throws Exception{
          
           java.util.Properties props = new  java.util.Properties();
           props.load(ProcedureUtilsTest.class.getClassLoader().getResourceAsStream("connection.properties")); 
          
           Class.forName(props.getProperty("driver").trim());
           connection = java.sql.DriverManager.getConnection(props.getProperty("url"), props);
           assertTrue(connection != null);
          
          TestSuite suite = new TestSuite(ProcedureUtilsTest.class);
          
          return suite;
      }
      
      public void testCreate() {
      
          Demo demo = (Demo)ProcedureUtils.getInstance(Demo.class ,connection);
          try{
          demo.drop();
          }catch(Exception e){e.printStackTrace();}
          demo.create();
      }
      public void testGetInstance() {
          
         Demo demo = (Demo)ProcedureUtils.getInstance(Demo.class ,connection);
         demo.clear();
         assertTrue( !demo.exists(1) );
         assertTrue( demo.addId(1)  == 1 );
         assertTrue( demo.exists(1)  );
         
      }
      
      
      
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org