001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package core.tut.pori.context;
017
018import java.util.Date;
019import java.util.concurrent.ArrayBlockingQueue;
020import java.util.concurrent.ExecutorService;
021import java.util.concurrent.ThreadPoolExecutor;
022import java.util.concurrent.TimeUnit;
023
024import org.apache.log4j.Logger;
025import org.quartz.Scheduler;
026import org.quartz.SchedulerException;
027import org.quartz.impl.StdSchedulerFactory;
028
029import core.tut.pori.properties.ExecutorProperties;
030import core.tut.pori.utils.StringUtils;
031
032/**
033 * Handles system executors. 
034 * 
035 * This class can be used to retrieve instances of the system executor service and the quartz scheduler.
036 * 
037 * This class requires PropertyHandler to be initialized.
038 * 
039 * One should not initialize this handler directly, as an instantiated version is available from ServiceInitializer.
040 */
041public class ExecutorHandler {
042  private static final Logger LOGGER = Logger.getLogger(ExecutorHandler.class);
043  private static final String QUARTZ_CONFIGURATION_FILE = "../quartz.properties";
044  private static final String QUARTZ_SYSTEM_PROPERTY = "org.quartz.properties";
045  private Scheduler _scheduler = null;
046  private ExecutorService _executor = null;
047
048  /**
049   * 
050   */
051  public void close() {
052    if(_scheduler != null){
053      try {
054        _scheduler.shutdown(true);
055      } catch (SchedulerException ex) {
056        LOGGER.error(ex, ex);
057      }
058    }
059    if(_executor != null){
060      _executor.shutdown();
061      try {
062        _executor.awaitTermination(2, TimeUnit.SECONDS);  //await for a short while before giving up
063      } catch (InterruptedException ex) {
064        LOGGER.error(ex, ex);
065      }
066    }
067  }
068
069  /**
070   * 
071   * @throws IllegalArgumentException
072   */
073  public ExecutorHandler() throws IllegalArgumentException{
074    LOGGER.debug("Initializing handler...");
075    Date started = new Date();
076    System.setProperty(QUARTZ_SYSTEM_PROPERTY, QUARTZ_CONFIGURATION_FILE);  // load quartz configuration
077    try {
078      _scheduler  = StdSchedulerFactory.getDefaultScheduler();
079      _scheduler.start();
080    } catch (SchedulerException ex) {
081      LOGGER.error(ex, ex);
082      throw new IllegalArgumentException("Failed to initialize Scheduler.");
083    }
084    
085    ExecutorProperties properties = ServiceInitializer.getPropertyHandler().getSystemProperties(ExecutorProperties.class);
086    _executor = new ThreadPoolExecutor(properties.getCoreCount(), properties.getPoolSize(), properties.getKeepAlive(), TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(properties.getQueueSize()));
087    
088    LOGGER.debug("Property Handler initialized in "+StringUtils.getDurationString(started, new Date()));
089  }
090  
091  /**
092   * Note: you should not run long-running background tasks, which may reserve the scheduler for a long time.
093   * If you need to do multiple functions, split the task to separate Jobs, and use triggers to launch new jobs.
094   * Especially, do NOT use sleep(), if you need to wait, schedule your job to re-run again at a later date.
095   * 
096   * Do NOT close or cleanup the instances returned by this method, the initialization and destruction is handled automatically.
097   * 
098   * @return quartz scheduler for background jobs
099   */
100  public Scheduler getScheduler(){
101    return _scheduler;
102  }
103
104  /**
105   * Note: if you are planning to run repetitive and non-time specific background tasks, you should implement Job and use getScheduler().
106   * 
107   * The scheduler is meant for short duration tasks. Do not abuse it.
108   * 
109   * Do NOT close or cleanup the instances returned by this method, the initialization and destruction is handled automatically.
110   * 
111   * @return the executor service
112   */
113  public ExecutorService getExecutor() {
114    return _executor;
115  }
116}