Scheduler.java :  » JMX » XMOJO » javax » management » timer » Java Open Source

Java Open Source » JMX » XMOJO 
XMOJO » javax » management » timer » Scheduler.java
/**
* The XMOJO Project 5
* Copyright  2003 XMOJO.org. All rights reserved.

* NO WARRANTY

* BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
* THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
* OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
* PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
* OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
* TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE
* LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
* REPAIR OR CORRECTION.

* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
* ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
* THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
* GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
* USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF
* DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
* PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
* EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGES.
**/

package javax.management.timer;

import java.util.*;
import java.io.*;

/**
 * A scheduler for running tasks in a Java VM.
 * This class can be used to schedule a particular task at a
 * specified time. This is basically to control effectively a number of tasks
 * using a limited number of threads
 */

public class Scheduler extends Thread {

    /**
     * The maximum numer of threads to be used in executing tasks for this
     * scheduler
     */
    int MAX_THREADS = 4;

    /*
     * To get the number of threads that this scheduler controls
     */

    public int getMaxThreads() {
  return MAX_THREADS ;
    }

    private static int DEFAULT_MAX_THREADS = 4;

    /*
     * In case a scheduler is initialized without specifying the max number
     * of threads neither in the conf file , nor in the arguments passed
     * to the method , then what should the default number
     */

    public static int getDefaultMaxThreads() {
  return DEFAULT_MAX_THREADS ;
    }
    /*
     * In case a scheduler is initialized without specifying the max number
     * of threads neither in the conf file , nor in the arguments passed
     * to the method , then what should the default number
     */

    public static void setDefaultMaxThreads(int i) {
  if ( (i>=0) && (i<100) ) {
      DEFAULT_MAX_THREADS=i;
  }
    }

    /*
     * To set/change the number of threads that this scheduler controls .
     * Note this can be done only when the scheduler has been stopped by
     * the stopThis or stopAll methods .
     * The boolean returned will indicate whether the operation was successful
     * or not .
     */

    public boolean setMaxThreads(int i) {
  if (isAlive()) return false;
  if ( (i>=0) && (i<100) ) {
      MAX_THREADS=i;
      return true ;
  }
  return false ;
    }


    /*
     * The total number of threads which are scheduled via schedulers . that is
     * the combined total of all active schedulers .
     */
    static int TOTAL_THREADS = 0;


    /*
     * To get the total number of active threads that all the schedulers
     * put together control.
     */

    public static int getTotalThreads() {
  return TOTAL_THREADS ;
    }

    // The boolean for one to be able to stop all schedulers
    static boolean STOP_ALL = false;

    // The boolean for one to be able to stop this scheduler alone
    boolean STOP_THIS = false;

    // the number of threads that have been stopped for this scheduler alone
    int NUM_THREADS_STOPPED=0;

    Vector runnables = new Vector(); // The tasks to be run
    Vector times = new Vector(); // when to run them
    Vector workers = new Vector(); // the guys who do the work
    Vector ready_tasks = new Vector(); // the tasks to be run immediately


    // We will store internally reference to all the schedulers when they
    // are instantiated . Schedulers can no longer be instantiated publicly

    private static Hashtable schedulers = new Hashtable(15) ;

    private static Hashtable maxThreads = new Hashtable(15);

    // The conffile which should be used to read the details of the number
    // of threads etc .
    private static String confFile = "conf/threads.conf" ;

    private static boolean readConfFile = false ;

    public static String getConfFile() {
  return confFile;
    }

    public static void setConfFile(String s) {
  confFile=s;
    }

    private static synchronized void readTheConfFile() {
  if (readConfFile) return;
  BufferedReader is = null;
  String line = null;
  try {
      File ff = new File(confFile);
      if (!ff.exists()) {
    //System.err.println(" in 135 Scheduler "+confFile+" does not exist");
    readConfFile=true;
    return ;
      }
      is =  new BufferedReader(new FileReader(ff));
      while ( (line = is.readLine()) != null) {
    if (line.trim().equals("")) continue;
    else if (line.startsWith("#")) continue;
    else {
        StringTokenizer tok = new StringTokenizer(line);
        if (tok.countTokens()==2) {
      String s = tok.nextToken();
      int numb =-1;
      try {
          numb =Integer.parseInt(tok.nextToken());
      } catch ( NumberFormatException nfe) {}
      if ( (numb<0) || (numb>100) ) {
          System.err.println(" Invalid line in the conf file "+
          confFile+
          " :"+line);
          continue;
      }
      maxThreads.put(s,new Integer(numb));
        } else {
      System.err.println(" Invalid line in the conf file "+confFile+
            " :"+line);
        }
    }
      }
  } catch (IOException e) {
      System.err.println("Scheduler  File read Error:"+confFile + ": "+e);
  } catch (SecurityException anye) {}
  readConfFile = true ;
    }

    public static  Scheduler createScheduler(String nam) {
  return createScheduler(nam,-1);
    }


    /*
     * This is the method to create a new instance of the Scheduler
     * and give it . If there already exists a scheduler with that name
     * then that is returned .
     */

    public static Scheduler createScheduler(String nam,int maxThreadNumber) {
  synchronized (schedulers) {
      if (nam==null) return null;
      Scheduler sch = getScheduler(nam);
      if (sch!=null) return sch ;
      readTheConfFile();
      if ((maxThreadNumber<=0) || (maxThreadNumber>100) ) {
    Integer integ = (Integer)maxThreads.get(nam);
    if (integ!=null) sch =new Scheduler(nam,integ.intValue());
    else sch =new Scheduler(nam);
      } else sch =new Scheduler(nam,maxThreadNumber);
      schedulers.put(nam ,sch);
      //commentSystem.out.println("Instantiated "+sch.getName()+" scheduler with "+
    //comment       sch.MAX_THREADS +" threads ");
      return sch;
  }
    }
    /*
     * One should use this method to get a reference to the scheduler . If
     * a scheduler with the given name does not exist then it returns null;
     * I agree this method is dangerous in the sense that malicious code can call
     * this method get reference and say suspend all scheduling .So should be
     * used with care
     */

    public static Scheduler getScheduler(String nam) {
  if (nam==null) return null;
  return (Scheduler)schedulers.get(nam);
    }

    /**
     * The constructor initializes the worker threads which invokes the task
     * to be scheduled at a specific time.
     */
    private Scheduler(String name,int maxThreads)
    {
  super(name);
        MAX_THREADS = maxThreads;
    }
    /**
     * The constructor initializes the worker threads which invokes the task
     * to be scheduled at a specific time.
     */
    private Scheduler(String name)
    {
  this(name,DEFAULT_MAX_THREADS);
    }

/**
 * This methood schedules a one-time task at the specified time
*/
    public synchronized void scheduleTask(Runnable task, Date when)
    {
  if (when == null) when = new Date();
  for (int i=0;i<times.size();i++) {
      Date d = (Date) times.elementAt(i);
      if (d.after(when)) {
    times.insertElementAt(when,i);
    runnables.insertElementAt(task,i);
    return;
      }
  }
  times.addElement(when);
  runnables.addElement(task);
  notifyAll();
    }

    /**
     * This methood is used to remove a task from being scheduled.
     */

    public synchronized void removeTask(Runnable task)
    {
        if (task == null) return;
  for (int i=0;i<runnables.size();i++) {
      Runnable r = (Runnable) runnables.elementAt(i);
      if (task.equals(r)) {
          runnables.removeElement(r);
          times.removeElementAt(i);
                i--;
      }
  }
    }

    /*
     * If you have used stopAll method to suspend all schedulers , then using this
     * will restart all of them
     */

    public boolean resumeAll() {
  synchronized (schedulers) {
      if (!STOP_ALL) return false;
      STOP_ALL=false;
      for (Enumeration en=schedulers.elements();en.hasMoreElements();) {
    Scheduler sch = (Scheduler)en.nextElement();
    sch.start();
      }
  }
  return false ;
    }

  //Stops and destroys the schduler and its worker threads
  //Cannot reuse scheduler when this method is called
  public void killScheduler()
  {
    if (STOP_ALL) return ;
    STOP_THIS= true;
    STOP_ALL = true;
    try{
    for (int i=0;i<workers.size();i++) {
      WorkerThread worker = (WorkerThread) workers.elementAt(i);
      worker.wakeUp();
    }
    }catch(Throwable th){th.printStackTrace();}
    //waits at the max 1sec for the this scheduler thread to die
    for(int i = 0; i < 50; i++) {
      if(isAlive())
      {
        try{
        Thread.sleep(20);
        }catch(Exception e){}
      }
      else
        break;
    }
  }
    /*
     * This method will stop not only this but all schedulers threads .
     * so  be very careful in using this .
     * Will return false if it could not  stop any thread
     */

    public static boolean stopAll()
    {
  synchronized (schedulers) {
      if (STOP_ALL) return false;
      int count=0;
      STOP_ALL = true;
      int totalorg =TOTAL_THREADS;
      while (TOTAL_THREADS>0)
    {
        if(count >= STOP_TIME_OUT) {
      System.err.println("Schedulers did not stop properly: "
             + (totalorg-TOTAL_THREADS) +
             " threads stopped out of " +
             totalorg);
      System.err.println("The remaining "+
             TOTAL_THREADS+
             " threads did not stop in "+
             STOP_TIME_OUT+ " seconds ");
      return false;
        }
        try {
      Thread.sleep(1000);
      count++;
        }
        catch (Exception e){}
    }
      System.out.println((totalorg-TOTAL_THREADS) +
             " of the "+totalorg+
             " active threads in the control "+
             " of  the schedulers stopped");

      TOTAL_THREADS=0;
      return true;
  }
    }


    /*
     * This method will stop this scheduler alone . The scheduler will not
     * clean up the runnables queue by calling this method . One can restart
     * by invoking the start method . If you want this scheduler to get
     * cleaned up invoke the cleanup method after invoking this method
     * Will return false if it could not  stop any thread
     */

    public boolean stopThis()
    {
        int count=0;
        STOP_THIS = true;
        while (NUM_THREADS_STOPPED < MAX_THREADS)
        {
            if(count >= STOP_TIME_OUT) {
                System.err.println("Scheduler:"+getName()+" did not stop properly: " + NUM_THREADS_STOPPED + " threads stopped out of " + MAX_THREADS);
    System.err.println("The remaining "+
           (MAX_THREADS-NUM_THREADS_STOPPED)+
           " threads of scheduler:"+getName()+
           "did not stop in "+
           STOP_TIME_OUT+ " seconds ");

                return false;
            }
            try {
                Thread.sleep(1000);
                count++;
            }
            catch (Exception e){}
        }
        System.out.println(NUM_THREADS_STOPPED + "out of "+MAX_THREADS+
         " active threads stopped in "+
         " Scheduler:"+getName());

        return true;
    }

    /*
     * This method should be used if you want to cleanup the scheduler and
     * release all resources from it. Remember the external code has to take
     * care of the references it has to this object .This should be called
     * when you do a stopThis on a scheduler and you have no intentions
     * on using it (that is restarting it) again .
     */

    public boolean cleanUp() {
  //if (isAlive())
  //{
  //  System.out.println(" *********** Returning from cleanUp isAlive is true "+this.getName());
  //  return false;
  //}
  synchronized (schedulers) {
      times.removeAllElements();
      runnables.removeAllElements();
      ready_tasks.removeAllElements();
      workers.removeAllElements();
      schedulers.remove(getName());
      return true;
  }
    }

    static int STOP_TIME_OUT = 15;

    /*
     * The time in seconds that the calling thread should wait while invoking
     * the stopALl or stopThis methods . That is when these two methods are
     * invoked the method will block for a maximum of this time before
     * printing a message that all the threads could not be stopped . Of course
     * if all the releveant threads stop then the method will return immediately
     */



    public void setStopTimeout(int timeout)
    {
        STOP_TIME_OUT = timeout;
    }

    /** something to let this thread rest when nothing to do **/
    synchronized Runnable getTheWork() {
  while (times.size() == 0) try {
      wait(10);
            if ( (STOP_ALL) || (STOP_THIS) )return null;
  } catch (InterruptedException iex) {}

  Date first = (Date) times.firstElement();
  Date now = new Date();
  if (first.after(now)) return null;
  Runnable task = (Runnable) runnables.firstElement();
        runnables.removeElement(task);
  times.removeElement(first);
  return task;
    }


 /** The main thread which kicks off the task execution **/
    public void run() {
  synchronized (schedulers) {
      STOP_ALL=false;
      STOP_THIS=false;
  }
  startWorkers(); // first start the workers
  if (MAX_THREADS==0) return ;
  while ( (!STOP_ALL) && (!STOP_THIS) )
      try {
    Runnable task = getTheWork();
    if (task == null) {
        try  {
      waitSchedule();
        } catch (InterruptedException iex) {}
    } else {
        startTask(task);
    }
      } catch (Exception ex) {
    System.err.println("Exception scheduling task in scheduler:"
           +getName()+" "+ ex);
//    ex.printStackTrace();
      }
  return;
    }

    synchronized void waitSchedule() throws InterruptedException {
        wait(10);
    }

    /** start the task **/
    synchronized void startTask(Runnable task) {
  ready_tasks.addElement(task);
  for (int i=0;i<workers.size();i++) { // first start the workers
      WorkerThread worker = (WorkerThread) workers.elementAt(i);
      worker.wakeUp();
  }
    }


    /** get the next task ready to run **/
    synchronized Runnable getNextTask() {
  if (ready_tasks.size() == 0) return null;
  Runnable task = (Runnable) ready_tasks.firstElement();
  ready_tasks.removeElement(task);
  return task;
    }

    /** start the workers**/
    synchronized void startWorkers() {
  if ( (STOP_ALL) || (STOP_THIS) ) return;
  workers = new Vector();
  for (int i=0;i<MAX_THREADS;i++) {
      TOTAL_THREADS += 1;
      WorkerThread worker = new WorkerThread(this,getName()+"-"+(i+1));
      workers.addElement(worker);
      worker.start();
  }
    }

    public void deregisterThisScheduler(String nam)// Devesh...because of reload problem in JavaUI
    {
        if(nam == null)
            return;
        else
        {
            Scheduler s = (Scheduler)schedulers.remove(nam);
            s.stopAll();
        }

    }

}






java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.