Package ca.eandb.jdcp.console

Source Code of ca.eandb.jdcp.console.WorkerState

/*
* Copyright (c) 2008 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

package ca.eandb.jdcp.console;

import java.io.File;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import javax.security.auth.login.LoginException;

import org.apache.derby.jdbc.EmbeddedDataSource;
import org.apache.log4j.Logger;

import ca.eandb.jdcp.JdcpUtil;
import ca.eandb.jdcp.remote.AuthenticationService;
import ca.eandb.jdcp.remote.JobService;
import ca.eandb.jdcp.remote.ProtocolVersionException;
import ca.eandb.jdcp.worker.JobServiceFactory;
import ca.eandb.jdcp.worker.ThreadServiceWorker;
import ca.eandb.jdcp.worker.policy.CourtesyMonitor;
import ca.eandb.jdcp.worker.policy.ExecCourtesyMonitor;
import ca.eandb.jdcp.worker.policy.UnconditionalCourtesyMonitor;
import ca.eandb.util.args.CommandArgument;
import ca.eandb.util.args.OptionArgument;
import ca.eandb.util.concurrent.BackgroundThreadFactory;
import ca.eandb.util.progress.ProgressState;
import ca.eandb.util.progress.ProgressStateFactory;

/**
* Provides commands for managing a worker process.
* @author Brad Kimmel
*/
public final class WorkerState {

  /** The <code>Logger</code> to use to log messages. */
  private static final Logger logger = Logger.getLogger(WorkerState.class);

  /** The interval between connection attempts (in seconds). */
  private static final int RECONNECT_INTERVAL = 60;

  private static final long DEFAULT_COURTESY_POLLING_INTERVAL = 10;

  /** The list of <code>ProgressMonitor</code>s for each worker thread. */
  private List<ProgressState> taskProgressStates = null;

  /**
   * The <code>ThreadServiceWorker</code> that manages the worker threads.
   */
  private ThreadServiceWorker worker = null;

  /**
   * The <code>Thread</code> on which the <code>ThreadServiceWorker</code>
   * executes.
   */
  private Thread workerThread = null;

  /**
   * The number of seconds until the next reconnection attempt is made.
   */
  private int reconnectCountdown = -1;

  /**
   * Starts the worker process.
   * @param numberOfCpus The number of worker threads to spawn.
   * @param host The name of the host to connect to.
   * @param username The user name to log in with.
   * @param password The password to log in with.
   */
  @CommandArgument
  public void start(
      @OptionArgument("ncpus") int numberOfCpus,
      @OptionArgument("host") final String host,
      @OptionArgument("username") final String username,
      @OptionArgument("password") final String password,
      @OptionArgument(value="nodb", shortKey='i') final boolean internal,
      @OptionArgument("courtesy") final String courtesyCommand,
      @OptionArgument(value="courtesyWorkingDirectory", shortKey='W') File courtesyWorkingDirectory,
      @OptionArgument(value="courtesyPollingInterval", shortKey='P') long courtesyPollingInterval
      ) {

    int availableCpus = Runtime.getRuntime().availableProcessors();
    if (numberOfCpus <= 0 || numberOfCpus > availableCpus) {
      numberOfCpus = availableCpus;
    }
    System.out.println("Starting worker with " + Integer.toString(numberOfCpus) + " cpus");

    if (worker != null) {
      logger.info("Shutting down worker");
      worker.shutdown();
      try {
        workerThread.join();
      } catch (InterruptedException e) {
      }
    }

    logger.info("Starting worker");

    JobServiceFactory serviceFactory = new JobServiceFactory() {
      public JobService connect() {
        return waitForService(
            host.equals("") ? "localhost" : host,
            username.equals("") ? "guest" : username,
            password, RECONNECT_INTERVAL);
      }
    };

    CourtesyMonitor courtesyMonitor;
    if (!courtesyCommand.equals("")) {
      logger.info("Initializing courtesy monitor");
      if (courtesyPollingInterval == 0) {
        courtesyPollingInterval = DEFAULT_COURTESY_POLLING_INTERVAL;
      }
      ExecCourtesyMonitor exec = new ExecCourtesyMonitor(courtesyCommand, courtesyWorkingDirectory);
      exec.startPolling(courtesyPollingInterval, TimeUnit.SECONDS);
      courtesyMonitor = exec;
    } else {
      courtesyMonitor = new UnconditionalCourtesyMonitor();
    }

    ThreadFactory threadFactory = new BackgroundThreadFactory();
    ProgressStateFactory monitorFactory = new ProgressStateFactory();
    worker = new ThreadServiceWorker(serviceFactory, threadFactory, monitorFactory, courtesyMonitor);
    worker.setMaxWorkers(numberOfCpus);

    taskProgressStates = monitorFactory.getProgressStates();

    if (!internal) {
      logger.info("Preparing data source");
      EmbeddedDataSource ds = null;
      try {
        Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
        ds = new EmbeddedDataSource();
        ds.setConnectionAttributes("create=true");
        ds.setDatabaseName("classes");
        worker.setDataSource(ds);
      } catch (ClassNotFoundException e) {
        logger.error("Could not locate database driver.", e);
      } catch (SQLException e) {
        logger.error("Error occurred while initializing data source.", e);
      }
    }

    workerThread = new Thread(worker);
    workerThread.start();

  }

  private JobService waitForService(String host, String username, String password, int retryInterval) {
    JobService service = null;
    while (true) {
      reconnectCountdown = 0;
      service = connect(host, username, password);
      if (service != null) {
        break;
      }

      for (int i = retryInterval; i > 0; i--) {
        reconnectCountdown = i;
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          reconnectCountdown = -1;
          return null;
        }
      }
    }
    reconnectCountdown = -1;
    return service;
  }

  private JobService connect(String host, String username, String password) {
    JobService service = null;
    try {
      Registry registry = LocateRegistry.getRegistry(host, JdcpUtil.DEFAULT_PORT);
      AuthenticationService auth = (AuthenticationService) registry.lookup("AuthenticationService");
      service = auth.authenticate(username, password, JdcpUtil.PROTOCOL_VERSION_ID);
    } catch (NotBoundException e) {
      logger.error("Job service not found at remote host.", e);
    } catch (RemoteException e) {
      logger.error("Could not connect to job service.", e);
    } catch (LoginException e) {
      logger.error("Login failed.", e);
    } catch (ProtocolVersionException e) {
      logger.error("Client is incompatible with remote server.", e);
    }
    return service;
  }

  /**
   * Sets the maximum number of concurrent workers.
   * @param numberOfCpus The number of CPUs to use (zero to use all available
   *     CPUs on the machine).
   */
  @CommandArgument
  public void setcpus(int numberOfCpus) {
    if (worker == null) {
      System.err.println("Worker not running.");
      return;
    }
    int availableCpus = Runtime.getRuntime().availableProcessors();
    if (numberOfCpus <= 0 || numberOfCpus > availableCpus) {
      numberOfCpus = availableCpus;
    }
    System.out.printf("Setting number of CPUs to %d\n", numberOfCpus);
    worker.setMaxWorkers(numberOfCpus);
  }

  /**
   * Stops the worker process.
   */
  @CommandArgument
  public void stop() {
    System.out.println("Stopping worker");
    worker.shutdown();
    workerThread.interrupt();
    try {
      workerThread.join();
    } catch (InterruptedException e) {
      logger.warn("Joining to worker thread interrupted", e);
    }
    worker = null;
    workerThread = null;
    taskProgressStates = null;
  }

  /**
   * Prints the status of the worker threads.
   * @param index The 1-based index of the worker thread to print the status
   *     of, or zero to print the status of all worker threads.
   */
  @CommandArgument
  public void stat(int index) {
    if (reconnectCountdown > 0) {
      System.out.printf("Lost connection, reconnecting in %d seconds.\n", reconnectCountdown);
      return;
    }
    if (reconnectCountdown == 0) {
      System.out.println("Connecting...");
      return;
    }
    if (taskProgressStates == null) {
      System.out.println("Worker not running");
      return;
    }
    Iterator<ProgressState> iter = taskProgressStates.iterator();
    while (iter.hasNext()) {
      ProgressState state = iter.next();
      if (state.isCancelled() || state.isComplete()) {
        iter.remove();
      }
    }
    if (index == 0) { // print status of all workers.
      List<ProgressState> taskProgressStates = new ArrayList<ProgressState>(this.taskProgressStates);
      if (taskProgressStates != null) {
        System.out.println("  # Progress                         Status                             ");
        System.out.println("------------------------------------------------------------------------");
        for (int i = 0, n = taskProgressStates.size(); i < n; i++) {
          ProgressState state = taskProgressStates.get(i);
          char flag = ' ';
          if (state.isComplete()) {
            flag = '*';
          } else if (state.isCancelled()) {
            flag = 'X';
          } else if (state.isCancelPending()) {
            flag = 'C';
          }
          String status = state.getStatus();
          if (status.length() > 35) {
            status = status.substring(0, 34) + ">";
          }
          boolean indeterminant = state.isIndeterminant();
          double progress = state.getProgress();
          String progressBar;
          if (!indeterminant) {
            StringBuilder progressBarBuilder = new StringBuilder("|");
            for (int j = 0; j < 25; j++) {
              if (indeterminant) {
              }
              progressBarBuilder.append((progress >= (double) (j + 1) / 25.0) ? "=" : " ");
            }
            progressBarBuilder.append("|");
            progressBar = progressBarBuilder.toString();
          } else {
            progressBar = "|?????????????????????????|";
          }
          String progStr = (indeterminant ? "????" : String.format("% 3.0f%%", 100.0 * progress));
          System.out.printf("%c% 2d %s %s %-35s\n",
              flag, i + 1, progressBar, progStr, status);
        }
      }
    } else if (index > 0 && index <= this.taskProgressStates.size()) {
      // print status of a single worker.
      ProgressState state = this.taskProgressStates.get(index - 1);
      System.out.printf("Worker #%d", index);
      if (state.isComplete()) {
        System.out.print(" [COMPLETE]");
      } else if (state.isCancelled()) {
        System.out.print(" [CANCELLED]");
      } else if (state.isCancelPending()) {
        System.out.print(" [CANCEL PENDING]");
      }
      System.out.println();
      if (state.isIndeterminant()) {
        System.out.print("Progress : ???");
      } else {
        System.out.printf("Progress : %.2f%%", 100.0 * state.getProgress());
      }
      int maximum = state.getMaximum();
      int value = state.getValue();
      if (maximum > 0) {
        System.out.printf(" (%d/%d)", value, maximum);
      }
      System.out.println();
      System.out.printf("Status   : %s\n", state.getStatus());
    } else {
      System.err.println("Invalid worker number");
    }

  }

}
TOP

Related Classes of ca.eandb.jdcp.console.WorkerState

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.