All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.bonita.runtime.event.EventExecutor Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2009-2013 BonitaSoft S.A.
 * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA  02110-1301, USA.
 **/
package org.ow2.bonita.runtime.event;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ow2.bonita.services.CommandService;
import org.ow2.bonita.util.EnvTool;
import org.ow2.bonita.util.Misc;
import org.ow2.bonita.util.ReflectUtil;

/**
 * 
 * @author Charles Souillard, Matthieu Chaffotte
 * 
 */
public class EventExecutor implements Serializable {

  private static final Logger LOG = Logger.getLogger(EventExecutor.class.getName());

  private static final long serialVersionUID = 1L;

  // injected
  transient CommandService commandService;

  int nbrOfThreads = 3;

  int idleMillis = 5000; // default normal poll interval is 5 seconds

  int lockMillis = 120000; // default max lock time is 2 minutes

  int minimumInterval = 50;

  int retries = 1;

  boolean expressionMatcherEnable = true;

  int matcherMaxCouples = 50;

  String name;

  private transient EventMatcher eventMatcher;

  private transient WebTokensCleaner tokensCleaner;

  String jobExecutorClassName;

  String eventMatcherClassName;

  String masterCheckerClassName;

  private transient JobExecutor jobExecutor = null;

  int locksToQuery = 50;

  int lockIdleTime = 5000;

  boolean cleanLocks = false;

  private boolean isActive = false;

  private String domain;

  private MasterChecker masterChecker;

  boolean masterCheckerEnable;

  int masterCheckerMasterHeartbeatDelay;

  int masterCheckerSlaveHeartbeatDelay;

  int masterCheckerMaxIdleDelay;
  
  int cleanWebTokensInterval = 3600000;

  public JobExecutor getJobExecutor() {
    return jobExecutor;
  }

  public synchronized void start() {
    domain = commandService.execute(new GetDomainCommand());
    name = EventExecutor.class.getSimpleName() + "-" + Misc.getHostName() + "-" + domain;
    if (isActive) {
      LOG.severe("Cannot start event executor '" + name + "' because it is already running...");
      return;
    }
    if (!isActive) {
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("starting event executor threads for event executor '" + name + "'...");
      }

      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Starting job dispatcher thread for executing events '" + name + "'...");
      }

      final Class jobExecutorClass = (Class) ReflectUtil.loadClass(Thread.currentThread()
          .getContextClassLoader(), jobExecutorClassName);
      final Constructor jobExecutorConstructor = ReflectUtil.getConstructor(jobExecutorClass, new Class[] {
          EventExecutor.class, String.class, int.class, int.class, int.class });
      jobExecutor = ReflectUtil.newInstance(jobExecutorConstructor,
          new Object[] { this, jobExecutorClass.getSimpleName() + "-" + Misc.getHostName() + "-" + domain,
              nbrOfThreads, locksToQuery, lockIdleTime });
      // jobExecutor.setMaxParallelJobs(maxParallelJobs);
      jobExecutor.start();

      final Class masterCheckerClass = (Class) ReflectUtil.loadClass(Thread
          .currentThread().getContextClassLoader(), masterCheckerClassName);
      final Constructor masterCheckerConstructor = ReflectUtil.getConstructor(masterCheckerClass,
          new Class[] { EventExecutor.class, String.class });
      masterChecker = ReflectUtil.newInstance(masterCheckerConstructor,
          new Object[] { this, masterCheckerClass.getSimpleName() + "-" + Misc.getHostName() + "-" + domain });
      masterChecker.setEnable(masterCheckerEnable);
      masterChecker.setMasterHeartbeatDelay(masterCheckerMasterHeartbeatDelay);
      masterChecker.setSlaveHeartbeatDelay(masterCheckerSlaveHeartbeatDelay);
      masterChecker.setMaxIdleDelay(masterCheckerMaxIdleDelay);

      masterChecker.start();

      isActive = true;
    }
  }

  static final class EventRejectionHandler implements RejectedExecutionHandler {

    static final EventRejectionHandler INSTANCE = new EventRejectionHandler();

    @Override
    public void rejectedExecution(final Runnable task, final ThreadPoolExecutor executor) {
      try {
        executor.getQueue().put(task);
      } catch (final InterruptedException e) {
        throw new RejectedExecutionException("queuing " + task + " got interrupted", e);
      }
    }
  }

  public synchronized boolean isActive() {
    return isActive;
  }

  public synchronized void stop() {
    stop(false);
  }

  public synchronized void stop(final boolean join) {
    if (LOG.isLoggable(Level.INFO)) {
      LOG.info("stopping event executor");
    }

    if (isActive) {
      isActive = false;

      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Event executor: deactivating job dispatcher thread...");
      }
      jobExecutor.deactivate(join);
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Event executor: job dispatcher thread deactivated.");
      }

      if (eventMatcher != null) {
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: deactivating event matcher...");
        }
        eventMatcher.deactivate(true);
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: event matcher deactivated.");
        }
      }

      if (tokensCleaner != null) {
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: deactivating web tokens cleaner...");
        }
        tokensCleaner.deactivate(true);
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: web tokens cleaner deactivated.");
        }
      }

      if (masterChecker != null) {
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: deactivating masterChekcer...");
        }
        masterChecker.interrupt();
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Event executor: masterChecker deactivated.");
        }
      }
    } else if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("ignoring stop: event executor '" + name + "' not started");
    }
    if (LOG.isLoggable(Level.INFO)) {
      LOG.info("Event executor stopped");
    }
  }

  public int getNbrOfThreads() {
    return nbrOfThreads;
  }

  public int getIdleMillis() {
    return idleMillis;
  }

  public int getLockMillis() {
    return lockMillis;
  }

  public CommandService getCommandService() {
    return commandService;
  }

  public int getMinimumInterval() {
    return minimumInterval;
  }

  public int getRetries() {
    return retries;
  }

  public void setCommandService(final CommandService commandService) {
    this.commandService = commandService;
  }

  public void internalJobExecutorRefresh() {
    if (jobExecutor != null && jobExecutor.isActive()) {
      jobExecutor.refresh();
    }
  }

  public void internalEventMatcherRefresh() {
    if (eventMatcher != null && eventMatcher.isActive()) {
      eventMatcher.refresh();
    }
  }

  public void refreshJobExecutor() {
    EnvTool.getTransaction().registerSynchronization(new NewJobNotification(this));
  }

  public void refreshEventMatcher() {
    EnvTool.getTransaction().registerSynchronization(new EventAddedNotification(this));
  }

  public synchronized boolean isJobExecutorActive() {
    return isActive && jobExecutor != null && jobExecutor.isActive();
  }

  public synchronized boolean isMatcherActive() {
    return isActive && eventMatcher != null && eventMatcher.isActive();
  }

  public synchronized boolean isWebTokensCleanerActive() {
    return isActive && tokensCleaner != null && tokensCleaner.isActive();
  }

  public synchronized boolean isMatchingConditionMatcherActive() {
    return isMatcherActive() && expressionMatcherEnable;
  }

  public synchronized boolean isMasterCheckerActive() {
    return isActive && masterChecker != null && masterChecker.isActive();
  }

  public synchronized void startMatcher() {
    if (!isMatcherActive()) {
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Starting matcher of message correlation based on correlation keys/no expression '" + name + "'...");
      }

      final Class eventMatcherClass = (Class) ReflectUtil.loadClass(Thread.currentThread()
          .getContextClassLoader(), eventMatcherClassName);
      final Constructor constructor = ReflectUtil.getConstructor(eventMatcherClass, new Class[] {
          EventExecutor.class, String.class });
      eventMatcher = ReflectUtil.newInstance(constructor,
          new Object[] { this, eventMatcherClassName + "-" + Misc.getHostName() + "-" + domain });

      eventMatcher.setMaxCouples(matcherMaxCouples);
      eventMatcher.setMatchingConditionMatcher(expressionMatcherEnable);
      eventMatcher.start();
    }
  }

  public synchronized void startMatchingConditionMatcher() {
    if (isMatcherActive()) {
      expressionMatcherEnable = true;
      eventMatcher.setMatchingConditionMatcher(true);
    }
  }

  public synchronized void stopMatcher() {
    if (isMatcherActive()) {
      eventMatcher.deactivate(true);
      eventMatcher = null;
    }
  }

  public synchronized void stopMatchingConditionMatcher() {
    if (isMatchingConditionMatcherActive() && isMatcherActive()) {
      expressionMatcherEnable = false;
      eventMatcher.setMatchingConditionMatcher(false);
    }
  }
  
  public synchronized void startWebTokensCleaner() {
    if (!isWebTokensCleanerActive()) {
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Starting web tokens cleaner with interval " + cleanWebTokensInterval + " for event executor '" + name + "'...");
      }

      tokensCleaner = new WebTokensCleaner(this, WebTokensCleaner.class.getName() + "-" + Misc.getHostName() + "-" + domain, cleanWebTokensInterval);
      tokensCleaner.start();
    }
  }
  
  public synchronized void stopWebTokensCleaner() {
    if (isWebTokensCleanerActive()) {
      tokensCleaner.deactivate(true);
      tokensCleaner = null;
    }
  }

  public synchronized void declareMaster() {
    startMatcher();
    startWebTokensCleaner();
  }

  public synchronized void declareSlave() {
    stopMatcher();
    stopWebTokensCleaner();
  }

  public void setMasterChecker(final MasterChecker masterChecker) {
    this.masterChecker = masterChecker;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy