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

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

/**
 * Copyright (C) 2009-20102 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.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ow2.bonita.facade.uuid.ProcessInstanceUUID;
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 expressionMessageMatcherEnable = true;

  boolean mainMatcherEnable = true;

  String name;

  private transient ThreadPoolExecutor threadPool;

  private transient EventMatcher eventMatcher = null;

  private transient ExpressionMessageEventMatcher expressionMessageMatcher = null;

  String jobExecutorClassName;

  private transient JobExecutor jobExecutor = null;

  int maxParallelJobs = 50;

  boolean cleanLocks = false;

  private boolean isActive = false;

  public synchronized void start() {
    final String 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) {
      isActive = true;
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("starting event executor threads for event executor '" + name + "'...");
      }
      threadPool = new ThreadPoolExecutor(nbrOfThreads, nbrOfThreads, 0L, TimeUnit.MILLISECONDS,
          new ArrayBlockingQueue(nbrOfThreads), EventRejectionHandler.INSTANCE);

      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 constructor = ReflectUtil.getConstructor(jobExecutorClass, new Class[] {
          EventExecutor.class, String.class });
      jobExecutor = ReflectUtil.newInstance(constructor, new Object[] { this,
          JobExecutorThread.class.getSimpleName() + "-" + Misc.getHostName() + "-" + domain });
      jobExecutor.setMaxParallelJobs(maxParallelJobs);
      jobExecutor.setCleanLocks(cleanLocks);
      jobExecutor.start();

      if (expressionMessageMatcherEnable) {
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Starting matcher of message correlation based on an expression '" + name + "'...");
        }
        expressionMessageMatcher = new ExpressionMessageEventMatcher(this,
            ExpressionMessageEventMatcher.class.getSimpleName() + "-" + Misc.getHostName() + "-" + domain);
        expressionMessageMatcher.start();
      }

      if (mainMatcherEnable) {
        if (LOG.isLoggable(Level.INFO)) {
          LOG.info("Starting matcher of message correlation based on correlation keys/no expression '" + name + "'...");
        }
        eventMatcher = new EventMatcher(this, EventMatcher.class.getSimpleName() + "-" + Misc.getHostName() + "-"
            + domain);
        eventMatcher.start();
      }
    }
  }

  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 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(true);
      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: message event deactivated...");
        }
      }

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

      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Event executor: shutdown threadpool...");
      }
      threadPool.shutdown();
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Event executor: threadpool shutdowned...");
      }
      if (join) {
        try {
          if (LOG.isLoggable(Level.INFO)) {
            LOG.info("Event executor: waiting for threadPool termination...");
          }
          threadPool.awaitTermination(1000 * 60 * 5, TimeUnit.MILLISECONDS);
          if (LOG.isLoggable(Level.INFO)) {
            LOG.info("Event executor: threadPool termination OK...");
          }
        } catch (final InterruptedException e) {
          LOG.severe("joining got interrupted");
        }
      }
    } 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 ThreadPoolExecutor getThreadPool() {
    return threadPool;
  }

  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 notifyJobThreadFinished(final ProcessInstanceUUID rootInstanceUUID) {
    jobExecutor.notifyThreadFinished(rootInstanceUUID);
  }

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

  public void internalExpressionMessageEventMatcherRefresh() {
    if (expressionMessageMatcher != null && expressionMessageMatcher.isActive()) {
      expressionMessageMatcher.refresh();
    }
  }

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

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

  public void refreshExpressionMessageEventMatcher() {
    EnvTool.getTransaction().registerSynchronization(new ExpressionMessageEventAddedNotification(this));
  }

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

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

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy