/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
package com.sun.enterprise.deployment;
 
import com.sun.enterprise.util.LocalStringManagerImpl;
import java.util.*;
    
    /**
    * Objects of this kind represent the deployment information describing a single 
    * Session Ejb, either stateful or stateless.
    *@author Danny Coward
    */

public final class EjbSessionDescriptor extends EjbDescriptor {
    private boolean isStateless = false;
    private int timeout = 0;

    private Set<LifecycleCallbackDescriptor> postActivateDescs =
        new HashSet<LifecycleCallbackDescriptor>();
    private Set<LifecycleCallbackDescriptor> prePassivateDescs =
        new HashSet<LifecycleCallbackDescriptor>();

    // For EJB 3.0 stateful session beans, information about the assocation
    // between a business method and bean removal.
    private Map<MethodDescriptor, EjbRemovalInfo> removeMethods
        = new HashMap<MethodDescriptor, EjbRemovalInfo>();

    // For EJB 3.0 stateful session beans with adapted homes, list of
    // business methods corresponding to Home/LocalHome create methods.
    private Set<EjbInitInfo> initMethods=new HashSet<EjbInitInfo>();

    /** The Session type String.*/
    public final static String TYPE = "Session";
    /** The String to indicate stalessness. */
    public final static String STATELESS = "Stateless";
    /** Idicates statefullness of a session ejb.*/
    public final static String STATEFUL = "Stateful";
    
    private static LocalStringManagerImpl localStrings =
	    new LocalStringManagerImpl(EjbSessionDescriptor.class); 

    /**
	*  Default constructor.
	*/
    public EjbSessionDescriptor() {
    }
    
    /** 
    * The copy constructor.
    */
    
    public EjbSessionDescriptor(EjbDescriptor other) {
	super(other);
	if (other instanceof EjbSessionDescriptor) {
	    EjbSessionDescriptor session = (EjbSessionDescriptor) other;
	    this.isStateless = session.isStateless;
	    this.timeout = session.timeout;
	}
    }
    
	/**
	* Returns the type of this bean - always "Session".
	*/
    public String getType() {
	return TYPE;
    }
    
    /**
    * Returns the string STATELESS or STATEFUL according as to whether
    * the bean is stateless or stateful.
    **/
    
    public String getSessionType() {
	if (this.isStateless()) {
	    return STATELESS;
	} else {
	    return STATEFUL;
	}
    }
    
	/** 
	* Accepts the Strings STATELESS or STATEFUL.
	*/
    public void setSessionType(String sessionType) {
	if (STATELESS.equals(sessionType)) {
	    this.setStateless(true);
	    return;
	}
	if (STATEFUL.equals(sessionType)) {
	    this.setStateless(false);
	    return;
	}
	if (this.isBoundsChecking()) {
	    throw new IllegalArgumentException(localStrings.getLocalString(
									   "enterprise.deployment.exceptionsessiontypenotlegaltype",
									   "{0} is not a legal session type for session ejbs. The type must be {1} or {2}", new Object[] {sessionType, STATEFUL, STATELESS}));
	}
    }
    
	/**
	* Sets my type
	*/
    public void setType(String type) {
	throw new IllegalArgumentException(localStrings.getLocalString(
								   "enterprise.deployment.exceptioncannotsettypeofsessionbean",
								   "Cannot set the type of a session bean"));
    }
    
	/**
	* Sets the timeout value for this session bean. 
	*/

    public void setTimeout(int timeout) {
	this.timeout = timeout;
    }
    
	/**
	* Returns the timeout value of this bean. 
	*/
    public int getTimeout() {
	return this.timeout;
    }
    
	/**
	*  Sets the transaction type for this bean. Must be either BEAN_TRANSACTION_TYPE or CONTAINER_TRANSACTION_TYPE.
	*/
    public void setTransactionType(String transactionType) {
	boolean isValidType = (BEAN_TRANSACTION_TYPE.equals(transactionType) ||
				CONTAINER_TRANSACTION_TYPE.equals(transactionType));
				
	if (!isValidType && this.isBoundsChecking()) {
	    throw new IllegalArgumentException(localStrings.getLocalString(
									   "enterprise.deployment..exceptointxtypenotlegaltype",
									   "{0} is not a legal transaction type for session beans", new Object[] {transactionType}));
	} else {
	    super.transactionType = transactionType;
	    super.setMethodContainerTransactions(new Hashtable());
	    super.changed();
	}
    }
    
	/**
	* Returns true if I am describing a stateless session bean.
	*/
    public boolean isStateless() {
	return isStateless;
    }
    
    public boolean isStateful() {
        return !isStateless();
    }
    
	/**
	* Sets the isStateless attribute of this session bean.
	*/
    public void setStateless(boolean isStateless) {
	this.isStateless = isStateless;
	super.changed();
    }

    public boolean hasRemoveMethods() {
        return (!removeMethods.isEmpty());
    }

    /**
     * @return remove method info for the given method or null if the
     * given method is not a remove method for this stateful session bean.
     */
    public EjbRemovalInfo getRemovalInfo(MethodDescriptor method) {
        return removeMethods.get(method);
    }

    public Set<EjbRemovalInfo> getAllRemovalInfo() {
        return new HashSet<EjbRemovalInfo>(removeMethods.values());
    }

    public void addRemoveMethod(EjbRemovalInfo removalInfo) {
        removeMethods.put(removalInfo.getRemoveMethod(), removalInfo);
    }

    public boolean hasInitMethods() {
        return (!initMethods.isEmpty());
    }

    public Set<EjbInitInfo> getInitMethods() {
        return new HashSet<EjbInitInfo>(initMethods);
    }

    public void addInitMethod(EjbInitInfo initInfo) {
        initMethods.add(initInfo);
    }
    
    public Set<LifecycleCallbackDescriptor> getPostActivateDescriptors() {
        if (postActivateDescs == null) {
            postActivateDescs = 
                new HashSet<LifecycleCallbackDescriptor>(); 
        }
        return postActivateDescs;
    }   
            
    public void addPostActivateDescriptor(LifecycleCallbackDescriptor
        postActivateDesc) {
        String className = postActivateDesc.getLifecycleCallbackClass();
        boolean found = false;
        for (LifecycleCallbackDescriptor next :
             getPostActivateDescriptors()) {
            if (next.getLifecycleCallbackClass().equals(className)) {
                found = true;
                break;
            }
        }
        if (!found) {
            getPostActivateDescriptors().add(postActivateDesc);
        }
    }

    public LifecycleCallbackDescriptor 
        getPostActivateDescriptorByClass(String className) {

        for (LifecycleCallbackDescriptor next :
                 getPostActivateDescriptors()) {
            if (next.getLifecycleCallbackClass().equals(className)) {
                return next;
            }
        }
        return null;
    }

    public boolean hasPostActivateMethod() {
        return (getPostActivateDescriptors().size() > 0);
    }

    public Set<LifecycleCallbackDescriptor> getPrePassivateDescriptors() {
        if (prePassivateDescs == null) {
            prePassivateDescs = 
                new HashSet<LifecycleCallbackDescriptor>(); 
        }
        return prePassivateDescs;
    }   
            
    public void addPrePassivateDescriptor(LifecycleCallbackDescriptor
        prePassivateDesc) {
        String className = prePassivateDesc.getLifecycleCallbackClass();
        boolean found = false;
        for (LifecycleCallbackDescriptor next :
             getPrePassivateDescriptors()) {
            if (next.getLifecycleCallbackClass().equals(className)) {
                found = true;
                break;
            }
        }
        if (!found) {
            getPrePassivateDescriptors().add(prePassivateDesc);
        }
    }

    public LifecycleCallbackDescriptor 
        getPrePassivateDescriptorByClass(String className) {

        for (LifecycleCallbackDescriptor next :
                 getPrePassivateDescriptors()) {
            if (next.getLifecycleCallbackClass().equals(className)) {
                return next;
            }
        }
        return null;
    }

    public boolean hasPrePassivateMethod() {
        return (getPrePassivateDescriptors().size() > 0);
    }

    public Vector getPossibleTransactionAttributes() {
        Vector txAttributes = super.getPossibleTransactionAttributes();

        // Session beans that implement SessionSynchronization interface
        // have a limited set of possible transaction attributes.
        if( isStateful() ) {
            try {
                EjbBundleDescriptor ejbBundle = getEjbBundleDescriptor();

                ClassLoader classLoader = ejbBundle.getClassLoader();
                Class ejbClass = classLoader.loadClass(getEjbClassName());
                Class sessionSynchClass = 
                    javax.ejb.SessionSynchronization.class;
                if( sessionSynchClass.isAssignableFrom(ejbClass) ) {
                    txAttributes = new Vector();
                    txAttributes.add(new ContainerTransaction
                        (ContainerTransaction.REQUIRED, ""));
                    txAttributes.add(new ContainerTransaction
                        (ContainerTransaction.REQUIRES_NEW, ""));
                    txAttributes.add(new ContainerTransaction
                        (ContainerTransaction.MANDATORY, ""));
                }
            } catch(Exception e) {
                // Don't treat this as a fatal error.  Just return full
                // set of possible transaction attributes.
            }
        }
        return txAttributes;
    }
    
    
	/**
	* Returns a formatted String of the attributes of this object.
	*/
    public void print(StringBuffer toStringBuffer) {
	toStringBuffer.append("Session descriptor");
	toStringBuffer.append("\n isStateless ").append(isStateless);
	super.print(toStringBuffer);
    }


}
