/*
 * The contents of this file are subject to the JOnAS Public License Version
 * 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License on the JOnAS web site.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 * See the License for the specific terms governing rights and limitations under
 * the License.
 *
 * The Original Code is JOnAS application server code released July 1999.
 *
 * The Initial Developer of the Original Code is Bull S.A.
 * The Original Code and portions created by Bull S.A. are
 *    Copyright (C) 1999 Bull S.A. All Rights Reserved.
 *
 * Contributor(s):
 *
 * 00/09/14 Santiago Gala (sgala@hisitech.com)
 *          Parameters can be followed by a number in the WHERE clausey
 *
 * --------------------------------------------------------------------------
 * $Id: GenICEntityCMbyJDBCBean.java,v 1.3 2000/12/15 15:09:19 jonas Exp $
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas_ejb.tools;


import java.lang.String;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.Vector;
import org.objectweb.jonas_ejb.deployment.api.EntityCmpDesc;
import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
import org.objectweb.jonas_ejb.deployment.api.EntityJdbcCmpDesc;
import org.objectweb.jonas_ejb.deployment.api.FieldDesc;
import org.objectweb.jonas_ejb.deployment.api.MethodJdbcDesc;
import org.objectweb.jonas_ejb.lib.BeanNaming;
import org.objectweb.jonas_ejb.lib.JavaType;


/**
 *  This class allows to generate the source of the derived class of a given
 *  Entity Enterprise Java Bean with container managed persistence by JDBC.
 *  Its extends GenICEntityCMBean class, itself extends GenICBean class.
 */
class GenICEntityCMbyJDBCBean extends GenICEntityCMBean {

    /**
     * GenICEntityCMbyJDBCBean Constructor
     *
     * @param dd       deployment descriptor of the Entity Enterprise Java Bean
     *                 with container managed persistence by JDBC
     * @param fileName name of the source file of the class to generate
     * @exception GenICException in error case
     */

    // Database Table Name
    String  dbTableName   = null;
    // List of the container-managed fields of the bean
    Vector fieldsPers     = null;
    // List of the fields of the PrimaryKey
    Vector fieldsPK       = null;
    // List of the container-managed fields of the bean which are not PrimaryKey's fields
    Vector fieldsPersNoPK = null;
    // Is there a Primary Key Field ?
    boolean hasPrimaryKeyField;
    // Full name of the PrimaryClass class
    String ejbPrimaryKeyName = null;

    GenICEntityCMbyJDBCBean(EntityJdbcCmpDesc dd, String fileName) throws GenICException {
	super(dd, fileName);

	ejbPrimaryKeyName = ((EntityDesc)ddesc).getPrimaryKeyClass().getName();

	// Get the database table name
	dbTableName = dd.getJdbcTableName();


	// Construct the fieldsPers list,  fieldsPK list and fieldsPersNoPK list
	// and check if all fields can be treated.
	fieldsPers = new Vector();
	fieldsPK   = new Vector();
	fieldsPersNoPK = new Vector();
	Field[] fieldsBean = ddesc.getEjbClass().getFields();
	for (int i = 0; i<fieldsBean.length; i++) {
	    Field f = fieldsBean[i];
	    if (((EntityCmpDesc)ddesc).hasCmpFieldDesc(f)) {
		FieldDesc fd = ((EntityCmpDesc)ddesc).getCmpFieldDesc(f);
		if ((JavaType.getSQLGetMethod(f.getType()) == null) &&
		    (JavaType.getSQLSetMethod(f.getType()) == null)) {
		    throw new GenICException("Cannot container manage the bean's field '" +
					     f.getName() +
					     "' (Type '" + JavaType.getName(f.getType()) + "')");
		}
		fieldsPers.add(f);
		if (fd.isPrimaryKey()) {
		    fieldsPK.add(f);
		} else {
		    fieldsPersNoPK.add(f);
		}
	    }
	}
	//
	hasPrimaryKeyField = ((EntityCmpDesc)ddesc).hasPrimaryKeyField();
    }

    /**
     * Source generation of the import clauses
     * @exception GenICException in error case
     */
    void genImport() throws GenICException {
	src.println("import java.sql.Connection;");
	src.println("import java.sql.PreparedStatement;");
	src.println("import java.sql.ResultSet;");
	src.println("import java.sql.SQLException;");
	src.println("import java.sql.Types;");
	src.println("import java.util.Enumeration;");
	src.println("import java.util.Vector;");
	src.println();
	src.println("import javax.ejb.EJBException;");
	src.println("import javax.ejb.EJBHome;");
	src.println("import javax.ejb.EJBObject;");
	src.println("import javax.ejb.EntityContext;");
	src.println("import javax.ejb.FinderException;");
	src.println("import javax.ejb.ObjectNotFoundException;");
	src.println("import javax.sql.DataSource;");
	src.println();
	src.println("import org.objectweb.jonas_ejb.container.TraceEjb;");
	src.println("import org.objectweb.jonas_ejb.container.JEntityHome;");
	src.println("import org.objectweb.jonas_ejb.lib.MarshallTool;");

    }

    /**
     * Source generation of the ejbCreate() method associated to the given create() method
     * described in the Home interface
     * @exception GenICException in error case
     */
    void genEjbCreate(Method method) throws GenICException {

	Class params[] = method.getParameterTypes();
	Method methodBean = null;
	try {
	    methodBean = ejbBeanClass.getMethod("ejbCreate", params);
	} catch (Exception e) {
	    throw new GenICException("Cannot get the "+ejbBeanName+".ejbCreate("+params+") method by reflection ("+e.getMessage()+")");
	}

	try {
	    genHeaderMethod(method, wrpBeanBaseName, "ejbCreate", methodBean.getReturnType(),
			    methodBean.getExceptionTypes(), false);
	    // Container-managed fields are set to the Java language defaults
	    for (int i=0; i<fieldsPers.size(); i++) {
		Field f = (Field)fieldsPers.get(i);
		src.println("this."+f.getName()+" = "
			    +JavaType.getDefaultValue(f.getType())+";");
	    }
	    src.print  ("super.ejbCreate(");
	    for (int p=1; p <= params.length; p++) {
		src.print("p" + p, false);
		if (p < params.length) {
		    src.print(", ", false);
		}
	    }
	    src.println(");", false);
	    src.println(ejbPrimaryKeyName+" pk = new "+ejbPrimaryKeyName+"();");
	    if (hasPrimaryKeyField) {
		for (int i=0; i<fieldsPK.size(); i++) {
		    Field f = (Field)fieldsPK.get(i);
		    src.println("pk = this."+f.getName()+";");
		}
	    } else {
		for (int i=0; i<fieldsPK.size(); i++) {
		    Field f = (Field)fieldsPK.get(i);
		    src.println("pk."+f.getName()+" = this."+f.getName()+";");
		}
	    }
	    /*
	     * These 5 lines work only if ejbCreate throws DuplicateKeyException!
	     * to be done more properly later!
	     */
	    //src.println("if (this.ejbHome.getEJBObject(pk) != null) {");
	    //src.indentPlus();
	    //src.println("throw new javax.ejb.DuplicateKeyException(pk.toString());");
	    //src.indentMinus();
	    //src.println("}");
	    src.println("Connection conn = null;");
	    src.println("PreparedStatement pStmt = null;");
	    src.println("try {");
	    src.indentPlus();
	    src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
	    src.println("conn = ds.getConnection();");
	    src.print  ("pStmt = conn.prepareStatement(\"insert into " + dbTableName +" (");
	    for (int i=0; i<fieldsPers.size(); i++) {
		Field f = (Field)fieldsPers.get(i);
		if (i > 0) {
		    src.print(", ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName(), false);
	    }
	    src.print  (") values (", false);
	    for (int i=0; i<fieldsPers.size(); i++) {
		if (i > 0) {
		    src.print(", ", false);
		}
		src.print("?", false);
	    }
	    src.println(")\");", false);
	    for (int i=0; i<fieldsPers.size(); i++) {
		int index = i+1;
		Field f = (Field)fieldsPers.get(i);
		Class  attrType = f.getType();
		String sqlTypeName = JavaType.getSQLType(attrType);
		String methName = JavaType.getSQLSetMethod(attrType);
		String attrName = "this."+f.getName();
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "(java.lang.Object)";
		} else {
		    castS = "";
		}
		if (! attrType.isPrimitive()) {
		    src.println("if ("+attrName+" == null) {");
		    src.indentPlus();
		    src.println("pStmt.setNull("+ index + ", " + sqlTypeName + ");");
		    src.indentMinus();
		    src.println("} else {");
		    src.indentPlus();
		}
		if (methName.equals("setSerializable")) {
		    src.println("pStmt.setBytes(" +
				index + ", MarshallTool.toBytes(" + attrName + "));");
		} else {
		    src.println("pStmt." + methName + "(" +
				index + ", " + castS + attrName + ");");
		}
		if (! attrType.isPrimitive()) {
		    src.indentMinus();
		    src.println("}");
		}
	    }
	    src.println("pStmt.executeUpdate();");
	    src.indentMinus();
	    //src.println("} catch (SQLException e) {");
	    src.println("} catch (Exception e) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to create bean in database\", e);");
	    src.println("throw new EJBException(e);");
	    src.indentMinus();
	    src.println("} finally {");
	    src.indentPlus();
	    src.println("if (pStmt != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("pStmt.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the PreparedStatement (ejbCreate)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.println("if (conn != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("conn.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the Connection (ejbCreate)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}"); // try-catch-finally
	    src.println("return(pk);");
	    src.indentMinus();
	    src.println("}");
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
    }


    /**
     * Source generation of the ejbFindByPrimaryKey() method associated to the given
     * findByPrimaryKey() method described in the Home interface
     * @exception GenICException in error case
     */
    void genEjbFindByPK(Method method) throws GenICException {

	Class params[] = method.getParameterTypes();

	src.print  ("public " + ejbPrimaryKeyName + " ejbFindByPrimaryKey(");
	// Useful is the parameter of findByPrimaryKey() is java.lang.Object
	src.print  (ejbPrimaryKeyName + " p1) ", false);
	src.println(" throws javax.ejb.FinderException {", false);
	// core
	src.indentPlus();
	src.print  ("TraceEjb.debugGenIC(\""+wrpHomeBaseName+".ejbFindByPrimaryKey(");
	for (int p=1; p <= params.length; p++) {
	    src.print(JavaType.getName(params[p-1]), false);
	    if (p < params.length) {
		src.print(", ", false);
	    }
	}
	src.println(")\");", false);
	src.println("Connection conn = null;");
	src.println("PreparedStatement pStmt = null;");
	src.println("try {");
	src.indentPlus();
	src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
	src.println("conn = ds.getConnection();");
	src.print  ("pStmt = conn.prepareStatement(\"select ");
	try {
	    for (int i=0; i<fieldsPK.size(); i++) {
		Field f = (Field)fieldsPK.get(i);
		if (i > 0) {
		    src.print(", ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName(), false);
	    }
	    src.print (" from " + ((EntityJdbcCmpDesc)ddesc).getJdbcTableName() + " where ", false);
	    for (int i=0; i<fieldsPK.size(); i++) {
		Field f = (Field)fieldsPK.get(i);
		if (i > 0) {
		    src.print(" and ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName() +
			  "=?", false);
	    }
	    src.println("\");", false);
	    for (int i=0; i<fieldsPK.size(); i++) {
		int index = i + 1;
		Field f = (Field)fieldsPK.get(i);
		String methName = JavaType.getSQLSetMethod(f.getType());
		String attrName;
		if (hasPrimaryKeyField) {
		    attrName = "p1";
		} else {
		    attrName = "p1."+f.getName();
		}
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "(java.lang.Object)";
		} else {
		    castS = "";
		}
		if (methName.equals("setSerializable")){
		    src.println("pStmt.setBytes(" +
				index + ", MarshallTool.toBytes(" + attrName + "));");
		} else {
		    src.println("pStmt."+ methName +
				"(" + index + ", " + castS + attrName + ");");
		}
	    }
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
	src.println("ResultSet rs = pStmt.executeQuery();");
	src.println("if (rs.next() == false) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Object not found in database ("+
		    method.getName()+")\");");
	src.println("throw new ObjectNotFoundException(\"Object not found in database ("+
		    method.getName()+")\");");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
// BEGIN MHALAS:
	src.println("} catch (ObjectNotFoundException oe) {");
	src.println("throw oe;");
// END MHALAS
	src.println("} catch (Exception e) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Failed to find bean from database ("+
		    method.getName()+")\", e);");
	src.println("throw new FinderException(\"Failed to find bean from database ("+
		    method.getName()+")\");");
	src.indentMinus();
	src.println("} finally {");
	src.indentPlus();
	src.println("if (pStmt != null) {");
	src.indentPlus();
	src.println("try {");
	src.indentPlus();
	src.println("pStmt.close();");
	src.indentMinus();
	src.println("} catch (Exception ignore) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Failed to close the PreparedStatement ("+
		    method.getName()+")\" ,ignore);");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}");
	src.println("if (conn != null) {");
	src.indentPlus();
	src.println("try {");
	src.indentPlus();
	src.println("conn.close();");
	src.indentMinus();
	src.println("} catch (Exception ignore) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Failed to close the Connection ("+
		    method.getName()+")\" ,ignore);");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}"); // try-catch-finally
	src.println("return(p1);");
	src.indentMinus();
	src.println("}");
    }

    /**
     * Source generation of the ejbFindXXX() method associated to the given
     * findXXX() method described in the Home interface
     * @exception GenICException in error case
     */
    void genEjbFindOther(Method method) throws GenICException {

	boolean isWithCollection = ! method.getReturnType().equals(ejbRemoteClass);
	Class params[] = method.getParameterTypes();

	if (isWithCollection) {
	    src.print  ("public " +  method.getReturnType().getName() +
			" ejb" + BeanNaming.firstToUpperCase(method.getName()) +
			"(");
	} else {
	    src.print  ("public " + ejbPrimaryKeyName +
			" ejb" + BeanNaming.firstToUpperCase(method.getName()) +
			"(");
	}
	for (int p=1; p <= params.length; p++) {
	    src.print(JavaType.getName(params[p-1]) + " " + "p" + p, false);
	    if (p < params.length) {
		src.print(", ", false);
	    }
	}
	src.print  (") ", false);
	src.println(" throws javax.ejb.FinderException {", false);
	// core
	src.indentPlus();
	src.print  ("TraceEjb.debugGenIC(\""+wrpBeanBaseName+".ejb"+
		    BeanNaming.firstToUpperCase(method.getName())+"(");
	for (int p=1; p <= params.length; p++) {
	    src.print(JavaType.getName(params[p-1]), false);
	    if (p < params.length) {
		src.print(", ", false);
	    }
	}
	src.println(")\");", false);
	if (isWithCollection) {
	    src.println("Vector pkC = new Vector();");
	} else {
	    if (hasPrimaryKeyField) {
		src.println(ejbPrimaryKeyName + " pk;");
	    } else {
		src.println(ejbPrimaryKeyName + " pk = " +
			    "new " + ejbPrimaryKeyName + "();");
	    }
	}
	src.println("Connection conn = null;");
	src.println("PreparedStatement pStmt = null;");
	src.println("try {");
	src.indentPlus();
	src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
	src.println("conn = ds.getConnection();");
	src.print  ("pStmt = conn.prepareStatement(\"select ");
	try {
	    for (int i=0; i<fieldsPK.size(); i++) {
		Field f = (Field)fieldsPK.get(i);
		if (i > 0) {
		    src.print(", ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName(), false);
	    }
	    if (!((MethodJdbcDesc)ddesc.getMethodDesc(method)).hasWhereClause()) {
		throw new GenICException("No WHERE clause defined for the finder method '" +
					 method + "')");
	    }
	    Vector posParams = new Vector();
	    String clauseWhere = parseWhere(((MethodJdbcDesc)ddesc.getMethodDesc(method)).getWhereClause(), posParams);
	    src.println(" from " + ((EntityJdbcCmpDesc)ddesc).getJdbcTableName() + " " +
			clauseWhere + "\");",
			false);
	    for (int i=1; i <= posParams.size(); i++) {
		int pos = ((Integer)posParams.elementAt(i-1)).intValue();
		String methName = JavaType.getSQLSetMethod(params[pos]);
		String attrName = new String("p" + (pos+1));
		if (methName == null) {
		    throw new GenICException("Cannot container manage the bean's method '" +
					     method +
					     "' (Param '" + JavaType.getName(params[pos]) + "')");
		}
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "(java.lang.Object)";
		} else {
		    castS = "";
		}
		if (methName.equals("setSerializable")) {
		    src.println("pStmt.setBytes(" +
				i + ", MarshallTool.toBytes(" + attrName + "));");
		} else {
		    src.println("pStmt."+ methName +
				"(" + i + ", " + castS + attrName + ");");
		}
	    }
	    src.println("ResultSet rs = pStmt.executeQuery();");
	    if (isWithCollection) {
		src.println("while (rs.next()) {");
		src.indentPlus();
		if (hasPrimaryKeyField) {
		    src.println(ejbPrimaryKeyName + " pk;");
		} else {
		    src.println(ejbPrimaryKeyName + " pk = " +
				"new " + ejbPrimaryKeyName + "();");
		}
		for (int i=0; i<fieldsPK.size(); i++) {
		    Field f = (Field)fieldsPK.get(i);
		    String methName = JavaType.getSQLGetMethod(f.getType());
		    String attrName;
		    if (hasPrimaryKeyField) {
			attrName = "pk";
		    } else {
			attrName = "pk."+f.getName();
		    }
		    String dbclName = ((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName();
		    if (methName == null) {
			throw new GenICException("Cannot container manage the bean's method '" +
						 method +
						 "' (Param '" + JavaType.getName(params[i-1]) + "')");
		    }
		    String castS;
		    if (JavaType.isXxxObjectMethod(methName)) {
			castS = "("+JavaType.getName(f.getType())+")";
		    } else {
			castS = "";
		    }
		    if (methName.equals("getSerializable")) {
			castS = "(" + JavaType.getName(f.getType()) + ")";
			src.println(attrName + " = " + castS +
				    "MarshallTool.fromBytes((byte[])rs.getBytes(\"" + dbclName + "\"));");
		    } else {
			src.println(attrName + " = " + castS + "rs." + methName +
				    "(\"" + dbclName + "\");");
		    }
		}
		src.println("pkC.addElement((Object)pk);");
		src.indentMinus();
		src.println("}");
	    } else {
		src.println("if (rs.next() == false) {");
		src.indentPlus();
		src.println("TraceEjb.error(\"Object not found in database ("+
			    method.getName()+")\");");
		src.println("throw new ObjectNotFoundException(\"Object not found in database ("+
			    method.getName()+")\");");
		src.indentMinus();
		src.println("}");
		for (int i=0; i<fieldsPK.size(); i++) {
		    Field f = (Field)fieldsPK.get(i);
		    String methName = JavaType.getSQLGetMethod(f.getType());
		    String attrName;
		    if (hasPrimaryKeyField) {
			attrName = "pk";
		    } else {
			attrName = "pk."+f.getName();
		    }
		    String dbclName = ((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName();
		    String castS;
		    if (JavaType.isXxxObjectMethod(methName)) {
			castS = "("+JavaType.getName(f.getType())+")";
		    } else {
			castS = "";
		    }
		    if (methName.equals("getSerializable")) {
			castS = "(" + JavaType.getName(f.getType()) + ")";
			src.println(attrName + " = " + castS +
				   "MarshallTool.fromBytes((byte[])rs.getBytes(\"" + dbclName + "\"));");
		    } else {
			src.println(attrName + " = " + castS + "rs." + methName +
				    "(\"" + dbclName + "\");");
		    }
		}
	    }
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
	src.indentMinus();
	src.println("} catch (Exception e) {");
	src.indentPlus();
// BEGIN MHALAS:
	src.println("if (e instanceof ObjectNotFoundException)");
	src.println("{");
	src.indentPlus();
	src.println("throw (ObjectNotFoundException)e;");
	src.indentMinus();
	src.println("}");
// END MHALAS
	src.println("TraceEjb.error(\"Failed to find bean from database ("+
		    method.getName()+")\", e);");
	src.println("throw new FinderException(\"Failed to find bean from database ("+
		    method.getName()+")\");");
	src.indentMinus();
	src.println("} finally {");
	src.indentPlus();
	src.println("if (pStmt != null) {");
	src.indentPlus();
	src.println("try {");
	src.indentPlus();
	src.println("pStmt.close();");
	src.indentMinus();
	src.println("} catch (Exception ignore) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Failed to close the PreparedStatement ("+
		    method.getName()+")\", ignore);");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}");
	src.println("if (conn != null) {");
	src.indentPlus();
	src.println("try {");
	src.indentPlus();
	src.println("conn.close();");
	src.indentMinus();
	src.println("} catch (Exception ignore) {");
	src.indentPlus();
	src.println("TraceEjb.error(\"Failed to close the connection ("+
		    method.getName()+")\", ignore);");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}");
	src.indentMinus();
	src.println("}"); // try-catch-finally
	if (isWithCollection) {
	    if (method.getReturnType().equals(java.util.Enumeration.class)) {
		// java.util.Enumeration
		src.println("return(pkC.elements());");
	    } else {
		// java.util.Collection
		src.println("return(pkC);");
	    }
	} else {
	    src.println("return(pk);");
	}
	src.indentMinus();
	src.println("}");
    }

    /**
     * Source generation of the ejbLoad() method
     * @exception GenICException in error case
     */
    void genEjbLoad() throws GenICException {

	Method method = null;
	try {
	    method = ejbBeanClass.getMethod("ejbLoad", new Class[0]);
	} catch (Exception e) {
	    throw new GenICException("Cannot get the "+ejbBeanName+".ejbLoad() method by reflection ("+e.getMessage()+")");
	}

	try {
	    genHeaderMethod(method, wrpBeanBaseName);
	    src.println("Connection conn = null;");
	    src.println("PreparedStatement pStmt = null;");
	    src.println("try {");
	    src.indentPlus();
	    src.println(ejbPrimaryKeyName+" pk = ("+ejbPrimaryKeyName+")(this.ejbContext.getEJBObject().getPrimaryKey());");
	    src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
	    src.println("conn = ds.getConnection();");
	    src.print  ("pStmt = conn.prepareStatement(\"select ");
	    for (int i=0; i<fieldsPers.size(); i++) {
		Field f = (Field)fieldsPers.get(i);
		if (i > 0) {
		    src.print(", ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName(), false);
	    }
	    src.print (" from " + dbTableName + " where ", false);
	    for (int i=0; i<fieldsPK.size(); i++) {
		Field f = (Field)fieldsPK.get(i);
		if (i > 0) {
		    src.print(" and ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName() + "=?", false);
	    }
	    src.println("\");", false);
	    for (int i=0; i<fieldsPK.size(); i++) {
		int index = i+1;
		Field f = (Field)fieldsPK.get(i);
		String methName = JavaType.getSQLSetMethod(f.getType());
		String attrName;
		if (hasPrimaryKeyField) {
		    attrName = "pk";
		} else {
		    attrName = "pk."+f.getName();
		}
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "(java.lang.Object)";
		} else {
		    castS = "";
		}
		if (methName.equals("setSerializable")) {
		    src.println("pStmt.setBytes(" +
				index + ", MarshallTool.toBytes(" + attrName + "));");
		} else {
		    src.println("pStmt."+ methName +
				"(" + index + ", " + castS + attrName + ");");
		}
	    }
	    src.println("ResultSet rs = pStmt.executeQuery();");
	    src.println("if (rs.next() == false) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to load bean from database\");");
	    src.println("throw new EJBException(\"Failed to load bean from database\");");
	    src.indentMinus();
	    src.println("}");
	    for (int i=0; i<fieldsPers.size(); i++) {
		Field f = (Field)fieldsPers.get(i);
		String methName = JavaType.getSQLGetMethod(f.getType());
		String attrName = "this."+f.getName();
		String dbclName = ((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName();
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "("+JavaType.getName(f.getType())+")";
		} else {
		    castS = "";
		}
		if (methName.equals("getSerializable")) {
		    castS = "(" + JavaType.getName(f.getType()) + ")";
		    src.println(attrName + " = " + castS +
				"MarshallTool.fromBytes((byte[])rs.getBytes(\"" + dbclName + "\"));");
		} else {
		    src.println(attrName + " = " + castS + "rs." + methName +
				"(\"" + dbclName + "\");");
		}
		// To turn around a possible JDBC driver problem with getObject()
		if (methName.equals("getObject")) {
		    src.println("if (rs.wasNull()) {");
		    src.indentPlus();
		    src.println(attrName + " = null;");
		    src.indentMinus();
		    src.println("}");
		}
	    }
	    src.indentMinus();
	    //src.println("} catch (SQLException e) {");
	    src.println("} catch (Exception e) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to load bean from database\", e);");
	    src.println("throw new EJBException(e);");
	    src.indentMinus();
	    src.println("} finally {");
	    src.indentPlus();
	    src.println("if (pStmt != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("pStmt.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the PreparedStatement (ejbLoad)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.println("if (conn != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("conn.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the Connection (ejbLoad)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}"); // try-catch-finally
	    src.println("super.ejbLoad();");
	    src.indentMinus();
	    src.println("}");
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
    }

    /**
     * Source generation of the ejbStore() method
     * @exception GenICException in error case
     */
    void genEjbStore() throws GenICException {

	Method method = null;
	try {
	    method = ejbBeanClass.getMethod("ejbStore", new Class[0]);
	} catch (Exception e) {
	    throw new GenICException("Cannot get the "+ejbBeanName+".ejbStore() method by reflection ("+e.getMessage()+")");
	}

	try {
	    genHeaderMethod(method, wrpBeanBaseName);
	    src.println("if (this.isModifiedData()) {");
	    src.indentPlus();
	    src.println("super.ejbStore();");
	    if (fieldsPersNoPK.size() != 0) {
		src.println("Connection conn = null;");
		src.println("PreparedStatement pStmt = null;");
		src.println("try {");
		src.indentPlus();
		src.println(ejbPrimaryKeyName+" pk = ("+ejbPrimaryKeyName+")(this.ejbContext.getEJBObject().getPrimaryKey());");
		src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
		src.println("conn = ds.getConnection();");
		src.print  ("pStmt = conn.prepareStatement(\"update " + dbTableName + " set ");
		for (int i=0; i<fieldsPersNoPK.size(); i++) {
		    Field f = (Field)fieldsPersNoPK.get(i);
		    if (i > 0) {
			src.print(", ", false);
		    }
		    src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName() + "=?", false);
		}
		src.print (" where ", false);
		for (int i=0; i<fieldsPK.size(); i++) {
		    Field f = (Field)fieldsPK.get(i);
		    if (i > 0) {
			src.print(" and ", false);
		    }
		    src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName() + "=?", false);
		}
		src.println("\");", false);
		for (int i=0; i<fieldsPersNoPK.size(); i++) {
		    int index = i+1;
		    Field f = (Field)fieldsPersNoPK.get(i);
		    Class  attrType = f.getType();
		    String sqlTypeName = JavaType.getSQLType(attrType);
		    String methName = JavaType.getSQLSetMethod(attrType);
		    String attrName = "this."+f.getName();
		    String castS;
		    if (JavaType.isXxxObjectMethod(methName)) {
			castS = "(java.lang.Object)";
		    } else {
			castS = "";
		    }
		    if (! attrType.isPrimitive()) {
			src.println("if ("+attrName+" == null) {");
			src.indentPlus();
			src.println("pStmt.setNull("+ index + ", " + sqlTypeName + ");");
			src.indentMinus();
			src.println("} else {");
			src.indentPlus();
		    }
		    if (methName.equals("setSerializable")){
			src.println("pStmt.setBytes(" + index + ", MarshallTool.toBytes(" + attrName + "));");
		    } else {
			src.println("pStmt." + methName +
				    "(" + index + ", " + castS + attrName + ");");
		    }
		    if (! attrType.isPrimitive()) {
			src.indentMinus();
			src.println("}");
		    }
		}
		for (int i=0; i<fieldsPK.size(); i++) {
		    int index = fieldsPersNoPK.size()+i+1;
		    Field f = (Field)fieldsPK.get(i);
		    Class  attrType = f.getType();
		    String sqlTypeName = JavaType.getSQLType(attrType);
		    String methName = JavaType.getSQLSetMethod(attrType);
		    String attrName;
		    if (hasPrimaryKeyField) {
			attrName = "pk";
		    } else {
			attrName = "pk."+f.getName();
		    }
		    String castS;
		    if (JavaType.isXxxObjectMethod(methName)) {
			castS = "(java.lang.Object)";
		    } else {
			castS = "";
		    }
		    if (! attrType.isPrimitive()) {
			src.println("if ("+attrName+" == null) {");
			src.indentPlus();
			src.println("pStmt.setNull("+ index + ", " + sqlTypeName + ");");
			src.indentMinus();
			src.println("} else {");
			src.indentPlus();
		    }
		    if (methName.equals("setSerializable")) {
			src.println("pStmt.setBytes(" +
				    index + ", MarshallTool.toBytes(" + attrName + "));");
		    } else {
			src.println("pStmt." + methName +
				    "(" + index + ", " + castS + attrName + ");");
		    }
		    if (! attrType.isPrimitive()) {
			src.indentMinus();
			src.println("}");
		    }
		}
		src.println("pStmt.executeUpdate();");
		src.indentMinus();
		//src.println("} catch (SQLException e) {");
		src.println("} catch (Exception e) {");
		src.indentPlus();
		src.println("TraceEjb.error(\"Failed to store bean to database\", e);");
		src.println("throw new EJBException(e);");
		src.indentMinus();
		src.println("} finally {");
		src.indentPlus();
		src.println("if (pStmt != null) {");
		src.indentPlus();
		src.println("try {");
		src.indentPlus();
		src.println("pStmt.close();");
		src.indentMinus();
		src.println("} catch (Exception ignore) {");
		src.indentPlus();
		src.println("TraceEjb.error(\"Failed to close the PreparedStatement (StoreData)\",ignore);");
		src.indentMinus();
		src.println("}");
		src.indentMinus();
		src.println("}");
		src.println("if (conn != null) {");
		src.indentPlus();
		src.println("try {");
		src.indentPlus();
		src.println("conn.close();");
		src.indentMinus();
		src.println("} catch (Exception ignore) {");
		src.indentPlus();
		src.println("TraceEjb.error(\"Failed to close the Connection (StoreData)\",ignore);");
		src.indentMinus();
		src.println("}");
		src.indentMinus();
		src.println("}");
		src.indentMinus();
		src.println("}"); // try-catch-finally
	    }
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
    }

    /**
     * Source generation of the ejbRemove() method
     * @exception GenICException in error case
     */
    void genEjbRemove() throws GenICException {
	Method method = null;
	try {
	    method = ejbBeanClass.getMethod("ejbRemove", new Class[0]);
	} catch (Exception e) {
	    throw new GenICException("Cannot get the "+ejbBeanName+".ejbRemove() method by reflection ("+e.getMessage()+")");
	}
	try {
	    genHeaderMethod(method, wrpBeanBaseName);
	    src.println("super.ejbRemove();");
	    src.println("Connection conn = null;");
	    src.println("PreparedStatement pStmt = null;");
	    src.println("try {");
	    src.indentPlus();
	    src.println(ejbPrimaryKeyName+" pk = ("+ejbPrimaryKeyName+")(this.ejbContext.getEJBObject().getPrimaryKey());");
	    src.println("DataSource ds = (DataSource)(this.ejbHome.getDataSource());");
	    src.println("conn = ds.getConnection();");
	    src.print  ("pStmt = conn.prepareStatement(\"delete from " + dbTableName + " where ");
	    for (int i=0; i<fieldsPK.size(); i++) {
		Field f = (Field)fieldsPK.get(i);
		if (i > 0) {
		    src.print(" and ", false);
		}
		src.print(((EntityJdbcCmpDesc)ddesc).getFieldJdbcDesc(f).getJdbcFieldName() + "=?", false);
	    }
	    src.println("\");", false);
	    for (int i=0; i<fieldsPK.size(); i++) {
		int index = i+1;
		Field f = (Field)fieldsPK.get(i);
		String methName = JavaType.getSQLSetMethod(f.getType());
		String attrName;
		if (hasPrimaryKeyField) {
		    attrName = "pk";
		} else {
		    attrName = "pk."+f.getName();
		}
		String castS;
		if (JavaType.isXxxObjectMethod(methName)) {
		    castS = "(java.lang.Object)";
		} else {
		    castS = "";
		}
		if (methName.equals("setSerializable")) {
		    src.println("pStmt.setBytes(" +
				index + ", MarshallTool.toBytes(" + attrName + "));");
		} else {
		    src.println("pStmt." + methName +
				"(" + index + ", " + castS + attrName + ");");
		}
	    }
	    src.println("pStmt.executeUpdate();");
	    src.indentMinus();
	    //src.println("} catch (SQLException e) {");
	    src.println("} catch (Exception e) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to delete bean from database\", e);");
	    src.println("throw new EJBException(e);");
	    src.indentMinus();
	    src.println("} finally {");
	    src.indentPlus();
	    src.println("if (pStmt != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("pStmt.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the PreparedStatement (RemoveData)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.println("if (conn != null) {");
	    src.indentPlus();
	    src.println("try {");
	    src.indentPlus();
	    src.println("conn.close();");
	    src.indentMinus();
	    src.println("} catch (Exception ignore) {");
	    src.indentPlus();
	    src.println("TraceEjb.error(\"Failed to close the Connection (RemoveData)\", ignore);");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}");
	    src.indentMinus();
	    src.println("}"); // try-catch-finally
	    src.indentMinus();
	    src.println("}");
	} catch (Exception e) {
	    throw new GenICException(e.getMessage());
	}
    }

    /**
     * Parses Strings with syntax "WHERE summary like ?<nnn>"
     * where <nnn> is a decimal integer that indexes (starting by 0)
     * the parameters in the findByXXX method
     * @author: Santiago Gala (sgala@hisitech.com)
     */
    private String parseWhere(String fragment, Vector pos) {
	StringTokenizer parseWhere = new StringTokenizer(fragment, "?\n", true);
	int numpos = pos.size();
	String new_where = "";
	String tok;
	while(parseWhere.hasMoreTokens()) {
	    //new_where += "?";
	    tok = parseWhere.nextToken();
	    String numVar = "";
	    if(Character.isDigit(tok.charAt(0))) {
		for(int i = 0; tok.length() > i && Character.isDigit(tok.charAt(i)); i++) {
		    numVar += tok.charAt(i);
		}
		if (numVar.length() > 0) {
		    new_where += tok.substring(numVar.length(),tok.length());
		    pos.setElementAt((Object)new Integer(Integer.parseInt(numVar)-1), numpos - 1);
		}
	    } else {
		new_where += tok;
		if(tok.charAt(0) == '?')
		    pos.addElement(new Integer(numpos++));
	    }
	    //System.err.println("(" + numpos + ") TOKEN: " + tok);
	}
	return new_where;
    }

}



