/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * 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
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): Eric Hardesty
 *
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.generators.raconfig;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.naming.Context;

import org.ow2.jonas.deployment.common.DeploymentDescException;
import org.ow2.jonas.deployment.rar.ConfigPropertyDesc;
import org.ow2.jonas.deployment.rar.RarDeploymentDesc;
import org.ow2.jonas.deployment.rar.RarDeploymentDescException;
import org.ow2.jonas.deployment.rar.lib.RarDeploymentDescManager;
import org.ow2.jonas.deployment.rar.xml.Activationspec;
import org.ow2.jonas.deployment.rar.xml.Adminobject;
import org.ow2.jonas.deployment.rar.xml.ConfigProperty;
import org.ow2.jonas.deployment.rar.xml.ConnectionDefinition;
import org.ow2.jonas.deployment.rar.xml.Connector;
import org.ow2.jonas.deployment.rar.xml.InboundResourceadapter;
import org.ow2.jonas.deployment.rar.xml.JdbcConnParams;
import org.ow2.jonas.deployment.rar.xml.JonasActivationspec;
import org.ow2.jonas.deployment.rar.xml.JonasAdminobject;
import org.ow2.jonas.deployment.rar.xml.JonasConfigProperty;
import org.ow2.jonas.deployment.rar.xml.JonasConnectionDefinition;
import org.ow2.jonas.deployment.rar.xml.JonasConnector;
import org.ow2.jonas.deployment.rar.xml.JonasSecurityMapping;
import org.ow2.jonas.deployment.rar.xml.Messageadapter;
import org.ow2.jonas.deployment.rar.xml.Messagelistener;
import org.ow2.jonas.deployment.rar.xml.OutboundResourceadapter;
import org.ow2.jonas.deployment.rar.xml.PoolParams;
import org.ow2.jonas.deployment.rar.xml.RequiredConfigProperty;
import org.ow2.jonas.deployment.rar.xml.Resourceadapter;
import org.ow2.jonas.deployment.rar.xml.SecurityEntry;
import org.ow2.jonas.lib.naming.ComponentContext;
import org.ow2.jonas.lib.util.Base64;






/**
 * This class may be used to parse a resource adapter deployment descriptor and
 * generate the corresponding properties files for the jca service java
 * RAConfig -j jndiname -r rarlink -verbose
 * <input_rar>java org.ow2.jonas.generators.raconfig.RAConfig -u jonas-ra.xml
 * <input_rar>java org.ow2.jonas.generators.raconfig.RAConfig -dm -p db.properties
 * <input_rar><output_rar>
 */
public class RAConfig {

    /**
     * Buffer Size
     */
    private static final int BUFFER_SIZE = 500;

    /** JCA 1.5 */
    private static final double JCA_1_5 = 1.5;
    /** JCA 1.0 */
    private static final double JCA_1_0 = 1.0;

    RarDeploymentDesc rarDD = null;

    /**
     * Validate the XML
     */
    private static boolean validation = true;

    /**
     * jonas-ra.xml XML filename
     */
    private static final String JONAS_RA_FILENAME = "META-INF/jonas-ra.xml";

    /**
     * Constructor
     */
    public RAConfig(String fileName) throws RAConfigException {
        ClassLoader curLoader = Thread.currentThread().getContextClassLoader();

        try {
            RarDeploymentDescManager.setParsingWithValidation(validation);
            rarDD = getRarDD(fileName, curLoader);
        } catch (Exception e) {
            throw new RAConfigException(e);
        }

    }

    /**
     * Get an instance of an RAR deployment descriptor by parsing the ra.xml and
     * jonas-ra.xml deployment descriptors.
     * @param rarFileName the fileName of the rar file for the deployment
     *        descriptors.
     * @param classLoader the classloader for the classes.
     * @return an RAR deployment descriptor by parsing the ra.xml & jonas-ra.xml
     *         deployment descriptors.
     * @throws DeploymentDescException if the deployment descriptors are
     *         corrupted.
     */
    private RarDeploymentDesc getRarDD(String rarFileName, ClassLoader classLoader)
            throws DeploymentDescException {

        // The context to give for the creation of an instance
        // of RarDeploymentDesc
        Context contctx = null;
        try {
            contctx = new ComponentContext(rarFileName);
            contctx.rebind("rarFileName", rarFileName);
            contctx.rebind("classloader", classLoader);
        } catch (Exception e) {
            // An exception occurred trying to bind context
            //            logger.log(BasicLevel.ERROR, "Error when binding context for
            // RarDeploymentDesc for '" + rarFileName + "'");
            //            logger.log(BasicLevel.ERROR, e.getMessage());

            throw new RarDeploymentDescException("Error during the deployment", e);
        }
        // want both ra.xml & jonas-ra.xml
        return RarDeploymentDescManager.getInstance(contctx);
    }

    public RarDeploymentDesc getRarDeploymentDesc() {
        return rarDD;
    }

    /**
     * Process the ra.xml file in the input rar file and build the corresponding
     * jonas-ra.xml. If the -p argument is specified, then retrieve the
     * appropriate configuration values to pre-configure the corrsponding JDBC
     * RA config properties.
     * @param fileInputName String file name
     * @param jndiname String jndi name
     * @param rarlink String rar link
     * @param dbProps Properties
     * @param encrypt boolean
     * @param securityfile String security file
     * @param path String path
     * @param isVerbose boolean
     * @param createNew boolean
     * @throws RAConfigException if an Exception occurs
     */
    private static void buildXML(String fileInputName, String jndiname, String rarlink, Properties dbProps,
            boolean encrypt, String securityfile, String path,
            boolean isVerbose, boolean createNew) throws RAConfigException {

        // Check if jonas-ra.xml already exists and return it
        if (!createNew) {
            boolean ext = extractJonasRAXml(fileInputName, path);
            if (ext) {
                return;
            }
        }

        RAConfig raxml = new RAConfig(fileInputName);
        Connector conn = raxml.getRarDeploymentDesc().getConnector();
        double specVersion = 0.0;
        ConfigPropertyDesc[] raProps = raxml.getRarDeploymentDesc().getRaConfigPropTags();
        if (raProps == null) {
            throw new RAConfigException("RAR file doesn't contain ra.xml");
        }
        if (conn.getSpecVersion().equals("1.0")) {
            specVersion = JCA_1_0;
        } else if (conn.getSpecVersion().equals("1.5")) {
            specVersion = JCA_1_5;
        } else {
            throw new RAConfigException("ra.xml doesn't correct spec version");
        }

        JonasConnector jConn = new JonasConnector();
        PoolParams jPool = new PoolParams();
        JdbcConnParams jConnParams = new JdbcConnParams();
        JonasConfigProperty jCfg = null;

        String val = "";
        String str = "";
        jPool.setPoolInit("0");

        val = "0";
        if (dbProps.getProperty("jdbc.minconpool") != null && dbProps.getProperty("jdbc.minconpool").length() > 0) {
            val = dbProps.getProperty("jdbc.minconpool").trim();
        }
        jPool.setPoolMin(val);

        val = "-1";
        if (dbProps.getProperty("jdbc.maxconpool") != null && dbProps.getProperty("jdbc.maxconpool").length() > 0) {
            val = dbProps.getProperty("jdbc.maxconpool").trim();
        }
        jPool.setPoolMax(val);

        val = "0";
        if (dbProps.getProperty("jdbc.connmaxage") != null && dbProps.getProperty("jdbc.connmaxage").length() > 0) {
            val = dbProps.getProperty("jdbc.connmaxage").trim();
        }
        jPool.setPoolMaxAgeMinutes(val);

        jPool.setPstmtMax("10");

        val = "0";
        if (dbProps.getProperty("jdbc.maxopentime") != null && dbProps.getProperty("jdbc.maxopentime").length() > 0) {
            val = dbProps.getProperty("jdbc.maxopentime").trim();
        }
        jPool.setPoolMaxOpentime(val);

        val = "0";
        if (dbProps.getProperty("jdbc.maxwaiters") != null && dbProps.getProperty("jdbc.maxwaiters").length() > 0) {
            val = dbProps.getProperty("jdbc.maxwaiters").trim();
        }
        jPool.setPoolMaxWaiters(val);

        val = "0";
        if (dbProps.getProperty("jdbc.maxwaittime") != null && dbProps.getProperty("jdbc.maxwaittime").length() > 0) {
            val = dbProps.getProperty("jdbc.maxwaittime").trim();
        }
        jPool.setPoolMaxWaittime(val);

        val = "30";
        if (dbProps.getProperty("jdbc.samplingperiod") != null && dbProps.getProperty("jdbc.samplingperiod").length() > 0) {
            val = dbProps.getProperty("jdbc.samplingperiod").trim();
        }
        jPool.setPoolSamplingPeriod(val);

        val = "14";
        if (dbProps.getProperty("jdbc.pstmtmax") != null && dbProps.getProperty("jdbc.pstmtmax").length() > 0) {
            val = dbProps.getProperty("jdbc.pstmtmax").trim();
            jPool.setPstmtMax(val);
        }

        jConn.setLogEnabled("false");
        jConn.setLogTopic("");
        jConn.setNativeLib("");
        if (jndiname.length() == 0) {
            jndiname = dbProps.getProperty("datasource.name", "").trim();
        }

        val = "0";
        if (dbProps.getProperty("jdbc.connchecklevel") != null
                && dbProps.getProperty("jdbc.connchecklevel").length() > 0) {
            val = dbProps.getProperty("jdbc.connchecklevel").trim();
        }
        jConnParams.setJdbcCheckLevel(val);

        val = "";
        if (dbProps.getProperty("jdbc.connteststmt") != null && dbProps.getProperty("jdbc.connteststmt").length() > 0) {
            val = dbProps.getProperty("jdbc.connteststmt").trim();
            jConnParams.setJdbcTestStatement(val);
        }

        if (specVersion == JCA_1_0) {
            jConn.setJndiName(jndiname);
        }
        jConn.setRarlink(rarlink);
        jConn.setPoolParams(jPool);
        jConn.setJdbcConnParams(jConnParams);

        if (specVersion == JCA_1_0) {
            val = "";
            str = "";
            for (int i = 0; i < raProps.length; i++) {
                jCfg = new JonasConfigProperty();
                str = raProps[i].getConfigPropertyName();
                jCfg.setJonasConfigPropertyName(str);
                if (dbProps.size() > 0) {
                    val = getProp(dbProps, str);
                } else {
                    val = "";
                }
                jCfg.setJonasConfigPropertyValue(val);
                jConn.addJonasConfigProperty(jCfg);
            }
        } else if (specVersion == JCA_1_5) {
            Resourceadapter rAdapter = conn.getResourceadapter();
            ConfigProperty cProperty = null;
            // TODO rProperty never used !!!
            RequiredConfigProperty rProperty = null;
            // Process config properties if they exist
            for (Iterator i = rAdapter.getConfigPropertyList().iterator(); i.hasNext();) {
                cProperty = (ConfigProperty) i.next();
                jCfg = new JonasConfigProperty();
                str = cProperty.getConfigPropertyName();
                jCfg.setJonasConfigPropertyName(str);
                if (dbProps.size() > 0) {
                    val = getProp(dbProps, str);
                } else {
                    val = "";
                }
                jCfg.setJonasConfigPropertyValue(val);
                jConn.addJonasConfigProperty(jCfg);
            }

            // is it the first jonas-connection-definition
            boolean first = true;

            // Now process the outbound-resourceadapter
            OutboundResourceadapter oRes = rAdapter.getOutboundResourceadapter();
            if (oRes != null) {
                ConnectionDefinition cDef = null;
                JonasConnectionDefinition jcDef = null;
                for (Iterator it = oRes.getConnectionDefinitionList().iterator(); it.hasNext();) {
                    cDef = (ConnectionDefinition) it.next();
                    jcDef = new JonasConnectionDefinition();
                    jcDef.setId(cDef.getId());
                    jcDef.addDescription(cDef.getManagedconnectionfactoryClass());

                    // This allows the jndi name to be set for the first jonas-connection-definition
                    // with a 1.5 version of the connector.
                    if (first && (jndiname.length() != 0)) {
                        jcDef.setJndiName(jndiname);
                        first = false;
                    } else {
                        jcDef.setJndiName("");
                    }

                    for (Iterator i = cDef.getConfigPropertyList().iterator(); i.hasNext();) {
                        cProperty = (ConfigProperty) i.next();
                        jCfg = new JonasConfigProperty();
                        str = cProperty.getConfigPropertyName();
                        jCfg.setJonasConfigPropertyName(str);
                        jCfg.setJonasConfigPropertyValue("");
                        jcDef.addJonasConfigProperty(jCfg);
                    }
                    jConn.addJonasConnectionDefinition(jcDef);
                }
            }
            // Now process the inbound-resourceadapter
            InboundResourceadapter iRes = rAdapter.getInboundResourceadapter();
            if (iRes != null) {
                Messageadapter mAdapter = iRes.getMessageadapter();
                if (mAdapter != null) {
                    Messagelistener mList = null;
                    JonasActivationspec jaSpec = null;
                    Activationspec aSpec = null;
                    for (Iterator it = mAdapter.getMessagelistenerList().iterator(); it.hasNext();) {
                        mList = (Messagelistener) it.next();
                        aSpec = mList.getActivationspec();
                        if (aSpec != null) {
                            jaSpec = new JonasActivationspec();
                            jaSpec.setId(mList.getId());
                            jaSpec.addDescription(mList.getMessagelistenerType());
                            jaSpec.setJndiName("");
                            jConn.addJonasActivationspec(jaSpec);
                        }
                    }
                }
            }
            // Now process the adminobject
            for (Iterator it = rAdapter.getAdminobjectList().iterator(); it.hasNext();) {
                Adminobject aObj = (Adminobject) it.next();
                JonasAdminobject jaObj = null;
                if (aObj != null) {
                    jaObj = new JonasAdminobject();
                    jaObj.setId(aObj.getId());
                    jaObj.addDescription(aObj.getAdminobjectClass());
                    jaObj.setJndiName("");
                    // Process config properties if they exist
                    for (Iterator i = aObj.getConfigPropertyList().iterator(); i.hasNext();) {
                        cProperty = (ConfigProperty) i.next();
                        jCfg = new JonasConfigProperty();
                        str = cProperty.getConfigPropertyName();
                        jCfg.setJonasConfigPropertyName(str);
                        jCfg.setJonasConfigPropertyValue("");
                        jaObj.addJonasConfigProperty(jCfg);
                    }
                    jConn.addJonasAdminobject(jaObj);
                }
            }
        }

        if (securityfile != null) {
            Properties secProps = new Properties();
            File f = null;
            try {
                f = new File(securityfile);
                FileInputStream is = new FileInputStream(f);
                secProps.load(is);
            } catch (FileNotFoundException e) {
                System.err.println("Cannot find security properties file: " + securityfile);
                System.err.println("Continuing with creation of jonas-ra.xml");
            } catch (IOException e) {
                System.err.println(e);
            }

            JonasSecurityMapping jsMap = new JonasSecurityMapping();
            String pName = null;
            String user = null;
            String pass = null;
            String tmp = null;
            int offset = 0;
            SecurityEntry sEnt = null;
            for (Enumeration e = secProps.propertyNames(); e.hasMoreElements();) {
                pName = (String) e.nextElement();
                tmp = secProps.getProperty(pName);
                offset = tmp.indexOf("::");
                if (offset < 0) {
                    System.err.println("Error in format of file:  principalName = user::password");
                    continue;
                }
                user = tmp.substring(0, offset);
                pass = tmp.substring(offset + 2);

                sEnt = new SecurityEntry();
                sEnt.setPrincipalName(pName);
                sEnt.setUser(user);
                if (encrypt) {
                    try {
                        pass = new String(Base64.encode(pass.getBytes()));
                        sEnt.setEncrypted("" + encrypt);
                    } catch (Exception ex) {
                        System.err.println("Unable to encrypt the password.");
                    }
                }
                sEnt.setPassword(pass);
                jsMap.addSecurityEntry(sEnt);
            }
            jConn.setJonasSecurityMapping(jsMap);
        }

        try {
            String tmpDir = path;
            if (path.length() == 0) {
                tmpDir = System.getProperty("java.io.tmpdir");
            }
            String fileName = tmpDir;
            int fileLen = fileName.length();
            if (fileName.charAt(fileLen-1) != File.separatorChar) {
                fileName += File.separatorChar;
            }
            fileName += "jonas-ra.xml";
            FileWriter fw = new FileWriter(fileName);
            fw.write(jConn.toXML());
            fw.close();
            if (isVerbose) {
                System.out.println("Build Jonas Specific DD File '" + fileName + "' OK");
            }

        } catch (Exception e) {
            throw new RAConfigException("Error writing output", e);
        }
    }

    /**
     * Mapping routine for the JDBC RA config values and the existing
     * <DB>.properties values.
     * @param prop Properties
     * @param str String
     * @return String
     */
    private static String getProp(Properties prop, String str) {
        //                     ra-keys          | properties-keys
        String[][] mapping = {{"connCheckLevel", "jdbc.connchecklevel"},
                              {"connMaxAge", "jdbc.connmaxage"},
                              {"connTestStmt", "jdbc.connteststmt"},
                              {"URL", "datasource.url"},
                              {"dsClass", "datasource.classname"},
                              {"user", "datasource.username"},
                              {"password", "datasource.password"},
                              {"isolationLevel", "datasource.isolationlevel"},
                              {"mapperName", "datasource.mapper"}, };

        String ret = "";
        for (int i = 0; i < mapping.length; i++) {
            if (mapping[i][0].equalsIgnoreCase(str)) {
                String value = prop.getProperty(mapping[i][1]);
                if (value == null) {
                    ret = "";
                } else {
                    ret = value.trim();
                }
            }
        }

        return ret;
    }

    /**
     * Update the RAR file
     * @param infile String input RAR file
     * @param outfile String output RAR file
     * @param updatename String update file
     * @param rarlink String RAR link
     * @throws RAConfigException to throw if an Exception occurs
     */
    private static void updateRAR(String infile, String outfile, String updatename, String rarlink)
            throws RAConfigException {

        ZipOutputStream zipOutput = null;
        ZipFile zipFile = null;
        Enumeration zippedFiles = null;
        ZipEntry currEntry = null;
        ZipEntry entry = null;
        byte[] buffer = new byte[BUFFER_SIZE];
        int num = 0;

        String filename = infile;
        String outfilename = infile;
        boolean outNew = false;
        if (outfile != null && outfile.length() != 0) {
            outfilename = outfile;
            outNew = true;
        }

        try {
            File file = new File(filename);
            if (file.exists()) {
                zipFile = new ZipFile(file.getAbsolutePath());
                //get an enumeration of all existing entries
                zippedFiles = zipFile.entries();
                //create your output zip file
                if (!outNew) {
                    zipOutput = new ZipOutputStream(new FileOutputStream(new File(file.getAbsolutePath() + "NEW")));
                } else {
                    File ofile = new File(outfilename);
                    if (ofile.exists()) {
                        ofile.delete();
                    }

                    zipOutput = new ZipOutputStream(new FileOutputStream(new File(outfilename)));
                }
                //Get all the data out of the previously zipped files and
                // write
                // it to a new ZipEntry to go into a new file archive
                if ((outfile == null || outfile.length() == 0) && rarlink.length() == 0) {
                    while (zippedFiles.hasMoreElements()) {
                        //Retrieve entry of existing files
                        currEntry = (ZipEntry) zippedFiles.nextElement();
                        if (currEntry.getName().equalsIgnoreCase(JONAS_RA_FILENAME)) {
                            continue;
                        }
                        //Read data from existing file
                        zipOutput.putNextEntry(new ZipEntry(currEntry.getName()));
                        InputStream reader = zipFile.getInputStream(currEntry);
                        while ((num = reader.read(buffer)) != -1) {
                            zipOutput.write(buffer, 0, num);
                        }
                        //Commit the data
                        zipOutput.flush();
                        zipOutput.closeEntry();
                    }
                }
                //Close the old zip file
                zipFile.close();

                //Write the 'new' file to the archive, commit, and close
                entry = new ZipEntry(JONAS_RA_FILENAME);
                zipOutput.putNextEntry(entry);

                //Read data from existing file
                try {
                    BufferedReader reader = new BufferedReader(new FileReader(updatename));
                    int ch = 0;
                    while ((ch = reader.read()) != -1) {
                        zipOutput.write(ch);
                    }
                } catch (Exception ex) {
                    System.out.println("Error reading input file: " + updatename + " " + ex);
                    //Commit the data
                    zipOutput.flush();
                    zipOutput.closeEntry();
                    zipOutput.finish();
                    zipOutput.close();
                }
                //Commit the data
                zipOutput.flush();
                zipOutput.closeEntry();
                zipOutput.finish();
                zipOutput.close();

                if (!outNew) {
                    //delete the old file and rename the new one
                    File toBeDeleted = new File(file.getAbsolutePath());
                    toBeDeleted.delete();
                    File toBeRenamed = new File(file.getAbsolutePath() + "NEW");
                    toBeRenamed.renameTo(file);
                }
            } else {
                //create your output zip file
                zipOutput = new ZipOutputStream(new FileOutputStream(new File(outfilename)));

                //Write the file to the archive, commit, and close
                entry = new ZipEntry(JONAS_RA_FILENAME);
                zipOutput.putNextEntry(entry);
                //Read data from existing file
                BufferedReader reader = new BufferedReader(new FileReader(updatename));
                int ch = 0;
                while ((ch = reader.read()) != -1) {
                    zipOutput.write(ch);
                }

                //Commit the data
                zipOutput.flush();
                zipOutput.closeEntry();
                zipOutput.finish();
                zipOutput.close();
            }
            // finally, we delete generated jonas-ra.xml
            new File(updatename).delete();
        } catch (Exception ex) {
            throw new RAConfigException(ex);
        }

    }

    /**
     * Extract the jonas-ra.xml file if it exists in the rar
     *
     * @param infile String rar file name
     * @param path String path
     */
    private static boolean extractJonasRAXml(String infile, String path) {
        ZipFile zipFile = null;
        ZipEntry entry = null;
        byte[] buffer = new byte[BUFFER_SIZE];

        String filename = infile;
        File file = new File(filename);
        if (file.exists()) {
            try {
                zipFile = new ZipFile(file.getAbsolutePath());
                entry = zipFile.getEntry(JONAS_RA_FILENAME);
                if (entry != null) {
                    InputStream input = zipFile.getInputStream(entry);
                    String tmpDir = path;
                    if (path.length() == 0) {
                        tmpDir = System.getProperty("java.io.tmpdir");
                    }
                    String fileName = tmpDir;
                    int fileLen = fileName.length();
                    if (fileName.charAt(fileLen-1) != File.separatorChar) {
                        fileName += File.separatorChar;
                    }
                    fileName += "jonas-ra.xml";

                    FileOutputStream output = new FileOutputStream( fileName );
                    for ( int j = 0 ; ;  ) {
                        int length = input.read( buffer );
                        if ( length <= 0 )
                            break;
                        output.write( buffer, 0, length );
                    }
                    output.close();
                    return true;
                }
            } catch (Exception ex) {
                return false;
            }
        }
        return false;
    }

    /**
     * Usage of RAConfig
     *
     */
    public static void usage() {
        System.out.println("");
        System.out.println("Usage: java org.ow2.jonas.generators.raconfig.RAConfig <Options> <Input_File> [Output_File]");
        System.out.println("     to generate the jonas-ra.xml file for a Resource Adapter.");
        System.out.println("   The output file will be written to the default location of the java ");
        System.out.println("     system property 'java.io.tmpdir' unless the -path parameter is specified");
        System.out.println("");
        System.out.println("   Note: for a parameter either the whole name must be used or only the");
        System.out.println("         the capital letters, e.g.  -jndiname or -j are equivalent");
        System.out.println("");
        System.out.println("       With Options:");
        System.out.println("         -? or -help                print this help message");
        System.out.println("         -DM,-DS,-CP,-XA            DriverManager, Datasource, ConnectionPoolDatasource,");
        System.out.println("                                    XAConnection only used with -p.  Additional");
        System.out.println("                                    user configuration of the jonas-ra.xml file");
        System.out.println("                                    will be necessary for any option but -DM.");
        System.out.println("         -Jndiname <jndiname>       specifies the jndiname RA");
        System.out.println("         -Property <property file>  specifies the database property file");
        System.out.println("                                     to process");
        System.out.println("         -Rarlink <rarlink>         specifies the rar file to link to");
        System.out.println("         -Update <input name>       update the input rar with the specified file");
        System.out.println("                                    unless an output_file named is specified");
        System.out.println("         -ENcrypt                   used with -sf to encrypt the passwords ");
        System.out.println("         -SecurityFile              security xml file to add to jonas-ra.xml ");
        System.out.println("         -Verbose                   output the contents of the  deployment descriptor ");
        System.out.println("         -NoValidation              turn off xml dtd/schema validation ");
        System.out.println("         -PATH <path>               path where jonas-ra.xml should be written to ");
        System.out.println("                                     default is System.property('java.io.tmpdir')");
        System.out.println("         -NEW                       don't extract jonas-ra.xml create a new one ");
        System.out.println("");
        System.out.println("       Input_File     Resource Adapter RAR file");
        System.out.println("       Output_File    Resource Adapter RAR file only used with ");
        System.out.println("                          -p(required) or -u(optional)");
        System.out.println("");
    }

    // Main Method
    /**
     * Main routine
     * @param args String [] input arguments
     * @throws RAConfigException if an Exception occurs
     */
    public static void main(String[] args) throws RAConfigException {
        boolean isHelp = false;
        boolean isVerbose = false;
        boolean doProperty = false;
        boolean doUpdate = false;
        boolean encrypt = false;
        boolean newXml = false;
        String fileInputName = null;
        String fileOutputName = null;
        String securityfile = null;
        String jndiname = "";
        String rarlink = "";
        String updatename = "";
        String jdbcRarLink = "";
        String jonasRarStr = "JOnASJDBC_";
        String propertyFile = "";
        String path = "";
        // Get command args

        Properties dbProps = null;

        if (args.length < 1) {
            isHelp = true;
        }
        for (int argn = 0; argn < args.length; argn++) {
            String arg = args[argn].toLowerCase();
            if (arg.equals("-help") || arg.equals("-?")) {
                isHelp = true;
                continue;
            }
            if (arg.equals("-verbose") || arg.equals("-v")) {
                isVerbose = true;
                continue;
            }
            if (arg.equals("-encrypt") || arg.equals("-en")) {
                encrypt = true;
                continue;
            }
            if (arg.equals("-securityfile") || arg.equals("-sf")) {
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -sf input");
                }
                securityfile = args[argn];
                continue;
            }
            if (arg.equals("-novalidation") || arg.equals("-nv")) {
                validation = false;
                continue;
            }
            if (arg.equals("-update") || arg.equals("-u")) {
                doUpdate = true;
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -u input");
                }
                updatename = args[argn];
                continue;
            }
            if (arg.equals("-jndiname") || arg.equals("-j")) {
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -j input");
                }
                jndiname = args[argn];
                continue;
            }
            if (arg.equals("-rarlink") || arg.equals("-r")) {
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -r input");
                }
                rarlink = args[argn];
                continue;
            }
            if (arg.equals("-property") || arg.equals("-p")) {
                doProperty = true;
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -p input");
                }
                propertyFile = args[argn];
                continue;
            }
            if (arg.equals("-dm")) {
                jdbcRarLink = jonasRarStr + "DM";
                continue;
            }
            if (arg.equals("-ds")) {
                jdbcRarLink = jonasRarStr + "DS";
                continue;
            }
            if (arg.equals("-xa")) {
                jdbcRarLink = jonasRarStr + "XA";
                continue;
            }
            if (arg.equals("-cp")) {
                jdbcRarLink = jonasRarStr + "CP";
                continue;
            }
            if (arg.equals("-path")) {
                if (argn + 1 == args.length || args[++argn].startsWith("-")) {
                    usage();
                    throw new RAConfigException("Error with -path");
                }
                path = args[argn];
                continue;
            }
            if (arg.equals("-new")) {
                newXml = true;
                continue;
            }
            if (fileInputName == null) {
                fileInputName = args[argn];
                if (!fileInputName.endsWith(".rar")) {
                    fileInputName += ".rar";
                }
            } else if (doProperty || doUpdate) {
                if (fileOutputName == null) {
                    fileOutputName = args[argn];
                    if (!fileOutputName.endsWith(".rar")) {
                        fileOutputName += ".rar";
                    }
                }
            } else {
                usage();
                throw new RAConfigException("Error multiple input files specified without -property or -update");
            }
        }

        // Usage ?
        if (isHelp) {
            usage();
            System.exit(0);
        }
        if (fileInputName == null) {
            usage();
            throw new RAConfigException("Error missing input file");
        }
        if (doProperty && fileOutputName == null) {
            usage();
            throw new RAConfigException("Error missing output file");
        }
        if (fileInputName.equals(fileOutputName)) {
            throw new RAConfigException("Input and Output filenames cannot be the same");
        }

        dbProps = new Properties();
        if (doProperty) {
            if (jdbcRarLink.length() > 0 && rarlink.length() == 0) {
                rarlink = jdbcRarLink;
            }
            try {
                dbProps.load(new FileInputStream(propertyFile));
            } catch (Exception ex) {
                if (propertyFile.endsWith(".properties")) {
                    System.out.println("Error reading " + propertyFile + " " + ex);
                } else {
                    try {
                        dbProps.load(new FileInputStream(propertyFile + ".properties"));
                    } catch (Exception ex1) {
                        System.out.println("Error reading " + propertyFile + " " + ex);
                    }
                }
            }
            buildXML(fileInputName, jndiname, rarlink, dbProps, encrypt, securityfile, path, isVerbose, true);
            if (updatename.length() == 0) {
                updatename = System.getProperty("java.io.tmpdir") + File.separator + "jonas-ra.xml";
            }
            updateRAR(fileInputName, fileOutputName, updatename, rarlink);
        } else if (doUpdate) {
            updateRAR(fileInputName, fileOutputName, updatename, rarlink);
        } else {
            buildXML(fileInputName, jndiname, rarlink, dbProps, encrypt, securityfile, path, isVerbose, newXml);
        }
    }
}
