Package org.rzo.yajsw.wrapper

Source Code of org.rzo.yajsw.wrapper.AbstractWrappedProcess

package org.rzo.yajsw.wrapper;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXAuthenticator;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXPrincipal;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.commons.configuration.Configuration;
import org.rzo.yajsw.Constants;
import org.rzo.yajsw.action.Action;
import org.rzo.yajsw.action.ActionFactory;
import org.rzo.yajsw.cache.Cache;
import org.rzo.yajsw.condition.Condition;
import org.rzo.yajsw.config.YajswConfigurationImpl;
import org.rzo.yajsw.controller.Message;
import org.rzo.yajsw.controller.jvm.Controller;
import org.rzo.yajsw.io.CircularBuffer;
import org.rzo.yajsw.log.DateFileHandler;
import org.rzo.yajsw.log.MyLogger;
import org.rzo.yajsw.log.PatternFormatter;
import org.rzo.yajsw.os.OperatingSystem;
import org.rzo.yajsw.os.Process;
import org.rzo.yajsw.os.StopableService;
import org.rzo.yajsw.os.ms.win.w32.ClusterNodeChangeListener;
import org.rzo.yajsw.script.Script;
import org.rzo.yajsw.script.ScriptFactory;
import org.rzo.yajsw.timer.Timer;
import org.rzo.yajsw.timer.TimerFactory;
import org.rzo.yajsw.tray.WrapperTrayIconFactory;
import org.rzo.yajsw.tray.ahessian.server.AHessianJmxServer;
import org.rzo.yajsw.util.DaemonThreadFactory;
import org.rzo.yajsw.util.SimpleThreadFactory;
import org.rzo.yajsw.util.Utils;

import com.sun.jna.Platform;

public abstract class AbstractWrappedProcess implements WrappedProcess, Constants, AbstractWrappedProcessMBean
{

  /** The _os process. */
  volatile public Process        _osProcess;
  /** The _controller. */
  protected Controller        _controller;
  /** The _debug. */
  protected boolean          _debug            = false;
  /** The _config. */
  protected YajswConfigurationImpl  _config;
  /** The _restarts. */
  // protected int _restarts;
  /** The _gobler_err. */
  volatile protected Gobler      _gobler_err;
  /** The _gobler_in. */
  volatile protected Gobler      _gobler_in;
  /** The Constant executor. */
  protected static final Executor    executor          = Executors.newCachedThreadPool(new DaemonThreadFactory("wrappedProcess"));

  protected static final Executor    scriptExecutor        = Executors.newCachedThreadPool(new SimpleThreadFactory("scriptExecutor"));

  /** The _first restart time. */
  protected long            _firstRestartTime;
  /** The _state. */
  protected volatile int        _state            = STATE_IDLE;
  /** The _startup exit codes. */
  Set                  _startupExitCodes      = new HashSet();
  /** The _shutdown exit codes. */
  Set                  _shutdownExitCodes      = new HashSet();
  /** The _exit code default restart. */
  boolean                _exitCodeDefaultRestart    = false;
  /** The _local configuration. */
  protected Configuration        _localConfiguration      = new BaseConfiguration();
  /** The _app logger. */
  Logger                _appLogger;
  /** The _tmp path. */
  protected String          _tmpPath;
  /** The _wrapper logger. */
  Logger                _wrapperLogger;
  /** The _wrapper logger name. */
  String                _wrapperLoggerName      = "wrapper";
  /** The _app logger name. */
  String                _appLoggerName;
  String                _appLoggerPid;
  /** The _use system properties. */
  boolean                _useSystemProperties    = true;
  /** The Constant PATHSEP. */
  protected static final String    PATHSEP            = System.getProperty("path.separator");
  /** The _restart count. */
  int                  _restartCount;
  int                  _totalRestartCount      = 0;
  /** The _timer. */
  Timer                _timer;
  /** The _lock. */
  FileLock              _lock;
  /** The _lock file. */
  File                _lockFile;
  /** The _lock file channel. */
  FileChannel              _lockFileChannel;
  /** The _pid file. */
  File                _pidFile;
  /** The _successful invocation time. */
  long                _successfulInvocationTime;
  MultiMap              _listeners          = MultiValueMap.decorate(new HashMap(), HashSet.class);

  String                _triggerLine;
  Condition              _condition;
  Process                _trayIconProcess;
  volatile Date            _appStarted;
  volatile Date            _appStopped;
  Date                _wrapperStarted;
  volatile boolean          _drainActive        = false;
  volatile int            _exitCode          = -99;
  boolean                _haltWrapperOnApp      = false;
  boolean                _haltAppOnWrapper      = false;
  Object                _cluster          = null;
  ClusterNodeChangeListener      _clusterListener;
  boolean                _clusterTriggered      = false;
  Cache                _cache            = null;
  boolean                _exiting          = false;
  volatile TrayIconProxy        _trayIconMessages      = null;
  Script                _restartDelayScript      = null;
  Object                _service          = null;
  boolean                _stopRequested        = false;
  boolean                _startRequested        = false;
  MBeanServer              _mbeanServer        = null;
  AHessianJmxServer          _ahessianServer        = null;
  boolean                _reconnecting        = false;
  boolean                _init            = false;

  public static final int        MIN_PROCESS_LINES_TO_LOG  = 40;
 
  List<Thread>            _shutdownHooks = new ArrayList<Thread>();
 
  volatile boolean _stopper = false;

  /**
   * Inits the.
   */
  public void init()
  {
    if (_init)
      return;
    Map utils = new HashMap();
    utils.put("util", new Utils(this));
    _config = new YajswConfigurationImpl(_localConfiguration, _useSystemProperties, utils);

    getWrapperLogger().info("init ");
    if (!_config.isLocalFile())
      if (_cache == null)
      {
        _cache = new Cache();
        _cache.load(_config);
      }

    String dbg = _config.getString("wrapper.debug");
    _debug = dbg == null ? false : dbg.equals("true");
    _successfulInvocationTime = _config.getLong("wrapper.successful_invocation_time", DEFAULT_SUCCESSFUL_INVOCATION_TIME) * 1000;

    String control = _config.getString("wrapper.control", DEFAULT_CONTROL);
    if ("TIGHT".equals(control) || "WRAPPER".equals(control))
      _haltWrapperOnApp = true;

    if ("TIGHT".equals(control) || "APPLICATION".equals(control))
      _haltAppOnWrapper = true;

    for (Iterator it = _config.getKeys("wrapper.on_exit"); it.hasNext();)
    {
      String key = (String) it.next();
      String value = _config.getString(key);
      if ("RESTART".equals(value))
      {
        String postfix = key.substring(key.lastIndexOf(".") + 1);
        if ("default".equals(postfix))
          _exitCodeDefaultRestart = true;
        else
          try
          {
            _startupExitCodes.add(Integer.parseInt(postfix));
          }
          catch (Exception ex)
          {
            getWrapperLogger().info("error evaluating " + key + " " + ex.getMessage());
          }

      }
      if ("SHUTDOWN".equals(value))
      {
        String postfix = key.substring(key.lastIndexOf(".") + 1);
        if ("default".equals(postfix))
        // do nothing
        {
        }
        else
          try
          {
            _shutdownExitCodes.add(Integer.parseInt(postfix));
          }
          catch (Exception ex)
          {
            getWrapperLogger().info("error evaluating " + key + " " + ex.getMessage());
          }

      }
    }

    if (_timer == null)
      _timer = TimerFactory.createTimer(_config, this);
    _timer.init();
    if (_condition == null)
      _condition = new Condition(_config, this, getWrapperLogger());
    _condition.init();
    _restartCount = 0;

    // in case of active triggers control == LOOSE
    if (_timer.isHasTrigger() || _condition.isHasTrigger())
    {
      _haltWrapperOnApp = false;
      // do not halt app on wrapper -> service stop takes too long
      // _haltAppOnWrapper = false;
    }

    // if we need the tray or jmx -> create and register a wrapper mbean
    if (_config.getBoolean("wrapper.tray", false) || _config.getBoolean("wrapper.jmx", false))
      registerMBean();

    // if we need a try -> start asynch hessian jmx remote service & create
    // a tray proxy for displaying messages
    if (_config.getBoolean("wrapper.tray", false))
    {
      startAhessianService();
      _trayIconMessages = new TrayIconProxy();
    }

    // if we are not running as a sevice -> spawn the tray icon as a
    // separate process
    if ((!_reconnecting) && _config.getBoolean("wrapper.tray", false) && _trayIconProcess == null && !isService())
    {
      _trayIconProcess = WrapperTrayIconFactory.startTrayIconProcess(_config);
    }

    // if jmx is required -> start jmx rmi remote service
    if (_config.getBoolean("wrapper.jmx", false))
      startJMXRmiService();

    configStateChangeListeners();
    configShutdownHook();

    String clusterScript = _config.getString("wrapper.windows.cluster.script", null);
    configClusterScript(clusterScript);
    _init = true;

  }

  private void configClusterScript(String clusterScript)
  {
    if (clusterScript != null && !"".equals(clusterScript))
    {
      List args = _config.getList("wrapper.windows.cluster.script.args", new ArrayList());
      int timeout = _config.getInt("wrapper.windows.cluster.script.timeout", 0);
      final Script script = ScriptFactory.createScript(clusterScript, "", this, args, getWrapperLogger(), timeout);
      if (script == null)
        return;
      try
      {
        Class clazz = this.getClass().getClassLoader().loadClass("org.rzo.yajsw.os.ms.win.w32.Cluster");
        _cluster = clazz.newInstance();
        _clusterListener = new ClusterNodeChangeListener()
        {
          public void nodeChanged()
          {
            script.execute();
          }
        };
        Method m = clazz.getMethod("addNodeChangeListener", ClusterNodeChangeListener.class);
        m.invoke(_cluster, _clusterListener);
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }

    }
  }

  private void startCluster()
  {
    try
    {
      Class clazz = this.getClass().getClassLoader().loadClass("org.rzo.yajsw.os.ms.win.w32.Cluster");
      _clusterTriggered = true;
      _clusterListener.nodeChanged();
      Method m = clazz.getMethod("start");
      m.invoke(_cluster);
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  private void configShutdownHook()
  {
    // on windows services: shutdown is handeled by the onStop method not by
    // the hook
    if (OperatingSystem.instance().getOperatingSystemName().toLowerCase().startsWith("windows") && isService())
      return;
    if (_haltAppOnWrapper)
    {
      Thread hook = new Thread()
      {
        public void run()
        {
          getWrapperLogger().info("Shutting down Wrapper");
          if (!_exiting)
          {
            setExiting();
            AbstractWrappedProcess.this.stop();
            AbstractWrappedProcess.this.shutdown();
          }
          // give eventually running scripts time to terminate
          try
          {
            Thread.sleep(5000);
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
            Thread.currentThread().interrupt();
          }
        }

      };
      Runtime.getRuntime().addShutdownHook(hook);
      // remember the hook so that we can remove it to avoid mem leaks
      _shutdownHooks.add(hook);
    }
     

  }

  private void configStateChangeListeners()
  {
    Iterator listeners = _config.getKeys("wrapper.script");
    for (Iterator it = listeners; it.hasNext();)
    {
      String key = (String) it.next();
      if (!key.endsWith(".args"))
      {
        String value = _config.getString(key);
        List args = _config.getList(key + ".args", new ArrayList());
        int timeout = _config.getInt(key + ".timeout", 0);

        String state = key.substring(key.lastIndexOf(".") + 1);
        final Script script = ScriptFactory.createScript(value, state, this, args, getWrapperLogger(), timeout);
        int iState = toIntState(state);
        if (iState >= 0 && script != null)
          addStateChangeListener(iState, new StateChangeListener()
          {

            public void stateChange(int newState, int oldState)
            {
              script.executeWithTimeout();
            }

          });
      }
    }

    if (_haltWrapperOnApp)
      addStateChangeListener(STATE_IDLE, new StateChangeListener()
      {
        public void stateChange(int newState, int oldState)
        {
          if (_exiting)
            return;
          _exiting = true;
          executor.execute(new Runnable()
          {

            public void run()
            {
              if (_stopper)
                return;
              // if this is a service: do not exit here so that we
              // can inform the service controller
              if (!isService())
                System.exit(0);
              else
              {
                Object service = getService();
                if (service != null)
                {
                  // windows service
                  getWrapperLogger().info("calling onStop");
                  ((StopableService) service).onStop();
                  ((StopableService) service).waitOnStop();
                  Runtime.getRuntime().halt(0);
                }
                else if (isService() && _haltWrapperOnApp)
                {
                  // posix service
                  try
                  {
                    Thread.sleep(5000);
                  }
                  catch (InterruptedException e)
                  {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                  }
                  Runtime.getRuntime().halt(0);
                }
              }
            }

          });
        }
      });

  }

  private int toIntState(String state)
  {
    if ("START".equals(state))
      return STATE_STARTING;
    else if ("RUN".equals(state))
      return STATE_RUNNING;
    else if ("RESTART".equals(state))
      return STATE_RESTART;
    else if ("STOP".equals(state))
      return STATE_USER_STOP;
    else if ("ABORT".equals(state))
      return STATE_ABORT;
    else if ("SHUTDOWN".equals(state))
      return STATE_SHUTDOWN;
    else if ("IDLE".equals(state))
      return STATE_IDLE;
    else
      return -1;
  }

  private void startJMXRmiService()
  {
    try
    {
      int port = _config.getInt("wrapper.jmx.rmi.port", Constants.DEFAULT_RMI_PORT);
      if (port > 0)
      {
        Registry rmiRegistry = LocateRegistry.createRegistry(port);
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/server");
        Map environment = null;
        if (_config.getString("wrapper.jmx.rmi.user", null) != null)
        {
          final String myUser = _config.getString("wrapper.jmx.rmi.user");
          final String myPassword = _config.getString("wrapper.jmx.rmi.password", "");
          environment = new HashMap();
          JMXAuthenticator authenticator = new JMXAuthenticator()
          {

            public Subject authenticate(Object credentials)
            {
              if (!(credentials instanceof String[]))
                throw new SecurityException("Bad credentials");
              String[] creds = (String[]) credentials;
              if (creds.length != 2)
                throw new SecurityException("Bad credentials");

              String user = creds[0];
              String password = creds[1];

              if (password == null)
                password = "";

              if (!myUser.equals(user))
                throw new SecurityException("Unknown user " + user);
              if (!myPassword.equals(password))
                throw new SecurityException("Bad password");

              Set principals = new HashSet();
              principals.add(new JMXPrincipal(user));
              return new Subject(true, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
            }

          };
          environment.put(JMXConnectorServer.AUTHENTICATOR, authenticator);
        }

        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, environment, _mbeanServer);
        cs.start();

      }
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }

  }

  private void startAhessianService()
  {
    if (_ahessianServer != null)
      return;
    String canonName;
    try
    {
      canonName = new File(_config.getString("wrapper.config")).getCanonicalPath();
      _ahessianServer = new AHessianJmxServer(_mbeanServer, "+n:localhost, -n:*", canonName, _config.getInt("wrapper.tray.port", 0), getWrapperLogger());
    }
    catch (IOException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void registerMBean()
  {
    ArrayList servers = MBeanServerFactory.findMBeanServer(null);
    try
    {
      if (servers != null && servers.size() > 0)
        _mbeanServer = (MBeanServer) servers.get(0);
      if (_mbeanServer == null)
        _mbeanServer = MBeanServerFactory.createMBeanServer();
      if (_mbeanServer != null)
      {
        String name = _config.getString("wrapper.console.title");
        if (name == null)
          name = _config.getString("wrapper.ntservice.name");
        if (name == null)
          name = "yajsw.noname";
        ObjectName oName = new ObjectName("org.rzo.yajsw", "name", name);
        _mbeanServer.registerMBean(this, oName);
      }
      else
        getWrapperLogger().severe("ERROR: no mbean server found ");
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * Gets the priority.
   *
   * @param priority
   *            the priority
   *
   * @return the priority
   */
  protected int getPriority(String priority)
  {

    if ("LOW".equals(priority))
      return Process.PRIORITY_LOW;
    else if ("BELOW_NORMAL".equals(priority))
      return Process.PRIORITY_BELOW_NORMAL;
    else if ("NORMAL".equals(priority))
      return Process.PRIORITY_NORMAL;
    else if ("ABOVE_NORMAL".equals(priority))
      return Process.PRIORITY_ABOVE_NORMAL;
    else if ("HIGH".equals(priority))
      return Process.PRIORITY_HIGH;
    return Process.PRIORITY_UNDEFINED;
  }

  /**
   * Gets the affinity.
   *
   * @param affinity
   *            the affinity
   *
   * @return the affinity
   */
  protected int getAffinity(String affinity)
  {
    try
    {
      return Integer.parseInt(affinity);
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
      return 0;
    }
  }

  /**
   * Exit code restart.
   *
   * @return true, if successful
   */
  protected boolean exitCodeRestart()
  {
    if (_state == STATE_USER_STOP || _state == STATE_SHUTDOWN)
      return false;
    if (_startupExitCodes.contains(_osProcess.getExitCode()))
    {
      getWrapperLogger().info("restart process due to exit code rule");
      return true;
    }
    else if (_exitCodeDefaultRestart)
    {
      getWrapperLogger().info("restart process due to default exit code rule");
      return true;
    }

    return false;
  }

  /**
   * Exit code shutdown.
   *
   * @return true, if successful
   */
  protected boolean exitCodeShutdown()
  {
    if (_shutdownExitCodes.contains(_osProcess.getExitCode()))
    {
      getWrapperLogger().info("shutdown process due to exit code rule");
      return true;
    }

    return false;
  }

  /**
   * Sets the state.
   *
   * @param state
   *            the new state
   */
  protected void setState(int state)
  {
    int oldState = _state;
    if (_state != state)
    {
      getWrapperLogger().info("set state " + getStringState(_state) + "->" + getStringState(state));
      _state = state;
      if (state == STATE_IDLE)
      {
        removeLockFile();
      }
      Collection listeners = (Collection) _listeners.get(_state);
      Collection listeners999 = (Collection) _listeners.get(999);
      Collection allListeners = new HashSet();
      if (listeners != null)
        allListeners.addAll(listeners);
      if (listeners999 != null)
        allListeners.addAll(listeners999);

      for (Iterator it = allListeners.iterator(); it.hasNext();)
      {
        StateChangeListener listener = (StateChangeListener) it.next();
        if (listener != null)
          listener.stateChange(state, oldState);
      }
    if (_state == STATE_IDLE && _startRequested)
      executor.execute(new Runnable()
      {
        public void run()
        {
          start();
        }
      });
     
    }
  }

  /**
   * String state.
   *
   * @param state
   *            the state
   *
   * @return the string
   */
  static public String getStringState(int state)
  {
    switch (state)
    {
    case STATE_IDLE:
      return "IDLE";
    case STATE_RESTART:
      return "RESTART";
    case STATE_RESTART_START:
      return "RESTART_START";
    case STATE_RESTART_STOP:
      return "RESTART_STOP";
    case STATE_RESTART_WAIT:
      return "RESTART_WAIT";
    case STATE_RUNNING:
      return "RUNNING";
    case STATE_STARTING:
      return "STARTING";
    case STATE_STOP:
      return "STOP";
    case STATE_USER_STOP:
      return "STATE_USER_STOP";
    case STATE_ABORT:
      return "STATE_ABORT";
    case STATE_SHUTDOWN:
      return "STATE_SHUTDOWN";
    default:
      return "?";
    }
  }

  /** The _start by timer. */
  boolean  _startByTimer  = false;

  /**
   * Start by timer.
   */
  public synchronized void startByTimer()
  {
    _startByTimer = true;
    start();
    _startByTimer = false;
  }

  public synchronized void start()
  {
    if (!_init)
      init();

    _startRequested = true;
    _stopRequested = false;
    if (_state != STATE_IDLE)
    {
      getWrapperLogger().info("Process not IDLE -> Delaying start request");
    }
    startInternal();
  }

  /**
   * Start.
   */
  public synchronized void startInternal()
  {
    if (!saveLockFile())
      return;
    savePidFile();
    if (_timer.isHasTrigger() && !_timer.isTriggered())
      _timer.start();
    if (_condition.isHasTrigger() && !_condition.isTriggered())
    {
      _condition.start();
      return;
    }
    if (!_timer.isStartImmediate() && !_startByTimer)
      return;

    if (_cluster != null && !_clusterTriggered)
    {
      startCluster();
      return;
    }

    if (_state == STATE_IDLE)
      setState(STATE_STARTING);
    else if (_state == STATE_RESTART_WAIT)
      setState(STATE_RESTART_START);
    else
      return;

    if (_shutdownHooks.isEmpty())
      configShutdownHook();

    long startTimeout = _config.getLong("wrapper.startup.delay", 0);
    if (_state == STATE_STARTING && startTimeout > 0)
    {
      try
      {
        getWrapperLogger().info("startup delay " + startTimeout + "sec");
        Thread.sleep(startTimeout * 1000);
        if (_stopRequested)
        {
          setState(STATE_IDLE);
          return;
        }
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
        Thread.currentThread().interrupt();
      }
    }

    getWrapperLogger().info("starting Process");

    if (_wrapperStarted == null)
      _wrapperStarted = new Date();

    if (_config.getBoolean("wrapper.restart.reload_configuration", DEFAULT_RELOAD_CONFIGURATION))
      reloadConfiguration();

    if (_debug)
      getWrapperLogger().info("starting controller");
    if (_controller != null)
    {
      // release resources if controller was running before this call to
      // start
      // otherwise resources will be released by gc -> finalize
      _controller.reset();
      _controller.setDebug(isDebug());
      _controller.setLogger(getWrapperLogger());
      configController();
      if (!_controller.start())
      {
        getWrapperLogger().info("could not start controller -> abort");
        setState(STATE_ABORT);
        setState(STATE_IDLE);
        return;
      }
      else if (_debug)
        getWrapperLogger().info("controller started");

      try
      {
        Thread.sleep(100);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
        Thread.currentThread().interrupt();
      }
    }
    if (_osProcess == null)
    {
      _osProcess = OperatingSystem.instance().processManagerInstance().createProcess();
    }
    else
    {
      // release resources if _osProcess was running before this call to
      // start
      // otherwise resources will be released by gc -> finalize
      if (_debug)
        getWrapperLogger().info("_osProcess destroyed");
      _osProcess.destroy();
    }
    configProcess();
    _firstRestartTime = System.currentTimeMillis();
    // _restartCount++;
    Map triggerActions = getTriggerActions();
    Map regexTriggerActions = getRegexTriggerActions();
    Map missingTriggerActions = getMissingTriggerActions();
    Map missingRegexTriggerActions = getMissingRegexTriggerActions();
    _osProcess.setLogger(getWrapperLogger());
    _exitCode = -3;
    getWrapperLogger().info("spawning wrapped process");
    if (_osProcess.start())
    {
      _controller.processStarted();
      _totalRestartCount++;
      postStart();
      getWrapperLogger().info("started process with pid " + _osProcess.getPid());
      if (pipeStreams())
      {

        _gobler_in = new Gobler(_osProcess.getInputStream(), getAppLogger(), triggerActions, regexTriggerActions, missingTriggerActions,
            missingRegexTriggerActions, "OUTPUT " + _osProcess.getPid(), _osProcess.getPid());
        _gobler_err = new Gobler(_osProcess.getErrorStream(), getAppLogger(), triggerActions, regexTriggerActions, missingTriggerActions,
            missingRegexTriggerActions, "ERROR " + _osProcess.getPid(), _osProcess.getPid());
        executor.execute(_gobler_err);
        executor.execute(_gobler_in);
      }
      if (getState() != STATE_IDLE)
      {
        _appStarted = new Date();
        setState(STATE_RUNNING);
        updateAppLoggerName();
      }
    }
    else
    {
      getWrapperLogger().severe("failed to spawn wrapped process");
      _controller.processFailed();
    }

    // win 64 test
    // WindowsXPProcess.getProcess(getPid());

  }

  protected void reloadConfiguration()
  {
    {
      Map utils = new HashMap();
      utils.put("util", new Utils(this));
      _config = new YajswConfigurationImpl(_localConfiguration, _useSystemProperties, utils);

      getWrapperLogger().info("reloaded configuration ");
    }
  }

  abstract void configController();

  abstract void postStart();

  void configProcess()
  {
    String priority = _config.getString("wrapper.priority");
    if (priority != null)
      _osProcess.setPriority(getPriority(priority));

    String affinity = _config.getString("wrapper.affinity");
    if (affinity != null)
      _osProcess.setCpuAffinity(getAffinity(affinity));

    String title = _config.getString("wrapper.console.title");
    if (title != null)
      _osProcess.setTitle(title);

    _osProcess.setVisible(_config.getBoolean("wrapper.console.visible", Constants.DEFAULT_CONSOLE_VISIBLE)
        && !_config.getBoolean("wrapper.service", false));
    _osProcess.setMinimized(_config.getBoolean("wrapper.console.minimized", Constants.DEFAULT_CONSOLE_MINIMIZED)
        && !_config.getBoolean("wrapper.service", false));
    _osProcess.setUser(_config.getString("wrapper.app.account"));
    _osProcess.setPassword(_config.getString("wrapper.app.password"));

    if (_debug)
      _osProcess.setDebug(true);

    String workingDir = _config.getString("wrapper.working.dir", ".");
    if (workingDir != null)
    {
      File wd = new File(workingDir);
      if (!wd.exists() || !wd.isDirectory())
        getWrapperLogger().warning("working directory " + workingDir + " not found");
      else
        _osProcess.setWorkingDir(wd.getAbsolutePath());
      getWrapperLogger().info("working dir " + wd.getAbsolutePath());
    }
    _osProcess.setEnvironment(getProcessEnvironment(_config));
    if (Platform.isWindows() && Platform.isWinVista() && _config.getBoolean("wrapper.service", false) && _config.getBoolean("wrapper.ntservice.logon_active_session", false))
    {
      _osProcess.setLogonActiveSession(true);
      if (_debug)
        getWrapperLogger().info("setLogonActiveSession");
      if (!_config.getBoolean("wrapper.ntservice.autoreport.startup", true))
        getWrapperLogger().warning("WARNING: do not set autoreport.startup & wrapper.ntservice.logon_active_session");
      if (_config.getString("wrapper.ntservice.account", null) != null)
        getWrapperLogger().warning("WARNING: do not set wrapper.ntservice.account & wrapper.ntservice.logon_active_session");
      if (_config.getString("wrapper.app.account", null) != null)
        getWrapperLogger().warning("WARNING: do not set wrapper.app.account & wrapper.ntservice.logon_active_session");
    }
    String desktop = _config.getString("wrapper.ntservice.desktop", null);
    if (Platform.isWindows() && Platform.isWinVista() && _config.getBoolean("wrapper.service", false) && desktop != null)
      _osProcess.setDesktop(desktop);

     

  }

  private List<String[]> getProcessEnvironment(YajswConfigurationImpl config)
  {
    if (!config.getKeys("wrapper.app.env").hasNext())
    {
      //getWrapperLogger().info("env: no yajsw env");
      return null;
    }
    List<String[]> env = OperatingSystem.instance().processManagerInstance().getProcess(
        OperatingSystem.instance().processManagerInstance().currentProcessId()).getEnvironment();
    for (Iterator keys = config.getKeys("wrapper.app.env"); keys.hasNext();)
    {
      String key = (String) keys.next();
      String value = config.getString(key);
      String envKey = key.substring("wrapper.app.env.".length());
      //getWrapperLogger().info("env: "+envKey+"="+value);
      updateEnvKey(envKey, value, env);
    }
    return env;
  }

  private void updateEnvKey(String envKey, String value, List<String[]> env)
  {
    String[] entry = findEnvEntry(envKey, env);
    if (entry != null)
      entry[1] = value;
    else
      env.add(new String[]
      { envKey, value });
  }

  private String[] findEnvEntry(String envKey, List<String[]> env)
  {
    for (String[] entry : env)
      if (envKeyEqual(envKey, entry[0]))
        return entry;
    return null;
  }

  private boolean envKeyEqual(String envKey1, String envKey2)
  {
    if (Platform.isWindows())
      return envKey1.toLowerCase().equals(envKey2.toLowerCase());
    else
      return envKey1.equals(envKey2);

  }

  /**
   * Pipe streams.
   *
   * @return true, if successful
   */
  protected boolean pipeStreams()
  {
    return true;// getAppLogger() != null;

  }

  /** The _file handler. */
  Handler  _fileHandler;
  /** The _console handler. */
  Handler  _consoleHandler;

  /**
   * Restart log file.
   */
  void restartLogFile()
  {
    if (_fileHandler == null)
      return;
    String rollMode = _config.getString("wrapper.logfile.rollmode", "");
    boolean append = !(rollMode.contains("WRAPPER") || rollMode.contains("JVM"));
    if (!append && _appLogger != null)
    {
      _fileHandler.close();
      getFileHandler();
    }
  }

  /**
   * Gets the console handler.
   *
   * @return the console handler
   */
  public Handler getConsoleHandler()
  {
    if (_consoleHandler != null)
      return _consoleHandler;

    String consoleLogLevel = _config.getString("wrapper.console.loglevel", "INFO");
    if (consoleLogLevel.equals("NONE"))
      return null;

    // per default java console handler uses err -> use out instead
    _consoleHandler = new ConsoleHandler()
    {
      protected synchronized void setOutputStream(OutputStream out) throws SecurityException
      {
        super.setOutputStream(System.out);
      }
    };
    _consoleHandler.setFormatter(getConsoleFormatter());
    _consoleHandler.setLevel(getLogLevel(consoleLogLevel));

    return _consoleHandler;
  }

  /**
   * Gets the file handler.
   *
   * @return the file handler
   */
  public Handler getFileHandler()
  {
    if (_fileHandler != null)
      return _fileHandler;

    String fileName = getLogFile();
    String fileLogLevel = _config.getString("wrapper.logfile.loglevel", "INFO");
    if ((fileName.equals("") || fileLogLevel.equals("NONE")))
      return null;

    File f = new File(fileName).getParentFile();
    if (!f.exists())
      try
      {
        f.mkdirs();
      }
      catch (Exception ex)
      {
        ex.printStackTrace();
      }

    try
    {
      String rollMode = _config.getString("wrapper.logfile.rollmode", "");
      boolean append = !(rollMode.contains("WRAPPER") || rollMode.contains("JVM"));
      int count = _config.getInt("wrapper.logfile.maxfiles", 1);
      int limit = getLogLimit();
      _fileHandler = fileName.contains("%d") ? new DateFileHandler(fileName, limit, count, append) : new FileHandler(fileName, limit, count,
          append);
      _fileHandler.setFormatter(getFileFormatter());
      _fileHandler.setLevel(getLogLevel(fileLogLevel));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return _fileHandler;

  }

  /**
   * Update app logger name.
   */
  private void updateAppLoggerName()
  {
    if (_appLogger == null)
      return;
    _appLoggerPid = getAppPid() + "/" + _restartCount;
    ((MyLogger) _appLogger).setPID(_appLoggerPid);
    _appLoggerName = getName() == null ? "" : getName();
    ((MyLogger) _appLogger).setName(_appLoggerName);
  }

  /**
   * Gets the app logger.
   *
   * @return the app logger
   */
  protected Logger getAppLogger()
  {
    if (_appLogger != null)
      return _appLogger;

    if (_appLogger == null)
    {
      _appLogger = new MyLogger();
      updateAppLoggerName();
      _appLogger.setUseParentHandlers(false);
      if (_controller != null)
        _controller.setLogger(_appLogger);
    }
    if (getFileHandler() != null)
      _appLogger.addHandler(getFileHandler());
    if (getConsoleHandler() != null)
      _appLogger.addHandler(getConsoleHandler());
    _appLogger.setLevel(Level.ALL);
    return _appLogger;
  }

  /**
   * Gets the log level.
   *
   * @param logLevel
   *            the log level
   *
   * @return the log level
   */
  private Level getLogLevel(String logLevel)
  {
    if (logLevel.equals("INFO"))
      return Level.ALL;
    else if (logLevel.equals("FATAL"))
      return Level.SEVERE;
    else if (logLevel.equals("ERROR"))
      return Level.WARNING;
    else if (logLevel.equals("STATUS"))
      return Level.INFO;

    return Level.INFO;
  }

  /**
   * Gets the log limit.
   *
   * @return the log limit
   */
  private int getLogLimit()
  {
    String res = _config.getString("wrapper.logfile.maxsize");
    String units = "";
    if (res == null)
      return 0;
    res = res.toLowerCase();
    if (res.endsWith("m"))
    {
      res = res.substring(0, res.length() - 1);
      units = "m";
    }
    else if (res.endsWith("k"))
    {
      res = res.substring(0, res.length() - 1);
      units = "k";
    }
    int result = Integer.parseInt(res);
    if (units.equals("m"))
      result = result * 1024 * 1024;
    else if (units.equals("k"))
      result = result * 1024;
    return result;
  }

  /**
   * Gets the file formatter.
   *
   * @return the file formatter
   */
  private PatternFormatter getFileFormatter()
  {
    String wFormat = _config.getString("wrapper.logfile.format", Constants.DEFAULT_LOG_FORMAT);
    return getFormatter(wFormat);

  }

  /**
   * Gets the console formatter.
   *
   * @return the console formatter
   */
  private java.util.logging.Formatter getConsoleFormatter()
  {
    String wFormat = _config.getString("wrapper.console.format", Constants.DEFAULT_LOG_FORMAT);
    return getFormatter(wFormat);
  }

  /**
   * Gets the formatter.
   *
   * @param wFormat
   *            the w format
   *
   * @return the formatter
   */
  private PatternFormatter getFormatter(String wFormat)
  {
    PatternFormatter formatter = new PatternFormatter();
    String pattern = "";
    if (wFormat.contains("Z"))
    {
      formatter.setTimeFormat("yy-MM-dd HH:mm:ss.SS");
    }
    else
    {
      formatter.setTimeFormat("yy-MM-dd HH:mm:ss");
    }
    for (int i = 0; i < wFormat.length(); i++)
    {
      if (i > 0)
        pattern += "|";
      char c = wFormat.charAt(i);
      switch (c)
      {
      case 'L':
        pattern += "%LEVEL%";
        break;
      case 'P':
        pattern += "%PARAM0%";
        break;
      case 'N':
        pattern += "%PARAM1%";
        break;
      case 'T':
      case 'Z':
        pattern += "%TIME%";
        break;
      case 'M':
        pattern += "%MESSAGE%";
        break;
      default:
        ;
      }
    }
    pattern += "\n";
    formatter.setLogPattern(pattern);
    return formatter;
  }

  /**
   * Gets the log file.
   *
   * @return the log file
   */
  private String getLogFile()
  {
    String result = _config.getString("wrapper.logfile", "wrapper.log");
    File r = new File(result);
    File f = null;
    if (!r.isAbsolute())
    {
      String wDir = _config.getString("wrapper.working.dir", ".");
      f = new File(wDir, result);
    }
    else
      f = new File(result);
    result = f.getAbsolutePath();
    if (result.contains("ROLLNUM"))
      result = result.replace("ROLLNUM", "%g");
    else
      result = result + ".%g";
    if (result.contains("YYYYMMDD"))
      result = result.replace("YYYYMMDD", "%d");
    return result;
  }

  protected Map getMissingTriggerActions()
  {
    Map result = new HashMap();
    for (Iterator it = _config.getKeys("wrapper.filter.missing.trigger"); it.hasNext();)
    {
      String tKey = (String) it.next();
      List lValue = _config.getList(tKey);
      if (lValue == null || lValue.size() != 3)
      {
        getWrapperLogger().info("check parameters for " + tKey);
        continue;
      }
      String tValue = (String) lValue.get(0);
      // commons configuration does no accept <space>, 1, 1 as valid list
      // -> using * instead of space
      if ("*".equals(tValue))
        tValue = "";
      int countValue = -1;
      try
      {
        countValue = Integer.parseInt((String) lValue.get(1));
      }
      catch (Exception ex)
      {
        getWrapperLogger().log(Level.SEVERE, "check parameters for " + tKey, ex);
      }
      long periodValue = -1;
      try
      {
        periodValue = Long.parseLong((String) lValue.get(2)) * 1000;
      }
      catch (Exception ex)
      {
        getWrapperLogger().log(Level.SEVERE, "check parameters for " + tKey, ex);
      }
      String tName = tKey.substring("wrapper.filter.missing.trigger.".length());
      boolean autoStop = _config.getBoolean("wrapper.filter.missing.autostop."+tName, true);
      String aKey = "wrapper.filter.missing.action." + tName;
      String aValue = _config.getString(aKey, "");
      Object action = getTriggerAction(aValue);
      String sKey = "wrapper.filter.missing.script." + tName;
      String sValue = _config.getString(sKey, "");
      List args = _config.getList(sKey + ".args", null);
      int timeout = _config.getInt(sKey + ".timeout", 0);
      String[] strArgs = null;
      if (args != null && args.size() > 0)
      {
        strArgs = new String[args.size()];
        for (int i = 0; i < strArgs.length; i++)
          strArgs[i] = args.get(i).toString();
      }
      Object script = getTriggerScript(sValue, tKey.substring(tKey.lastIndexOf('.')), strArgs, timeout);
      if (action != null || script != null)
      {
        result.put(tValue, new MissingTriggerAction(executor, periodValue, countValue, new TriggerAction[]
        { (TriggerAction) script, (TriggerAction) action }, autoStop, getWrapperLogger()));
      }
    }
    return result;
  }

  /**
   * Gets the regex trigger actions.
   *
   * @return the regex trigger actions
   */
  protected Map getMissingRegexTriggerActions()
  {
    Map result = new HashMap();
    for (Iterator it = _config.getKeys("wrapper.filter.missing.trigger-regex"); it.hasNext();)
    {
      String tKey = (String) it.next();
      List lValue = _config.getList(tKey);
      if (lValue == null || lValue.size() != 3)
      {
        getWrapperLogger().info("check parameters for " + tKey);
        continue;
      }
      String tValue = (String) lValue.get(0);
      int countValue = -1;
      try
      {
        countValue = Integer.parseInt((String) lValue.get(1));
      }
      catch (Exception ex)
      {
        getWrapperLogger().log(Level.SEVERE, "check parameters for " + tKey, ex);
      }
      long periodValue = -1;
      try
      {
        getWrapperLogger().info("check parameters for " + tKey);
        periodValue = Long.parseLong((String) lValue.get(2)) * 1000;
      }
      catch (Exception ex)
      {
        getWrapperLogger().log(Level.SEVERE, "check parameters for " + tKey, ex);
      }
      String tName = tKey.substring("wrapper.filter.missing.trigger-regex.".length());
      boolean autoStop = _config.getBoolean("wrapper.filter.missing.autostop."+tName, true);
      String aKey = "wrapper.filter.missing.action." + tName;
      String aValue = _config.getString(aKey, "");
      Object action = getTriggerAction(aValue);
      String sKey = "wrapper.filter.missing.script." + tName;
      String sValue = _config.getString(sKey, "");
      List args = _config.getList(sKey + ".args", null);
      int timeout = _config.getInt(sKey + ".timeout", 0);
      String[] strArgs = null;
      if (args != null && args.size() > 0)
      {
        strArgs = new String[args.size()];
        for (int i = 0; i < strArgs.length; i++)
          strArgs[i] = args.get(i).toString();
      }
      Object script = getTriggerScript(sValue, tKey.substring(tKey.lastIndexOf('.')), strArgs, timeout);
      if (action != null || script != null)
      {
        result.put(tValue, new MissingTriggerAction(executor, periodValue, countValue, new TriggerAction[]
        { (TriggerAction) script, (TriggerAction) action }, autoStop, getWrapperLogger()));
      }
    }
    return result;
  }

  /**
   * Gets the trigger actions.
   *
   * @return the trigger actions
   */
  protected Map getTriggerActions()
  {
    Map result = new HashMap();
    List configList = new ArrayList();
    for (Iterator it = _config.getKeys("wrapper.filter.trigger"); it.hasNext();)
    {
      configList.add(it.next());
    }
    Collections.sort(configList, new AlphanumComparator());

    for (Iterator it = configList.listIterator(); it.hasNext();)
    {
      String tKey = (String) it.next();
      String tValue = _config.getString(tKey);
      if (tValue == null || tValue.length() == 0)
        continue;
      String tName = tKey.substring("wrapper.filter.trigger.".length());
      String aKey = "wrapper.filter.action." + tName;
      String aValue = _config.getString(aKey, "");
      Object action = getTriggerAction(aValue);
      String sKey = "wrapper.filter.script." + tName;
      String sValue = _config.getString(sKey, "");
      List args = _config.getList(sKey + ".args", null);
      int timeout = _config.getInt(sKey + ".timeout", 0);
      String[] strArgs = null;
      if (args != null && args.size() > 0)
      {
        strArgs = new String[args.size()];
        for (int i = 0; i < strArgs.length; i++)
          strArgs[i] = args.get(i).toString();
      }
      Object script = getTriggerScript(sValue, tKey.substring(tKey.lastIndexOf('.')), strArgs, timeout);
      if (action != null && script != null)
      {
        addToActionMap(result, tValue, Arrays.asList(new Object[]
        { script, action }));
      }
      else if (action != null)
        addToActionMap(result, tValue, action);
      else if (script != null)
        addToActionMap(result, tValue, script);
      else
        addToActionMap(result, aKey, "RESTART");
    }
    return result;
  }

  private void addToActionMap(Map actionsMap, String key, Object value)
  {
    Object c = actionsMap.get(key);
    if (c == null)
    {
      actionsMap.put(key, value);
    }
    else if (c instanceof Collection && value instanceof Collection)
    {
      ArrayList l = new ArrayList();
      l.addAll((Collection) c);
      l.addAll((Collection) value);
      actionsMap.put(key, l);
    }
    else if (c instanceof Collection && !(value instanceof Collection))
    {
      ArrayList l = new ArrayList();
      l.addAll((Collection) c);
      l.add(value);
      actionsMap.put(key, l);
    }
    else if (!(c instanceof Collection) && value instanceof Collection)
    {
      ArrayList l = new ArrayList();
      l.add((Collection) c);
      l.addAll((Collection) value);
      actionsMap.put(key, l);
    }
    else
    // c is not a collection && value is not a collection
    {
      actionsMap.put(key, Arrays.asList(new Object[]
      { c, value }));
    }

  }

  /**
   * Gets the regex trigger actions.
   *
   * @return the regex trigger actions
   */
  protected Map getRegexTriggerActions()
  {
    Map result = new HashMap();
    for (Iterator it = _config.getKeys("wrapper.filter.trigger-regex"); it.hasNext();)
    {
      String tKey = (String) it.next();
      String tValue = _config.getString(tKey);
      if (tValue == null || tValue.length() == 0)
        continue;
      String tName = tKey.substring("wrapper.filter.trigger-regex.".length());
      String aKey = "wrapper.filter.action." + tName;
      String aValue = _config.getString(aKey, "");
      Object action = getTriggerAction(aValue);
      String sKey = "wrapper.filter.script." + tName;
      String sValue = _config.getString(sKey, "");
      List args = _config.getList(sKey + ".args", null);
      int timeout = _config.getInt(sKey + ".timeout", 0);
      String[] strArgs = null;
      if (args != null && args.size() > 0)
      {
        strArgs = new String[args.size()];
        for (int i = 0; i < strArgs.length; i++)
          strArgs[i] = args.get(i).toString();
      }

      Object script = getTriggerScript(sValue, tKey.substring(tKey.lastIndexOf('.')), strArgs, timeout);
      if (action != null && script != null)
      {
        addToActionMap(result, tValue, Arrays.asList(new Object[]
        { script, action }));
      }
      else if (action != null)
        addToActionMap(result, tValue, action);
      else if (script != null)
        addToActionMap(result, tValue, script);
      else
        addToActionMap(result, aKey, "RESTART");
    }
    return result;
  }

  /**
   * Gets the trigger script.
   *
   * @param script
   *            the script
   * @param key
   *            the key
   *
   * @return the trigger script
   */
  private Object getTriggerScript(String script, String key, String[] args, int timeout)
  {
    final Script s = ScriptFactory.createScript(script, key, this, args, getWrapperLogger(), timeout);
    if (s == null)
    {
      this.getWrapperLogger().info("error initializing script " + script);
      return null;
    }
    this.getWrapperLogger().info("found script " + s.getScript());
    // final String id = key;

    return new TriggerAction()
    {
      public Object execute(final String line)
      {
        scriptExecutor.execute(new Runnable()
        {

          public void run()
          {
            AbstractWrappedProcess.this.getWrapperLogger().info("start script " + s.getScript());
            s.executeWithTimeout(new String(line));
            AbstractWrappedProcess.this.getWrapperLogger().info("end script " + s.getScript());
          }
        });
        return null;
      }
    };
  }

  /**
   * Gets the trigger action.
   *
   * @param value
   *            the value
   *
   * @return the trigger action
   */
  private Object getTriggerAction(String value)
  {
    if ("RESTART".equals(value))
      return new TriggerAction()
      {
        public Object execute(String line)
        {
          if (allowRestart())
            restartInternal();
          else
            stop();
          return null;
        }
      };
    else if ("SHUTDOWN".equals(value))
      return new TriggerAction()
      {
        public Object execute(String line)
        {
          stop();
          return null;
        }
      };

    return null;
  }

  /**
   * Stop timer.
   */
  public synchronized void stopTimer()
  {
    _timer.stop();
  }

  public synchronized void stopCondition()
  {
    _condition.stop();
  }

  public synchronized void stop()
  {
    _stopRequested = true;
    _startRequested = false;
    if (_state != STATE_RUNNING)
    {
      getWrapperLogger().info("process not in state RUNNING -> Delying stop");
    }
    stopInternal();
  }

  /**
   * Stop.
   */
  public synchronized void stopInternal()
  {
    if (_state == STATE_RESTART)
    {
      _appStopped = new Date();
      setState(STATE_RESTART_STOP);
    }
    else if (_state == STATE_RUNNING)
    {
      _appStopped = new Date();
      setState(STATE_USER_STOP);
    }
    else
      return;

    // if (_debug)
    int shutdownWaitTime = _config.getInt("wrapper.shutdown.timeout", Constants.DEFAULT_SHUTDOWN_TIMEOUT) * 1000;
    shutdownWaitTime += _config.getInt("wrapper.jvm_exit.timeout", Constants.DEFAULT_JVM_EXIT_TIMEOUT) * 1000;
    getWrapperLogger().info("stopping process with pid/timeout " + _osProcess.getPid() + " " + shutdownWaitTime);

    stopController(shutdownWaitTime);
    stopOsProcess(shutdownWaitTime);

    _appStopped = new Date();
    if (_state == STATE_USER_STOP)
      if (!_exiting)
        setState(STATE_IDLE);
    removeShutdownHooks();
  }

  private void removeShutdownHooks()
  {
    if (_exiting)
      return;
    for (Thread hook : _shutdownHooks)
    {
      Runtime.getRuntime().removeShutdownHook(hook);
    }
    _shutdownHooks.clear();
  }

  private void stopOsProcess(int shutdownWaitTime)
  {
    boolean externalStop = false;
    String stopConfigName = _config.getString("wrapper.stop.conf");
    getWrapperLogger().info("stop config name " + stopConfigName);
    File stopConfigFile = null;
    if (stopConfigName != null)
    {
      stopConfigFile = new File(stopConfigName);
      try
      {
        stopConfigName = stopConfigFile.getCanonicalPath();
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
      externalStop = stopConfigFile.isFile() && stopConfigFile.exists();
    }
    WrappedProcess stopper = null;
    getWrapperLogger().info("externalStop " + externalStop);
    if (externalStop)
    {
      getWrapperLogger().info("starting stop application");
      Configuration stopLocalConf = new BaseConfiguration();
      stopLocalConf.setProperty("wrapper.config", stopConfigName);
      YajswConfigurationImpl stopConf = new YajswConfigurationImpl(stopLocalConf, _useSystemProperties);
      stopper = WrappedProcessFactory.createProcess(stopConf);
      stopper.getLocalConfiguration().setProperty("wrapper.config", stopConfigName);
      stopper.setUseSystemProperties(_useSystemProperties);
      stopper.setStopper(true);
      // stopper.setDebug(true);
      stopper.init();
      stopper.start();
    }

    // else normally process is stopped by the controller
    // _osProcess.stop(shutdownWaitTime, 999);

    if (shutdownWaitTime > 0)
      _osProcess.waitFor(shutdownWaitTime);
    if (_osProcess.isRunning())
    {
      getWrapperLogger().info("process did not stop after " + shutdownWaitTime + " sec. -> hard kill");
    }
    _osProcess.kill(999);

    if (stopper != null && stopper.getState() != STATE_IDLE)
      stopper.stop();

    // give the OS some time to clean up
    try
    {
      Thread.sleep(500);
    }
    catch (InterruptedException e)
    {
      e.printStackTrace();
      Thread.currentThread().interrupt();
    }
    _osProcess.destroy();

    getWrapperLogger().info("process exit code: " + _osProcess.getExitCode());
  }

  abstract void stopController(int timeout);

  /**
   * Allow restart.
   *
   * @return true, if successful
   */
  protected boolean allowRestart()
  {
    if (System.currentTimeMillis() - _firstRestartTime > _successfulInvocationTime)
      _restartCount = 0;
    if (_state == STATE_USER_STOP || _state == STATE_RESTART || _state == STATE_RESTART_STOP || _state == STATE_RESTART_WAIT)
      return false;
    if (_restartCount < _config.getInt("wrapper.max_failed_invocations", DEFAULT_MAX_FAILED_INVOCATIONS))
      return true;
    getWrapperLogger().info("too many restarts ");
    return false;
  }

  /**
   * Restart.
   */
  public void restart()
  {
    if (_state != STATE_RUNNING)
      return;
    restartInternal();
  }

  /**
   * Restart by timer.
   */
  boolean  _timerRestart  = false;

  public void restartByTimer()
  {
    if (_timerRestart)
      return;
    _timerRestart = true;
    stop();
    try
    {
      Thread.sleep(getRestartDelay());
    }
    catch (InterruptedException e)
    {
      if (_debug)
        getWrapperLogger().log(Level.SEVERE, this.getClass().getName() + " restart", e);
      Thread.currentThread().interrupt();
    }

    startByTimer();
    _timerRestart = false;
  }

  /**
   * Checks if is debug.
   *
   * @return true, if is debug
   */
  boolean isDebug()
  {
    return _debug;
  }

  /**
   * Sets the debug.
   *
   * @param debug
   *            the new debug
   */
  public void setDebug(boolean debug)
  {
    _debug = debug;
  }

  /**
   * Gets the pid.
   *
   * @return the pid
   */
  public int getAppPid()
  {
    if (_osProcess != null)
      return _osProcess.getPid();
    else
      return -1;
  }

  /**
   * Save pid file.
   */
  private void savePidFile()
  {
    String file = _config.getString("wrapper.pidfile");
    if (file != null)
    {
      try
      {
        _pidFile = new File(file);
        if (!_pidFile.exists())
          _pidFile.createNewFile();
        FileWriter out = new FileWriter(_pidFile, false);
        out.write("" + OperatingSystem.instance().processManagerInstance().currentProcessId());
        out.flush();
        out.close();
        Thread hook = new Thread()
        {
          public void run()
          {
            removePidFile();
          }
        };
        Runtime.getRuntime().addShutdownHook(hook);
        _shutdownHooks.add(hook);
        if (_debug)
          getWrapperLogger().info("created pid file " + _pidFile.getAbsolutePath());
      }
      catch (Exception e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  /**
   * Removes the pid file.
   */
  private void removePidFile()
  {
    if (_pidFile != null)
    {
      try
      {
        _pidFile.delete();
        if (_config.getBoolean("wrapper.service", false))
          this.stop();

        if (_debug)
          getWrapperLogger().info("removed pid file " + _pidFile.getAbsolutePath());
        _pidFile = null;
      }
      catch (Exception e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  /**
   * Save lock file.
   *
   * @return true, if successful
   */
  protected boolean saveLockFile()
  {
    if (_lock != null)
      return true;
    String file = _config.getString("wrapper.lockfile", null);
    if (file != null && !"".equals(file))
    {
      try
      {
        _lockFile = new File(file);
        // Check if the lock exist
        if (_lockFile.exists())
        {
          // if exist try to delete it
          _lockFile.delete();
        }
        // Try to get the lock
        _lockFileChannel = new RandomAccessFile(_lockFile, "rw").getChannel();
        _lock = _lockFileChannel.tryLock();
        if (_lock == null)
        {
          // File is lock by other application
          _lockFileChannel.close();
          getWrapperLogger().warning("Lock file " + file + " already locked by another application -> abort");
          return false;
        }
        if (_debug)
          getWrapperLogger().info("created lock file " + _lockFile.getAbsolutePath());

      }
      catch (IOException e)
      {
        e.printStackTrace();
        return false;
      }
    }
    return true;
  }

  /**
   * Removes the lock file.
   */
  private void removeLockFile()
  {
    if (_lock != null)
    {
      // release and delete file lock
      try
      {
        _lock.release();
        if (_debug)
          getWrapperLogger().info("removed lock file " + _lockFile.getAbsolutePath());
        _lock = null;
        _lockFileChannel.close();
        _lockFileChannel = null;
        _lockFile.delete();
        _lockFile = null;
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    }
  }

  /**
   * File writer.
   *
   * @param file
   *            the file
   *
   * @return the file writer
   */
  private FileWriter FileWriter(String file)
  {
    // TODO Auto-generated method stub
    return null;
  }

  /**
   * Wait for.
   */
  public void waitFor()
  {
    waitFor(Long.MAX_VALUE);
  }

  /**
   * Wait for.
   *
   * @param t
   *            the t
   */
  public void waitFor(long t)
  {
    if (_state == STATE_IDLE)
      return;
    final Lock lock = new ReentrantLock();
    final java.util.concurrent.locks.Condition isIdle = lock.newCondition();
    StateChangeListener listener = new StateChangeListener()
    {

      public void stateChange(int newState, int oldState)
      {
        lock.lock();
        isIdle.signal();
        lock.unlock();
      }

    };
    this.addStateChangeListener(STATE_IDLE, listener);
    if (_state != STATE_IDLE)
      try
      {
        lock.lock();
        isIdle.await(t, TimeUnit.MILLISECONDS);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
        Thread.currentThread().interrupt();
      }
    lock.unlock();
    this.removeStateChangeListener(listener);
  }

  /**
   * Gets the local configuration.
   *
   * @return the local configuration
   */
  public Configuration getLocalConfiguration()
  {
    return _localConfiguration;
  }

  public void setLocalConfiguration(Configuration config)
  {
    _localConfiguration = config;
  }

  /**
   * Gets the exit code.
   *
   * @return the exit code
   */
  public int getExitCode()
  {
    return _exitCode;
  }

  /**
   * Gets the wrapper logger.
   *
   * @return the wrapper logger
   */
  public Logger getWrapperLogger()
  {
    if (_wrapperLogger != null)
      return _wrapperLogger;
    _wrapperLogger = new MyLogger();
    ((MyLogger) _wrapperLogger).setPID(_wrapperLoggerName);
    ((MyLogger) _wrapperLogger).setName(getName());
    _wrapperLogger.setUseParentHandlers(false);
    if (_controller != null)
      _controller.setLogger(_appLogger);
    if (getFileHandler() != null)
      _wrapperLogger.addHandler(getFileHandler());
    if (getConsoleHandler() != null)
      _wrapperLogger.addHandler(getConsoleHandler());
    return _wrapperLogger;
  }

  /**
   * Sets the use system properties.
   *
   * @param useSystemProperties
   *            the new use system properties
   */
  public void setUseSystemProperties(boolean useSystemProperties)
  {
    _useSystemProperties = useSystemProperties;
  }

  /**
   * Gets the tmp path.
   *
   * @return the tmp path
   */
  public String getTmpPath()
  {
    return _tmpPath;
  }

  /**
   * Start drain.
   */
  public synchronized void startDrain()
  {
    if (_gobler_err != null)
      _gobler_err.setDrain(true);
    if (_gobler_in != null)
      _gobler_in.setDrain(true);
    _drainActive = true;
  }

  /**
   * Stop drain.
   */
  public synchronized void stopDrain()
  {
    if (_gobler_err != null)
      _gobler_err.setDrain(false);
    if (_gobler_in != null)
      _gobler_in.setDrain(false);
    _drainActive = false;
  }

  /**
   * Read drain line.
   *
   * @return the string
   */
  public String readDrainLine()
  {
    String result = null;
    if (!_drainActive)
      return null;
    if (_gobler_err != null)
      try
      {
        if (!_gobler_err.isDrain())
          startDrain();
        result = _gobler_err.getDrainReader().readLine();
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    if (result == null && _gobler_in != null)
      try
      {
        if (!_gobler_in.isDrain())
          startDrain();
        result = _gobler_in.getDrainReader().readLine();
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    return result;

  }

  public int getState()
  {
    return _state;
  }

  /**
   * Restart internal.
   */
  public void restartInternal()
  {
    getWrapperLogger().info("restart internal " + getStringState());
    if (_state == STATE_RUNNING || _state == STATE_STARTING || _state == STATE_RESTART_START)
      setState(STATE_RESTART);
    else
      return;
    _restartCount++;
    if (_debug)
    {
      getWrapperLogger().info("restarting " + _restartCount + " time");
    }
    stopInternal();
    if (!_stopRequested)
    {
      setState(STATE_RESTART_WAIT);
      try
      {
        Thread.sleep(getRestartDelay());
      }
      catch (InterruptedException e)
      {
        if (_debug)
          getWrapperLogger().log(Level.SEVERE, this.getClass().getName() + " restart", e);
        Thread.currentThread().interrupt();
      }
      if (!_stopRequested)
        startInternal();
      else
      {
        getWrapperLogger().log(Level.SEVERE, "Process " + getName() + " stop requested, setting IDLE in restart internal");
        _stopRequested = false;
        if (!_osProcess.isRunning())
          setState(STATE_IDLE);
      }
    }
    else
    {
      if (_debug)
        getWrapperLogger().info(" stop requested, setting IDLE in restart internal");
      _stopRequested = false;
      if (!_osProcess.isRunning())
        setState(STATE_IDLE);
    }
  }

  private long getRestartDelay()
  {
    Script script = getRestartDelayScript();
    if (script != null)
    {
      Object time = script.execute();
      if (time instanceof Number)
        return ((Number) time).longValue() * 1000;
    }
    return _config.getLong("wrapper.restart.delay", DEFAULT_RESTART_DELAY) * 1000;
  }

  private Script getRestartDelayScript()
  {
    if (_restartDelayScript != null)
      return _restartDelayScript;
    String script = _config.getString("wrapper.restart.delay.script", null);
    if (script != null)
    {
      List args = _config.getList("wrapper.restart.delay.script.args", null);
      int timeout = _config.getInt("wrapper.restart.delay.script.timeout", 0);
      _restartDelayScript = ScriptFactory.createScript(script, "", this, args, getWrapperLogger(), 0);
    }
    return _restartDelayScript;
  }

  /**
   * The Class Gobler.
   */
  protected class Gobler implements Runnable
  {

    /** The _input stream. */
    InputStream                  _inputStream;

    /** The _name. */
    String                    _name;

    /** The _gobler log. */
    Logger                    _goblerLog;

    /** The _actions regex. */
    Map                      _actionsRegex;
    Map                      _missingActionsRegex;

    /** The _action triggers regex. */
    com.karneim.util.collection.regex.Pattern[]  _actionTriggersRegex;
    com.karneim.util.collection.regex.Pattern[]  _missingActionTriggersRegex;

    /** The _actions. */
    Map                      _actions;
    Map                      _missingActions;

    /** The _action triggers. */
    String[]                  _actionTriggers;
    String[]                  _missingActionTriggers;

    /** The _drain. */
    volatile boolean              _drain;

    /** The _drain buffer. */
    volatile CircularBuffer            _drainBuffer;

    /** The _drain reader. */
    volatile BufferedReader            _drainReader;
    volatile int                _pid;

    /**
     * Sets the drain.
     *
     * @param drain
     *            the new drain
     */
    public void setDrain(boolean drain)
    {
      if (drain && !_drain)
      {
        _drainBuffer = new CircularBuffer(16384, false);
        _drainReader = new BufferedReader(_drainBuffer);
      }
      else if (!drain && _drain)
      {
        try
        {
          _drainReader.close();
          _drainBuffer = null;
        }
        catch (IOException e)
        {
          e.printStackTrace();
        }
      }

      _drain = drain;
    }

    /**
     * Gets the drain reader.
     *
     * @return the drain reader
     */
    public BufferedReader getDrainReader()
    {
      return _drainReader;
    }

    /**
     * Instantiates a new gobler.
     *
     * @param stream
     *            the stream
     * @param log
     *            the log
     * @param events
     *            the events
     * @param eventsRegex
     *            the events regex
     * @param name
     *            the name
     */
    public Gobler(InputStream stream, Logger log, Map events, Map eventsRegex, Map missingEvents, Map missingEventsRegex, String name, int pid)
    {
      _inputStream = stream;
      _name = name;
      _goblerLog = log;
      _actions = events;
      if (events != null)
      {
        _actionTriggers = new String[events.size()];
        int i = 0;
        for (Iterator it = events.keySet().iterator(); it.hasNext(); i++)
        {
          _actionTriggers[i] = (String) it.next();
        }
      }
      _actionsRegex = eventsRegex;
      if (eventsRegex != null)
      {
        _actionTriggersRegex = new com.karneim.util.collection.regex.Pattern[eventsRegex.size()];
        int i = 0;
        for (Iterator it = eventsRegex.keySet().iterator(); it.hasNext(); i++)
        {
          String s = (String) it.next();
          try
          {
            _actionTriggersRegex[i] = new com.karneim.util.collection.regex.Pattern(s);
          }
          catch (Throwable ex)
          {
            getWrapperLogger().log(Level.SEVERE, "error in regular expression " + s, ex);
          }
        }
      }
      _missingActions = missingEvents;
      if (_missingActions != null)
      {
        _missingActionTriggers = new String[_missingActions.size()];
        int i = 0;
        for (Iterator it = _missingActions.keySet().iterator(); it.hasNext(); i++)
        {
          _missingActionTriggers[i] = (String) it.next();
        }
      }
      _missingActionsRegex = missingEventsRegex;
      if (_missingActionsRegex != null)
      {
        _missingActionTriggersRegex = new com.karneim.util.collection.regex.Pattern[_missingActionsRegex.size()];
        int i = 0;
        for (Iterator it = missingEventsRegex.keySet().iterator(); it.hasNext(); i++)
        {
          String s = (String) it.next();
          try
          {
            _missingActionTriggersRegex[i] = new com.karneim.util.collection.regex.Pattern(s);
          }
          catch (Throwable ex)
          {
            getWrapperLogger().log(Level.SEVERE, "error in regular expression " + s, ex);
          }
        }
      }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Runnable#run()
     */
    public void run()
    {
      try
      {
        if (_inputStream == null)
        {
          _goblerLog.info("cannot run stream gobler with a null stream");
          return;
        }
        InputStreamReader isr = new InputStreamReader(_inputStream);
        BufferedReader br = new BufferedReader(isr);
        String line = null;
        int k = 0;
        if (_missingActions != null)
          for (Iterator it = _missingActions.values().iterator(); it.hasNext();)
          {
            ((MissingTriggerAction) it.next()).start();
          }
        if (_missingActionsRegex != null)
          for (Iterator it = _missingActionsRegex.values().iterator(); it.hasNext();)
          {
            ((MissingTriggerAction) it.next()).start();
          }
        while ((line = br.readLine()) != null)
        {
          if (_drain)
            _drainBuffer.write(line);
          if (k > MIN_PROCESS_LINES_TO_LOG)
            _goblerLog.finest(line);
          else
          {
            _goblerLog.info(line);
            k++;
          }

          if (_actionTriggers != null)
            for (int i = 0; i < _actionTriggers.length; i++)
            {
              if (line.contains(_actionTriggers[i]))
              {
                Object obj = _actions.get(_actionTriggers[i]);
                if (obj instanceof TriggerAction)
                {
                  TriggerAction action = (TriggerAction) obj;
                  getWrapperLogger().info("Trigger found: " + _actionTriggers[i]);
                  action.execute(new String(line));
                }
                else if (obj instanceof Collection)
                {
                  Collection c = (Collection) obj;
                  for (Iterator it = c.iterator(); it.hasNext();)
                  {
                    TriggerAction action = (TriggerAction) it.next();
                    getWrapperLogger().info("Trigger found: " + _actionTriggers[i]);
                    action.execute(new String(line));
                  }
                }
                break;
              }
            }

          if (_actionTriggersRegex != null)
            for (int i = 0; i < _actionTriggersRegex.length; i++)
            {
              if (_actionTriggersRegex[i].contains(line))
              {
                Object obj = (TriggerAction) _actionsRegex.get(_actionTriggersRegex[i].getRegEx());
                if (obj instanceof TriggerAction)
                {
                  TriggerAction action = (TriggerAction) obj;
                  getWrapperLogger().info("Trigger found: " + _actionTriggersRegex[i]);
                  action.execute(new String(line));
                }
                else if (obj instanceof Collection)
                {
                  Collection c = (Collection) obj;
                  for (Iterator it = c.iterator(); it.hasNext();)
                  {
                    TriggerAction action = (TriggerAction) it.next();
                    getWrapperLogger().info("Trigger found: " + _actionTriggersRegex[i]);
                    action.execute(new String(line));
                  }
                }
                break;
              }
            }

          if (_missingActionTriggers != null)
            for (int i = 0; i < _missingActionTriggers.length; i++)
            {
              if ("".equals(_missingActionTriggers[i]) || line.contains(_missingActionTriggers[i]))
              {
                Object obj = (TriggerAction) _missingActions.get(_missingActionTriggers[i]);
                if (obj instanceof TriggerAction)
                {
                  TriggerAction action = (TriggerAction) obj;
                  // getWrapperLogger().info("Trigger found: "
                  // + _missingActionTriggers[i]);
                  action.execute(new String(line));
                }
                // break;
              }
            }

          if (_missingActionTriggersRegex != null)
            for (int i = 0; i < _missingActionTriggersRegex.length; i++)
            {
              if (_missingActionTriggersRegex[i].contains(line))
              {
                Object obj = (TriggerAction) _actionsRegex.get(_missingActionTriggersRegex[i].getRegEx());
                if (obj instanceof TriggerAction)
                {
                  TriggerAction action = (TriggerAction) obj;
                  // getWrapperLogger().info("Trigger found: "
                  // + _missingActionTriggersRegex[i]);
                  action.execute(new String(line));
                }
                // break;
              }
            }

          Thread.yield();
        }
      }
      catch (Exception ioe)
      {
        // ioe.printStackTrace();
        // _goblerLog.info("gobler execption " + _name + " " +
        // ioe.getMessage());
        if (_debug)
          _goblerLog.log(Level.INFO, " gobler exeception " + _name, ioe);
      }
      if (AbstractWrappedProcess.this._osProcess != null && _pid == AbstractWrappedProcess.this._osProcess.getPid()
          && AbstractWrappedProcess.this._osProcess.isRunning())
        AbstractWrappedProcess.this.executor.execute(new Runnable()
        {
          public void run()
          {
            if (AbstractWrappedProcess.this._state != STATE_RESTART_START && AbstractWrappedProcess.this._state != STATE_RESTART
                && AbstractWrappedProcess.this._state != STATE_RESTART_STOP
                && AbstractWrappedProcess.this._state != STATE_RESTART_WAIT)
            {
              _goblerLog.warning("yajsw panicking: gobler stopped but process is still running -> restart process");
              AbstractWrappedProcess.this.restartInternal();
            }
          }
        });

      if (_debug)
        _goblerLog.info("gobler terminated " + _name);
      if (_missingActions != null)
        for (Iterator it = _missingActions.values().iterator(); it.hasNext();)
        {
          ((MissingTriggerAction) it.next()).stop();
        }
      if (_missingActionsRegex != null)
        for (Iterator it = _missingActionsRegex.values().iterator(); it.hasNext();)
        {
          ((MissingTriggerAction) it.next()).stop();
        }

    }

    public boolean isDrain()
    {
      return _drain;
    }
  }

  public void addStateChangeListener(int state, StateChangeListener listener)
  {
    _listeners.put(state, listener);
  }

  public void addStateChangeListener(StateChangeListener listener)
  {
    _listeners.put(999, listener);
  }

  public void removeStateChangeListener(StateChangeListener listener)
  {

  }

  public void removeStateChangeListener(int state)
  {
    _listeners.remove(state);
  }

  public int getRestartCount()
  {
    return _restartCount;
  }

  public String getStringState()
  {
    return getStringState(_state);
  }

  public String getName()
  {
    String result = "";
    if (_config == null)
      return result;
    if (_config.getBoolean("wrapper.service", false))
      result += "Service ";
    String name = _config.getString("wrapper.console.title");
    if (name == null)
      name = _config.getString("wrapper.ntservice.name");
    if (name == null)
      name = _config.getString("wrapper.image");
    if (name == null)
      name = _config.getString("wrapper.groovy");
    if (name == null)
      name = _config.getString("wrapper.java.app.mainclass");
    if (name == null)
      name = _config.getString("wrapper.java.app.jar");
    if (name == null)
      name = "";
    result += name;
    return result;

  }

  public OutputStream getOutputStream()
  {
    if (_osProcess != null)
      return _osProcess.getOutputStream();
    return null;
  }

  public Date getAppStarted()
  {
    return _appStarted;
  }

  public Date getAppStopped()
  {
    return _appStopped;
  }

  public Date getWrapperStarted()
  {
    return _wrapperStarted;
  }

  public int getAppThreads()
  {
    if (_osProcess != null)
      return _osProcess.getCurrentThreads();
    else
      return -1;
  }

  public long getAppMemory()
  {
    if (_osProcess != null)
      return _osProcess.getCurrentVirtualMemory();
    else
      return -1;
  }

  public int getAppCpu()
  {
    if (_osProcess != null)
      return _osProcess.getCurrentCpu();
    else
      return -1;
  }

  public int getAppHandles()
  {
    if (_osProcess != null)
      return _osProcess.getCurrentHandles();
    else
      return -1;
  }

  public void addTriggerListener(TriggerListener listener)
  {
    // TODO ;
  }

  public int getWrapperPid()
  {
    return OperatingSystem.instance().processManagerInstance().currentProcessId();
  }

  public boolean isTimerActive()
  {
    return (_timer != null) && _timer.isTriggered();
  }

  public boolean isConditionActive()
  {
    return (_condition != null) && _condition.isTriggered();
  }

  public void threadDump()
  {
    if (_osProcess != null && this instanceof WrappedJavaProcess && _osProcess.isRunning())
      ((WrappedJavaProcess) this).requestThreadDump();

  }

  public void wrapperThreadDump()
  {
    Message m = new Message(Constants.WRAPPER_MSG_THREAD_DUMP, null);
    Action a = ActionFactory.getAction(m);
    try
    {
      ByteArrayOutputStream str = new ByteArrayOutputStream();
      PrintStream pr = new PrintStream(str);
      a.execute(m, null, pr, null);
      pr.flush();
      getWrapperLogger().info(str.toString());
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }

  public void stopTimerCondition()
  {
    stopTimer();
    stopCondition();
  }

  public boolean isOSProcessRunning()
  {
    if (_osProcess == null)
      return false;
    else
      return _osProcess.isRunning();
  }

  public int getTotalRestartCount()
  {
    return _totalRestartCount;
  }

  public boolean isService()
  {
    return _config.getBoolean("wrapper.service", false);
  }

  public String getType()
  {
    if (_config.getBoolean("wrapper.service", false))
      return "Service";
    else if (_config.getBoolean("wrapper.console.visible", false))
      return "Console";
    else
      return "Process";
  }

  public void shutdown()
  {
    setState(STATE_SHUTDOWN);
  }

  public void osProcessTerminated()
  {
    Process process = _osProcess;
    if (process != null)
      _exitCode = process.getExitCode();
  }

  public boolean isHaltWrapperOnApp()
  {
    return _haltWrapperOnApp;
  }

  public boolean isHaltAppOnWrapper()
  {
    return _haltAppOnWrapper;
  }

  public void setExiting()
  {
    _exiting = true;
  }

  public boolean isExiting()
  {
    return _exiting;
  }

  public TrayIconProxy getTrayIcon()
  {
    return _trayIconMessages;
  }

  public String[][] getTrayIconMessages()
  {
    if (_trayIconMessages == null)
      return null;
    return _trayIconMessages.toArrayAndClear();
  }

  public void stopWrapper()
  {
    if (_haltAppOnWrapper)
      stop();
    shutdown();
    try
    {
      Thread.sleep(5000);
    }
    catch (InterruptedException e)
    {
      e.printStackTrace();
    }
    System.exit(0);
  }

  public boolean hasOutput()
  {
    return getOutputStream() != null;
  }

  public void writeOutput(String txt)
  {
    ((PrintStream) getOutputStream()).println(txt);
  }

  public void writeInquireResponse(String s)
  {
    if (_trayIconMessages != null)
    {
      _trayIconMessages._inquireResponse = s;
      _trayIconMessages._inquireMessage = null;
    }
  }

  public String getInquireMessage()
  {
    if (_trayIconMessages != null)
      return _trayIconMessages._inquireMessage;
    else
      return null;
  }

  public void setService(Object service)
  {
    _service = service;
  }

  public Object getService()
  {
    return _service;
  }

  public void setProperty(String key, String value)
  {
    getWrapperLogger().info("set property " + key + " " + value);
    _localConfiguration.setProperty(key, value);
  }

  public void resetCache()
  {
    getWrapperLogger().info("reset cache ");
    _cache = null;
  }

  public long getMaxStartTime()
  {
    if (_config == null)
      return 0;
    long startDelay = _config.getLong("wrapper.startup.delay", 0);
    long startupTimeout = _config.getInt("wrapper.startup.timeout", DEFAULT_STARTUP_TIMEOUT) * 1000;
    if (startDelay < Integer.MAX_VALUE && startupTimeout < Integer.MAX_VALUE)
      return startDelay + startupTimeout;
    else
      return Integer.MAX_VALUE;
  }

  public boolean isReconnecting()
  {
    return _reconnecting;
  }

  void setReconnecting(boolean reconnecting)
  {
    _reconnecting = reconnecting;
  }
 
  public void setStopper(boolean b)
  {
    _stopper = b;
  }
 
  public void monitorConf()
  {
    boolean monitor = _config.getBoolean("wrapper.monitor.config", false);
    if (!monitor)
      return;
    if (_config.isStopper())
      return;
    final long fileTime = _config.getConfigFileTime();
    if (fileTime <= 0)
    {
      getWrapperLogger().info("wrapper.monitor.config: cannot start: could not get file time");
      return;
    }

    _localConfiguration.setProperty("wrapper.restart.reload_configuration", true);

    executor.execute(new Runnable()
      {
        public void run()
        {
          getWrapperLogger().info("wrapper.monitor.config: start");
          while (getState() == STATE_RUNNING)
          {
            long t = _config.getConfigFileTime();
            if (t > fileTime)
            {
              getWrapperLogger().info("wrapper.monitor.config: config file changed: "+new Date(fileTime)+" -> "+new Date(t)+" Restarting Application");
              executor.execute(new Runnable()
              {
                public void run()
                {
                  restart();
                }
              });
              break;
            }
            try
            {
            Thread.sleep(5000);
            }
            catch (Exception ex)
            {
              break;
            }
          }
          getWrapperLogger().info("wrapper.monitor.config: end");
        }
      });

  }


}
TOP

Related Classes of org.rzo.yajsw.wrapper.AbstractWrappedProcess

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.