stg.pr.engine.startstop.CStartEngine.java Source code

Java tutorial

Introduction

Here is the source code for stg.pr.engine.startstop.CStartEngine.java

Source

/**
 * Copyright (c) 2014 Mastek Ltd. All rights reserved.
 * 
 * This file is part of JBEAM. JBEAM 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.
 *
 * JBEAM 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 the specific language governing permissions and 
 * limitations.
 *
 *
 * $Revision: 3320 $
 *
 * $Header: http://172.16.209.156:8080/svn/ProductTools/JavaTools/AdvancedPRE/trunk/src/stg/pr/engine/startstop/CStartEngine.java 1419 2010-06-15 03:27:43Z kedar $
 *
 * $Log: /Utilities/PRE/src/stg/pr/engine/startstop/CStartEngine.java $
 * 
 * 11    11/11/09 3:16p Kedarr
 * Changes made to identify the java version to 1 point 6.
 * 
 * 10    9/01/09 8:27a Kedarr
 * Removed un-necessary null check and removed the poolconfig file
 * parameter as now this is being stored in pr.properties.
 * 
 * 9     2/04/09 1:15p Kedarr
 * Added static keyword to a final variable.
 * 
 * 8     9/15/08 10:06a Kedarr
 * Changes made for:
 * 1. Enabling and Disabling of log4j logger so that the same properties
 * can be used for both the processes.
 * 2. Reading the JVM properties for PRE through the pr.properties file.
 * 
 * 7     6/20/08 5:06p Kedarr
 * Changes are made to supress an exception that might be caused due to
 * the closing of stream. The error/exception is printed as a warning and
 * only if the loglevel is set to finest.
 * 
 * 6     4/07/08 2:23p Kedarr
 * Changed the Revision from private to public and thus avoid the method
 * getVersion() or showVersion().
 * 
 * 5     3/22/08 12:32a Kedarr
 * Removed the static keyword from the REVISION variable and made it
 * private. In case of interfaces made it as public.
 * 
 * 4     3/22/08 12:14a Kedarr
 * Added REVISION variable.
 * 
 * 3     6/06/06 2:36p Kedarr
 * Implemented interface IStartStop which is a marker interface.
 * 
 * 2     6/06/06 2:35p Kedarr
 * Updated javadoc.
 * 
 * 1     6/01/06 1:05p Kedarr
 * The PRE Controller. Class responsible to start, reboot, bounce and
 * shutdown the PRE.
 * 
 */
package stg.pr.engine.startstop;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import stg.utils.CSettings;

import com.stg.logger.LogLevel;

/**
 * Process Request Engine Controller.
 * 
 * This class is responsible for starting the PRE, rebooting / bouncing the PRE.
 * 
 * @version $Revision: 3320 $
 * @author kedarr
 * @since 23.00
 * 
 */
public class CStartEngine implements IStartStop {

    /**
     * Stores the REVISION number of the class from the configuration management
     * tool.
     */
    public static final String REVISION = "$Revision:: 3320              $";

    /**
     * Stores the maximum reboot counter. Comment for
     * <code>iRebootMaxCounter_</code>.
     */
    private int iRebootMaxCounter_;

    /**
     * Stores the sleep time in between reboots. Comment for
     * <code>lRebootSleepTime_</code>.
     */
    private long lRebootSleepTime_;

    /**
     * Stores the current reboot counter. Comment for
     * <code>iRebootCounter_</code>.
     */
    private int iRebootCounter_;

    /**
     * Defines REBOOT mode. Comment for <code>REBOOT</code>.
     */
    public final static String REBOOT = "Reboot";

    /**
     * Defines the BOUNCE mode. Comment for <code>BOUNCE</code>.
     */
    public final static String BOUNCE = "Bounce";

    /**
     * Defines the SHUTDOWN mode. Comment for <code>SHUTDOWN</code>.
     */
    public final static String SHUTDOWN = "Shutdown";

    /**
     * OS related FILE SEPARATOR. Comment for <code>FILE_SEPARATOR</code>.
     */
    final String FILE_SEPARATOR = System.getProperty("file.separator");

    /**
     * Stores the log4j logger. Comment for <code>logger_</code>.
     */
    private Logger logger_ = null;

    //    /**
    //     * Format for logger pattern layout.
    //     */
    //    private final String LOG4J_LAYOUT_PATTERN = "<%d{EEEE MMM dd, yyyy HH:mm:ss:SSS}><%p><%t><%c>%m%n";

    private String strLog4jFile_;

    /**
     * Constructor.
     * 
     * @param log4jFile
     *            Log4j configuration file.
     * @throws IOException
     * @throws FileNotFoundException
     * 
     */
    public CStartEngine(String log4jFile) throws FileNotFoundException, IOException {
        super();
        strLog4jFile_ = log4jFile;
        enableLog4j();
        if (logger_.isEnabledFor(LogLevel.FINE)) {
            logger_.log(LogLevel.FINE, "Initializing");
        }
    }

    /**
     * Main method.
     * 
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        CStartEngine engine = new CStartEngine(args[1]);
        engine.start(args);
    }

    /**
     * Starts the controller.
     * 
     * Method responsible to handle start, reboot, shutdown of PRE.
     * 
     * @param args
     */
    public void start(String[] args) {
        if (logger_.isEnabledFor(LogLevel.FINE)) {
            logger_.log(LogLevel.FINE, "Initialized.");
        }
        if (!SystemUtils.IS_JAVA_1_6) {
            logger_.log(LogLevel.NOTICE, "Unable to start. Requires Java 1.6");
            return;
        }

        boolean bStart = true;
        String[] cmd = null;
        while (bStart) {
            CSettings settings = null;
            ErrReader errReader = null;
            OutReader outReader = null;
            Process process = null;
            try {
                if (logger_.isEnabledFor(LogLevel.FINER)) {
                    logger_.log(LogLevel.FINER, "Loading Runtime settings.");
                }
                settings = CSettings.getInstance();
                settings.load(args[0]);
                try {
                    iRebootMaxCounter_ = Integer.parseInt(CSettings.get("pr.rebootmaxcounter", "-1"));
                    lRebootSleepTime_ = Long.parseLong(CSettings.get("pr.sleepbeforereboottime", "5"));

                } catch (NumberFormatException e) {
                    logger_.fatal("Please check the properties 'rebootmaxcounter' and 'sleepbeforereboottime' ", e);
                    throw e;
                }
                if (cmd == null) {
                    cmd = buildCommand(null, args);
                }
                if (logger_.isEnabledFor(LogLevel.FINE)) {
                    logger_.log(LogLevel.FINE, "Starting Engine...");
                }
                disableLog4j();
                process = Runtime.getRuntime().exec(cmd);
                BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()));
                BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                outReader = new OutReader(out);
                errReader = new ErrReader(err);
                outReader.setFlag("");
                errReader.setFlag("");
                outReader.start();
                errReader.start();

                if (outReader != null) {
                    outReader.waitForDone();
                }
                if (errReader != null) {
                    errReader.waitForDone();
                }
                outReader.shutdown();
                errReader.shutdown();
                out.close();
                err.close();
                process.waitFor();
                enableLog4j();
                Properties properties = getMessageFromPRE();
                String strAction = properties.getProperty("action");
                if (logger_.isEnabledFor(LogLevel.FINEST)) {
                    logger_.log(LogLevel.FINEST, "Action initiated #" + strAction);
                }
                if (strAction.equals(REBOOT)) {
                    ArrayList<String> list = new ArrayList<String>();
                    if (Integer.parseInt(properties.getProperty("counter")) <= 0) {
                        iRebootCounter_ = 1;
                    } else {
                        iRebootCounter_++;
                    }
                    if (iRebootCounter_ > iRebootMaxCounter_) {
                        logger_.log(LogLevel.NOTICE,
                                iRebootCounter_ + " Re-boot attempt(s) failed to start the engine");
                        bStart = false; // shutdown
                    }
                    if (bStart) {
                        list.add("-Dpre.reboot.attempt=" + iRebootCounter_);
                        sleep(lRebootSleepTime_,
                                "Re-booting the Engine after a wait of " + lRebootSleepTime_ + " minute(s).");
                        cmd = buildCommand(list, args);
                    }
                } else if (strAction.equals(BOUNCE)) {
                    logger_.log(LogLevel.NOTICE, "Process Request Engine has CRASHED. The PRE will be bounced. ");
                    logger_.log(LogLevel.NOTICE, "Bouncing the engine");
                    iRebootCounter_ = 0;
                    sleep(lRebootSleepTime_,
                            "Bouncing the Engine after a wait of " + lRebootSleepTime_ + " minute(s).");
                } else if (strAction.equals(SHUTDOWN)) {
                    if (iRebootCounter_ > iRebootMaxCounter_) {
                        logger_.log(LogLevel.NOTICE,
                                iRebootCounter_ + " Re-boot attempt(s) failed to start the engine");
                    }
                    if (logger_.isEnabledFor(LogLevel.FINE)) {
                        logger_.log(LogLevel.FINE, "Shuting down the controller.");
                    }
                    bStart = false;
                }
            } catch (IOException e) {
                bStart = false;
            } catch (InterruptedException e) {
                bStart = false;
            } finally {
                if (settings != null) {
                    enableLog4j();
                    if (logger_.isEnabledFor(LogLevel.FINEST)) {
                        logger_.log(LogLevel.FINEST, "Destroying Runtime settings.");
                    }
                    settings.destroy();
                }
                // if (process != null) {
                // process.destroy();
                // }
            }
        } // end of while
        if (logger_.isEnabledFor(LogLevel.FINE)) {
            logger_.log(LogLevel.FINE, "Shutdown complete.");
        }
        disableLog4j();
    }

    /**
     * Sleeps for the specified time.
     * 
     * @param time
     * @param message
     *            Message to be logged.
     */
    public void sleep(long time, String message) {
        try {
            logger_.log(LogLevel.NOTICE, message);
            TimeUnit.MINUTES.sleep(time);
            //            Thread.sleep(time);
        } catch (InterruptedException e) {
            // do nothing
        }

    }

    /**
     * Command builder.
     * 
     * @param extraCommands
     *            if any
     * @param args
     *            Program arguments for PRE.
     * @return Command
     */
    public String[] buildCommand(ArrayList<String> extraCommands, String[] args) {
        long lCurrentTimestamp = System.currentTimeMillis();
        ArrayList<String> commandBuilder = new ArrayList<String>();
        if (logger_.isEnabledFor(LogLevel.FINER)) {
            logger_.log(LogLevel.FINER, "Building command.");
        }
        commandBuilder.add(System.getProperty("java.home") + FILE_SEPARATOR + "bin" + FILE_SEPARATOR + "java");
        if (CSettings.get("pr.javaruntimevmargs", null) != null) {
            // following code is to handle the space delimiter within double
            // quotes. Example value for this property
            // can be =-Xms128M -Xmx128M -D.pre.home="/u0201/apps/stg pre"
            StringCharacterIterator sci = new java.text.StringCharacterIterator(
                    CSettings.get("pr.javaruntimevmargs"));
            boolean bEscapeCharacter = false;
            boolean bQuoted = false;
            StringBuffer cmdBuffer = new StringBuffer();
            for (char c = sci.first(); c != CharacterIterator.DONE; c = sci.next()) {
                switch (c) {
                case '\\':
                    if (bEscapeCharacter) {
                        cmdBuffer.append(c + "" + c);
                        bEscapeCharacter = false;
                    } else {
                        bEscapeCharacter = true;
                    }
                    break;
                case ' ':
                    if (!bQuoted) {
                        commandBuilder.add(cmdBuffer.toString());
                        cmdBuffer.delete(0, cmdBuffer.length());
                    } else {
                        cmdBuffer.append(c);
                    }
                    bEscapeCharacter = false;
                    break;
                case '"':
                    if (!bEscapeCharacter) {
                        if (!bQuoted) {
                            bQuoted = true;
                        } else {
                            bQuoted = false;
                        }
                    }
                    bEscapeCharacter = false;
                    break;
                default:
                    cmdBuffer.append(c);
                    break;
                } // end of switch case.
            } // end for string character iterator
            if (cmdBuffer.length() > 0) {
                commandBuilder.add(cmdBuffer.toString());
            }
        } // pr.javaruntimevmarg != null
        if (extraCommands != null) {
            if (logger_.isEnabledFor(LogLevel.FINEST)) {
                logger_.log(LogLevel.FINEST, "Adding extra commands if any.");
            }
            commandBuilder.addAll(extraCommands);
        }
        if (logger_.isEnabledFor(LogLevel.FINER)) {
            logger_.log(LogLevel.FINER, "Adding constants.");
        }
        commandBuilder.add("-classpath");
        String classpath = "";
        //        if (CSettings.get("pr.reportService","OFF").equalsIgnoreCase("ON")) {
        //           File directory = new File(CSettings.get("pr.birt.home") + "/lib");
        //           if (!directory.exists()) {
        //              throw new IllegalArgumentException("Directory is non-existant. Check property birt.home " + CSettings.getInstance().getSource("pr").getConfigFile().getAbsolutePath());
        //           }
        //           ArrayList<String> list = new ArrayList<String>();
        //           list.add(".jar");
        //           list.add(".zip");
        //           classpath = getExtraClasspath(directory, list);
        //           System.out.println(classpath);
        //        }
        if (CSettings.get("pr.javaextraclasspath", null) != null) {
            commandBuilder.add(System.getProperty("java.class.path") + File.pathSeparatorChar
                    + CSettings.get("pr.javaextraclasspath") + File.pathSeparatorChar + classpath);
        } else {
            commandBuilder.add(System.getProperty("java.class.path") + File.pathSeparatorChar + classpath);
        }
        commandBuilder.add("stg.pr.engine.CProcessRequestEngine");
        commandBuilder.add(args[0]);
        commandBuilder.add(args[1]);
        String[] cmd = new String[commandBuilder.size()];
        commandBuilder.toArray(cmd);
        if (logger_.isEnabledFor(LogLevel.FINEST)) {
            logger_.log(LogLevel.FINEST, "Command " + commandBuilder);
            logger_.log(LogLevel.FINEST, "Elapsed Time taken to build command "
                    + (System.currentTimeMillis() - lCurrentTimestamp) + " ms.");
        }
        return cmd;
    } // end of buildCommand(..)

    /**
     * Reads messsage from PRE.
     * 
     * @return Properties.
     */
    private Properties getMessageFromPRE() {
        logger_.log(LogLevel.FINEST, "Reading message method start.");
        String strTmpDir = System.getProperty("java.io.tmpdir");
        String strFileSeparator = System.getProperty("file.separator");
        if (!strTmpDir.endsWith(strFileSeparator)) {
            strTmpDir = strTmpDir + strFileSeparator;
        }
        File file = new File(strTmpDir + "pre.ini");
        FileInputStream fis = null;
        Properties properties = new Properties();
        try {
            fis = new FileInputStream(file);
            properties.load(fis);
        } catch (FileNotFoundException e) {
            logger_.log(LogLevel.FINEST, "FNFE. Unable to read the message.");
        } catch (IOException e) {
            logger_.log(LogLevel.FINEST, "IOE. Unable to read the message.");
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    // dummy
                }
            }
        }
        if (properties.size() == 0) {
            properties.setProperty("action", "Shutdown");
            properties.setProperty("attempt", "0");
        }
        if (!file.delete()) {
            logger_.log(LogLevel.FINEST, "Unable to delete file #" + file.getName());
        }
        logger_.log(LogLevel.FINEST, "Reading message method end.");
        return properties;
    } // end of getMessageFromPRE()

    /**
     * Helper base class for both STDOUT and STDERR Readers.
     */
    private class Reader extends Thread {

        private boolean _isRunning = true;

        private String _flag = null;

        public Reader(String name) {
            super(name);
        }

        public synchronized void setFlag(String flag) {
            _flag = flag;
            notifyAll();
        }

        public synchronized void waitForDone() throws InterruptedException {
            while (_flag != null) {
                wait();
            }
        }

        public synchronized void shutdown() {
            _isRunning = false;
            setFlag(null);
            interrupt();
        }

        public synchronized boolean isRunning() {
            return _isRunning;
        }

    } // End of class Reader

    /**
     * Helper class for reading the STDOUT reader on the Command. The thread is
     * tiggered to start reading when setCommand(command) is called, after
     * completion is calls setCommand(null) it notify that it is done..
     * 
     * The main caller thread will wait for the setCommand(null) trigger until
     * it continues and a new caller can run.
     */
    private class OutReader extends Reader {

        private BufferedReader reader;

        public OutReader(BufferedReader reader) {
            super("OutReader");
            this.reader = reader;
        }

        public void run() {
            try {
                while (isRunning()) {
                    try {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            System.out.println(line);
                        } // end while
                    } catch (InterruptedIOException e) {
                        // do not log as it is bound to come on interrupt.
                    } catch (IOException e) {
                        enableLog4j();
                        if (logger_.isEnabledFor(LogLevel.FINEST)) {
                            logger_.warn("Exception occured while reading OUT", e);
                        }
                    }
                    setFlag(null);
                } // end while
            } catch (Throwable t) {
                enableLog4j();
                if (logger_.isEnabledFor(LogLevel.FINEST)) {
                    logger_.warn("Exception occured while reading OUT", t);
                }
            }
        }

    } // End of class OutReader

    /**
     * Helper class for reading the STDERR reader on the Command.
     * 
     * The thread is triggered to start reading when setCommand(command) is
     * called, after completion is calls setCommand(null) it notify that it is
     * done..
     * 
     * The main caller thread will wait for the setCommand(null) trigger until
     * it continues and a new caller can run.
     */
    private class ErrReader extends Reader {

        /**
         * Stores the REVISION number of the class from the configuration
         * management tool.
         */

        private BufferedReader reader;

        public ErrReader(BufferedReader reader) {
            super("ErrReader");
            this.reader = reader;
        }

        public void run() {
            try {
                while (isRunning()) {
                    try {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            System.err.println(line);
                        }
                    } catch (InterruptedIOException e) {
                        // do not log as it is bound to come on interrupt.
                    } catch (IOException e) {
                        enableLog4j();
                        if (logger_.isEnabledFor(LogLevel.FINEST)) {
                            logger_.warn("Exception occured while reading OUT", e);
                        }
                    }
                    setFlag(null);
                }
            } catch (Throwable t) {
                enableLog4j();
                if (logger_ != null) {
                    if (logger_.isEnabledFor(LogLevel.FINEST)) {
                        logger_.warn("Exception occured while reading ERR", t);
                    }
                }
            }
        }
    } // End of class ErrReader

    /**
     * Enables the log4j logger.
     */
    private synchronized void enableLog4j() {
        if (logger_ == null) {
            PropertyConfigurator.configure(strLog4jFile_);
            logger_ = Logger.getLogger("Controller");
        }
    }

    /**
     * Disables the log4j Logger.
     * 
     * @see LogManager#shutdown()
     */
    private synchronized void disableLog4j() {
        if (logger_ != null) {
            LogManager.shutdown();
            logger_ = null;
        }
    }

    //    /**
    //     * Creates extra classpath from the files ending with pattern list within the directory supplied.
    //     *  
    //     * @param directory to be used for finding files.
    //     * @param patternList file extensions list
    //     * @return String representation of the classpath
    //     */
    //    private String getExtraClasspath(File directory, final List<String> patternList) {
    //       File[] files = directory.listFiles(new FilenameFilter() {
    //         
    //         public boolean accept(File arg0, String arg1) {
    //            for (String extenssion : patternList) {
    //               if (arg1.toLowerCase().endsWith(extenssion)) {
    //                  return true;
    //               }
    //            }
    //            return false;
    //         }
    //      });
    //       StringBuilder sb = new StringBuilder();
    //       for (File file : files) {
    //          sb.append(file.getPath());
    //          sb.append(File.pathSeparatorChar);
    //       }
    //       return sb.toString();
    //    }

}