/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.webapp.jonasadmin.service.ejb;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.objectweb.jonas.jmx.JonasManagementRepr;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.jmx.JoramObjectName;
import org.objectweb.jonas.webapp.jonasadmin.JonasAdminJmx;
import org.objectweb.jonas.webapp.jonasadmin.JonasBaseAction;
import org.objectweb.jonas.webapp.jonasadmin.WhereAreYou;
import org.objectweb.jonas.webapp.jonasadmin.joramplatform.EditJoramBaseAction;
import org.objectweb.jonas.webapp.jonasadmin.service.container.ContainerForm;

/**
 * @author Michel-Ange ANTON
 */

public abstract class EditEjbAction extends JonasBaseAction {

    /**
     * The EJB's OBJECT_NAME (the stringified ObjetName)
     */
    private String ejbObjectName = null;

    // --------------------------------------------------------- Public Methods
    /**
     * Execute a action.
     *
     * @param pMapping <code>ActionForward</code> instance
     * @param pForm <code>ActionForm</code> instance
     * @param pRequest <code>HttpServletRequest</code> instance
     * @param pResponse <code>HttpServletResponse</code> instance
     * @return <code>ActionForward</code> instance
     */
    public ActionForward executeAction(ActionMapping pMapping,
            ActionForm pForm,
            HttpServletRequest pRequest,
            HttpServletResponse pResponse) {

        // Current server
        WhereAreYou oWhere = (WhereAreYou) pRequest.getSession().getAttribute(WhereAreYou.
                SESSION_NAME);
        String serverName = oWhere.getCurrentJonasServerName();

        // setForm is used specifically when this action is invoked as a result of invalid input in editEjbSession*.jsp.
        EjbForm setForm = (EjbForm) m_Session.getAttribute("ejbForm");
        // Determine the EJB's ObjectName
        String sObjectName = pRequest.getParameter("select");
        if (sObjectName == null) {
            // Accept request attribute forced by a EditEjbAction
            sObjectName = (String) pRequest.getAttribute("select");
        }

        if (sObjectName == null) {
            // Use the objectname specified in the cached input form before invalid data was submitted by user.
            sObjectName = (setForm != null && setForm.getObjectName() != null) ? setForm.getObjectName() : null;
        }

        ObjectName oObjectName = null;
        if (sObjectName != null) {
            try {
                oObjectName = ObjectName.getInstance(sObjectName);
            } catch (Throwable t) {
                addGlobalError(t);
                saveErrors(pRequest, m_Errors);
                return (pMapping.findForward("Global Error"));
            }
        }

        // Form used
        EjbForm oForm = getEjbForm();
        ejbObjectName = sObjectName;
        String msParamType = oObjectName.getKeyProperty("j2eeType");
        String msParamName = oObjectName.getKeyProperty("name");
        String msParamFile = getStringAttribute(oObjectName, "fileName");

        // Put global properties
        oForm.setType(msParamType);
        oForm.setName(msParamName);
        oForm.setObjectName(ejbObjectName);
        oForm.setFile(msParamFile);
        if (msParamType != null) {
            String sFullType = m_Resources.getMessage("ejb.fulltype." + msParamType);
            oForm.setFullType(sFullType);
        }

        // Force the node selected in tree
        //m_WhereAreYou.selectNameNode(getTreeBranchName(DEPTH_SERVER)
        // DEPTH_SERVER is not good in case the currently selected node do no belongs to the Server JOnAS node
        // this situation can be found when the selected node is a JMS destination managed by Joram and
        // when trying to navigate through the EJBs used by a JMS destination
        String serverNodeName = "domain" + WhereAreYou.NODE_SEPARATOR
            + m_WhereAreYou.getCurrentJonasServerName();

        m_WhereAreYou.selectNameNode(serverNodeName
                + WhereAreYou.NODE_SEPARATOR + "services"
                + WhereAreYou.NODE_SEPARATOR + "ejbContainers"
                + WhereAreYou.NODE_SEPARATOR + JonasAdminJmx.extractFilename(oForm.getFile())
                + WhereAreYou.NODE_SEPARATOR + oForm.getName(), true);

        try {
            // Fill Ejb infos
            fillEjbInfo(oForm, oObjectName, serverName);
            // Fill Ejb dependencies (Datasource, JMS, ...)
            fillEjbDependencies(oForm, oObjectName, serverName);
        } catch (Throwable t) {
            addGlobalError(t);
            saveErrors(pRequest, m_Errors);
            return (pMapping.findForward("Global Error"));
        }

        if (setForm != null && oForm.getObjectName() == null) {
            sObjectName = setForm.getObjectName();
            oForm = setForm;
        }
        pRequest.setAttribute("select", sObjectName);

        m_Session.setAttribute("ejbForm", oForm);


        // Ejb Forward
        String sForward = getEjbForward();



        // Control if the Container in session is the parent of the current Ejb
        ContainerForm oContForm = (ContainerForm) m_Session.getAttribute("containerForm");
        boolean bChangeForward = false;
        if (oContForm == null || oContForm.getPath() == null) {
            bChangeForward = true;
        } else {
            if (!oContForm.getPath().equals(oForm.getFile())) {
                bChangeForward = true;
            }
        }
        // Change enabled
        if (bChangeForward) {
            // Next forward in EditContainerAction
            pRequest.setAttribute("NextForward", sForward);
            //p_Request.setAttribute("selectedEjb", sObjectName);
            // Change the forward to Edit the container
            sForward = "ActionEditContainer";
        }

        // Forward to the jsp or the action
        return (pMapping.findForward(sForward));
    }

// --------------------------------------------------------- Protected Methods

    /**
     * The global forward to go.
     *
     * @return Forward
     */
    protected abstract String getEjbForward();

    /**
     * Return a <code>EjbForm</code> instance associate to the EJB.
     *
     * @return A form instance
     */
    protected abstract EjbForm getEjbForm();

    /**
     * Fill all infos of EJB in the <code>EjbForm</code> instance.
     *
     * @param pForm Instance to fill
     * @param pObjectName Instance to get infos
     * @throws Exception Could not fill info
     */
    protected abstract void fillEjbInfo(EjbForm pForm, ObjectName pObjectName, String serverName)
        throws Exception;

    /**
     * Get a <code>ObjectName</code> instance for the Ejb given with the parameters of the HTPP request.
     *
     * @return The ObjectName instance
     * @throws Exception Could not construct ObjectName
     */
    protected ObjectName getEjbObjectName()
        throws Exception {
        return ObjectName.getInstance(ejbObjectName);
    }

    /**
     * Fill all global infos of EJB in the <code>EjbForm</code> instance.
     *
     * @param pForm Instance to fill
     * @param pObjectName Instance to get infos
     */
    protected void fillEjbGlobalInfo(EjbForm pForm, ObjectName pObjectName) {
        pForm.setCacheSize(getIntegerAttribute(pObjectName, "cacheSize"));
        pForm.setMaxCacheSize(getIntegerAttribute(pObjectName, "maxCacheSize"));
        pForm.setMinPoolSize(getIntegerAttribute(pObjectName, "minPoolSize"));
        pForm.setPoolSize(getIntegerAttribute(pObjectName, "poolSize"));
        pForm.setDisplayName(getStringAttribute(pObjectName, "displayName"));
        pForm.setEjbClass(getStringAttribute(pObjectName, "ejbClass"));
        pForm.setEjbFileName(getStringAttribute(pObjectName, "fileName"));
        pForm.setEjbName(pObjectName.getKeyProperty("name"));
        pForm.setHomeClass(getStringAttribute(pObjectName, "homeClass"));
        pForm.setJndiName(getStringAttribute(pObjectName, "jndiName"));
        pForm.setLocalClass(getStringAttribute(pObjectName, "localClass"));
        pForm.setLocalHomeClass(getStringAttribute(pObjectName, "localHomeClass"));
        pForm.setRemoteClass(getStringAttribute(pObjectName, "remoteClass"));
    }

    /**
     * Fill all dependencies of EJB in the <code>EjbForm</code> instance.
     *
     * @param pForm Instance to fill
     * @param pObjectName Instance to get infos
     */
    protected void fillEjbDependencies(EjbForm pForm, ObjectName pObjectName, String serverName) {
        // Dependency with Datasource service
        pForm.setDatabaseServiceActivated(JonasManagementRepr.isRegistered(
                JonasObjectName.databaseService(), serverName));
        pForm.setResourceServiceActivated(JonasManagementRepr.isRegistered(
                JonasObjectName.resourceService(), serverName));
        HashMap hDataSources = new HashMap((Map) JonasManagementRepr.getAttribute(pObjectName
            , "allDataSourceName", serverName));
        HashMap hJdbcRAs = new HashMap((Map) JonasManagementRepr.getAttribute(pObjectName
                , "allJdbcResourceAdapterName", serverName));
        if (hDataSources.size() > 0) {
            pForm.setDataSource(true);
            pForm.setDataSources(hDataSources);
        }
        if (hJdbcRAs.size() > 0) {
            pForm.setDataSource(true);
            pForm.setJdbcRas(hJdbcRAs);
        }
        // Dependency with JMS service or Joram resource
        pForm.setJmsServiceActivated(JonasManagementRepr.isRegistered(JonasObjectName.jmsService(), serverName));
        ObjectName jormamAdapterObjectName = null;
        try {
            jormamAdapterObjectName = JoramObjectName.joramAdapter();
            pForm.setJoramResourceLoaded(JonasManagementRepr.isRegistered(jormamAdapterObjectName, serverName));
        } catch (MalformedObjectNameException e) {
            pForm.setJoramResourceLoaded(false);
        }
        ArrayList alJmsConnections = new ArrayList((Collection) JonasManagementRepr.getAttribute(
            pObjectName, "allJMSConnectionFactoryName", serverName));
        if (alJmsConnections.size() > 0) {
            pForm.setJmsConnection(true);
            pForm.setJmsConnections(alJmsConnections);
        }
        ArrayList alJmsDestinations = new ArrayList((Collection) JonasManagementRepr.getAttribute(
            pObjectName, "allJMSDestinationName", serverName));
        if (alJmsDestinations.size() > 0) {
            pForm.setJmsDestination(true);
            if (pForm.isJoramResourceLoaded()) {
                // for each destination, look for the Joram destination MBean
                ArrayList jmsDestinationItems = new ArrayList();
                EjbDependency depItem = null;
                for (int i = 0; i < alJmsDestinations.size(); i++) {
                    String name = (String) alJmsDestinations.get(i);
                    try {
                        ObjectName topicObjectName = JoramObjectName.joramTopic(name);
                        if (JonasManagementRepr.isRegistered(topicObjectName, serverName)) {
                            String agentId = (String) JonasManagementRepr.getAttribute(topicObjectName, "Name", serverName);
                            String serverId = EditJoramBaseAction.currentServerId(topicObjectName);
                            depItem = new EjbDependency(name, "topic", serverId);
                        } else {
                            ObjectName queueObjectName = JoramObjectName.joramQueue(name);
                            if (JonasManagementRepr.isRegistered(queueObjectName, serverName)) {
                                String agentId = (String) JonasManagementRepr.getAttribute(queueObjectName, "Name", serverName);
                                String serverId = EditJoramBaseAction.currentServerId(queueObjectName);
                                depItem = new EjbDependency(name, "queue", serverId);
                            } else {
                                depItem = new EjbDependency(name, null, "0");
                            }
                        }
                    } catch (MalformedObjectNameException e) {
                        depItem = new EjbDependency(name, null, "0");
                    }
                    jmsDestinationItems.add(depItem);
                }
                pForm.setJmsDestinations(jmsDestinationItems);
            } else {
                pForm.setJmsDestinations(alJmsDestinations);
            }
        }
        // Dependency with Mail service
        pForm.setMailServiceActivated(JonasManagementRepr.isRegistered(JonasObjectName.mailService(), serverName));
        HashMap hMailSessions = new HashMap((Map) JonasManagementRepr.getAttribute(pObjectName
            , "allMailFactorySName", serverName));
        if (hMailSessions.size() > 0) {
            pForm.setMailSession(true);
            pForm.setMailSessions(hMailSessions);
        }
        HashMap hMailMimes = new HashMap((Map) JonasManagementRepr.getAttribute(pObjectName
            , "allMailFactoryMName", serverName));
        if (hMailMimes.size() > 0) {
            pForm.setMailMime(true);
            pForm.setMailMimes(hMailMimes);
        }
        // Detect one dependency
        pForm.setDependency(pForm.isDataSource() || pForm.isJmsConnection()
            || pForm.isJmsDestination() || pForm.isMailSession() || pForm.isMailMime());
    }
}
