/**
   * Resolves the on-box dir.
   *
   * <p>Initialize and pre-create the right onbox working dir, if an ssh machine location. Logs a
   * warning if not.
   */
  @SuppressWarnings("deprecation")
  public static String resolveOnBoxDir(EntityInternal entity, MachineLocation machine) {
    String base = entity.getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base == null) base = machine.getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base != null && Boolean.TRUE.equals(entity.getConfig(ON_BOX_BASE_DIR_RESOLVED)))
      return base;
    if (base == null)
      base = entity.getManagementContext().getConfig().getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base == null) base = entity.getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null) base = machine.getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null)
      base =
          entity.getManagementContext().getConfig().getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null) base = "~/brooklyn-managed-processes";
    if (base.equals("~")) base = ".";
    if (base.startsWith("~/")) base = "." + base.substring(1);

    String resolvedBase = null;
    if (entity.getConfig(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION)
        || machine.getConfig(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION)) {
      if (log.isDebugEnabled())
        log.debug("Skipping on-box base dir resolution for " + entity + " at " + machine);
      if (!Os.isAbsolutish(base)) base = "~/" + base;
      resolvedBase = Os.tidyPath(base);
    } else if (machine instanceof SshMachineLocation) {
      SshMachineLocation ms = (SshMachineLocation) machine;
      ProcessTaskWrapper<Integer> baseTask =
          SshEffectorTasks.ssh(
                  BashCommands.alternatives(
                      "mkdir -p \"${BASE_DIR}\"",
                      BashCommands.chain(
                          BashCommands.sudo("mkdir -p \"${BASE_DIR}\""),
                          BashCommands.sudo("chown " + ms.getUser() + " \"${BASE_DIR}\""))),
                  "cd ~",
                  "cd ${BASE_DIR}",
                  "echo BASE_DIR_RESULT':'`pwd`:BASE_DIR_RESULT")
              .environmentVariable("BASE_DIR", base)
              .requiringExitCodeZero()
              .summary("initializing on-box base dir " + base)
              .newTask();
      DynamicTasks.queueIfPossible(baseTask).orSubmitAsync(entity);
      resolvedBase =
          Strings.getFragmentBetween(
              baseTask.block().getStdout(), "BASE_DIR_RESULT:", ":BASE_DIR_RESULT");
    }
    if (resolvedBase == null) {
      if (!Os.isAbsolutish(base)) base = "~/" + base;
      resolvedBase = Os.tidyPath(base);
      log.warn(
          "Could not resolve on-box directory for "
              + entity
              + " at "
              + machine
              + "; using "
              + resolvedBase
              + ", though this may not be accurate at the target (and may fail shortly)");
    }
    entity.config().set(BrooklynConfigKeys.ONBOX_BASE_DIR, resolvedBase);
    entity.config().set(ON_BOX_BASE_DIR_RESOLVED, true);
    return resolvedBase;
  }
    public void run() {
      log.info("Starting {} on machine {}", entity(), machine);
      Collection<Location> oldLocs = entity().getLocations();
      if (!oldLocs.isEmpty()) {
        List<MachineLocation> oldSshLocs =
            ImmutableList.copyOf(Iterables.filter(oldLocs, MachineLocation.class));
        if (!oldSshLocs.isEmpty()) {
          // check if existing locations are compatible
          log.debug(
              "Entity "
                  + entity()
                  + " had machine locations "
                  + oldSshLocs
                  + " when starting at "
                  + machine
                  + "; checking if they are compatible");
          for (MachineLocation oldLoc : oldSshLocs) {
            // machines are deemed compatible if hostname and address are the same, or they are
            // localhost
            // this allows a machine create by jclouds to then be defined with an ip-based spec
            if (!"localhost".equals(machine.getConfig(AbstractLocation.ORIGINAL_SPEC))) {
              checkLocationParametersCompatible(
                  machine,
                  oldLoc,
                  "hostname",
                  oldLoc.getAddress().getHostName(),
                  machine.getAddress().getHostName());
              checkLocationParametersCompatible(
                  machine,
                  oldLoc,
                  "address",
                  oldLoc.getAddress().getHostAddress(),
                  machine.getAddress().getHostAddress());
            }
          }
          log.debug(
              "Entity "
                  + entity()
                  + " old machine locations "
                  + oldSshLocs
                  + " were compatible, removing them to start at "
                  + machine);
          entity().removeLocations(oldSshLocs);
        }
      }
      entity().addLocations(ImmutableList.of((Location) machine));

      // elsewhere we rely on (public) hostname being set _after_ subnet_hostname
      // (to prevent the tiny possibility of races resulting in hostname being returned
      // simply because subnet is still being looked up)
      Maybe<String> lh = Machines.getSubnetHostname(machine);
      Maybe<String> la = Machines.getSubnetIp(machine);
      if (lh.isPresent()) entity().sensors().set(Attributes.SUBNET_HOSTNAME, lh.get());
      if (la.isPresent()) entity().sensors().set(Attributes.SUBNET_ADDRESS, la.get());
      entity().sensors().set(Attributes.HOSTNAME, machine.getAddress().getHostName());
      entity().sensors().set(Attributes.ADDRESS, machine.getAddress().getHostAddress());
      if (machine instanceof SshMachineLocation) {
        SshMachineLocation sshMachine = (SshMachineLocation) machine;
        UserAndHostAndPort sshAddress =
            UserAndHostAndPort.fromParts(
                sshMachine.getUser(), sshMachine.getAddress().getHostName(), sshMachine.getPort());
        // FIXME: Who or what is SSH_ADDRESS intended for? It's not necessarily the address that
        // the SshMachineLocation is using for ssh connections (because it accepts SSH_HOST as an
        // override).
        entity().sensors().set(Attributes.SSH_ADDRESS, sshAddress);
      }

      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.OPEN_IPTABLES))) {
        if (machine instanceof SshMachineLocation) {
          @SuppressWarnings("unchecked")
          Iterable<Integer> inboundPorts =
              (Iterable<Integer>) machine.config().get(CloudLocationConfig.INBOUND_PORTS);
          machineInitTasks.openIptablesAsync(inboundPorts, (SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag OPEN_IPTABLES on non-ssh location {}", machine);
        }
      }
      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.STOP_IPTABLES))) {
        if (machine instanceof SshMachineLocation) {
          machineInitTasks.stopIptablesAsync((SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag STOP_IPTABLES on non-ssh location {}", machine);
        }
      }
      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.DONT_REQUIRE_TTY_FOR_SUDO))) {
        if (machine instanceof SshMachineLocation) {
          machineInitTasks.dontRequireTtyForSudoAsync((SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag DONT_REQUIRE_TTY_FOR_SUDO on non-ssh location {}", machine);
        }
      }
      resolveOnBoxDir(entity(), machine);
      preStartCustom(machine);
    }