/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2009 Bull S.A.S
 * Contact: jonas-team@ow2.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.ow2.jonas.webapp.jonasadmin.service.ejb;

import java.net.URL;
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.ow2.jonas.lib.management.extensions.base.BaseManagement;
import org.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.JoramObjectName;
import org.ow2.jonas.management.extensions.base.api.ManagementException;
import org.ow2.jonas.webapp.jonasadmin.JonasAdminJmx;
import org.ow2.jonas.webapp.jonasadmin.JonasBaseAction;
import org.ow2.jonas.webapp.jonasadmin.WhereAreYou;
import org.ow2.jonas.webapp.jonasadmin.joramplatform.EditJoramBaseAction;
import org.ow2.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
     */
    @Override
    public ActionForward executeAction(final ActionMapping pMapping, final ActionForm pForm, final HttpServletRequest pRequest,
            final HttpServletResponse pResponse) {

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

        // 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);

                if (!JonasManagementRepr.isRegistered(oObjectName, serverName)) {
                    refreshServicesTree(pRequest);
                    return (pMapping.findForward("ActionListContainers"));
                }
            } 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 fname = null;
        boolean ejb3 = false;
        try {
            fname = (String) JonasManagementRepr.getAttribute(oObjectName, "fileName", serverName);
        } catch (ManagementException e) {
            Throwable cause = e.getCause();
            if (cause.getClass().getName().equals("javax.management.AttributeNotFoundException")) {
                // maybe ejb3 - TO DO check this
                ejb3 = true;
                String moduleName = oObjectName.getKeyProperty("EJBModule");
                String applicationName = oObjectName.getKeyProperty("J2EEApplication");
                ObjectName moduleOn = J2eeObjectName.getEJBModule(oObjectName.getDomain(), serverName, applicationName,
                        moduleName);
                // patch EJBModule ObjectName pb.
                if (applicationName == null) {
                    String patchON = oObjectName.getDomain() + ":j2eeType=EJBModule,J2EEServer=" + serverName + ",name="
                            + moduleName;
                    try {
                        moduleOn = ObjectName.getInstance(patchON);
                    } catch (Exception e1) {
                        addGlobalError(e1);
                        saveErrors(pRequest, m_Errors);
                        return (pMapping.findForward("Global Error"));
                    }
                }
                if (JonasManagementRepr.isRegistered(moduleOn, serverName)) {
                    URL moduleUrl = (URL) JonasManagementRepr.getAttribute(moduleOn, "url", serverName);
                    fname = moduleUrl.getPath();
                }
            }
        }
        oForm.setEjb3(ejb3);

        // Put global properties
        oForm.setType(msParamType);
        oForm.setName(msParamName);
        oForm.setObjectName(ejbObjectName);
        oForm.setFile(fname);
        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 {
            oForm.setAttributes(BaseManagement.getInstance().getAttributes(oObjectName, serverName));
            // Fill Ejb infos
            fillEjbInfo(ejb3, oForm, oObjectName, serverName);
            // Fill Ejb dependencies (Datasource, JMS, ...)
            fillEjbDependencies(ejb3, oForm, oObjectName, domainName, 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(boolean ejb3, 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(final boolean ejb3, final EjbForm pForm, final ObjectName pObjectName) {
        if (ejb3) {
            return;
        }
        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(final boolean ejb3, final EjbForm pForm, final ObjectName pObjectName,
            final String domainName, final String serverName) {
        if (ejb3) {
            return;
        }
        // Dependency with Datasource service
        pForm.setDatabaseServiceActivated(JonasManagementRepr.isRegistered(JonasObjectName.databaseService(domainName),
                serverName));
        pForm.setResourceServiceActivated(JonasManagementRepr.isRegistered(JonasObjectName.resourceService(domainName),
                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(domainName), 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(domainName), 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());
    }
}
