@Override
 protected <T> Task<T> runAtEntity(
     final Entity entity,
     final Effector<T> eff,
     @SuppressWarnings("rawtypes") final Map parameters) {
   manageIfNecessary(entity, eff);
   // prefer to submit this from the current execution context so it sets up correct cross-context
   // chaining
   ExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
   if (ec == null) {
     log.debug("Top-level effector invocation: {} on {}", eff, entity);
     ec = getExecutionContext(entity);
   }
   return ec.submit(Effectors.invocation(entity, eff, parameters));
 }
Example #2
0
  /**
   * attempt to resolve the given value as the given type, waiting on futures, submitting if
   * necessary, and coercing as allowed by TypeCoercions; contextMessage (optional) will be
   * displayed in status reports while it waits (e.g. the name of the config key being looked up)
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  public static <T> T resolveValue(
      Object v, Class<T> type, ExecutionContext exec, String contextMessage)
      throws ExecutionException, InterruptedException {
    // if the expected type is a closure or map and that's what we have, we're done (or if it's
    // null);
    // but not allowed to return a future or DeferredSupplier as the resolved value
    if (v == null
        || (type.isInstance(v)
            && !Future.class.isInstance(v)
            && !DeferredSupplier.class.isInstance(v))) return (T) v;
    try {
      // if it's a task or a future, we wait for the task to complete
      if (v instanceof Task) {
        // if it's a task, we make sure it is submitted
        // (perhaps could run it here? ... tbd)
        if (!((Task) v).isSubmitted()) {
          exec.submit((Task) v);
        }
      }

      if (v instanceof Future) {
        final Future<?> vfuture = (Future<?>) v;

        // including tasks, above
        if (!vfuture.isDone()) {
          final AtomicReference<Object> vref = new AtomicReference<Object>(v);

          withBlockingDetails(
              "Waiting for " + (contextMessage != null ? contextMessage + ", " : "") + v,
              new Callable<Void>() {
                public Void call() throws Exception {
                  vref.set(vfuture.get());
                  return null;
                }
              });

          v = vref.get();

        } else {
          v = vfuture.get();
        }

      } else if (v instanceof DeferredSupplier<?>) {
        v = ((DeferredSupplier<?>) v).get();

      } else if (v instanceof Map) {
        // and if a map or list we look inside
        Map result = Maps.newLinkedHashMap();
        for (Map.Entry<?, ?> entry : ((Map<?, ?>) v).entrySet()) {
          result.put(
              entry.getKey(),
              resolveValue(
                  entry.getValue(),
                  type,
                  exec,
                  (contextMessage != null ? contextMessage + ", " : "")
                      + "map entry "
                      + entry.getKey()));
        }
        return (T) result;

      } else if (v instanceof List) {
        List result = Lists.newArrayList();
        int count = 0;
        for (Object it : (List) v) {
          result.add(
              resolveValue(
                  it,
                  type,
                  exec,
                  (contextMessage != null ? contextMessage + ", " : "") + "list entry " + count));
          count++;
        }
        return (T) result;

      } else {
        return TypeCoercions.coerce(v, type);
      }

    } catch (Exception e) {
      throw new IllegalArgumentException(
          "Error resolving "
              + (contextMessage != null ? contextMessage + ", " : "")
              + v
              + ", in "
              + exec
              + ": "
              + e,
          e);
    }
    return resolveValue(v, type, exec, contextMessage);
  }