@Override
  public Integer executeNativeOrPsCommand(
      Map flags, String regularCommand, String powerShellCommand, String phase, Boolean allowNoOp) {
    if (Strings.isBlank(regularCommand) && Strings.isBlank(powerShellCommand)) {
      if (allowNoOp) {
        return new WinRmToolResponse("", "", 0).getStatusCode();
      } else {
        throw new IllegalStateException(
            String.format("Exactly one of cmd or psCmd must be set for %s of %s", phase, entity));
      }
    } else if (!Strings.isBlank(regularCommand) && !Strings.isBlank(powerShellCommand)) {
      throw new IllegalStateException(
          String.format(
              "%s and %s cannot both be set for %s of %s",
              regularCommand, powerShellCommand, phase, entity));
    }

    ByteArrayOutputStream stdIn = new ByteArrayOutputStream();
    ByteArrayOutputStream stdOut =
        flags.get("out") != null
            ? (ByteArrayOutputStream) flags.get("out")
            : new ByteArrayOutputStream();
    ByteArrayOutputStream stdErr =
        flags.get("err") != null
            ? (ByteArrayOutputStream) flags.get("err")
            : new ByteArrayOutputStream();

    Task<?> currentTask = Tasks.current();
    if (currentTask != null) {
      if (BrooklynTaskTags.stream(Tasks.current(), BrooklynTaskTags.STREAM_STDIN) == null) {
        writeToStream(stdIn, Strings.isBlank(regularCommand) ? powerShellCommand : regularCommand);
        Tasks.addTagDynamically(
            BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDIN, stdIn));
      }

      if (BrooklynTaskTags.stream(currentTask, BrooklynTaskTags.STREAM_STDOUT) == null) {
        Tasks.addTagDynamically(
            BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDOUT, stdOut));
        flags.put("out", stdOut);
        Tasks.addTagDynamically(
            BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDERR, stdErr));
        flags.put("err", stdErr);
      }
    }

    WinRmToolResponse response;
    if (Strings.isBlank(regularCommand)) {
      response = getLocation().executePsScript(ImmutableList.of(powerShellCommand));
    } else {
      response = getLocation().executeCommand(ImmutableList.of(regularCommand));
    }

    if (currentTask != null) {
      writeToStream(stdOut, response.getStdOut());
      writeToStream(stdErr, response.getStdErr());
    }

    return response.getStatusCode();
  }
  @Override
  public final T get() {
    if (log.isDebugEnabled())
      log.debug("Queuing task to resolve " + dsl + ", called by " + Tasks.current());

    EntityInternal entity =
        (EntityInternal) BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
    ExecutionContext exec =
        (entity != null)
            ? entity.getExecutionContext()
            : BasicExecutionContext.getCurrentExecutionContext();
    if (exec == null) {
      throw new IllegalStateException("No execution context available to resolve " + dsl);
    }

    Task<T> task = newTask();
    T result;
    try {
      result = exec.submit(task).get();
    } catch (InterruptedException | ExecutionException e) {
      Task<?> currentTask = Tasks.current();
      if (currentTask != null && currentTask.isCancelled()) {
        task.cancel(true);
      }
      throw Exceptions.propagate(e);
    }

    if (log.isDebugEnabled()) log.debug("Resolved " + result + " from " + dsl);
    return result;
  }
  /**
   * Default restart implementation for an entity.
   *
   * <p>Stops processes if possible, then starts the entity again.
   */
  public void restart(ConfigBag parameters) {
    ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPING);

    RestartMachineMode isRestartMachine =
        parameters.get(RestartSoftwareParameters.RESTART_MACHINE_TYPED);
    if (isRestartMachine == null) isRestartMachine = RestartMachineMode.AUTO;
    if (isRestartMachine == RestartMachineMode.AUTO)
      isRestartMachine =
          getDefaultRestartStopsMachine() ? RestartMachineMode.TRUE : RestartMachineMode.FALSE;

    // Calling preStopCustom without a corresponding postStopCustom invocation
    // doesn't look right so use a separate callback pair; Also depending on the arguments
    // stop() could be called which will call the {pre,post}StopCustom on its own.
    DynamicTasks.queue("pre-restart", new PreRestartTask());

    if (isRestartMachine == RestartMachineMode.FALSE) {
      DynamicTasks.queue("stopping (process)", new StopProcessesAtMachineTask());
    } else {
      Map<String, Object> stopMachineFlags = MutableMap.of();
      if (Entitlements.getEntitlementContext() != null) {
        stopMachineFlags.put(
            "tags",
            MutableSet.of(
                BrooklynTaskTags.tagForEntitlement(Entitlements.getEntitlementContext())));
      }
      Task<String> stopTask =
          Tasks.<String>builder()
              .displayName("stopping (machine)")
              .body(new StopMachineTask())
              .flags(stopMachineFlags)
              .build();
      DynamicTasks.queue(stopTask);
    }

    DynamicTasks.queue("starting", new StartInLocationsTask());
    restartChildren(parameters);
    DynamicTasks.queue("post-restart", new PostRestartTask());

    DynamicTasks.waitForLast();
    ServiceStateLogic.setExpectedState(entity(), Lifecycle.RUNNING);
  }
  protected void doStop(ConfigBag parameters, Callable<StopMachineDetails<Integer>> stopTask) {
    preStopConfirmCustom();

    log.info("Stopping {} in {}", entity(), entity().getLocations());

    StopMode stopMachineMode = getStopMachineMode(parameters);
    StopMode stopProcessMode = parameters.get(StopSoftwareParameters.STOP_PROCESS_MODE);

    DynamicTasks.queue("pre-stop", new PreStopCustomTask());

    // BROOKLYN-263:
    // With this change the stop effector will wait for Location to provision so it can terminate
    // the machine, if a provisioning request is in-progress.
    //
    // The ProvisionMachineTask stores transient internal state in PROVISIONING_TASK_STATE and
    // PROVISIONED_MACHINE: it records when the provisioning is running and when done; and it
    // records the final machine. We record the machine in the internal sensor (rather than
    // just relying on getLocations) because the latter is set much later in the start()
    // process.
    //
    // This code is a big improvement (previously there was a several-minute window in some
    // clouds where a call to stop() would leave the machine running).
    //
    // However, there are still races. If the start() code has not yet reached the call to
    // location.obtain() then we won't wait, and the start() call won't know to abort. It's
    // fiddly to get that right, because we need to cope with restart() - so we mustn't leave
    // any state behind that will interfere with subsequent sequential calls to start().
    // There is some attempt to handle it by ProvisionMachineTask checking if the expectedState
    // is stopping/stopped.
    Maybe<MachineLocation> machine = Machines.findUniqueMachineLocation(entity().getLocations());
    ProvisioningTaskState provisioningState =
        entity().sensors().get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);

    if (machine.isAbsent() && provisioningState == ProvisioningTaskState.RUNNING) {
      Duration maxWait = entity().config().get(STOP_WAIT_PROVISIONING_TIMEOUT);
      log.info(
          "When stopping {}, waiting for up to {} for the machine to finish provisioning, before terminating it",
          entity(),
          maxWait);
      boolean success =
          Repeater.create("Wait for a machine to appear")
              .until(
                  new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                      ProvisioningTaskState state =
                          entity()
                              .sensors()
                              .get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);
                      return (state != ProvisioningTaskState.RUNNING);
                    }
                  })
              .backoffTo(Duration.FIVE_SECONDS)
              .limitTimeTo(maxWait)
              .run();
      if (!success) {
        log.warn(
            "When stopping {}, timed out after {} waiting for the machine to finish provisioning - machine may we left running",
            entity(),
            maxWait);
      }
      machine = Maybe.ofDisallowingNull(entity().sensors().get(INTERNAL_PROVISIONED_MACHINE));
    }
    entity().sensors().remove(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);
    entity().sensors().remove(INTERNAL_PROVISIONED_MACHINE);

    Task<List<?>> stoppingProcess = null;
    if (canStop(stopProcessMode, entity())) {
      stoppingProcess =
          Tasks.parallel(
              "stopping",
              Tasks.create("stopping (process)", new StopProcessesAtMachineTask()),
              Tasks.create("stopping (feeds)", new StopFeedsAtMachineTask()));
      DynamicTasks.queue(stoppingProcess);
    }

    Task<StopMachineDetails<Integer>> stoppingMachine = null;
    if (canStop(stopMachineMode, machine.isAbsent())) {
      // Release this machine (even if error trying to stop process - we rethrow that after)
      Map<String, Object> stopMachineFlags = MutableMap.of();
      if (Entitlements.getEntitlementContext() != null) {
        stopMachineFlags.put(
            "tags",
            MutableSet.of(
                BrooklynTaskTags.tagForEntitlement(Entitlements.getEntitlementContext())));
      }
      Task<StopMachineDetails<Integer>> stopMachineTask =
          Tasks.<StopMachineDetails<Integer>>builder()
              .displayName("stopping (machine)")
              .body(stopTask)
              .flags(stopMachineFlags)
              .build();
      stoppingMachine = DynamicTasks.queue(stopMachineTask);

      DynamicTasks.drain(entity().getConfig(STOP_PROCESS_TIMEOUT), false);

      // shutdown the machine if stopping process fails or takes too long
      synchronized (stoppingMachine) {
        // task also used as mutex by DST when it submits it; ensure it only submits once!
        if (!stoppingMachine.isSubmitted()) {
          // force the stoppingMachine task to run by submitting it here
          StringBuilder msg =
              new StringBuilder("Submitting machine stop early in background for ")
                  .append(entity());
          if (stoppingProcess == null) {
            msg.append(". Process stop skipped, pre-stop not finished?");
          } else {
            msg.append(" because process stop has ")
                .append((stoppingProcess.isDone() ? "finished abnormally" : "not finished"));
          }
          log.warn(msg.toString());
          Entities.submit(entity(), stoppingMachine);
        }
      }
    }

    try {
      // This maintains previous behaviour of silently squashing any errors on the stoppingProcess
      // task if the
      // stoppingMachine exits with a nonzero value
      boolean checkStopProcesses =
          (stoppingProcess != null
              && (stoppingMachine == null || stoppingMachine.get().value == 0));

      if (checkStopProcesses) {
        // TODO we should test for destruction above, not merely successful "stop", as things like
        // localhost and ssh won't be destroyed
        DynamicTasks.waitForLast();
        if (machine.isPresent()) {
          // throw early errors *only if* there is a machine and we have not destroyed it
          stoppingProcess.get();
        }
      }
    } catch (Throwable e) {
      ServiceStateLogic.setExpectedState(entity(), Lifecycle.ON_FIRE);
      Exceptions.propagate(e);
    }
    entity().sensors().set(SoftwareProcess.SERVICE_UP, false);
    ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPED);

    DynamicTasks.queue("post-stop", new PostStopCustomTask());

    if (log.isDebugEnabled()) log.debug("Stopped software process entity " + entity());
  }
 protected EntityInternal entity() {
   return (EntityInternal) BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
 }
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public V call() {
      T value = source.getAttribute(sensor);

      // return immediately if either the ready predicate or the abort conditions hold
      if (ready(value)) return postProcess(value);

      final List<Exception> abortionExceptions = Lists.newCopyOnWriteArrayList();
      long start = System.currentTimeMillis();

      for (AttributeAndSensorCondition abortCondition : abortSensorConditions) {
        Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
        if (abortCondition.predicate.apply(abortValue)) {
          abortionExceptions.add(
              new Exception(
                  "Abort due to " + abortCondition.source + " -> " + abortCondition.sensor));
        }
      }
      if (abortionExceptions.size() > 0) {
        throw new CompoundRuntimeException(
            "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
      }

      TaskInternal<?> current = (TaskInternal<?>) Tasks.current();
      if (current == null)
        throw new IllegalStateException("Should only be invoked in a running task");
      Entity entity = BrooklynTaskTags.getTargetOrContextEntity(current);
      if (entity == null)
        throw new IllegalStateException(
            "Should only be invoked in a running task with an entity tag; "
                + current
                + " has no entity tag ("
                + current.getStatusDetail(false)
                + ")");

      final LinkedList<T> publishedValues = new LinkedList<T>();
      final Semaphore semaphore = new Semaphore(0); // could use Exchanger
      SubscriptionHandle subscription = null;
      List<SubscriptionHandle> abortSubscriptions = Lists.newArrayList();

      try {
        subscription =
            entity
                .subscriptions()
                .subscribe(
                    source,
                    sensor,
                    new SensorEventListener<T>() {
                      @Override
                      public void onEvent(SensorEvent<T> event) {
                        synchronized (publishedValues) {
                          publishedValues.add(event.getValue());
                        }
                        semaphore.release();
                      }
                    });
        for (final AttributeAndSensorCondition abortCondition : abortSensorConditions) {
          abortSubscriptions.add(
              entity
                  .subscriptions()
                  .subscribe(
                      abortCondition.source,
                      abortCondition.sensor,
                      new SensorEventListener<Object>() {
                        @Override
                        public void onEvent(SensorEvent<Object> event) {
                          if (abortCondition.predicate.apply(event.getValue())) {
                            abortionExceptions.add(
                                new Exception(
                                    "Abort due to "
                                        + abortCondition.source
                                        + " -> "
                                        + abortCondition.sensor));
                            semaphore.release();
                          }
                        }
                      }));
          Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
          if (abortCondition.predicate.apply(abortValue)) {
            abortionExceptions.add(
                new Exception(
                    "Abort due to " + abortCondition.source + " -> " + abortCondition.sensor));
          }
        }
        if (abortionExceptions.size() > 0) {
          throw new CompoundRuntimeException(
              "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
        }

        CountdownTimer timer = timeout != null ? timeout.countdownTimer() : null;
        Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT;
        Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD;
        while (true) {
          // check the source on initial run (could be done outside the loop)
          // and also (optionally) on each iteration in case it is more recent
          value = source.getAttribute(sensor);
          if (ready(value)) break;

          if (timer != null) {
            if (timer.getDurationRemaining().isShorterThan(nextPeriod)) {
              nextPeriod = timer.getDurationRemaining();
            }
            if (timer.isExpired()) {
              if (onTimeout.isPresent()) return onTimeout.get();
              throw new RuntimeTimeoutException("Unsatisfied after " + Duration.sinceUtc(start));
            }
          }

          String prevBlockingDetails = current.setBlockingDetails(blockingDetails);
          try {
            if (semaphore.tryAcquire(nextPeriod.toMilliseconds(), TimeUnit.MILLISECONDS)) {
              // immediately release so we are available for the next check
              semaphore.release();
              // if other permits have been made available (e.g. multiple notifications) drain them
              // all as no point running multiple times
              semaphore.drainPermits();
            }
          } finally {
            current.setBlockingDetails(prevBlockingDetails);
          }

          // check any subscribed values which have come in first
          while (true) {
            synchronized (publishedValues) {
              if (publishedValues.isEmpty()) break;
              value = publishedValues.pop();
            }
            if (ready(value)) break;
          }

          // if unmanaged then ignore the other abort conditions
          if (!ignoreUnmanaged && Entities.isNoLongerManaged(entity)) {
            if (onUnmanaged.isPresent()) return onUnmanaged.get();
            throw new NotManagedException(entity);
          }

          if (abortionExceptions.size() > 0) {
            throw new CompoundRuntimeException(
                "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
          }

          nextPeriod = nextPeriod.times(2).upperBound(maxPeriod);
        }
        if (LOG.isDebugEnabled()) LOG.debug("Attribute-ready for {} in entity {}", sensor, source);
        return postProcess(value);
      } catch (InterruptedException e) {
        throw Exceptions.propagate(e);
      } finally {
        if (subscription != null) {
          entity.subscriptions().unsubscribe(subscription);
        }
        for (SubscriptionHandle handle : abortSubscriptions) {
          entity.subscriptions().unsubscribe(handle);
        }
      }
    }
 /**
  * Returns the current management context; for use in implementations of {@link #get()} that are
  * not associated with an entity.
  */
 protected static final ManagementContextInternal managementContext() {
   return (ManagementContextInternal) BrooklynTaskTags.getManagementContext(Tasks.current());
 }