/*
 * 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): ______________________________________.
 *
 *    JOnAS 2.2.1 Joe Gittings has proposed to code method signature in order to avoid
 *                same signature for inherited methods.
 *
 * --------------------------------------------------------------------------
 * $Id: GenICCommon.java,v 1.4 2000/12/15 15:09:19 jonas Exp $
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas_ejb.tools;

import java.io.IOException;
import java.lang.reflect.Method;

import org.objectweb.jonas_ejb.deployment.api.BeanDesc;
import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
import org.objectweb.jonas_ejb.lib.BeanNaming;
import org.objectweb.jonas_ejb.lib.JavaType;

abstract class GenICCommon {

    // The generated source file
    IndentedFile src = null;
    // DeploymentDescriptor of the bean
    BeanDesc ddesc = null;
    // Full names of the interfaces and the bean classe
    String ejbRemoteName = null;
    String ejbHomeName   = null;
    String ejbBeanName   = null;
    // Classes of the interfaces and the bean
    Class  ejbRemoteClass = null;
    Class  ejbHomeClass   = null;
    Class  ejbBeanClass   = null;
    // Names of the implementation classes (Full names and base names)
    String wrpRemoteName     = null;
    String wrpHomeName       = null;
    String wrpHandleName     = null;
    String wrpBeanName       = null;
    String wrpRemoteBaseName = null;
    String wrpHomeBaseName   = null;
    String wrpHandleBaseName = null;
    String wrpBeanBaseName   = null;

    GenICCommon(BeanDesc dd, String fileName) throws GenICException {
	// Source File
	try {
	    src = new IndentedFile(fileName);
	} catch (IOException e) {
	    System.err.println("GenICCommon ERROR: "+e);
	    throw new GenICException("Cannot create '" + fileName + "' file");
	}
	// Deployment Descriptor
	ddesc = dd;
	// Names building
	BeanNaming bn     = new BeanNaming(ddesc);
	wrpRemoteBaseName = bn.getWrpRemoteName();
	wrpRemoteName     = bn.getFullWrpRemoteName();
	wrpHomeBaseName   = bn.getWrpHomeName();
	wrpHomeName       = bn.getFullWrpHomeName();
	wrpHandleBaseName = bn.getWrpHandleName();
	wrpHandleName     = bn.getFullWrpHandleName();
	wrpBeanBaseName   = bn.getDerivedBeanName();
	wrpBeanName       = bn.getFullDerivedBeanName();
	// Get the interfaces and the bean classes and names
	ejbRemoteName = ddesc.getRemoteClass().getName();
	ejbHomeName   = ddesc.getHomeClass().getName();
	ejbBeanName   = ddesc.getEjbClass().getName();
	ejbRemoteClass = ddesc.getRemoteClass();
	ejbHomeClass   = ddesc.getHomeClass();
	ejbBeanClass   = ddesc.getEjbClass();
    }

    /**
     * Source generation of the header of the given Method.
     * (Declaration and the begining of the core..)
     * @exception GenICException in error case
     */
    void genHeaderMethod(Method method,
			 String className) throws GenICException {
	genHeaderMethod(method, className, method.getName(), method.getReturnType(),
			method.getExceptionTypes(), false);
    }

    /**
     * Source generation of the header of the given Method.
     * (Declaration and the begining of the core..)
     * @exception GenICException in error case
     */
    void genHeaderMethod(Method method,
			 String className,
			 boolean modSynchronized) throws GenICException {
	genHeaderMethod(method, className, method.getName(), method.getReturnType(),
			method.getExceptionTypes(), modSynchronized);
    }

    /**
     * Source generation of the header of the given Method.
     * (Declaration and the begining of the core..)
     * @exception GenICException in error case
     */
    void genHeaderMethod(Method method,
			 String className,
			 String methodName,
			 Class  returnType,
			 Class[] exceptions,
			 boolean modSynchronized) throws GenICException {

	Class params[]     = method.getParameterTypes();

	// declaration
	src.print("public ");
	if (modSynchronized) {
	    src.print("synchronized ", false);
	}
	src.print(JavaType.getName(returnType) + " " + methodName + "(", false);
	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);
	for (int e=1; e <= exceptions.length; e++) {
	    if (e==1) {
		src.print("throws ", false);
	    }
	    src.print(exceptions[e-1].getName(), false);
	    if (e < exceptions.length) {
		src.print(",", false);
	    }
	    src.print(" ", false);
	}
	src.println("{", false);
	// begining of the core
	src.indentPlus();
	src.print("TraceEjb.debugGenIC(\""+className+"."+methodName+"(");
	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);
    }


    /**
     * Source generation of the 'catch' code following any call of a bean method
     * (such bussiness methods, ejbCreate(), ejbPostCreate(), ejbFind(), .....)
     * @param mInter                     the current generated method of the interface
     * @param alwaysCatchRemoteException the catch of the RemoteException have to be
     *                                   always generated
     */
    void genCatchBean(Method methodInter, boolean alwaysCatchRemoteException) {
	// The "try { ....;" has already been generated
	// The "}" will be generated

	boolean generateCatchRemoteException = alwaysCatchRemoteException;
	if (!alwaysCatchRemoteException) {
	    try {
		String methodBeanName;
		if (javax.ejb.EJBHome.class.isAssignableFrom(methodInter.getDeclaringClass())) {
		    // This is a method of the Home interface
		    methodBeanName = new String("ejb"+
						BeanNaming.firstToUpperCase(methodInter.getName()));
		} else {
		    // This is a method of the Remote interface
		    methodBeanName = methodInter.getName();
		}
		Method methodBean = ejbBeanClass.getMethod(methodBeanName,
							   methodInter.getParameterTypes());
		Class [] exceptions = methodBean.getExceptionTypes();
		for (int i=0; i < exceptions.length; i++) {
		    if (java.rmi.RemoteException.class.equals(exceptions[i])) {
			generateCatchRemoteException = true;
		    }
		}
	    } catch (Exception e) {
		// It could be normal to not have a corresponding method in the bean
		// (ejbFind() method in case of entities with container-managed persistence)
	    }
	}

	src.indentMinus();
	src.println("} catch (RuntimeException e) {");
	src.indentPlus();
	src.println("rctx.setSysExc(e);");
	src.println("throw new RemoteException(\"RuntimeException thrown by an enterprise Bean\", e);");
	src.indentMinus();
	src.println("} catch (Error e) {");
	src.indentPlus();
	src.println("rctx.setSysExc(e);");
	src.println("throw new RemoteException(\"Error thrown by an enterprise Bean\", e);");
	src.indentMinus();
	if (generateCatchRemoteException) {
	    src.println("} catch (RemoteException e) {");
	    src.indentPlus();
	    src.println("rctx.setSysExc(e);");
	    src.println("throw e;");
	    src.indentMinus();
	}
	// TGU
	src.println("} catch (Exception e) {");
	src.indentPlus();
	src.println("raiseUserException(e);");
	src.indentMinus();
	// TGU
    }
    
    /**
     * Source generation of the Method signature for Security access control
     *  We need to prepend the EJB name like this, otherwise methods inherited
     * by multiple EJBs from a common superinterface have the same signature.
     */

    void genSecuritySignature(Method  method) {
	String securitySignature = null ;
	MethodDesc md = ddesc.getMethodDesc(method) ;
	if (md.getRoleName().length == 0) 
	    securitySignature = "null" ;
	else {
	    securitySignature = BeanNaming.getSignature(ddesc.getEjbName(),method);
	    
	}
	src.println ("String methodSignature = \""+securitySignature+"\" ;");
    }
}
