/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2010 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.ant.jonasbase;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigInteger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.apache.tools.ant.BuildException;
import org.ow2.jonas.ant.JOnASBaseTask;
import org.ow2.jonas.datasource.binding.ConnectionManagerConfigurationType;
import org.ow2.jonas.datasource.binding.DatasourceConfigurationType;
import org.ow2.jonas.datasource.binding.DatasourceType;
import org.ow2.jonas.datasource.binding.Datasources;
import org.ow2.jonas.datasource.binding.ObjectFactory;
import org.ow2.jonas.datasource.reader.DatasourceXmlReader;


/**
 * Allow to create JDBC datasources.
 * @author Benoit Pelletier
 */
public class JdbcXml extends JTask implements BaseTaskItf {

    /**
     * Info for the logger.
     */
    private static final String INFO = "[JdbcXml] ";

    /**
     * New file or add into existing one
     */
    private boolean newFile = false;

    /**
     * Name of this JDBC Resource Adaptor.
     */
    private String name = null;

    /**
     * Mapper Name of this JDBC Resource Adaptor.
     */
    private String mapper = null;

    /**
     * username of this JDBC Resource Adaptor.
     */
    private String userName = null;

    /**
     * Password of this JDBC Resource Adaptor.
     */
    private String password = null;

    /**
     * URL of this JDBC Resource Adaptor.
     */
    private String url = null;

    /**
     * Driver Name of this JDBC Resource Adaptor (may be set to the P6Spy driver name).
     */
    private String className = null;

    /**
     * Init Pool Size.
     */
    private String initConPool = "1";

    /**
     * Min Pool Size.
     */
    private String minConPool = "10";

    /**
     * Max Pool Size.
     */
    private String maxConPool = "100";

    /**
     * Max Prepared Statements Size
     */
    private String pstmtMax = "10";

    /**
     * Pstmt cache policy
     */
    private String pstmtCachePolicy = "List";


    /**
     * Max Wait Time jdbc
     */
    private String maxWaitTime = "10";

    /**
     * Max Waiters jdbc
     */
    private String maxWaiters = "100";

    /**
     * connexion max age jdbc
     */
    private String connMaxAge = "1440";

    /**
     * Max open time jdbc
     */
    private String maxOpenTime = "60";

    /**
     * Connection check level
     */
    private String conCheckLevel = "0";

    /**
     * Connection check level
     */
    private String conTestStmt = "";

    /**
     * Sampling period
     */
    private String samplingPeriod = "30";


    /**
     * Set the name of the driver of this JDBC Resource Adaptor.
     * @param className the name of the driver of this JDBC Resource Adaptor
     */
    public void setClassName(final String className) {
        this.className = className;
    }

    /**
     * Set the init pool size of this JDBC Resource Adaptor Connection Pool.
     * @param initConPool init pool size of connection
     */
    public void setInitConPool(final String initConPool) {
        this.initConPool = initConPool;
    }

    /**
     * Set the min pool size of this JDBC Resource Adaptor Connection Pool.
     * @param minConPool min pool size of connection
     */
    public void setMinConPool(final String minConPool) {
        this.minConPool = minConPool;
    }

    /**
     * Set the max pool size of this JDBC Resource Adaptor Connection Pool.
     * @param maxConPool max pool size of connection
     */
    public void setMaxConPool(final String maxConPool) {
        this.maxConPool = maxConPool;
    }

    /**
     * Set the prepared statement pool size of this JDBC Resource Adaptor Connection Pool.
     * @param pstmtMax pool size of connection
     */
   public void setPstmtMax(final String pstmtMax) {
        this.pstmtMax = pstmtMax;
    }

   /**
    * Set the prepared statement cache policy of this JDBC Resource Adaptor Connection Pool.
    * @param pstmtCachePolicy cache policy
    */
  public void setPstmtCachePolicy(final String pstmtCachePolicy) {
       this.pstmtCachePolicy = pstmtCachePolicy;
   }

  /**
    * Set the connection check level.
    * @param conCheckLevel level
    */
   public void setConCheckLevel(final String conCheckLevel) {
        this.conCheckLevel = conCheckLevel;
    }

   /**
    * Set the statement for the connection check level.
    * @param conTestStmt request
    */
    public void setConTestStmt(final String conTestStmt) {
        this.conTestStmt = conTestStmt;
    }

    /**
     * Set the name of this JDBC Resource Adaptor.
     * @param name the name of this JDBC Resource Adaptor
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * Set the mapper name of this JDBC Resource Adaptor.
     * @param mapper the mappername of this JDBC Resource Adaptor
     */
    public void setMapper(final String mapperName) {
        this.mapper = mapperName;
    }

    /**
     * Set the user of this JDBC Resource Adaptor.
     * @param user the user of this JDBC Resource Adaptor
     */
    public void setUserName(final String user) {
        this.userName = user;
    }

    /**
     * Set the password of this JDBC Resource Adaptor.
     * @param password the name of this JDBC Resource Adaptor
     */
    public void setPassword(final String password) {
        this.password = password;
    }

    /**
     * Set the samplingPeriod of the JDBC Resource Adaptor.
     * @param samplingPeriod the sampling period
     */
    public void setSamplingPeriod(final String samplingPeriod) {
        this.samplingPeriod = samplingPeriod;
    }

    /**
     * Set the url of this JDBC Resource Adaptor.
     * @param url the name of this JDBC Resource Adaptor
     */
    public void setUrl(final String url) {
        this.url = url;
    }

    /**
     * Set the max wait time of this JDBC Resource Adaptor Connection Pool.
     * @param maxWaitTime of the connection
     */
    public void setMaxWaitTime(final String maxWaitTime) {
        this.maxWaitTime = maxWaitTime;
    }

    /**
     * Set the max waiters of this JDBC Resource Adaptor Connection Pool.
     * @param maxWaiters of connection
     */
    public void setMaxWaiters(final String maxWaiters) {
        this.maxWaiters = maxWaiters;
    }

    /**
     * Set the connexion max age of this JDBC Resource Adaptor Connection Pool.
     * @param maxConnMAxAge of connection
     */
    public void setConnMaxAge(final String connMaxAge) {
        this.connMaxAge = connMaxAge;
    }

    /**
     * Set the open time max of this JDBC Resource Adaptor Connection Pool.
     * @param maxWaiters of connection
     */
    public void setMaxOpenTime(final String maxOpenTime) {
        this.maxOpenTime = maxOpenTime;
    }

    /**
     *
     * @return true if a new file is requested
     */
    public boolean isNewFile() {
        return newFile;
    }

    /**
     * Set is a new file has to be created
     * @param newFile
     */
    public void setNewFile(final String newFile) {
        this.newFile = Boolean.valueOf(newFile);
    }

    private void checkProperties() {
        if (name == null) {
            throw new BuildException(INFO + "Property 'name' is missing.");
        } else if (mapper == null) {
            throw new BuildException(INFO + "Property 'mapper' is missing.");
        } else if (userName == null) {
            throw new BuildException(INFO + "Property 'userName' is missing.");
        } else if (password == null) {
            throw new BuildException(INFO + "Property 'password' is missing.");
        } else if (url == null) {
            throw new BuildException(INFO + "Property 'url' is missing.");
        } else if (className == null) {
            throw new BuildException(INFO + "Property 'className' is missing.");
        }
    }



    /**
     * Execute this task.
     */
    @Override
    public void execute() {

        final ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
        try {
            // Look for the JAXB2 JARs since the JDBC XML tasks require JAXB2,
            // not included in the Java 5 runtime. Please remove this piece of
            // code when JOnAS completely switches to Java 6.
            final String javaVersion = System.getProperty("java.version");
            if (javaVersion.startsWith("1.5")) {
                Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
            }

            // Check properties
            checkProperties();

            DatasourceXmlReader datasourceReader = new DatasourceXmlReader();
            if (datasourceReader == null) {
                throw new BuildException("DatasourceReader is null");
            }
            Datasources datasources = null;

            File dsXmlFile = new File(getDestDir().getPath() + File.separator + JOnASBaseTask.DEPLOY_DIR_NAME + File.separator + JOnASBaseTask.JDBC_DS_CONF_FILE);
//          if (!dsXmlFile.exists()) {
//              throw new BuildException("jdbc-ds.xml file doesn't exist");
//          }

            // if needed, load the current XML file
            if (!isNewFile()) {
                datasources = datasourceReader.extractDataSources(dsXmlFile);
            } else {
                datasources = new Datasources();
            }

            // add the datasource
            DatasourceType ds = new DatasourceType();

            DatasourceConfigurationType dsConf = new DatasourceConfigurationType();
            dsConf.setName(name);
            dsConf.setUsername(userName);
            dsConf.setPassword(password);
            dsConf.setUrl(url);
            dsConf.setMapper(mapper);
            dsConf.setClassname(className);
            dsConf.setDescription(name);
            ds.setDatasourceConfiguration(dsConf);

            ConnectionManagerConfigurationType cmConf = new ConnectionManagerConfigurationType();
            cmConf.setConnchecklevel(Integer.valueOf(this.conCheckLevel));
            cmConf.setConnteststmt(this.conTestStmt);
            cmConf.setConnmaxage(BigInteger.valueOf(Long.valueOf(connMaxAge)));
            cmConf.setInitconpool(BigInteger.valueOf(Long.valueOf(this.initConPool)));
            cmConf.setMinconpool(BigInteger.valueOf(Long.valueOf(this.minConPool)));
            cmConf.setMaxconpool(BigInteger.valueOf(Long.valueOf(this.maxConPool)));
            cmConf.setMaxopentime(BigInteger.valueOf(Long.valueOf(this.maxOpenTime)));
            cmConf.setMaxwaiters(BigInteger.valueOf(Long.valueOf(this.maxWaiters)));
            cmConf.setMaxwaittime(BigInteger.valueOf(Long.valueOf(this.maxWaitTime)));
            cmConf.setPstmtmax(BigInteger.valueOf(Long.valueOf(this.pstmtMax)));
            cmConf.setPstmtcachepolicy(this.pstmtCachePolicy);
            cmConf.setSamplingperiod(BigInteger.valueOf(Long.valueOf(this.samplingPeriod)));
            ds.setConnectionManagerConfiguration(cmConf);

            datasources.getDatasources().add(ds);

            // flush the file
            if (dsXmlFile.exists()) {
                dsXmlFile.delete();
            }
            dsXmlFile.createNewFile();

            JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
            FileOutputStream fileOut = new FileOutputStream(dsXmlFile);
            try {
                marshaller.marshal(datasources, fileOut);
            } finally {
                fileOut.close();
            }

            log(INFO + "JDBC XML generated : '" + dsXmlFile.getAbsolutePath() + "'.");
        } catch (BuildException e) {
            throw e;
        } catch (Throwable t) {
            throw new BuildException("Failed building JDBC XML: " + t, t);
        } finally {
            Thread.currentThread().setContextClassLoader(oldCL);
        }

    }
}
