/* ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Ant", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */ 

package org.apache.tools.ant.taskdefs.optional.ejb;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.taskdefs.LogStreamHandler;
import org.apache.tools.ant.taskdefs.Execute;

import java.io.IOException;
import java.io.File;

/**
 * Ant task to deploy an enterprise archive (.ear) on a Sun J2EE RI server.
 * @author <a href="mailto:stefano_mancarella@yahoo.com">Stefano Mancarella</a>
 */
public class J2EEDeploy extends Task {

	private static String deployToolClass =
			"com.sun.enterprise.tools.deployment.main.Main";
	private CommandlineJava commandline;
	private String _earFile;
	private String _hostname;
	private String _clientJar;
	private boolean _fork = true; // Always fork!
	private Path _classpath;
	private File _j2eeHome;
	private File _dir;

	/** Creates the task. */
	public J2EEDeploy() {
		commandline = new CommandlineJava();
		commandline.setClassname(deployToolClass);
	}

	/** Sets the filename of the enterprise archive to deploy.
	 * This attriute is required.
	 * @param earFile the enterprise archive filename.
	 */
	public void setEarFile(String earFile) {
		_earFile = earFile;
	}

	/** Gets the filename of the enterprise archive to deploy.
	 * @return the enterprise archive filename.
	 */
	public String getEarFile() {
		return _earFile;
	}

	/** Sets the hostname of J2EE server.
	 * Not required, defaults to &quot;localhost&quot;.
	 * @param hostname the J2EE server hostname.
	 */
	public void setHostname(String hostname) {
		_hostname = hostname;
	}

	/** Gets the hostname of J2EE server.
	 * @return the J2EE server hostname.
	 */
	public String getHostname() {
		return _hostname;
	}

	/** Sets the home directory of the local J2EE installation.
	 * The specified directory is used to search for J2EE classes and
	 * property files.
	 * This attriute is required.
	 * @param j2eeHome the local J2EE home.
	 */
	public void setJ2eeHome(File j2eeHome) {
		_j2eeHome = j2eeHome;
	}

	/** Gets the home directory of the local J2EE installation.
	 * @return the local J2EE home.
	 */
	public File getJ2eeHome() {
		return _j2eeHome;
	}

	/** Sets the filename of the client jar file to generate.
	 * If this attribute is not specified, no client jar is generated.
	 * @param clientJar the client jar filename.
	 */
	public void setClientJar(String clientJar) {
		_clientJar = clientJar;
	}

	/** Gets the filename of the client jar file to generate.
	 * @return the client jar filename.
	 */
	public String getClientJar() {
		return _clientJar;
	}

	/** Tells whether a JVM should be forked for the task.
	 * At the moment this attribute is ignored and a JVM is always forked.
	 * @param value <tt>true</tt> if a JVM should be forked, <tt>false</tt> otherwise.
	 */
	public void setFork(boolean fork) {
		// _fork = fork;
	}

	/** Sets a new VM to execute the task.
	 * Defaults to <tt>java</tt>. Ignored if no JVM is forked.
	 * @param value the new VM to use instead of <tt>java</tt>.
	 */
	public void setJvm(String value) {
		commandline.setVm(value);
	}

	/** Sets the directory to invoke the JVM from.
	 * Ignored if no JVM is forked.
	 * @param dir the directory to invoke the JVM from.
	 * @see #setFork(boolean)
	 */
	public void setDir(File dir) {
		_dir = dir;
	}

	/** Gets the directory from which the JVM is invoked.
	 * @return the JVM invocation directory.
	 */
	public File getDir() {
		return _dir;
	}

	/** Executes the task.
	 * @throws BuildException if execution fails.
	 */
	public void execute() throws BuildException {
		if (_earFile == null) {
			throw new BuildException("\"earFile\" argument required.");
		}
		if (_j2eeHome == null) {
			throw new BuildException("\"j2eeHome\" argument required.");
		}
		if (!(_j2eeHome.exists() && _j2eeHome.isDirectory())) {
			throw new BuildException("\"" + _j2eeHome.getPath()
					+ "\" is not a valid directory.");
		}
		if (_dir != null && !(_dir.exists() && _dir.isDirectory())) {
			throw new BuildException("\"" + _dir.getPath()
					+ "\" is not a valid directory.");
		}
		if (_hostname == null) { _hostname = "localhost"; }
		if (_fork) {
			log("Deploying " + _earFile + " on " + _hostname + " ...", Project.MSG_INFO);
			if (executeAsForked() != 0) {
				throw new BuildException("EJB deployment failed.", location);
			} else {
				log("Done", Project.MSG_INFO);
			}
		} else {
			executeInVM();
		}
	}

	/* Must investigate further if task can be executed inside the Ant JVM. */
	private void executeInVM() throws BuildException {
		throw new BuildException("Can't execute inside Ant JVM.", location);
	}

	/* Execute in a forked JVM */
	private int executeAsForked() {
		Path cpath = commandline.createClasspath(project);
		cpath.createPathElement().setPath(_j2eeHome.getPath() + "/lib/j2ee.jar");
		cpath.createPathElement().setPath(_j2eeHome.getPath() + "/lib/locale");
		commandline.createVmArgument().setValue("-Dcom.sun.enterprise.home=" + _j2eeHome.getPath());
		commandline.createArgument().setValue("-deploy");
		commandline.createArgument().setValue(_earFile);
		commandline.createArgument().setValue(_hostname);
		if (_clientJar != null) {
			commandline.createArgument().setValue(_clientJar);
		}
		Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_VERBOSE, Project.MSG_WARN));
		execute.setCommandline(commandline.getCommandline());
        if (_dir != null) {
            execute.setWorkingDirectory(_dir);
            execute.setAntRun(project);
	        log("Working directory set to: " + _dir.getPath(), Project.MSG_VERBOSE);
        }
        log("Executing: " + commandline.toString(), Project.MSG_VERBOSE);
		try {
			return execute.execute();
		} catch (IOException e) {
			throw new BuildException("Process fork failed.", e, location);
		}
	}

}
