Package com.thenetcircle.comsumerdispatcher.thread

Source Code of com.thenetcircle.comsumerdispatcher.thread.ConsumerJobExecutorPool$Worker

package com.thenetcircle.comsumerdispatcher.thread;

import java.lang.Thread.State;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.thenetcircle.comsumerdispatcher.distribution.watcher.CountChangedWatcher;
import com.thenetcircle.comsumerdispatcher.distribution.watcher.IJobPoolLevelWatcher;
import com.thenetcircle.comsumerdispatcher.distribution.watcher.QueuePurgeWatcher;
import com.thenetcircle.comsumerdispatcher.job.JobExecutor;

public class ConsumerJobExecutorPool implements ConsumerJobExecutorPoolMBean {
  private static Log _logger = LogFactory.getLog(ConsumerJobExecutorPool.class);
 
    private final ObjectName mbeanName;
    private final NamedThreadFactory threadFactory;
    private final JobExecutor job;
    private final HashSet<Worker> workers = new HashSet<Worker>();
   
    protected final AtomicInteger completeTaskCount = new AtomicInteger(0);
    private final AtomicInteger activeExecutorCount = new AtomicInteger(0);
    private final AtomicBoolean logErrorJobToFile = new AtomicBoolean(false);
   
    private IJobPoolLevelWatcher purgeWatcher, countChangedWatcher;

    public ConsumerJobExecutorPool(JobExecutor job) {
         String jmxType = job.getQueue() + "_" + job.getFetcherQConf().getHost() + "_" + job.getFetcherQConf().getVhost();
         this.job = job; 
      threadFactory = new NamedThreadFactory(jmxType);
     
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
       
        try
        {
            URL url = new URL(job.getUrl());
            String domain = url.getHost();
            Hashtable<String, String> kv = new Hashtable<String, String>();
            kv.put("queue", job.getQueue());
            kv.put("q_host", job.getFetcherQConf().getHost());
            kv.put("q_vhost", job.getFetcherQConf().getVhost());
            mbeanName =  new ObjectName(domain, kv);
            mbs.registerMBean(this, new ObjectName(domain, kv));
           
            //watchers
            purgeWatcher = new QueuePurgeWatcher();
            purgeWatcher.register(this);
            countChangedWatcher = new CountChangedWatcher();
            countChangedWatcher.register(this);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
   
    public JobExecutor getJobDefinition() {
      return this.job;
    }
   
    /**
     * initial job executors (threads)
     * according to the COUNT number defined in configuration
     *
     * @return the number of executors initialized
     */
    public int startJobExecutors() {
    addJobExecutor(job.getCount());
     
      return job.getCount();
    }
   
    public void setJobExecutorNum(int num) {
      _logger.info("[THREAD NUM Set] going to set " + num + " of executors ...");
      int currentNum = activeExecutorCount.intValue();
      if(currentNum > num) {
        removeJobExecutorsByNum(currentNum - num);
      } else if (currentNum < num) {
        addJobExecutorByNum(num - currentNum);
      }
    }
    //-----------------------  JMX ---------------------------
   
  @Override
  public long getCompletedTasks() {
    return this.completeTaskCount.longValue();
  }

  @Override
  public int getActiveJobExecutorCount() {
    return activeExecutorCount.intValue();
  }

  @Override
  public void addJobExecutor(int numToAdd) {
    _logger.info("[THREAD ADD] going to add " + numToAdd + " new executors ...");
   
        CountChangedWatcher ccw = (CountChangedWatcher) countChangedWatcher;
        ccw.setNumToSet(numToAdd + activeExecutorCount.intValue());
        ccw.execute();
  }
 
  @Override
  public void removeJobExecutors(int numToRemove) {
    _logger.info("[THREAD INTERRUPT] going to stop " + numToRemove + " executors ...");
        CountChangedWatcher ccw = (CountChangedWatcher) countChangedWatcher;
        ccw.setNumToSet(activeExecutorCount.intValue() - numToRemove);
        ccw.execute();
    _logger.info("[THREAD INTERRUPT] stopped");
  }
 
  @Override
    public void stopAllExecutors() {
    if(workers.size() <= 0) {
      _logger.info("[THREAD INTERRUPT] no executor to stop :" + job.getQueue());
      return;
    }
   
    _logger.info("[THREAD INTERRUPT] going to stop all executors ...");
   
        CountChangedWatcher ccw = (CountChangedWatcher) countChangedWatcher;
        ccw.setNumToSet(0);
        ccw.execute();
    }

  @Override
  public void purgeQueue() {
    _logger.info("[Queue Purge] going to purge queue ...: " + job.getQueue());
    ((QueuePurgeWatcher) purgeWatcher).execute();
  }
 
  @Override
  public void logErrorJobToFile(boolean onOrOff) {
    this.logErrorJobToFile.set(onOrOff);
    _logger.info("[Log Error Job] is " + onOrOff + " for queue: " + job.getQueue());
  }
 
  @Override
  public String getLoggingLevel() {
    return Logger.getRootLogger().getLevel().toString() ;
  }
 
  @Override
  public void setLoggingLevel(String level) {
    _logger.warn("Setting logging level to: " + level);
        Level newLevel = Level.toLevel(level, Level.INFO);
        Logger.getRootLogger().setLevel(newLevel);
  }
 
  //------------------------ Worker ------------------------
    private final class Worker implements Runnable {

        private final ReentrantLock runLock = new ReentrantLock(true);

        private JobExecutor task;

        Thread thread;

        Worker(Runnable task) {
            if(task instanceof JobExecutor) {
              this.task = (JobExecutor) task;
              this.task.setRunLock(runLock);
              this.task.setCompletedJobs(completeTaskCount);
              this.task.setLogErrorJobToFile(logErrorJobToFile);
            }
        }

        /**
         * Interrupts thread if the jobexecutor is not running
         */
        void interruptGracefully() {
            final ReentrantLock runLock = this.task.getRunLock();
            _logger.info("[THREAD INTERRUPT] try to get lock :" + thread.getName());
            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
            runLock.lock();
            _logger.info("[THREAD INTERRUPT] got lock :" + thread.getName());
            try {
              if (thread != Thread.currentThread())
                thread.interrupt();// get the jobexecutor out of loop
            } finally {
                runLock.unlock();
            }
           
            _logger.info("[THREAD INTERRUPT] gracefully interrupt :" + thread.getName());
        }

    @Override
    public void run() {
            if (Thread.interrupted())
                thread.interrupt();

            boolean ran = false;
            try {
                task.run();
                ran = true;
                afterExecute(this, null);
            } catch (RuntimeException ex) {
                if (!ran)
                    afterExecute(this, ex);
                throw ex;
            }
        }

    }
    //-------------- end worker ------------
   
    protected void unregisterMBean() {
        try {
            ManagementFactory.getPlatformMBeanServer().unregisterMBean(mbeanName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
   
  protected void removeJobExecutorsByNum(int numToRemove) {
    HashSet<Worker> workerSet = getWorkersToBeRemoved(numToRemove);
        for (Worker w : workerSet) {
            removeOneWorker(w);
        }
  }
 
  protected void addJobExecutorByNum(int numToAdd) {
    for(; numToAdd > 0; numToAdd--) {
      JobExecutor clonedJob;
      try {
        clonedJob = (JobExecutor) job.clone();
            Worker w = new Worker(clonedJob);
            Thread t = threadFactory.newThread(w);
            if (t != null) {
                w.thread = t;
                workers.add(w);
                activeExecutorCount.incrementAndGet();
                t.start();
            }
      } catch (CloneNotSupportedException e) {
        _logger.error(e, e);
      }
    }
  }
   
  protected void removeOneWorker(Worker w) {
    w.interruptGracefully();
    String tname = w.thread.getName();
    while(!w.thread.getState().equals(State.TERMINATED)){}
   
    _logger.info("[THREAD INTERRUPT] Thread is stopped...: " + tname);
  }
 
    protected void afterExecute(Runnable r, Throwable t) {
      Worker w = (Worker) r;
    workers.remove(w);
    activeExecutorCount.decrementAndGet();
   
    _logger.info("Thread is quitting...: " + w.thread.getName());
    }
   
    protected HashSet<Worker> getWorkersToBeRemoved(int numToRemove) {
      HashSet<Worker> result = new HashSet<Worker>();
      for (Worker w : workers) {
          if(numToRemove > 0) {
            result.add(w);
              numToRemove--;
          } else {
            break;
          }
      }
     
      return result;
    }
}
TOP

Related Classes of com.thenetcircle.comsumerdispatcher.thread.ConsumerJobExecutorPool$Worker

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.