/** @see #setTaskPreprocessorForTag(Object, TaskPreprocessor) */
 @SuppressWarnings("deprecation")
 public void setTaskPreprocessorForTag(
     Object tag, Class<? extends TaskPreprocessor> preprocessor) {
   synchronized (preprocessorByTag) {
     TaskPreprocessor old = getTaskPreprocessorForTag(tag);
     if (old != null) {
       if (preprocessor.isAssignableFrom(old.getClass())) {
         /* already have such an instance */
         return;
       }
       // might support multiple in future...
       throw new IllegalStateException(
           "Not allowed to set multiple TaskProcessors on ExecutionManager tag (tag "
               + tag
               + ", has "
               + old
               + ", setting new "
               + preprocessor
               + ")");
     }
     try {
       setTaskPreprocessorForTag(tag, preprocessor.newInstance());
     } catch (InstantiationException e) {
       throw Throwables.propagate(e);
     } catch (IllegalAccessException e) {
       throw Throwables.propagate(e);
     }
   }
 }
  @SuppressWarnings("deprecation")
  protected void beforeStart(Map flags, Task<?> task) {
    activeTaskCount.incrementAndGet();

    // set thread _before_ start time, so we won't get a null thread when there is a start-time
    if (log.isTraceEnabled()) log.trace("" + this + " beforeStart, task: " + task);
    if (!task.isCancelled()) {
      ((BasicTask) task).thread = Thread.currentThread();
      if (RENAME_THREADS) {
        String newThreadName =
            "brooklyn-"
                + CaseFormat.LOWER_HYPHEN.to(
                    CaseFormat.LOWER_CAMEL, task.getDisplayName().replace(" ", ""))
                + "-"
                + task.getId().substring(0, 8);
        ((BasicTask) task).thread.setName(newThreadName);
      }
      PerThreadCurrentTaskHolder.perThreadCurrentTask.set(task);
      ((BasicTask) task).startTimeUtc = System.currentTimeMillis();
    }
    for (Object to : (Collection) flags.get("tagLinkedPreprocessors")) {
      TaskPreprocessor t = (TaskPreprocessor) to;
      t.onStart(flags, task);
    }
    ExecutionUtils.invoke(flags.get("newTaskStartCallback"), task);
  }
  @SuppressWarnings("deprecation")
  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);
    List l = (List) flags.get("tagLinkedPreprocessors");
    Collections.reverse(l);
    for (Object li : l) {
      TaskPreprocessor t = (TaskPreprocessor) li;
      t.onEnd(flags, task);
    }

    PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
    ((BasicTask) task).endTimeUtc = 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-" + LanguageUtils.newUid();
      ((BasicTask) task).thread.setName(newThreadName);
    }
    ((BasicTask) task).thread = null;
    synchronized (task) {
      task.notifyAll();
    }

    ExpirationPolicy expirationPolicy = (ExpirationPolicy) flags.get("expirationPolicy");
    if (expirationPolicy == null) expirationPolicy = ExpirationPolicy.IMMEDIATE;
    if (expirationPolicy == ExpirationPolicy.IMMEDIATE) {
      for (Object t : ((BasicTask) task).tags) {
        getMutableTasksWithTag(t).remove(task);
      }
    }
  }
  @SuppressWarnings("deprecation")
  protected void beforeSubmit(Map flags, Task<?> task) {
    incompleteTaskCount.incrementAndGet();

    Task currentTask = getCurrentTask();
    if (currentTask != null) ((BasicTask) task).submittedByTask = currentTask;
    ((BasicTask) task).submitTimeUtc = System.currentTimeMillis();

    if (flags.get("tag") != null) ((BasicTask) task).tags.add(flags.remove("tag"));
    if (flags.get("tags") != null)
      ((BasicTask) task).tags.addAll((Collection) flags.remove("tags"));

    for (Object tag : ((BasicTask) task).tags) {
      getMutableTasksWithTag(tag).add(task);
    }

    List tagLinkedPreprocessors = new ArrayList();
    for (Object tag : ((BasicTask) task).tags) {
      TaskPreprocessor p = getTaskPreprocessorForTag(tag);
      if (p != null) tagLinkedPreprocessors.add(p);
    }
    flags.put("tagLinkedPreprocessors", tagLinkedPreprocessors);
    for (Object ppo : tagLinkedPreprocessors) {
      TaskPreprocessor t = (TaskPreprocessor) ppo;
      t.onSubmit(flags, task);
    }
  }
  /**
   * Defines a {@link TaskPreprocessor} to run on all subsequently submitted jobs with the given
   * tag.
   *
   * <p>Maximum of one allowed currently. Resubmissions of the same preprocessor (or preprocessor
   * class) allowed. If changing, you must call {@link #clearTaskPreprocessorForTag(Object)} between
   * the two.
   *
   * @see #setTaskPreprocessorForTag(Object, Class)
   */
  @SuppressWarnings("deprecation")
  public void setTaskPreprocessorForTag(Object tag, TaskPreprocessor preprocessor) {
    synchronized (preprocessorByTag) {
      preprocessor.injectManager(this);
      preprocessor.injectTag(tag);

      Object old = preprocessorByTag.put(tag, preprocessor);
      if (old != null && old != preprocessor) {
        // might support multiple in future...
        throw new IllegalStateException(
            "Not allowed to set multiple TaskProcessors on ExecutionManager tag (tag " + tag + ")");
      }
    }
  }