protected void afterEnd(Map<?, ?> flags, Task<?> task) {
    activeTaskCount.decrementAndGet();
    incompleteTaskCount.decrementAndGet();

    if (log.isTraceEnabled()) log.trace(this + " afterEnd, task: " + task);
    ExecutionUtils.invoke(flags.get("newTaskEndCallback"), task);

    PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
    ((TaskInternal<?>) task).setEndTimeUtc(System.currentTimeMillis());
    // clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
    if (RENAME_THREADS) {
      String newThreadName = "brooklyn-" + Identifiers.makeRandomId(8);
      task.getThread().setName(newThreadName);
    }
    ((TaskInternal<?>) task).setThread(null);
    synchronized (task) {
      task.notifyAll();
    }

    for (ExecutionListener listener : listeners) {
      try {
        listener.onTaskDone(task);
      } catch (Exception e) {
        log.warn("Error notifying listener " + listener + " of task " + task + " done", e);
      }
    }
  }
 public void execute(ExecutionListener executionListener) {
   try {
     action.execute(executionListener);
   } catch (ReportedException e) {
     executionListener.onFailure(e.getCause());
   } catch (Throwable t) {
     reporter.reportException(t);
     executionListener.onFailure(t);
   }
 }