User: forder  
  Date: 00/08/05 19:03:54

  Added:       src/main/org/jboss/ejb/plugins/jaws/jdbc
                        JDBCActivateEntityCommand.java
                        JDBCBeanExistsCommand.java JDBCCommand.java
                        JDBCCommandFactory.java
                        JDBCCreateEntityCommand.java
                        JDBCDefinedFinderCommand.java
                        JDBCDestroyCommand.java JDBCFindAllCommand.java
                        JDBCFindByCommand.java JDBCFindEntitiesCommand.java
                        JDBCFindEntityCommand.java JDBCFinderCommand.java
                        JDBCInitCommand.java JDBCLoadEntityCommand.java
                        JDBCPassivateEntityCommand.java
                        JDBCQueryCommand.java JDBCRemoveEntityCommand.java
                        JDBCStartCommand.java JDBCStopCommand.java
                        JDBCStoreEntityCommand.java JDBCUpdateCommand.java
  Log:
  Commands version of JAWS
  
  Revision  Changes    Path
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCActivateEntityCommand.java
  
  Index: JDBCActivateEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
   
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.rmi.RemoteException;
  import java.rmi.ServerException;
  
  import javax.ejb.EntityBean;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JAWSPersistenceManager;
  import org.jboss.ejb.plugins.jaws.JPMActivateEntityCommand;
  
  /**
   * JAWSPersistenceManager JDBCActivateEntityCommand
   *    
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
   
  public class JDBCActivateEntityCommand implements JPMActivateEntityCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCActivateEntityCommand(JDBCCommandFactory factory)
     {
     }
     
     // JPMActivateEntityCommand implementation -----------------------
     
     public void execute(EntityEnterpriseContext ctx)
        throws RemoteException
     {
        // Set new persistence context
        // JF: Passivation/Activation is losing persistence context!!!
        ctx.setPersistenceContext(new JAWSPersistenceManager.PersistenceContext());
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCBeanExistsCommand.java
  
  Index: JDBCBeanExistsCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.util.Iterator;
  
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.logging.Log;
  
  /**
   * JDBCBeanExistsCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCBeanExistsCommand extends JDBCQueryCommand
  {
     // Attributes ----------------------------------------------------
     
     private Object idArgument;    // the id given to execute()
     
     private boolean result;       // the result to be returned by execute()
     
     // Constructors --------------------------------------------------
     
     public JDBCBeanExistsCommand(JDBCCommandFactory factory)
     {
        super(factory, "Exists");
        String sql = "SELECT COUNT(*) AS Total FROM " + metaInfo.getTableName() +
                     " WHERE " + getPkColumnWhereList();
        setSQL(sql);
     }
     
     // Public --------------------------------------------------------
     
     // Checks whether the database already holds the entity
     
     public boolean execute(Object id)
     {
        // Save argument so setParameters() can access it
        idArgument = id;
        
        // Assume bean doesn't exist; handleResult() can change this
        result = false;
        
        try
        {
           jdbcExecute();
        } catch (Exception e)
        {
           log.exception(e);
        }
        
        return result;
     }
     
     // JDBCQueryCommand overrides ------------------------------------
     
     protected void setParameters(PreparedStatement stmt) 
        throws Exception
     {
        // Primary key in WHERE-clause
        Iterator it = metaInfo.getPkFieldInfos();
        int i = 1;   // parameter index
        
        if (metaInfo.hasCompositeKey())
        {
           // Compound key
           while (it.hasNext())
           {
              PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
              int jdbcType = pkFieldInfo.getJDBCType();
              Object value = getPkFieldValue(idArgument, pkFieldInfo);
              
              // Set this field of the key
              setParameter(stmt, i++, jdbcType, value);
           }
        } else
        {
           // We have a Field key
           // So just set that field
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           int jdbcType = pkFieldInfo.getJDBCType();
           setParameter(stmt, i, jdbcType, idArgument);
        }
     }
     
     protected void handleResult(ResultSet rs) throws Exception
     {
        if ( !rs.next() )
        {
           throw new SQLException("Unable to check for EJB in database");
        }
        int total = rs.getInt("Total");
        result = (total >= 1);
     }
  }
  
  
  
  1.1                  jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommand.java
  
  Index: JDBCCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Field;
  
  import java.util.Iterator;
  import java.util.Map;
  import java.util.HashMap;
  
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.sql.Types;
  
  import java.rmi.RemoteException;
  
  import javax.ejb.EJBObject;
  
  import javax.sql.DataSource;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsEntity;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  import org.jboss.logging.Log;
  
  /**
   * Abstract superclass for all JAWS Commands that use JDBC directly.
   * Provides a Template Method for jdbcExecute(), default implementations
   * for some of the methods called by this template, and a bunch of
   * utility methods that database commands may need to call.
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public abstract class JDBCCommand
  {
     // Attributes ----------------------------------------------------
     
     protected JDBCCommandFactory factory;
     protected MetaInfo metaInfo;
     protected Log log;
     protected String name;    // Command name, used for debug trace
     
     private String sql;
     private static Map jdbcTypeNames;
     
     // Constructors --------------------------------------------------
     
     protected JDBCCommand(JDBCCommandFactory factory, String name)
     {
        this.factory = factory;
        this.metaInfo = factory.getMetaInfo();
        this.log = factory.getLog();
        this.name = name;
     }
     
     // Protected -----------------------------------------------------
     
     /**
      * Template method handling the mundane business of opening
      * a database connection, preparing a statement, setting its parameters,
      * executing the prepared statement, handling the result,
      * and cleaning up.
      */
     protected void jdbcExecute() throws Exception
     {
        Connection con = null;
        PreparedStatement stmt = null;
        try
        {
           con = getConnection();
           String theSQL = getSQL();
           if (factory.debug)
           {
              log.debug(name + " command executing: " + theSQL);
           }
           stmt = con.prepareStatement(theSQL);
           setParameters(stmt);
           executeStatementAndHandleResult(stmt);
        } finally
        {
           if (stmt != null)
           {
              try
              {
                 stmt.close();
              } catch (SQLException e)
              {
                 e.printStackTrace();
              }
           }
           if (con != null)
           {
              try
              {
                 con.close();
              } catch (SQLException e)
              {
                 e.printStackTrace();
              }
           }
        }
     }
     
     /**
      * Used to set static SQL in subclass constructors.
      */
     protected void setSQL(String sql)
     {
        if (factory.debug)
        {
           log.debug(name + " SQL: " + sql);
        }
        this.sql = sql;
     }
     
     /**
      * Default implementation returns <code>sql</code> field value.
      * This is appropriate in all cases where static SQL can be
      * constructed in the Command constructor.
      * Override if dynamically-generated SQL, based on the arguments
      * given to execute(), is needed.
      */
     protected String getSQL() throws Exception
     {
        return sql;
     }
     
     /**
      * Default implementation does nothing.
      * Override if parameters need to be set.
      */
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
     }
     
     /**
      * Execute the PreparedStatement and handle result of successful execution.
      * This is implemented in subclasses for queries and updates.
      */
     protected abstract void executeStatementAndHandleResult(
        PreparedStatement stmt) throws Exception;
     
     // ---------- Utility methods for use in subclasses ----------
     
     protected void setParameter(PreparedStatement stmt,
                                 int idx,
                                 int jdbcType,
                                 Object value)
        throws SQLException
     {
        if (factory.debug)
        {
           log.debug("Set parameter: idx=" + idx +
                     ", jdbcType=" + getJDBCTypeName(jdbcType) +
                     ", value=" +
                     ((value == null) ? "NULL" : value));
        }
        
        if (value == null)
        {
           stmt.setNull(idx, jdbcType);
        } else
        {
           stmt.setObject(idx, value, jdbcType);
        }
     }
     
     protected int setForeignKey(PreparedStatement stmt,
                               int idx,
                               CMPFieldInfo fieldInfo,
                               Object value)
        throws SQLException
     {
        JawsCMPField[] pkInfo = fieldInfo.getForeignKeyCMPFields();
        Object pk = null;
        
        if (value != null)
        {
           try
           {
              pk = ((EJBObject)value).getPrimaryKey();
           } catch (RemoteException e)
           {
              throw new SQLException("Could not extract primary key from EJB 
reference:"+e);
           }
        }
        
        if (!((JawsEntity)pkInfo[0].getBeanContext()).getPrimaryKeyField().equals(""))
        {
           // Primitive key
           int jdbcType = getJawsCMPFieldJDBCType(pkInfo[0]);
           Object fieldValue = (value == null) ? null : pk;
           setParameter(stmt, idx, jdbcType, fieldValue);
           return idx+1;
        } else
        {
           // Compound key
           Field[] fields = (value == null) ? null : pk.getClass().getFields();
           try
           {
              for (int i = 0; i < pkInfo.length; i++)
              {
                 int jdbcType = getJawsCMPFieldJDBCType(pkInfo[i]);
                 Object fieldValue = (value == null) ? null : fields[i].get(pk);
                 setParameter(stmt, idx+i, jdbcType, fieldValue);
              }
           } catch (IllegalAccessException e)
           {
              throw new SQLException("Could not extract fields from primary key:"+e);
           }
           return idx+pkInfo.length;
        }
     }
     
     protected final int getJDBCType(String name)
     {
        try
        {
           Integer constant = (Integer)Types.class.getField(name).get(null);
           return constant.intValue();
        } catch (Exception e)
        {
           // JF: Dubious - better to throw a meaningful exception
           e.printStackTrace();
           return Types.OTHER;
        }
     }
     
     protected final String getJDBCTypeName(int jdbcType)
     {
        if (jdbcTypeNames == null)
        {
           setUpJDBCTypeNames();
        }
        
        return (String)jdbcTypeNames.get(new Integer(jdbcType));
     }
     
     protected final String getPkColumnList()
     {
        StringBuffer sb = new StringBuffer();
        Iterator it = metaInfo.getPkFieldInfos();
        while (it.hasNext())
        {
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           sb.append(pkFieldInfo.getColumnName());
           if (it.hasNext())
           {
              sb.append(",");
           }
        }
        return sb.toString();
     }
     
     protected final String getPkColumnWhereList()
     {
        StringBuffer sb = new StringBuffer();
        Iterator it = metaInfo.getPkFieldInfos();
        while (it.hasNext())
        {
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           sb.append(pkFieldInfo.getColumnName());
           sb.append("=?");
           if (it.hasNext())
           {
              sb.append(" AND ");
           }
        }
        return sb.toString();
     }
     
     // MF: PERF!!!!!!!
     protected Object[] getState(EntityEnterpriseContext ctx)
     {
        Object[] state = new Object[metaInfo.getNumberOfCMPFields()];
        Iterator iter = metaInfo.getCMPFieldInfos();
        int i = 0;
        while (iter.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)iter.next();
           try
           {
              // JF: Should clone
              state[i++] = getCMPFieldValue(ctx.getInstance(), fieldInfo);
           } catch (Exception e)
           {
              return null;
           }
        }
     
        return state;
     }
     
     protected Object getCMPFieldValue(Object instance, CMPFieldInfo fieldInfo)
        throws IllegalAccessException
     {
        Field field = fieldInfo.getField();
        return field.get(instance);
     }
     
     protected void setCMPFieldValue(Object instance,
                                     CMPFieldInfo fieldInfo,
                                     Object value)
        throws IllegalAccessException
     {
        Field field = fieldInfo.getField();
        field.set(instance, value);
     }
     
     protected Object getPkFieldValue(Object pk, PkFieldInfo pkFieldInfo)
        throws IllegalAccessException
     {
        Field field = pkFieldInfo.getPkField();
        
        // JF: Temp checks to narrow down bug
        if (pk == null) log.debug("***** getPkFieldValue: PK is null *****");
        if (field == null) log.debug("***** getPkFieldValue: Field is null *****");
        
        return field.get(pk);
     }
     
     // This is now only used in setForeignKey
     
     protected int getJawsCMPFieldJDBCType(JawsCMPField fieldInfo)
     {
        return getJDBCType(fieldInfo.getJdbcType());
     }
     
     // Private -------------------------------------------------------
     
     /** Get a database connection */
     private Connection getConnection() throws SQLException
     {
        DataSource ds = metaInfo.getDataSource();
        if (ds != null)
        {
           return ds.getConnection();
        } else
        {
           String url = metaInfo.getDbURL();
           return DriverManager.getConnection(url,"sa","");
        }
     }
     
     private final void setUpJDBCTypeNames()
     {
        jdbcTypeNames = new HashMap();
        
        Field[] fields = Types.class.getFields();
        int length = fields.length;
        for (int i = 0; i < length; i++) {
           Field f = fields[i];
           String fieldName = f.getName();
           try {
              Object fieldValue = f.get(null);
              jdbcTypeNames.put(fieldValue, fieldName);
           } catch (IllegalAccessException e) {
              // Should never happen
              e.printStackTrace();
           }
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommandFactory.java
  
  Index: JDBCCommandFactory.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Method;
  
  import javax.naming.Context;
  import javax.naming.InitialContext;
  
  import org.jboss.ejb.EntityContainer;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  import org.jboss.ejb.plugins.jaws.JPMCommandFactory;
  import org.jboss.ejb.plugins.jaws.JPMInitCommand;
  import org.jboss.ejb.plugins.jaws.JPMStartCommand;
  import org.jboss.ejb.plugins.jaws.JPMStopCommand;
  import org.jboss.ejb.plugins.jaws.JPMDestroyCommand;
  import org.jboss.ejb.plugins.jaws.JPMFindEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMFindEntitiesCommand;
  import org.jboss.ejb.plugins.jaws.JPMCreateEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMRemoveEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMLoadEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMStoreEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMActivateEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMPassivateEntityCommand;
  
  import org.jboss.ejb.plugins.jaws.deployment.Finder;
  
  import org.jboss.logging.Log;
  
  /**
   * JAWSPersistenceManager JDBCCommandFactory
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCCommandFactory implements JPMCommandFactory
  {
     // Attributes ----------------------------------------------------
     
     private EntityContainer container;
     private Context javaCtx;
     private MetaInfo metaInfo;
     private Log log;
     
     // These support singletons (within the scope of this factory)
     private JDBCBeanExistsCommand beanExistsCommand;
     private JPMFindEntitiesCommand findEntitiesCommand;
     
     /**
      * Gives compile-time control of tracing.
      */
     public static boolean debug = true;
     
     // Constructors --------------------------------------------------
     
     public JDBCCommandFactory(EntityContainer container,
                               Log log)
        throws Exception
     {
        this.container = container;
        this.javaCtx = (Context)new InitialContext().lookup("java:comp/env");
        this.metaInfo = new MetaInfo(container);
        this.log = log;
     }
     
     // Public --------------------------------------------------------
     
     public EntityContainer getContainer()
     {
        return container;
     }
     
     public Context getJavaCtx()
     {
        return javaCtx;
     }
     
     public MetaInfo getMetaInfo()
     {
        return metaInfo;
     }
     
     public Log getLog()
     {
        return log;
     }
     
     // Additional Command creation
     
     /**
      * Singleton: multiple callers get references to the 
      * same command instance.
      */
     public JDBCBeanExistsCommand createBeanExistsCommand()
     {
        if (beanExistsCommand == null)
        {
           beanExistsCommand = new JDBCBeanExistsCommand(this);
        }
        
        return beanExistsCommand;
     }
     
     public JPMFindEntitiesCommand createFindAllCommand()
     {
        return new JDBCFindAllCommand(this);
     }
     
     public JPMFindEntitiesCommand createDefinedFinderCommand(Finder f)
     {
        return new JDBCDefinedFinderCommand(this, f);
     }
     
     public JPMFindEntitiesCommand createFindByCommand(Method finderMethod)
        throws IllegalArgumentException
     {
        return new JDBCFindByCommand(this, finderMethod);
     }
     
     // JPMCommandFactory implementation ------------------------------
     
     // lifecycle commands
     
     public JPMInitCommand createInitCommand()
     {
        return new JDBCInitCommand(this);
     }
     
     public JPMStartCommand createStartCommand()
     {
        return new JDBCStartCommand(this);
     }
     
     public JPMStopCommand createStopCommand()
     {
        return new JDBCStopCommand(this);
     }
     
     public JPMDestroyCommand createDestroyCommand()
     {
        return new JDBCDestroyCommand(this);
     }
     
     // entity persistence-related commands
     
     public JPMFindEntityCommand createFindEntityCommand()
     {
        return new JDBCFindEntityCommand(this);
     }
     
     /**
      * Singleton: multiple callers get references to the 
      * same command instance.
      */
     public JPMFindEntitiesCommand createFindEntitiesCommand()
     {
        if (findEntitiesCommand == null)
        {
           findEntitiesCommand = new JDBCFindEntitiesCommand(this);
        }
        
        return findEntitiesCommand;
     }
     
     public JPMCreateEntityCommand createCreateEntityCommand()
     {
        return new JDBCCreateEntityCommand(this);
     }
     
     public JPMRemoveEntityCommand createRemoveEntityCommand()
     {
        return new JDBCRemoveEntityCommand(this);
     }
     
     public JPMLoadEntityCommand createLoadEntityCommand()
     {
        return new JDBCLoadEntityCommand(this);
     }
     
     public JPMStoreEntityCommand createStoreEntityCommand()
     {
        return new JDBCStoreEntityCommand(this);
     }
     
     // entity activation and passivation commands
     
     public JPMActivateEntityCommand createActivateEntityCommand()
     {
        return new JDBCActivateEntityCommand(this);
     }
     
     public JPMPassivateEntityCommand createPassivateEntityCommand()
     {
        return new JDBCPassivateEntityCommand(this);
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCreateEntityCommand.java
  
  Index: JDBCCreateEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Field;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  import java.util.Iterator;
  
  import java.rmi.RemoteException;
  import java.rmi.ServerException;
  
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  
  import javax.ejb.CreateException;
  import javax.ejb.DuplicateKeyException;
  
  import org.jboss.ejb.EntityContainer;
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JAWSPersistenceManager;
  import org.jboss.ejb.plugins.jaws.JPMCreateEntityCommand;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  
  /**
   * JAWSPersistenceManager JDBCCreateEntityCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCCreateEntityCommand
     extends JDBCUpdateCommand
     implements JPMCreateEntityCommand
  {
     // Attributes ----------------------------------------------------
     
     private JDBCBeanExistsCommand beanExistsCommand;
     
     private EntityEnterpriseContext ctxArgument;
     
     // Constructors --------------------------------------------------
     
     public JDBCCreateEntityCommand(JDBCCommandFactory factory)
     {
        super(factory, "Create");
        
        beanExistsCommand = factory.createBeanExistsCommand();
        
        // Insert SQL
        
        String sql = "INSERT INTO " + metaInfo.getTableName();
        String fieldSql = "";
        String valueSql = "";
        
        Iterator it = metaInfo.getCMPFieldInfos();
        boolean first = true;
        
        while (it.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)it.next();
           
           if (fieldInfo.isEJBReference())
           {
              JawsCMPField[] pkFields = fieldInfo.getForeignKeyCMPFields();
              
              for (int i = 0; i < pkFields.length; i++)
              {
                 fieldSql += (first ? "" : ",") +
                             fieldInfo.getColumnName() + "_" +
                             pkFields[i].getColumnName();
                 valueSql += first ? "?" : ",?";
                 first = false;
              }
           } else
           {
              fieldSql += (first ? "" : ",") +
                          fieldInfo.getColumnName();
              valueSql += first ? "?" : ",?";
              first = false;
           }
        }
        
        sql += " ("+fieldSql+") VALUES ("+valueSql+")";
        
        setSQL(sql);
     }
     
     // JPMCreateEntityCommand implementation -------------------------
     
     public Object execute(Method m,
                         Object[] args,
                         EntityEnterpriseContext ctx)
        throws RemoteException, CreateException
     {
        // Save ctx for use in setParameters(), handleResult()
        ctxArgument = ctx;
        
        try
        {
           // Extract pk
           Object id = null;
           Iterator it = metaInfo.getPkFieldInfos();
           
           if (metaInfo.hasCompositeKey())
           {
              try
              {
                 id = metaInfo.getPrimaryKeyClass().newInstance();
              } catch (InstantiationException e)
              {
                 throw new ServerException("Could not create primary key",e);
              }
              
              while (it.hasNext())
              {
                 PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
                 Field from = pkFieldInfo.getCMPField();
                 Field to = pkFieldInfo.getPkField();
                 to.set(id, from.get(ctx.getInstance()));
              }
           } else
           {
              PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
              Field from = pkFieldInfo.getCMPField();
              id = from.get(ctx.getInstance());
           }
           
           if (factory.debug)
           {
              log.debug("Create, id is "+id);
           }
           
           // Check duplicate
           if (beanExistsCommand.execute(id))
           {
              throw new DuplicateKeyException("Entity with key "+id+" already exists");
           }
           
           // Insert in db
           
           try
           {
              jdbcExecute();
           } catch (Exception e)
           {
              log.exception(e);
              throw new CreateException("Could not create entity:"+e);
           }
           
           return id;
           
        } catch (IllegalAccessException e)
        {
           log.exception(e);
           throw new CreateException("Could not create entity:"+e);
        }
     }
     
     // JDBCUpdateCommand overrides -----------------------------------
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        int idx = 1; // Parameter-index
        
        Iterator iter = metaInfo.getCMPFieldInfos();
        while (iter.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)iter.next();
           Object value = getCMPFieldValue(ctxArgument.getInstance(), fieldInfo);
           
           if (fieldInfo.isEJBReference())
           {
              idx = setForeignKey(stmt, idx, fieldInfo, value);
           } else
           {
              setParameter(stmt, idx++, fieldInfo.getJDBCType(), value);
           }
        }
     }
     
     protected void handleResult(int rowsAffected) throws Exception
     {
        // arguably should check one row went in!!!
        
        // Store state to be able to do tuned updates
        JAWSPersistenceManager.PersistenceContext pCtx =
           new JAWSPersistenceManager.PersistenceContext();
        
        // If read-only, set last read to now
        if (metaInfo.isReadOnly()) pCtx.lastRead = System.currentTimeMillis();
        
        // Save initial state for tuned updates
        pCtx.state = getState(ctxArgument);
        
        ctxArgument.setPersistenceContext(pCtx);
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCDefinedFinderCommand.java
  
  Index: JDBCDefinedFinderCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.util.ArrayList;
  import java.util.StringTokenizer;
  
  import java.sql.PreparedStatement;
  
  import org.jboss.ejb.plugins.jaws.deployment.Finder;
  
  /**
   * JAWSPersistenceManager JDBCDefinedFinderCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCDefinedFinderCommand extends JDBCFinderCommand
  {
     // Attributes ----------------------------------------------------
     
     private int[] parameterArray;
     
     // Constructors --------------------------------------------------
     
     public JDBCDefinedFinderCommand(JDBCCommandFactory factory, Finder f)
     {
        super(factory, f.getName());
        
        // Replace placeholders with ?
        String query = "";
        StringTokenizer finderQuery = new StringTokenizer(f.getQuery(),"{}", true);
        ArrayList parameters = new ArrayList();
        
        while (finderQuery.hasMoreTokens())
        {
           String t = finderQuery.nextToken();
           if (t.equals("{"))
           {
              query += "?";
              String idx = finderQuery.nextToken(); // Remove number
              parameters.add(new Integer(idx));
              finderQuery.nextToken(); // Remove }
           } else
              query += t;
        }
        
        // Copy index numbers to parameterArray
        parameterArray = new int[parameters.size()];
        for (int i = 0; i < parameterArray.length; i++)
           parameterArray[i] = ((Integer)parameters.get(i)).intValue();
        
        // Construct SQL
        String sql = "SELECT " + getPkColumnList() +
           (f.getOrder().equals("") ? "" : ","+f.getOrder()) + 
           " FROM " + metaInfo.getTableName() + " WHERE " + query;
        if (!f.getOrder().equals(""))
        {
           sql += " ORDER BY "+f.getOrder();
        }
        
        setSQL(sql);
     }
     
     // JDBCFinderCommand overrides ------------------------------------
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        for (int i = 0; i < parameterArray.length; i++)
        {
           stmt.setObject(i+1, argsArgument[parameterArray[i]]);
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCDestroyCommand.java
  
  Index: JDBCDestroyCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  
  import org.jboss.ejb.plugins.jaws.JPMDestroyCommand;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  
  /**
   * JAWSPersistenceManager JDBCDestroyCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCDestroyCommand
     extends JDBCUpdateCommand
     implements JPMDestroyCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCDestroyCommand(JDBCCommandFactory factory)
     {
        super(factory, "Destroy");
        
        // Drop table SQL
        String sql = "DROP TABLE " + metaInfo.getTableName();
        setSQL(sql);
     }
     
     // JPMDestroyCommand implementation ------------------------------
     
     public void execute()
     {
        if (metaInfo.getRemoveTable())
        {
           // Remove it!
           try
           {
              jdbcExecute();
           } catch (Exception e)
           {
              log.debug("Table "+metaInfo.getTableName()+" could not be removed");
           }
        }
     }
     
     // JDBCUpdateCommand overrides -----------------------------------
     
     protected void handleResult(int rowsAffected) throws Exception
     {
        log.debug("Table "+metaInfo.getTableName()+" removed");
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindAllCommand.java
  
  Index: JDBCFindAllCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  /**
   * JAWSPersistenceManager JDBCFindAllCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCFindAllCommand extends JDBCFinderCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCFindAllCommand(JDBCCommandFactory factory)
     {
        super(factory, "FindAll");
        
        String sql = "SELECT " + getPkColumnList() + " FROM " + 
metaInfo.getTableName();
  
        setSQL(sql);
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindByCommand.java
  
  Index: JDBCFindByCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Method;
  
  import java.sql.PreparedStatement;
  
  import java.util.Iterator;
  
  import org.jboss.ejb.plugins.jaws.deployment.Finder;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  
  /**
   * JAWSPersistenceManager JDBCFindByCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCFindByCommand extends JDBCFinderCommand
  {
     // Attributes ----------------------------------------------------
     
     // The meta-info for the field we are finding by
     private CMPFieldInfo fieldInfo;
     
     // The arguments for this finder invocation
     private Object[] argsArgument;
     
     // Constructors --------------------------------------------------
     
     public JDBCFindByCommand(JDBCCommandFactory factory, Method finderMethod)
        throws IllegalArgumentException
     {
        super(factory, finderMethod.getName());
        
        String cmpFieldName = finderMethod.getName().substring(6).toLowerCase();
        System.out.println("Finder:"+cmpFieldName);
        
        // Find the meta-info for the field we want to find by
        
        fieldInfo = null;
        Iterator iter = metaInfo.getCMPFieldInfos();
        
        while (fieldInfo == null && iter.hasNext())
        {
           CMPFieldInfo fi = (CMPFieldInfo)iter.next();
           
           if (cmpFieldName.equals(fi.getName().toLowerCase()))
           {
              fieldInfo = fi;
           }
        }
        
        if (fieldInfo == null)
        {
           throw new IllegalArgumentException(
              "No finder for this method: " + finderMethod.getName());
        }
        
        // Compute SQL
        
        String sql = "SELECT " + getPkColumnList() +
                     " FROM "+metaInfo.getTableName()+ " WHERE ";
        
        if (fieldInfo.isEJBReference())
        {
           JawsCMPField[] cmpFields = fieldInfo.getForeignKeyCMPFields();
           for (int j = 0; j < cmpFields.length; j++)
           {
              sql += (j==0?"":" AND ") + 
                 fieldInfo.getColumnName() + "_" + cmpFields[j].getColumnName() + "=?";
           }
        } else
        {
           sql += fieldInfo.getColumnName() + "=?";
        }
        
        setSQL(sql);
     }
     
     // JDBCFinderCommand overrides -----------------------------------
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        if (fieldInfo != null)
        {
           if (fieldInfo.isEJBReference())
           {
              setForeignKey(stmt, 1, fieldInfo, argsArgument[0]);
           } else
           {
              setParameter(stmt, 1, fieldInfo.getJDBCType(), argsArgument[0]);
           }
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntitiesCommand.java
  
  Index: JDBCFindEntitiesCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Method;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import java.rmi.RemoteException;
  
  import javax.ejb.FinderException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JPMFindEntitiesCommand;
  import org.jboss.ejb.plugins.jaws.deployment.Finder;
  
  /**
   * Keeps a map from finder name to specific finder command, and
   * delegates to the relevant specific finder command.
   * The map is initially populated with the defined finders.
   * It is lazily populated with commands for the magic finders (findAll and
   * findByXXX) as and when they are called.
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCFindEntitiesCommand implements JPMFindEntitiesCommand
  {
     // Attributes ----------------------------------------------------
     
     private JDBCCommandFactory factory;
     private HashMap knownFinderCommands = new HashMap();
     
     // Constructors --------------------------------------------------
     
     public JDBCFindEntitiesCommand(JDBCCommandFactory factory)
     {
        this.factory = factory;
        
        // Make commands for the defined finders
        
        Iterator definedFinders = factory.getMetaInfo().getFinders();
        while(definedFinders.hasNext())
        {
           Finder f = (Finder)definedFinders.next();
           
           if ( !knownFinderCommands.containsKey(f.getName()) )
           {
              JPMFindEntitiesCommand finderCommand =
                 factory.createDefinedFinderCommand(f);
                 
              knownFinderCommands.put(f.getName(), finderCommand);
           }
        }
     }
     
     // JPMFindEntitiesCommand implementation -------------------------
     
     public Collection execute(Method finderMethod,
                               Object[] args,
                               EntityEnterpriseContext ctx)
        throws RemoteException, FinderException
     {
        String finderName = finderMethod.getName();
        
        // Do we know a finder command for this method name?
        
        JPMFindEntitiesCommand finderCommand = 
           (JPMFindEntitiesCommand)knownFinderCommands.get(finderName);
        
        // If we didn't get a finder command, see if we can make one
        
        if (finderCommand == null)      
        {
           try
           {
              if (finderName.equals("findAll"))
              {
                 finderCommand = factory.createFindAllCommand();
              } else if (finderName.startsWith("findBy"))
              {
                 finderCommand = factory.createFindByCommand(finderMethod);
              }
              
              // Remember the new finder command
              knownFinderCommands.put(finderName, finderCommand);
              
           } catch (IllegalArgumentException e)
           {
              factory.getLog().warning(e.getMessage());
           }
        }
        
        // If we now have a finder command, delegate to it,
        // otherwise return an empty collection.
        
        return (finderCommand != null) ?
           finderCommand.execute(finderMethod, args, ctx) : new ArrayList();
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntityCommand.java
  
  Index: JDBCFindEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Method;
  
  import java.util.Collection;
  import java.util.ArrayList;
  
  import java.rmi.RemoteException;
  
  import javax.ejb.FinderException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JPMFindEntityCommand;
  import org.jboss.ejb.plugins.jaws.JPMFindEntitiesCommand;
  
  /**
   * JAWSPersistenceManager JDBCFindEntityCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCFindEntityCommand implements JPMFindEntityCommand
  {
     // Attributes ----------------------------------------------------
     
     JDBCBeanExistsCommand beanExistsCommand;
     JPMFindEntitiesCommand findEntitiesCommand;
     
     // Constructors --------------------------------------------------
     
     public JDBCFindEntityCommand(JDBCCommandFactory factory)
     {
        beanExistsCommand = factory.createBeanExistsCommand();
        findEntitiesCommand = factory.createFindEntitiesCommand();
     }
     
     // JPMFindEntityCommand implementation ---------------------------
     
     public Object execute(Method finderMethod,
                           Object[] args,
                           EntityEnterpriseContext ctx)
        throws RemoteException, FinderException
     {
        if (finderMethod.getName().equals("findByPrimaryKey"))
        {
        
           return findByPrimaryKey(args[0]);
        }
        else
        {
           ArrayList result =
              (ArrayList)findEntitiesCommand.execute(finderMethod, args, ctx);
           
           if (result.size() == 0)
           {
              throw new FinderException("No such entity!");
           } else
           {
              return result.get(0);
           }
        }
     }
     
     // Protected -----------------------------------------------------
     
     protected Object findByPrimaryKey(Object id) throws FinderException
     {
        if (beanExistsCommand.execute(id))
        {
           return id;
        } else
        {
           throw new FinderException("Object with primary key " + id +
                                     " not found in storage");
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFinderCommand.java
  
  Index: JDBCFinderCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Iterator;
  
  import java.rmi.RemoteException;
  import java.rmi.ServerException;
  
  import java.sql.ResultSet;
  
  import javax.ejb.FinderException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.ejb.plugins.jaws.JPMFindEntitiesCommand;
  
  /**
   * Abstract superclass of finder commands that return collections.
   * Provides the handleResult() implementation that these all need.
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public abstract class JDBCFinderCommand 
     extends JDBCQueryCommand
     implements JPMFindEntitiesCommand
  {
     // Attributes ----------------------------------------------------
     
     protected Object[] argsArgument;
     protected ArrayList result;
     
     // Constructors --------------------------------------------------
     
     public JDBCFinderCommand(JDBCCommandFactory factory, String name)
     {
        super(factory, name);
     }
     
     // JPMFindEntitiesCommand implementation -------------------------
     
     public Collection execute(Method finderMethod,
                               Object[] args,
                               EntityEnterpriseContext ctx)
        throws RemoteException, FinderException
     {
        argsArgument = args;
        
        try
        {
           jdbcExecute();
        } catch (Exception e)
        {
           log.exception(e);
           throw new FinderException("Find failed");
        }
        
        return result;
     }
     
     // JDBCQueryCommand overrides ------------------------------------
     
     protected void handleResult(ResultSet rs) throws Exception
     {
        result = new ArrayList();
        int i = 1;   // parameter index
        
        if (metaInfo.hasCompositeKey())
        {
           // Compound key
           try
           {
              while (rs.next())
              {
                 Object pk = metaInfo.getPrimaryKeyClass().newInstance();
                 
                 Iterator it = metaInfo.getPkFieldInfos();
                 while (it.hasNext())
                 {
                    PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
                    Field pkField = pkFieldInfo.getPkField();
                    pkField.set(pk, rs.getObject(i++));
                 }
                 result.add(pk);
              }
           } catch (Exception e)
           {
              throw new ServerException("Finder failed",e);
           }
        } else
        {
           // Primitive key
           while (rs.next())
           {
              result.add(rs.getObject(i));
           }
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCInitCommand.java
  
  Index: JDBCInitCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.util.Iterator;
  
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  
  import org.jboss.ejb.plugins.jaws.JPMInitCommand;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.MetaInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  
  /**
   * JAWSPersistenceManager JDBCInitCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCInitCommand
     extends JDBCUpdateCommand
     implements JPMInitCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCInitCommand(JDBCCommandFactory factory)
     {
        super(factory, "Init");
        
        // Create table SQL
        String sql = "CREATE TABLE " + metaInfo.getTableName() + " (";
        
        Iterator it = metaInfo.getCMPFieldInfos();
        boolean first = true;
        while (it.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)it.next();
           
           if (fieldInfo.isEJBReference())
           {
              JawsCMPField[] pkFields = fieldInfo.getForeignKeyCMPFields();
              
              for (int i = 0; i < pkFields.length; i++)
              {
                 sql += (first ? "" : ",") +
                        fieldInfo.getColumnName() + "_" +
                        pkFields[i].getColumnName() + " " +
                        pkFields[i].getSqlType();
                 first = false;
              }
           } else
           {
              sql += (first ? "" : ",") +
                     fieldInfo.getColumnName() + " " +
                     fieldInfo.getSQLType();
              first = false;
           }
        }
        
        sql += ")";
        
        setSQL(sql);
     }
     
     // JPMInitCommand implementation ---------------------------------
     
     public void execute() throws Exception
     {
        // Create table if necessary
        if (metaInfo.getCreateTable())
        {
           // Try to create it
           try
           {
              jdbcExecute();
           } catch (Exception e)
           {
              log.debug("Table " + metaInfo.getTableName() + " exists");
           }
        }
     }
     
     // JDBCUpdateCommand overrides -----------------------------------
     
     protected void handleResult(int rowsAffected) throws Exception
     {
        log.debug("Table " + metaInfo.getTableName() + " created");
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCLoadEntityCommand.java
  
  Index: JDBCLoadEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  
  import java.util.Iterator;
  
  import java.rmi.NoSuchObjectException;
  import java.rmi.RemoteException;
  import java.rmi.ServerException;
  
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JAWSPersistenceManager;
  import org.jboss.ejb.plugins.jaws.JPMLoadEntityCommand;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsEntity;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  
  /**
   * JAWSPersistenceManager JDBCLoadEntityCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCLoadEntityCommand
     extends JDBCQueryCommand
     implements JPMLoadEntityCommand
  {
     // Attributes ----------------------------------------------------
     
     private EntityEnterpriseContext ctxArgument;
     
     // Constructors --------------------------------------------------
     
     public JDBCLoadEntityCommand(JDBCCommandFactory factory)
     {
        super(factory, "Load");
        
        // Select SQL
        String sql = "SELECT ";
        
        Iterator it = metaInfo.getCMPFieldInfos();
        boolean first = true;
        
        while (it.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)it.next();
           
           if (fieldInfo.isEJBReference())
           {
              JawsCMPField[] pkFields = fieldInfo.getForeignKeyCMPFields();
              
              for (int i = 0; i < pkFields.length; i++)
              {
                 sql += (first ? "" : ",") +
                        fieldInfo.getColumnName() + "_" +
                        pkFields[i].getColumnName();
                 first = false;
              }
           } else
           {
              sql += (first ? "" : ",") +
                     fieldInfo.getColumnName();
              first = false;
           }
        }
        
        sql += " FROM " + metaInfo.getTableName() +
               " WHERE " + getPkColumnWhereList();
        
        setSQL(sql);
     }
     
     // JPMLoadEntityCommand implementation ---------------------------
     
     public void execute(EntityEnterpriseContext ctx)
        throws RemoteException
     {
        // Save the argument for use by setParameters() and handleResult()
        ctxArgument = ctx;
        
        if ( !metaInfo.isReadOnly() || isTimedOut() )
        {
           try
           {
              jdbcExecute();
           } catch (Exception e)
           {
              throw new ServerException("Load failed", e);
           }
        }
     }
     
     // JDBCQueryCommand overrides ------------------------------------
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        // Primary key in WHERE-clause
        Iterator it = metaInfo.getPkFieldInfos();
        int i = 1;   // parameter index
        
        if (metaInfo.hasCompositeKey())
        {
           // Compound key
           while (it.hasNext())
           {
              PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
              int jdbcType = pkFieldInfo.getJDBCType();
              Object value = getPkFieldValue(ctxArgument.getId(), pkFieldInfo);
              setParameter(stmt, i++, jdbcType, value);
           }
        } else
        {
           // Primitive key
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           int jdbcType = pkFieldInfo.getJDBCType();
           Object value = ctxArgument.getId();
           setParameter(stmt, i, jdbcType, value);
        }
     }
     
     protected void handleResult(ResultSet rs) throws Exception
     {
        if (!rs.next())
           throw new NoSuchObjectException("Entity "+ctxArgument.getId()+" not found");
        
        // Set values
        int idx = 1;
        
        Iterator iter = metaInfo.getCMPFieldInfos();
        while (iter.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)iter.next();
           
           if (fieldInfo.isEJBReference())
           {
              // Create pk
              JawsCMPField[] pkFields = fieldInfo.getForeignKeyCMPFields();
              JawsEntity referencedEntity = (JawsEntity)pkFields[0].getBeanContext();
              Object pk;
              if (referencedEntity.getPrimaryKeyField().equals(""))
              {
                 // Compound key
                 pk = 
factory.getContainer().getClassLoader().loadClass(referencedEntity.getPrimaryKeyClass()).newInstance();
                 Field[] fields = pk.getClass().getFields();
                 for(int j = 0; j < fields.length; j++)
                 {
                    Object val = rs.getObject(idx++);
                    fields[j].set(pk, val);
                    
                    if (factory.debug)
                    {
                       log.debug("Referenced pk field:" + val);
                    }
                 }
              } else
              {
                 // Primitive key
                 pk = rs.getObject(idx++);
                 
                 if (factory.debug)
                 {
                    log.debug("Referenced pk:" + pk);
                 }
              }
              
              // Find referenced entity
              try
              {
                 Object home = factory.getJavaCtx().lookup(fieldInfo.getSQLType());
                 Method[] homeMethods = home.getClass().getMethods();
                 Method finder = null;
                 
                 // We have to locate fBPK iteratively since we don't
                 // really know the pk-class
                 for (int j = 0; j < homeMethods.length; j++)
                 {
                    if (homeMethods[j].getName().equals("findByPrimaryKey"))
                    {
                       finder = homeMethods[j];
                       break;
                    }
                 }
                 
                 if (finder == null)
                 {
                    throw new NoSuchMethodException(
                       "FindByPrimaryKey method not found in home interface");
                 }
                 
                 log.debug("PK=" + pk);
                 Object ref = finder.invoke(home, new Object[] { pk });
                 
                 // Set found entity
                 setCMPFieldValue(ctxArgument.getInstance(), fieldInfo, ref);
              } catch (Exception e)
              {
                 throw new ServerException("Could not restore reference", e);
              }
           } else
           {
              // Load primitive
              
              // TODO: this probably needs to be fixed for BLOB's etc.
              setCMPFieldValue(ctxArgument.getInstance(), fieldInfo, 
rs.getObject(idx++));
           }
        }
        
        // Store state to be able to do tuned updates
        JAWSPersistenceManager.PersistenceContext pCtx =
           
(JAWSPersistenceManager.PersistenceContext)ctxArgument.getPersistenceContext();
        if (metaInfo.isReadOnly()) pCtx.lastRead = System.currentTimeMillis();
        pCtx.state = getState(ctxArgument);
     }
     
     // Protected -----------------------------------------------------
     
     protected boolean isTimedOut()
     {
        JAWSPersistenceManager.PersistenceContext pCtx =
           
(JAWSPersistenceManager.PersistenceContext)ctxArgument.getPersistenceContext();
        
        return (System.currentTimeMillis() - pCtx.lastRead) > 
metaInfo.getReadOnlyTimeOut();
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCPassivateEntityCommand.java
  
  Index: JDBCPassivateEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
   
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.rmi.RemoteException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  
  import org.jboss.ejb.plugins.jaws.JPMPassivateEntityCommand;
  
  /**
   * JAWSPersistenceManager JDBCPassivateEntityCommand
   *    
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
   
  public class JDBCPassivateEntityCommand implements JPMPassivateEntityCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCPassivateEntityCommand(JDBCCommandFactory factory)
     {
     }
     
     // JPMPassivateEntityCommand implementation ----------------------
     
     public void execute(EntityEnterpriseContext ctx) throws RemoteException
     {
        // There is nothing to do here.
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCQueryCommand.java
  
  Index: JDBCQueryCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  
  /**
   * Abstract superclass for all JAWS Commands that issue JDBC queries
   * directly.
   * Provides a Template Method implementation for
   * <code>executeStatementAndHandleResult</code>.
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public abstract class JDBCQueryCommand extends JDBCCommand
  {
     // Constructors --------------------------------------------------
     
     /**
      * Pass the arguments on to the superclass constructor.
      */
     protected JDBCQueryCommand(JDBCCommandFactory factory, String name)
     {
        super(factory, name);
     }
     
     // Protected -----------------------------------------------------
     
     /**
      * Template Method that executes the PreparedStatement and calls
      * <code>handleResult</code> on the resulting ResultSet.
      */
     protected void executeStatementAndHandleResult(PreparedStatement stmt)
        throws Exception
     {
        ResultSet rs = null;
        try
        {
           rs = stmt.executeQuery();
           handleResult(rs);
        } finally
        {
           if (rs != null)
           {
              try
              {
                 rs.close();
              } catch (SQLException e)
              {
                 e.printStackTrace();
              }
           }
        }
     }
     
     /**
      * Handle the result of successful execution of the query.
      */
     protected abstract void handleResult(ResultSet rs) throws Exception;
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCRemoveEntityCommand.java
  
  Index: JDBCRemoveEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.util.Iterator;
  
  import java.rmi.RemoteException;
  
  import java.sql.PreparedStatement;
  
  import javax.ejb.RemoveException;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JPMRemoveEntityCommand;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  
  /**
   * JAWSPersistenceManager JDBCRemoveEntityCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCRemoveEntityCommand
     extends JDBCUpdateCommand
     implements JPMRemoveEntityCommand
  {
     // Attributes ----------------------------------------------------
     
     private EntityEnterpriseContext ctxArgument;
     
     // Static --------------------------------------------------------
     
     // Constructors --------------------------------------------------
     
     public JDBCRemoveEntityCommand(JDBCCommandFactory factory)
     {
        super(factory, "Remove");
        
        // Remove SQL
        String sql = "DELETE FROM " + metaInfo.getTableName() +
                     " WHERE "+getPkColumnWhereList();
        setSQL(sql);
     }
     
     // JPMRemoveEntityCommand implementation -------------------------
     
     public void execute(EntityEnterpriseContext ctx)
        throws RemoteException, RemoveException
     {
        ctxArgument = ctx;
        
        try
        {
           // Remove from DB
           jdbcExecute();
        } catch (Exception e)
        {
           throw new RemoveException("Could not remove "+ctx.getId());
        }
     }
     
     // JDBCUpdateCommand overrides -----------------------------------
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        Iterator it = metaInfo.getPkFieldInfos();
        int i = 1;   // parameter index
        
        // Primary key in WHERE-clause
        if (metaInfo.hasCompositeKey())
        {
           // Compound key
           while (it.hasNext())
           {
              PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
              int jdbcType = pkFieldInfo.getJDBCType();
              Object value = getPkFieldValue(ctxArgument.getId(), pkFieldInfo);
              setParameter(stmt, i++, jdbcType, value);
           }
        } else
        {
           // Primitive key
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           int jdbcType = pkFieldInfo.getJDBCType();
           Object value = ctxArgument.getId();
           setParameter(stmt, i, jdbcType, value);
        }
     }
     
     protected void handleResult(int rowsAffected) throws Exception
     {
        if (rowsAffected == 0)
        {
           throw new RemoveException("Could not remove entity");
        }
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCStartCommand.java
  
  Index: JDBCStartCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
   
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import org.jboss.ejb.plugins.jaws.JPMStartCommand;
  
  /**
   * JAWSPersistenceManager JDBCStartCommand
   *    
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCStartCommand implements JPMStartCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCStartCommand(JDBCCommandFactory factory)
     {
     }
     
     // JPMStartCommand implementation --------------------------------
     
     public void execute() throws Exception
     {
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCStopCommand.java
  
  Index: JDBCStopCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
   
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import org.jboss.ejb.plugins.jaws.JPMStopCommand;
  
  /**
   * JAWSPersistenceManager JDBCStopCommand
   *    
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCStopCommand implements JPMStopCommand
  {
     // Constructors --------------------------------------------------
     
     public JDBCStopCommand(JDBCCommandFactory factory)
     {
     }
     
     // JPMStopCommand implementation ---------------------------------
     
     public void execute()
     {
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCStoreEntityCommand.java
  
  Index: JDBCStoreEntityCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.lang.reflect.Field;
  
  import java.util.Iterator;
  
  import java.rmi.RemoteException;
  import java.rmi.ServerException;
  
  import java.sql.PreparedStatement;
  
  import org.jboss.ejb.EntityEnterpriseContext;
  import org.jboss.ejb.plugins.jaws.JAWSPersistenceManager;
  import org.jboss.ejb.plugins.jaws.JPMStoreEntityCommand;
  import org.jboss.ejb.plugins.jaws.CMPFieldInfo;
  import org.jboss.ejb.plugins.jaws.PkFieldInfo;
  import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
  
  /**
   * JAWSPersistenceManager JDBCStoreEntityCommand
   *
   * @see <related>
   * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public class JDBCStoreEntityCommand
     extends JDBCUpdateCommand
     implements JPMStoreEntityCommand
  {
     // Attributes ----------------------------------------------------
     
     private EntityEnterpriseContext ctxArgument;
     private boolean tuned;
     private Object[] currentState;
     private boolean[] dirtyField;    // only used for tuned updates
     
     // Constructors --------------------------------------------------
     
     public JDBCStoreEntityCommand(JDBCCommandFactory factory)
     {
        super(factory, "Store");
        tuned = metaInfo.hasTunedUpdates();
        
        // If we don't have tuned updates, create static SQL
        if (!tuned)
        {
           setSQL(makeSQL());
        }
     }
     
     // JPMStoreEntityCommand implementation ---------------------------
     
     /**
      * if the readOnly flag is specified in the xml file this won't store.
      * if not a tuned or untuned update is issued.
      */
     public void execute(EntityEnterpriseContext ctx)
        throws RemoteException
     {
        // Check for read-only
        // JF: Shouldn't this throw an exception?
        if (metaInfo.isReadOnly())
        {
           return;
        }
        
        ctxArgument = ctx;
        currentState = getState(ctx);
        boolean dirty = false;
        
        // For tuned updates, need to see which fields have changed
        
        if (tuned)
        {
           dirtyField = new boolean[currentState.length];
           Object[] oldState =
              
((JAWSPersistenceManager.PersistenceContext)ctx.getPersistenceContext()).state;
           
           for (int i = 0; i < currentState.length; i++)
           {
              dirtyField[i] = changed(currentState[i], oldState[i]);
              dirty |= dirtyField[i];
           }
        }
        
        if (!tuned || dirty)
        {
           try
           {
              // Update db
              jdbcExecute();
              
           } catch (Exception e)
           {
              throw new ServerException("Store failed", e);
           }
        }
     }
     
     // JDBCUpdateCommand overrides -----------------------------------
     
     /**
      * Returns dynamically-generated SQL if this entity
      * has tuned updates, otherwise static SQL.
      */
     protected String getSQL() throws Exception
     {
        return tuned ? makeSQL() : super.getSQL();
     }
     
     protected void setParameters(PreparedStatement stmt) throws Exception
     {
        int idx = 1;
        Iterator iter = metaInfo.getCMPFieldInfos();
        int i = 0;
        while (iter.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)iter.next();
           
           if (!tuned || dirtyField[i])
           {
              if (fieldInfo.isEJBReference())
              {
                 idx = setForeignKey(stmt, idx, fieldInfo, currentState[i]);
              } else
              {
                 setParameter(stmt, idx++, fieldInfo.getJDBCType(), currentState[i]);
              }
           }
           
           i++;
        }
        
        // Primary key in WHERE-clause
        Iterator it = metaInfo.getPkFieldInfos();
        while (it.hasNext())
        {
           PkFieldInfo pkFieldInfo = (PkFieldInfo)it.next();
           int jdbcType = pkFieldInfo.getJDBCType();
           Field field = pkFieldInfo.getCMPField();
           Object value = field.get(ctxArgument.getInstance());
           
           // SA had introduced the change below, but it fails
           // for non-composite primary keys.
           // Object value = getPkFieldValue(ctxArgument.getId(), pkFieldInfo);
           
           setParameter(stmt, idx++, jdbcType, value);
        }
     }
     
     protected void handleResult(int rowsAffected) throws Exception
     {
        if (tuned)
        {
           // Save current state for tuned updates
           JAWSPersistenceManager.PersistenceContext pCtx =
              
(JAWSPersistenceManager.PersistenceContext)ctxArgument.getPersistenceContext();
           pCtx.state = currentState;
        }
     }
     
     // Protected -----------------------------------------------------
     
     protected final boolean changed(Object current, Object old)
     {
        return (current == null) ? (old != null) : current.equals(old);
     }
     
     /** 
      * Used to create static SQL (tuned = false) or dynamic SQL (tuned = true).
      */
     protected String makeSQL()
     {
        String sql = "UPDATE "+metaInfo.getTableName()+" SET ";
        Iterator iter = metaInfo.getCMPFieldInfos();
        int i = 0;
        boolean first = true;
        while (iter.hasNext())
        {
           CMPFieldInfo fieldInfo = (CMPFieldInfo)iter.next();
           
           if (!tuned || dirtyField[i++])
           {
              if (fieldInfo.isEJBReference())
              {
                 JawsCMPField[] pkFields = fieldInfo.getForeignKeyCMPFields();
                 
                 for (int j = 0; j < pkFields.length; j++)
                 {
                    sql += (first?"":",") + 
                       fieldInfo.getColumnName()+"_"+pkFields[j].getColumnName()+
                       "=?";
                    first = false;
                 }
              } else
              {
                 sql += (first?"":",") +
                    fieldInfo.getColumnName() + "=?";
                 first = false;
              }
           }
        }
        sql += " WHERE "+getPkColumnWhereList();
        return sql;
     }
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCUpdateCommand.java
  
  Index: JDBCUpdateCommand.java
  ===================================================================
  /*
   * jBoss, the OpenSource EJB server
   *
   * Distributable under GPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.ejb.plugins.jaws.jdbc;
  
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  
  /**
   * Abstract superclass for all JAWS Commands that issue JDBC updates
   * directly.
   * Provides a Template Method implementation for
   * <code>executeStatementAndHandleResult</code>.
   * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
   * @version $Revision: 1.1 $
   */
  public abstract class JDBCUpdateCommand extends JDBCCommand
  {
     // Constructors --------------------------------------------------
     
     /**
      * Pass the arguments on to the superclass constructor.
      */
     protected JDBCUpdateCommand(JDBCCommandFactory factory, String name)
     {
        super(factory, name);
     }
     
     // Protected -----------------------------------------------------
     
     /**
      * Template Method that executes the PreparedStatement and calls
      * <code>handleResult</code> on the integer result.
      */
     protected void executeStatementAndHandleResult(PreparedStatement stmt)
        throws Exception
     {
        int rowsAffected = stmt.executeUpdate();
        
        if (factory.debug)
        {
           log.debug("Rows affected = " + rowsAffected);
        }
        
        handleResult(rowsAffected);
     }
     
     /**
      * Handle the result of successful execution of the update.
      */
     protected abstract void handleResult(int rowsAffected) throws Exception;
  }
  
  
  

Reply via email to