/*
 * 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.phasing;

import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.util.DeploymentProperties;

import com.sun.enterprise.deployment.backend.DeploymentStatus;
import com.sun.enterprise.deployment.backend.DeploymentRequest;
import com.sun.enterprise.deployment.backend.DeployableObjectType;
import com.sun.enterprise.deployment.backend.DeploymentLogger;
import com.sun.enterprise.deployment.backend.IASDeploymentException;
import com.sun.enterprise.deployment.phasing.DeploymentServiceUtils;

import com.sun.enterprise.util.i18n.StringManager;
import com.sun.enterprise.resource.Resource;
import com.sun.enterprise.admin.common.MBeanServerFactory;
import com.sun.enterprise.admin.common.ObjectNames;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.MBeanException;

import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
 * This class is the base class for resource phases
 */
public abstract class ResourcePhase extends DeploymentPhase {

    protected static final String resourcesMBeanName = 
        "com.sun.appserv:type=resources,category=config";
    protected static final String CREATE_RESOURCE = 
        "createResource";
    protected static final String CREATE_RESOURCE_REF = 
        "createResourceReference";
    protected static final String CREATE_RESOURCE_AND_REF = 
        "createResourceAndResourceReference";
    protected static final String DELETE_RESOURCE = 
        "deleteResource";
    protected static final String DELETE_RESOURCE_REF = 
        "deleteResourceReference";
    protected static final String DELETE_RESOURCE_AND_REF = 
        "deleteResourceAndResourceReference";

    protected static final String DOMAIN_TARGET = 
        "domain";

    protected MBeanServer mbs = MBeanServerFactory.getMBeanServer();
                                                                                
    /** Deployment Logger object for this class */
    private static final Logger sLogger = DeploymentLogger.get();

    protected void doResourceOperation(DeploymentRequest req) throws Exception {
        String targetListString = req.getResourceTargetList();
        List<String> targetList = DeploymentServiceUtils.getTargetNamesFromTargetString(targetListString);

        String resourceAction = req.getResourceAction();
        if (resourceAction == null || 
            getActualAction(resourceAction).equals(
                DeploymentProperties.RES_NO_OP)) {
            return;
        }

        if (targetList == null || targetList.isEmpty()) {
            return;
        }

        List<Resource> resourceList = DeploymentServiceUtils.getResourceList(
            req, getForceParsing(resourceAction), deploymentCtx);

        // empty resource list, no resource to process
        if (resourceList.size() == 0) {
            return;
        }

        handleResources(resourceAction, targetList, 
            getRelevantResources(resourceList)); 
    }


    protected void handleResources(String resourceAction, 
        List<String> targetList, List<Resource> resourceList) 
        throws Exception {

        // empty sub resource list, no resource to process
        if (resourceList.size() == 0) {
            return;
        }

        if (resourceAction.equals(DeploymentProperties.RES_DEPLOYMENT)) {
            handleDeployment(targetList, resourceList);
        } else if (resourceAction.equals(DeploymentProperties.RES_CREATE_REF)){
            handleCreateApplicationRef(targetList, resourceList);
        } else if (resourceAction.equals(DeploymentProperties.RES_DELETE_REF)){
            handleDeleteApplicationRef(targetList, resourceList);
        } else if (resourceAction.equals(
            DeploymentProperties.RES_UNDEPLOYMENT)){
            handleUndeployment(targetList, resourceList);
        } else if (resourceAction.equals(
            DeploymentProperties.RES_REDEPLOYMENT)){
            handleRedeployment(targetList, resourceList);
        }
    }

    // invoke with both resource and resource-ref elements created
    // special case: when target is domain, only create resource element
    protected void handleDeployment(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);

        // if target is domain, only create resource
        if (targetList.size() == 1 &&
            targetList.get(0).equals(DOMAIN_TARGET)) {
            String[] signature = new String[]{
                "java.util.List", "java.lang.Boolean"};
            Object[] params = new Object[]{resourceList, Boolean.TRUE};
            mbs.invoke(mbeanName, CREATE_RESOURCE, params, signature);
        } else {
            String[] signature = new String[]{
                "java.util.List", "java.util.List", "java.lang.Boolean"};
            Object[] params = new Object[]{resourceList, targetList, 
                Boolean.TRUE};
            mbs.invoke(mbeanName, CREATE_RESOURCE_AND_REF, params, signature);
        }
    }

    // invoke with only resource-ref element created
    protected void handleCreateApplicationRef(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);
        String[] signature = new String[]{
            "java.util.List", "java.util.List", "java.lang.Boolean"};
        Object[] params = new Object[]{resourceList, targetList, 
            Boolean.TRUE};
        mbs.invoke(mbeanName, CREATE_RESOURCE_REF, params, signature);
    }

    // invoke with both resource and resource-ref elements deleted
    // special case: when target is domain, only delete resource element
    protected void handleUndeployment(List<String> targetList,
        List<Resource> resourceList) {
        try {
            ObjectName mbeanName = new ObjectName(resourcesMBeanName);

            // if target is domain, only delete resource
            if (targetList.size() == 1 &&
                targetList.get(0).equals(DOMAIN_TARGET)) {
                String[] signature = new String[]{"java.util.List"};
                Object[] params = new Object[]{resourceList};
                mbs.invoke(mbeanName,DELETE_RESOURCE, params, signature);
            } else {
                String[] signature = new String[]{
                    "java.util.List", "java.util.List"};
                Object[] params = new Object[]{resourceList, targetList};
                mbs.invoke(mbeanName, DELETE_RESOURCE_AND_REF, params, signature);
            }
        } catch (Exception e) {
            // we will just log the exception as warning message and will not 
            // fail undeployment
            sLogger.log(Level.WARNING, e.getMessage(), e);
        }
    }

    abstract protected void handleRedeployment(List<String> targetList,
        List<Resource> resourceList) throws Exception;

    // invoke with only resource-ref element deleted
    protected void handleDeleteApplicationRef(List<String> targetList,
        List<Resource> resourceList) throws Exception {
        ObjectName mbeanName = new ObjectName(resourcesMBeanName);
        String[] signature = new String[]{
            "java.util.List", "java.util.List"};
        Object[] params = new Object[]{resourceList, targetList};
        mbs.invoke(mbeanName, DELETE_RESOURCE_REF, params, signature);
    }

    protected boolean getForceParsing(String resAction) {
        return false;
    }

    protected String getActualAction(String resAction) {
        return resAction;
    }

    abstract protected List<Resource> getRelevantResources(
        List<Resource> allResources);
}
