/**
   * The start method is called when the WrapperManager is signaled by the native wrapper code that
   * it can start its application. This method call is expected to return, so a new thread should be
   * launched if necessary.
   *
   * @param args List of arguments used to initialize the application.
   * @return Any error code if the application should exit on completion of the start method. If
   *     there were no problems then this method should return null.
   */
  public Integer start(String[] args) {
    if (WrapperManager.isDebugEnabled()) {
      System.out.println(Main.getRes().getString("LoadedWrapperListener: start(args)"));
    }

    Thread mainThread = new Thread(this, "LoadedWrapperListenerMain");
    synchronized (this) {
      m_startMainArgs = args;
      mainThread.start();
      // Wait for five seconds to give the application a chance to have failed.
      try {
        this.wait(5000);
      } catch (InterruptedException e) {
      }
      m_waitTimedOut = true;

      if (WrapperManager.isDebugEnabled()) {
        System.out.println(
            Main.getRes()
                .getString(
                    "LoadedWrapperListener: start(args) end.  Main Completed={0}, exitCode={1}",
                    new Object[] {new Boolean(m_mainComplete), m_mainExitCode}));
      }
      return m_mainExitCode;
    }
  }
  /** Main method of the actual application. */
  private void appMain(String[] args) {
    System.out.println(Main.getRes().getString("App Main Starting."));
    System.out.println();

    // Loop and display 500 long lines of text to place to dump a lot of
    //  output before the CPU starts being loaded down.  This will strain
    //  the Wrapper just as the CPU suddenly hpegs at 100%.
    for (int i = 0; i < 500; i++) {
      System.out.println(
          new Date()
              + Main.getRes().getString("  Pre {0} of output. ", new Integer(i))
              + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    }

    // Start up a thread to thrash the hard disk.
    Thread diskThrasher =
        new Thread("LoadedWrapperListener_DiskThrasher") {
          public void run() {
            performDiskThrashing();
          }
        };
    diskThrasher.start();

    // Start up a thread to thrash memory.
    Thread memoryThrasher =
        new Thread("LoadedWrapperListener_MemoryThrasher") {
          public void run() {
            performMemoryThrashing();
          }
        };
    memoryThrasher.start();

    // Start up some threads to eat all available CPU
    for (int i = 0; i < 4; i++) {
      Thread cpuThrasher =
          new Thread("LoadedWrapperListener_CPUThrasher_" + i) {
            public void run() {
              performCPUThrashing();
            }
          };
      cpuThrasher.start();
    }

    // Loop and display 5000 long lines of text to place a heavy load on the
    //  JVM output processing code of the Wrapper while the above threads are
    //  eating all available CPU.
    for (int i = 0; i < 5000; i++) {
      System.out.println(
          new Date()
              + "  Row "
              + i
              + " of output. "
              + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    }
    System.out.println();
    System.out.println(Main.getRes().getString("App Main Complete."));
  }
  /**
   * Called when the application is shutting down. The Wrapper assumes that this method will return
   * fairly quickly. If the shutdown code code could potentially take a long time, then
   * WrapperManager.signalStopping() should be called to extend the timeout period. If for some
   * reason, the stop method can not return, then it must call WrapperManager.stopped() to avoid
   * warning messages from the Wrapper.
   *
   * @param exitCode The suggested exit code that will be returned to the OS when the JVM exits.
   * @return The exit code to actually return to the OS. In most cases, this should just be the
   *     value of exitCode, however the user code has the option of changing the exit code if there
   *     are any problems during shutdown.
   */
  public int stop(int exitCode) {
    if (WrapperManager.isDebugEnabled()) {
      System.out.println(
          Main.getRes().getString("LoadedWrapperListener: stop({0})", new Integer(exitCode)));
    }

    return exitCode;
  }
  /** Runner thread which actually launches the application. */
  public void run() {
    Throwable t = null;
    try {
      if (WrapperManager.isDebugEnabled()) {
        System.out.println(
            Main.getRes().getString("LoadedWrapperListener: invoking start main method"));
      }
      appMain(m_startMainArgs);
      if (WrapperManager.isDebugEnabled()) {
        System.out.println(
            Main.getRes().getString("LoadedWrapperListener: start main method completed"));
      }

      synchronized (this) {
        // Let the start() method know that the main method returned, in case it is
        //  still waiting.
        m_mainComplete = true;

        this.notifyAll();
      }

      return;
    } catch (Throwable e) {
      t = e;
    }

    // If we get here, then an error was thrown.  If this happened quickly
    // enough, the start method should be allowed to shut things down.
    System.out.println(Main.getRes().getString("Encountered an error running start main: {0}", t));
    t.printStackTrace();

    synchronized (this) {
      if (m_waitTimedOut) {
        // Shut down here.
        WrapperManager.stop(1);
        return; // Will not get here.
      } else {
        // Let start method handle shutdown.
        m_mainComplete = true;
        m_mainExitCode = new Integer(1);
        this.notifyAll();
        return;
      }
    }
  }
  private void performMemoryThrashing() {
    while (!m_mainComplete) {
      // 200MB block of memory
      byte[][] garbage = new byte[200][];
      for (int i = 0; i < garbage.length; i++) {
        garbage[i] = new byte[1024 * 1024];
      }
      garbage = null;

      Runtime runtime = Runtime.getRuntime();
      long totalMemory = runtime.totalMemory();
      long freeMemory = runtime.freeMemory();
      System.out.println(
          Main.getRes().getString("Total Memory=")
              + totalMemory
              + ", "
              + Main.getRes().getString("Used Memory=")
              + (totalMemory - freeMemory));
    }
  }
  /**
   * Called whenever the native wrapper code traps a system control signal against the Java process.
   * It is up to the callback to take any actions necessary. Possible values are:
   * WrapperManager.WRAPPER_CTRL_C_EVENT, WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or
   * WRAPPER_CTRL_SHUTDOWN_EVENT
   *
   * @param event The system control signal.
   */
  public void controlEvent(int event) {
    if (WrapperManager.isControlledByNativeWrapper()) {
      if (WrapperManager.isDebugEnabled()) {
        System.out.println(
            Main.getRes()
                .getString("LoadedWrapperListener: controlEvent({0}) Ignored", new Integer(event)));
      }
      // Ignore the event as the native wrapper will handle it.
    } else {
      if (WrapperManager.isDebugEnabled()) {
        System.out.println(
            Main.getRes()
                .getString(
                    "LoadedWrapperListener: controlEvent({0}) Stopping", new Integer(event)));
      }

      // Not being run under a wrapper, so this isn't an NT service and should always exit.
      //  Handle the event here.
      WrapperManager.stop(0);
      // Will not get here.
    }
  }
 private void performDiskThrashing() {
   while (!m_mainComplete) {
     File file = new File("loadedwrapperlistener.dat");
     try {
       PrintWriter w = new PrintWriter(new FileWriter(file));
       try {
         for (int i = 0; i < 100; i++) {
           w.println(
               new Date()
                   + Main.getRes().getString("  Row {0} of output. ", new Integer(i))
                   + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
         }
       } finally {
         w.close();
       }
     } catch (IOException e) {
       e.printStackTrace();
     }
     file.delete();
   }
 }