/**
   * Enqueues the specified workflow instance into the engine for execution.
   *
   * @param wf the workflow instance to run
   * @param con connection used for the inserting the workflow to the database
   * @throws CopperException if the engine can not run the workflow, e.g. in case of a unkown
   *     processor pool id
   */
  public void run(Workflow<?> wf, Connection con) throws CopperException {
    if (logger.isTraceEnabled()) logger.trace("run(" + wf + ")");
    if (!(wf instanceof PersistentWorkflow<?>)) {
      throw new IllegalArgumentException(wf.getClass() + " is no instance of PersistentWorkflow");
    }
    try {
      startupBlocker.pass();

      if (wf.getId() == null) {
        wf.setId(createUUID());
      }
      if (wf.getProcessorPoolId() == null) {
        wf.setProcessorPoolId(PersistentProcessorPool.DEFAULT_POOL_ID);
      }
      if (processorPoolManager.getProcessorPool(wf.getProcessorPoolId()) == null) {
        logger.error(
            "Unkown processor pool '" + wf.getProcessorPoolId() + "' - using default pool instead");
        wf.setProcessorPoolId(PersistentProcessorPool.DEFAULT_POOL_ID);
      }
      dbStorage.insert(wf, con);
      notifyProcessorPool(wf.getProcessorPoolId());
    } catch (RuntimeException e) {
      throw e;
    } catch (CopperException e) {
      throw e;
    } catch (Exception e) {
      throw new CopperException("run failed", e);
    }
  }
 @Override
 public synchronized void shutdown() {
   if (engineState != EngineState.STARTED) {
     logger.debug("engine is not running - shutdown aborted");
     return;
   }
   logger.info("Engine is shutting down...");
   engineState = EngineState.SHUTTING_DOWN;
   processorPoolManager.shutdown();
   dbStorage.shutdown();
   super.shutdown();
   logger.info("Engine is stopped");
   engineState = EngineState.STOPPED;
 }
 @Override
 public void notify(List<Response<?>> responses, Connection c) throws CopperRuntimeException {
   try {
     for (Response<?> r : responses) {
       if (r.getResponseId() == null) {
         r.setResponseId(createUUID());
       }
     }
     dbStorage.notify(responses, c);
   } catch (RuntimeException e) {
     throw e;
   } catch (Exception e) {
     throw new CopperRuntimeException(e);
   }
 }
 @Override
 public void notify(Response<?> response, Acknowledge ack) {
   if (logger.isTraceEnabled()) logger.trace("notify(" + response + ")");
   try {
     if (response.getResponseId() == null) {
       response.setResponseId(createUUID());
     }
     startupBlocker.pass();
     dbStorage.notify(response, ack);
     if (notifyProcessorPoolsOnResponse) {
       for (PersistentProcessorPool ppp : processorPoolManager.processorPools()) {
         ppp.doNotify();
       }
     }
   } catch (Exception e) {
     throw new CopperRuntimeException("notify failed", e);
   }
 }
  @Override
  public synchronized void startup() {
    if (engineState != EngineState.RAW) throw new IllegalStateException();
    try {
      logger.info("starting up...");

      processorPoolManager.setEngine(this);

      wfRepository.start();
      dbStorage.startup();

      processorPoolManager.startup();
      startupBlocker.unblock();
      engineState = EngineState.STARTED;

      logger.info("Engine is running");
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new CopperRuntimeException("startup failed", e);
    }
  }
 @Override
 public void restartAll() throws Exception {
   dbStorage.restartAll();
 }
 @Override
 public void restart(String workflowInstanceId) throws Exception {
   dbStorage.restart(workflowInstanceId);
 }