/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */


/*
 * WebArchiveDeployer.java
 *
 * Created on April 23, 2007, 6:13 PM
 *
 */

package com.sun.enterprise.deployment.backend;

import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.File;
import java.io.IOException;

import javax.enterprise.deploy.shared.ModuleType;

import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.RootDeploymentDescriptor;
import com.sun.enterprise.deployment.archivist.WebArchivist;
import com.sun.enterprise.deployment.archivist.ApplicationArchivist;
import com.sun.enterprise.deployment.pluggable.PluggableDeploymentInfo;
import com.sun.enterprise.deployment.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchive;
import com.sun.enterprise.deployment.util.ModuleContentLinker;
import com.sun.enterprise.deployment.util.XModuleType;
import com.sun.enterprise.instance.BaseManager;
import com.sun.enterprise.instance.ExtensionModuleConfigManager;
import com.sun.enterprise.security.util.IASSecurityException;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.zip.ZipFileException;
import com.sun.enterprise.util.zip.ZipItem;

import org.xml.sax.SAXParseException;



/**
 * This class abstracts functionality from the WebModuleDeployer by overriding
 * specific methods. The purpose of this abtstraction is to allow modules that
 * use the Extension Deployment SPI to re-use the logic from WebModuleDeployer
 * to process the Web components of the module that is currently being 
 * processed. An example is the converged SIP +HTTP application that is defined
 * by JSR289. The WebArchiveDeployer would provide a simple way to process 
 * the HTTP portion of the converged HTTP+SIP application
 * 
 * @author Prasad Subramanian
 */
public class WebArchiveDeployer extends WebModuleDeployer {
    
    
    private Application application = null;
    private DeployableObjectType _origType = null;
    private static StringManager localStrings =
		StringManager.getManager( WebArchiveDeployer.class );
    private boolean isConverged = false;
    private boolean isRuntimeXMLValidation = false;
    private String runtimeXMLValidationLevel = "none";
   
    protected static Logger logger = DeploymentLogger.get();
   
    public ExtensionModuleConfigManager configManager = null;

    
    public WebArchiveDeployer() {
    } 
    /** Getter and setter methods
     */
    public void setDeploymentRequest(DeploymentRequest r) {
        request = r;
        _origType = request.getType();
        instanceEnv = request.getInstanceEnv();
        if(instanceEnv == null) {
            String msg = localStrings.getString("enterprise.deployment.backend.nullInstanceEnv");
            logger.log(Level.SEVERE, msg);        
        }
        if(request.isVerifying()) {
            isRuntimeXMLValidation = true;
            runtimeXMLValidationLevel = "full";
        }
        try {
            request.verify();
        } catch(IASDeploymentException iasde) {
            String msg = localStrings.getString("enterprise.deployment.backend.iasde");
            logger.log(Level.SEVERE, msg, iasde.toString()); 
        }
    }
    
    public DeploymentRequest getDeploymentRequest() {
        return request;
    }
    
    public void setManager(ExtensionModuleConfigManager configManager) {
        modulesMgr = configManager;
    }
    
    public BaseManager getManager() {
        return modulesMgr;
    }
    
    public Application getApplication() {
        return this.application;
    }
    
    public boolean isConverged() {
        return isConverged;
    }
    
    public void setConverged(boolean isConverged) {
         this.isConverged = isConverged;
         if(request !=null) {
             if(isConverged) {
                 request.addOptionalArgument("isConverged", "true");
             } else {
                 request.addOptionalArgument("isConverged", "false");
             }
         }
    }
    
    public boolean getRuntimeXMLValidation() {
        return isRuntimeXMLValidation;
    }
    
    public String getRuntimeXMLValidationLevel() {
        return runtimeXMLValidationLevel;
    }
    
    public void processWebArchive() {
        try{
            doRequestFinish();
        } catch (IASDeploymentException iasde) {
            String msg = localStrings.getString("enterprise.deployment.backend.iasde");
            logger.log(Level.SEVERE, msg, iasde.toString());
        }
    }
    
    /** 
     * Overridden methods from ModuleDeployer/Deployer/WebModuleDeployer
     */
    
    /**
     * This method overrides the doRequestFinish in the ModuleDeployer
     * to call only those methods that are required to process the WEB components
     * of an Archive that has already been exploded.
     * @throws IASDeploymentException
     */
    public void doRequestFinish() throws IASDeploymentException {
       
        J2EECPhaseStatus = request.getCurrentDeploymentStatus();
        try {
            begin();
            if(request.isDeploy() || request.isReDeploy()) {
                beginFinish();
                preDeploy();
                // create a DeploymentStatus for runEJBC stage
                // it is a substage of J2EECPhase status
                DeploymentStatus runEJBCStatus =
                           new DeploymentStatus(J2EECPhaseStatus);
                request.setCurrentDeploymentStatus(runEJBCStatus);
                deploy();
                register();
                // DeploymentStatus for postDeploy
                // stage, it is a substage of J2EECPhase status
                DeploymentStatus postDeployStatus =
                        new DeploymentStatus(J2EECPhaseStatus);
                request.setCurrentDeploymentStatus(
                                    postDeployStatus);   
                postDeploy();
                generatePolicy();
            } else if(request.isUnDeploy()) {
                beginFinish();
        	preundeploy();
                undeploy();
                removePolicy();
            }
        } catch(Exception e) {
            throw new IASDeploymentException(); 
        } finally {
            request.setDeployableObjectType(_origType);
        }
    }
    
    /**
     * This method overudes the deploy() method in the WebModuleDeployer
     * and exposes only those methods that are needed for processing an 
     * exploded Web Application Archive
     * @throws IASDeploymentException
     */
    
    public void deploy() throws IASDeploymentException {
        //set the DeployableObjectType to WEB
        request.setDeployableObjectType(DeployableObjectType.WEB);
        application = super.loadDescriptors();
        WebBundleDescriptor bundleDesc =
                (WebBundleDescriptor) application.getStandaloneBundleDescriptor();
        
        // This is where we set the context root
        /** The rules for setting context root are as follows :
         * Check if the app is converged Application ( presence if web.xml)
         * if yes, follow the same rules as a web application
         * if no there is no context root
         */
        if(isConverged()) {
            if (request.getContextRoot() == null || 
                request.getContextRoot().trim().equals("")) { 
                if (bundleDesc.getContextRoot() != null &&
                    !bundleDesc.getContextRoot().trim().equals("")) {
                         request.setContextRoot(bundleDesc.getContextRoot());
                } else {
                        request.setContextRoot(request.getDefaultContextRoot());
                }
            }
        }
        ZipItem[] clientStubs = runEJBC();

	try {
	    if(request.getPrecompileJSP()) {
                long time = System.currentTimeMillis();
		    JSPCompiler.compile(moduleDir, 
                                          jspDir,
                                            bundleDesc,
                                              request.getCompleteClasspath());
		         	  addJSPCTime(System.currentTimeMillis() - time);
             }
             runVerifier();
         } catch(IASDeploymentException de) {            
	    throw de;
	 } catch(Exception e){            
	    throw new IASDeploymentException(e);
	 } 
    }
    
    public void expand(File archivePath, File moduleRootDirectory) 
                                                 throws Exception {
        J2EEModuleExploder.explodeJar(archivePath, moduleRootDirectory);
    }
    
    /**
     * Method to get an Application object from the exploded archive
     * during application server starrtup
     */
    public Application getApplication(String moduleName, 
                                         File moduleRootDirectory,
                                           File moduleScratchDirectory,
                                               ModuleType moduleType) {
        try {
            Application app = null;
            BaseManager emMgr = 
               (BaseManager)PluggableDeploymentInfo.
                    getExtensionModuleDeployer(moduleType).getConfigManager();
            FileArchive archive = emMgr.openDDArchive(moduleName, 
                                         moduleRootDirectory.getAbsolutePath());           

            WebArchivist webArchivist = new WebArchivist();
            app = ApplicationArchivist.openArchive(moduleName, 
                                               webArchivist, archive, true);
            //if(!isSystemAdmin(moduleName) && !isSystem(moduleName)) {
                // we need to read persistence descriptors separately
                    // because they are read from appDir as oppsed to xmlDir.
            emMgr.readPersistenceDeploymentDescriptors(
                                     moduleRootDirectory.getAbsolutePath(),
                                                                app);
            //}
                 
            app.setGeneratedXMLDirectory(
                              moduleScratchDirectory.getAbsolutePath());
            if (!app.getWebServiceDescriptors().isEmpty()) {
            ModuleContentLinker visitor = new ModuleContentLinker(archive);
            app.visit(
                  (com.sun.enterprise.deployment.util.ApplicationVisitor) visitor);
            }
            return app;
        } catch (IOException ioe) {
            logger.log(Level.SEVERE,ioe.toString()); 
            return null;
        } catch (ConfigException ce) {
            logger.log(Level.SEVERE,ce.toString()); 
            return null;
        } catch (SAXParseException spe) {
            logger.log(Level.SEVERE, spe.toString());
            return null;
        } catch (Exception ex) {
            logger.log(Level.SEVERE, ex.toString());
            return null;
        }        
    }
    
    /** 
     * Loads the bundle descriptor for the Web part of an extension module.
     * This method is called when the extension module is a part of an
     * enterprise application
     * @param modRoot - the application  or generated/xml directory for 
     *                   the module
     * @param classLoader the parent classloader
     * @return RootDeploymentDescriptor
     * @throws IOException  SAXParseException
     */
    public RootDeploymentDescriptor getBundleDescriptor(String modRoot,
                                                        ClassLoader classLoader) 
                                                           throws IOException,
                                                             SAXParseException {
        
        RootDeploymentDescriptor descriptor = null;
        FileArchive modArchive = new FileArchive();
        AbstractArchive embeddedArchive = 
                modArchive.getEmbeddedArchive(modRoot);
        WebArchivist webArchivist = new WebArchivist();
        webArchivist.setAnnotationProcessingRequested(true);
        webArchivist.setClassLoader(classLoader);
        descriptor = webArchivist.open(embeddedArchive);
        return descriptor;
        
    }
    
}
