/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2004-2008 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.antmodular.bootstrap;

import static org.ow2.jonas.antmodular.bootstrap.JOnASAntTool.createVariable;

import java.io.File;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.types.Path;

/**
 * Allow to use the BootStrap class <br/>It allows to do some operations like
 * <ul><li>starting/stopping JOnAS</li><li>Deploying some apps</li><li>
 * etc... </li></ul>
 * @author Florent Benoit
 */
public abstract class BootstrapTask extends Task {

    /**
     * Bootstrap class name.
     */
    private static final String BOOTSTRAP_CLASS = "org.ow2.jonas.client.boot.Bootstrap";

    /**
     * Default JOnAS server name.
     */
    private static final String DEFAULT_SERVER_NAME = "jonas";

    /**
     * Default maven2-internal repository subpath.
     */
    private static final String MAVEN2_REPOSITORY = "repositories" + File.separator + "maven2-internal";

    /**
     * Name of the task (to be displayed in log : default to JOnAS).
     */
    private String taskName = "JOnAS";

    /**
     * JOnAS Root.
     */
    private File jonasRoot = null;

    /**
     * Name of the server (default 'jonas').
     */
    private String serverName = DEFAULT_SERVER_NAME;

    /**
     * Name of the server (default 'jonas').
     */
    private String domainName = null;

    /**
     * JOnAS Base.
     */
    private File jonasBase = null;

    /**
     * Options given to the JVM.
     */
    private String jvmOpts = null;

    /**
     * Classpath used for this task.
     */
    private Path classpath = null;

    /**
     * Set the JOnAS root directory.
     * @param jonasRoot the JOnAS root directory.
     */
    public void setJonasRoot(final File jonasRoot) {
        this.jonasRoot = jonasRoot;
    }

    /**
     * Set the JOnAS base directory.
     * @param jonasBase the JOnAS base directory.
     */
    public void setJonasBase(final File jonasBase) {
        this.jonasBase = jonasBase;
    }

    /**
     * Set the additional args to pass to the JVM.
     * @param jvmOpts the options.
     */
    public void setJvmopts(final String jvmOpts) {
        this.jvmOpts = jvmOpts;
    }

    /**
     * Adds to the classpath the class of the project.
     * @return the path to be configured.
     */
    public Path createClasspath() {
        return new Path(getProject());
    }

    /**
     * Set the classpath for this task.
     * @param classpath the classpath to use.
     */
    public void setClasspath(final Path classpath) {
        this.classpath = classpath;
    }

    /**
     *
     * @param definedClass
     * @return
     * @see BootstrapTask.getBootstrapTask(String, boolean)
     */
    protected Java getBootstraptask(final String definedClass) {
        return getBootstraptask(definedClass, true, getProject());
    }

    /**
     *
     * @param definedClass
     * @param assignClasspath if true, will set the default Classpath for Ant task
     * @return
     * @see BootstrapTask.getBootstrapTask(String, boolean)
     */
    protected Java getBootstraptask(final String definedClass, final boolean assignClasspath) {
        return getBootstraptask(definedClass, assignClasspath, getProject());
    }

    /**
     * Run the task.
     * @param definedClass Main class to run
     * @param assignClasspath if true, will set the default Classpath for Ant task
     * @param project the ant project reference
     * @return a {@link Java} configured ant task
     * @see org.apache.tools.ant.Task#execute()
     */
    public Java getBootstraptask(final String definedClass, final boolean assignClasspath, final Project project) {
        if (jonasRoot == null) {
            // get ant property

            String jr = project.getProperty("jonas.root");

            if (jr == null) {
                throw new BuildException("JONAS_ROOT is not set.");
            }

            jonasRoot = new File(jr);
        }

        if (jonasBase == null) {
            jonasBase = jonasRoot;
        }

        project.createTask("java");
        Java bootstrapTask = (Java) project.createTask("java");
        bootstrapTask.setTaskName(taskName);
        bootstrapTask.setFork(true);
        bootstrapTask.setFailonerror(true);

        // Name of the server
        if (serverName != null) {
            bootstrapTask.addSysproperty(createVariable("jonas.name", serverName));
        }

        // Name of the domain
        if (domainName != null) {
            bootstrapTask.addSysproperty(createVariable("domain.name", domainName));
        }

        // jonas root
        // jonas.root ??
        bootstrapTask.addSysproperty(createVariable("jonas.root", jonasRoot));

        // jonas base
        bootstrapTask.addSysproperty(createVariable("jonas.base", jonasBase));

        // set headless (for unix without X running)
        bootstrapTask.addSysproperty(createVariable("java.awt.headless", "true"));

        // iiop
        bootstrapTask.addSysproperty(createVariable("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"));
        bootstrapTask.addSysproperty(createVariable("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"));
        bootstrapTask.addSysproperty(createVariable("org.omg.PortableInterceptor.ORBInitializerClass.standard_init",
                                                    "org.jacorb.orb.standardInterceptors.IORInterceptorInitializer"));

        File jonasLibDir = new File(jonasRoot, "lib");
        File jonasLibEndorsedDir = new File(jonasLibDir, "endorsed");
        bootstrapTask.addSysproperty(createVariable("javax.rmi.CORBA.PortableRemoteObjectClass",
                                                    "org.ow2.carol.rmi.multi.MultiPRODelegate"));
        bootstrapTask.addSysproperty(createVariable("java.endorsed.dirs", jonasLibEndorsedDir));

        // Rmi annotation
        // Disabled in OSGi
        /*
        bootstrapTask.createJvmarg().setValue(
                "-Djava.rmi.server.RMIClassLoaderSpi=org.ow2.jonas.lib.bootstrap.RemoteClassLoaderSpi");
        */

        // java policy file
        String jonasConfigDir = jonasBase + File.separator + "conf";
        File javaPolicyFile = new File(jonasConfigDir, "java.policy");
        if (javaPolicyFile.exists()) {
            bootstrapTask.addSysproperty(createVariable("java.security.policy", javaPolicyFile));
        }
        File javaAuthLoginFile = new File(jonasConfigDir, "jaas.config");
        bootstrapTask.addSysproperty(createVariable("java.security.auth.login.config", javaAuthLoginFile));

        // The bootstrap class must launch the defined class
        bootstrapTask.createArg().setValue(definedClass);

        // add jonas_base/conf
        classpath = new Path(project, jonasConfigDir);

        // then add ow_jonas_bootstrap.jar to classloader
        String bootJar = jonasRoot + File.separator + "lib" + File.separator + "bootstrap" + File.separator
                + "client-bootstrap.jar";
        classpath.append(new Path(project, bootJar));
        bootJar = jonasRoot + File.separator + "lib" + File.separator + "bootstrap" + File.separator
        + "felix-launcher.jar";
        classpath.append(new Path(project, bootJar));
        bootJar = jonasRoot + File.separator + "lib" + File.separator + "bootstrap" + File.separator
        + "jonas-commands.jar";
        classpath.append(new Path(project, bootJar));
        bootJar = jonasRoot + File.separator + "lib" + File.separator + "bootstrap" + File.separator
        + "jonas-version.jar";
        classpath.append(new Path(project, bootJar));
        // Add tools.jar
        String toolsJar = System.getProperty("java.home") + File.separator + ".." + File.separator + "lib"
                + File.separator + "tools.jar";
        classpath.append(new Path(project, toolsJar));

        // Set the classpath
        bootstrapTask.setClasspath(classpath);

        // class to use = bootstrap class
        bootstrapTask.setClassname(BOOTSTRAP_CLASS);

        // add user defined jvmopts
        if (jvmOpts != null && !jvmOpts.equals("")) {
            bootstrapTask.createJvmarg().setLine(jvmOpts);
        }

        // add jonas name
        /*
        if (serverName != null) {
            bootstrapTask.createArg().setValue("-n");
            bootstrapTask.createArg().setValue(getServerName());
        }
         */
        return bootstrapTask;

    }

    /**
     * @return the taskName.
     */
    @Override
    public String getTaskName() {
        return taskName;
    }

    /**
     * Set the name of the task.
     * @param taskName Name of the task
     */
    @Override
    public void setTaskName(final String taskName) {
        this.taskName = taskName;
    }

    /**
     * @return the server Name.
     */
    public String getServerName() {
        return serverName;
    }

    /**
     * Set the name of the server.
     * @param serverName The serverName to set.
     */
    public void setServerName(final String serverName) {
        this.serverName = serverName;
    }

    /**
     * Set catalina Home.
     * @param catalinaHome The catalinaHome to set.
     * @deprecated
     */
    @Deprecated
    public void setCatalinaHome(final String catalinaHome) {
        // deprecated
    }

    /**
     * Set jetty home path.
     * @param jettyHome The jettyHome to set.
     * @deprecated
     */
    @Deprecated
    public void setJettyHome(final String jettyHome) {
        // deprecated
    }

    /**
     * @return the jonasRoot.
     */
    public File getJonasRoot() {
        return jonasRoot;
    }

    /**
     * @return the relative maven2 repository path.
     */
    public String getMaven2Repository() {
        return MAVEN2_REPOSITORY;
    }

    /**
     * @return the domainName.
     */
    public String getDomainName() {
        return domainName;
    }

    /**
     * Set domainName.
     * @param domainName The domainName to set.
     */
    public void setDomainName(final String domainName) {
        this.domainName = domainName;
    }

}
