All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.uber.cadence.internal.sync.WorkflowClientInternal Maven / Gradle / Ivy

There is a newer version: 3.12.5
Show newest version
/*
 *  Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 *  Modifications copyright (C) 2017 Uber Technologies, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"). You may not
 *  use this file except in compliance with the License. A copy of the License is
 *  located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 *  or in the "license" file accompanying this file. This file is distributed on
 *  an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied. See the License for the specific language governing
 *  permissions and limitations under the License.
 */

package com.uber.cadence.internal.sync;

import com.google.common.base.Strings;
import com.google.common.reflect.TypeToken;
import com.uber.cadence.WorkflowExecution;
import com.uber.cadence.client.ActivityCompletionClient;
import com.uber.cadence.client.BatchRequest;
import com.uber.cadence.client.WorkflowClient;
import com.uber.cadence.client.WorkflowClientInterceptor;
import com.uber.cadence.client.WorkflowClientOptions;
import com.uber.cadence.client.WorkflowOptions;
import com.uber.cadence.client.WorkflowStub;
import com.uber.cadence.converter.DataConverter;
import com.uber.cadence.internal.external.GenericWorkflowClientExternalImpl;
import com.uber.cadence.internal.external.ManualActivityCompletionClientFactory;
import com.uber.cadence.internal.external.ManualActivityCompletionClientFactoryImpl;
import com.uber.cadence.internal.sync.WorkflowInvocationHandler.InvocationType;
import com.uber.cadence.serviceclient.IWorkflowService;
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
import com.uber.cadence.workflow.Functions;
import com.uber.cadence.workflow.QueryMethod;
import com.uber.cadence.workflow.WorkflowMethod;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public final class WorkflowClientInternal implements WorkflowClient {

  private final GenericWorkflowClientExternalImpl genericClient;
  private final ManualActivityCompletionClientFactory manualActivityCompletionClientFactory;
  private final DataConverter dataConverter;
  private final WorkflowClientInterceptor[] interceptors;

  /**
   * Creates worker that connects to the local instance of the Cadence Service that listens on a
   * default port (7933).
   *
   * @param domain domain that worker uses to poll.
   */
  public static WorkflowClient newInstance(String domain) {
    return new WorkflowClientInternal(
        new WorkflowServiceTChannel(), domain, new WorkflowClientOptions.Builder().build());
  }

  /**
   * Creates worker that connects to the local instance of the Cadence Service that listens on a
   * default port (7933).
   *
   * @param domain domain that worker uses to poll.
   * @param options Options (like {@link com.uber.cadence.converter.DataConverter}er override) for
   *     configuring client.
   */
  public static WorkflowClient newInstance(String domain, WorkflowClientOptions options) {
    return new WorkflowClientInternal(new WorkflowServiceTChannel(), domain, options);
  }

  /**
   * Creates client that connects to an instance of the Cadence Service.
   *
   * @param host of the Cadence Service endpoint
   * @param port of the Cadence Service endpoint
   * @param domain domain that worker uses to poll.
   */
  public static WorkflowClient newInstance(String host, int port, String domain) {
    return new WorkflowClientInternal(
        new WorkflowServiceTChannel(host, port),
        domain,
        new WorkflowClientOptions.Builder().build());
  }

  /**
   * Creates client that connects to an instance of the Cadence Service.
   *
   * @param host of the Cadence Service endpoint
   * @param port of the Cadence Service endpoint
   * @param domain domain that worker uses to poll.
   * @param options Options (like {@link com.uber.cadence.converter.DataConverter}er override) for
   *     configuring client.
   */
  public static WorkflowClient newInstance(
      String host, int port, String domain, WorkflowClientOptions options) {
    return new WorkflowClientInternal(new WorkflowServiceTChannel(host, port), domain, options);
  }

  /**
   * Creates client that connects to an instance of the Cadence Service.
   *
   * @param service client to the Cadence Service endpoint.
   * @param domain domain that worker uses to poll.
   */
  public static WorkflowClient newInstance(IWorkflowService service, String domain) {
    return new WorkflowClientInternal(service, domain, null);
  }

  /**
   * Creates client that connects to an instance of the Cadence Service.
   *
   * @param service client to the Cadence Service endpoint.
   * @param domain domain that worker uses to poll.
   * @param options Options (like {@link com.uber.cadence.converter.DataConverter}er override) for
   *     configuring client.
   */
  public static WorkflowClient newInstance(
      IWorkflowService service, String domain, WorkflowClientOptions options) {
    return new WorkflowClientInternal(service, domain, options);
  }

  private WorkflowClientInternal(
      IWorkflowService service, String domain, WorkflowClientOptions options) {
    if (options == null) {
      options = new WorkflowClientOptions.Builder().build();
    }
    this.genericClient =
        new GenericWorkflowClientExternalImpl(service, domain, options.getMetricsScope());
    this.dataConverter = options.getDataConverter();
    this.interceptors = options.getInterceptors();
    this.manualActivityCompletionClientFactory =
        new ManualActivityCompletionClientFactoryImpl(
            service, domain, dataConverter, options.getMetricsScope());
  }

  @Override
  public  T newWorkflowStub(Class workflowInterface) {
    return newWorkflowStub(workflowInterface, (WorkflowOptions) null);
  }

  @Override
  public String getDomain() {
    return genericClient.getDomain();
  }

  @Override
  @SuppressWarnings("unchecked")
  public  T newWorkflowStub(Class workflowInterface, WorkflowOptions options) {
    checkAnnotation(workflowInterface, WorkflowMethod.class);
    WorkflowInvocationHandler invocationHandler =
        new WorkflowInvocationHandler(
            workflowInterface, genericClient, options, dataConverter, interceptors);
    return (T)
        Proxy.newProxyInstance(
            WorkflowInternal.class.getClassLoader(),
            new Class[] {workflowInterface},
            invocationHandler);
  }

  @SafeVarargs
  private static  void checkAnnotation(
      Class workflowInterface, Class... annotationClasses) {
    TypeToken.TypeSet interfaces = TypeToken.of(workflowInterface).getTypes().interfaces();
    if (interfaces.isEmpty()) {
      throw new IllegalArgumentException("Workflow must implement at least one interface");
    }
    for (TypeToken i : interfaces) {
      for (Method method : i.getRawType().getMethods()) {
        for (Class annotationClass : annotationClasses) {
          Object workflowMethod = method.getAnnotation(annotationClass);
          if (workflowMethod != null) {
            return;
          }
        }
      }
    }
    throw new IllegalArgumentException(
        "Workflow interface "
            + workflowInterface.getName()
            + " doesn't have method annotated with any of "
            + Arrays.toString(annotationClasses));
  }

  @Override
  public  T newWorkflowStub(Class workflowInterface, String workflowId) {
    return newWorkflowStub(workflowInterface, workflowId, Optional.empty());
  }

  @Override
  public  T newWorkflowStub(
      Class workflowInterface, String workflowId, Optional runId) {
    checkAnnotation(workflowInterface, WorkflowMethod.class, QueryMethod.class);
    if (Strings.isNullOrEmpty(workflowId)) {
      throw new IllegalArgumentException("workflowId is null or empty");
    }
    WorkflowExecution execution = new WorkflowExecution();
    execution.setWorkflowId(workflowId);
    if (runId.isPresent()) {
      execution.setRunId(runId.get());
    }
    WorkflowInvocationHandler invocationHandler =
        new WorkflowInvocationHandler(
            workflowInterface, genericClient, execution, dataConverter, interceptors);
    @SuppressWarnings("unchecked")
    T result =
        (T)
            Proxy.newProxyInstance(
                WorkflowInternal.class.getClassLoader(),
                new Class[] {workflowInterface},
                invocationHandler);
    return result;
  }

  @Override
  public WorkflowStub newUntypedWorkflowStub(String workflowType, WorkflowOptions options) {
    WorkflowStub result = new WorkflowStubImpl(genericClient, dataConverter, workflowType, options);
    for (WorkflowClientInterceptor i : interceptors) {
      result = i.newUntypedWorkflowStub(workflowType, options, result);
    }
    return result;
  }

  @Override
  public WorkflowStub newUntypedWorkflowStub(
      String workflowId, Optional runId, Optional workflowType) {
    WorkflowExecution execution = new WorkflowExecution().setWorkflowId(workflowId);
    if (runId.isPresent()) {
      execution.setRunId(runId.get());
    }
    return newUntypedWorkflowStub(execution, workflowType);
  }

  @Override
  public WorkflowStub newUntypedWorkflowStub(
      WorkflowExecution execution, Optional workflowType) {
    return new WorkflowStubImpl(genericClient, dataConverter, workflowType, execution);
  }

  @Override
  public ActivityCompletionClient newActivityCompletionClient() {
    ActivityCompletionClient result =
        new ActivityCompletionClientImpl(manualActivityCompletionClientFactory);
    for (WorkflowClientInterceptor i : interceptors) {
      result = i.newActivityCompletionClient(result);
    }
    return result;
  }

  @Override
  public BatchRequest newSignalWithStartRequest() {
    return new SignalWithStartBatchRequest();
  }

  @Override
  public WorkflowExecution signalWithStart(BatchRequest signalWithStartBatch) {
    return ((SignalWithStartBatchRequest) signalWithStartBatch).invoke();
  }

  public static WorkflowExecution start(Functions.Proc workflow) {
    WorkflowInvocationHandler.initAsyncInvocation(InvocationType.START);
    try {
      workflow.apply();
      return WorkflowInvocationHandler.getAsyncInvocationResult(WorkflowExecution.class);
    } finally {
      WorkflowInvocationHandler.closeAsyncInvocation();
    }
  }

  public static  WorkflowExecution start(Functions.Proc1 workflow, A1 arg1) {
    return start(() -> workflow.apply(arg1));
  }

  public static  WorkflowExecution start(
      Functions.Proc2 workflow, A1 arg1, A2 arg2) {
    return start(() -> workflow.apply(arg1, arg2));
  }

  public static  WorkflowExecution start(
      Functions.Proc3 workflow, A1 arg1, A2 arg2, A3 arg3) {
    return start(() -> workflow.apply(arg1, arg2, arg3));
  }

  public static  WorkflowExecution start(
      Functions.Proc4 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4));
  }

  public static  WorkflowExecution start(
      Functions.Proc5 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5));
  }

  public static  WorkflowExecution start(
      Functions.Proc6 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5,
      A6 arg6) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5, arg6));
  }

  public static  WorkflowExecution start(Functions.Func workflow) {
    return start(
        () -> { // Need {} to call start(Proc...)
          workflow.apply();
        });
  }

  public static  WorkflowExecution start(Functions.Func1 workflow, A1 arg1) {
    return start(() -> workflow.apply(arg1));
  }

  public static  WorkflowExecution start(
      Functions.Func2 workflow, A1 arg1, A2 arg2) {
    return start(() -> workflow.apply(arg1, arg2));
  }

  public static  WorkflowExecution start(
      Functions.Func3 workflow, A1 arg1, A2 arg2, A3 arg3) {
    return start(() -> workflow.apply(arg1, arg2, arg3));
  }

  public static  WorkflowExecution start(
      Functions.Func4 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4));
  }

  public static  WorkflowExecution start(
      Functions.Func5 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5));
  }

  public static  WorkflowExecution start(
      Functions.Func6 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5,
      A6 arg6) {
    return start(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5, arg6));
  }

  @SuppressWarnings("unchecked")
  public static CompletableFuture execute(Functions.Proc workflow) {
    WorkflowInvocationHandler.initAsyncInvocation(InvocationType.EXECUTE);
    try {
      workflow.apply();
      return WorkflowInvocationHandler.getAsyncInvocationResult(CompletableFuture.class);
    } finally {
      WorkflowInvocationHandler.closeAsyncInvocation();
    }
  }

  public static  CompletableFuture execute(Functions.Proc1 workflow, A1 arg1) {
    return execute(() -> workflow.apply(arg1));
  }

  public static  CompletableFuture execute(
      Functions.Proc2 workflow, A1 arg1, A2 arg2) {
    return execute(() -> workflow.apply(arg1, arg2));
  }

  public static  CompletableFuture execute(
      Functions.Proc3 workflow, A1 arg1, A2 arg2, A3 arg3) {
    return execute(() -> workflow.apply(arg1, arg2, arg3));
  }

  public static  CompletableFuture execute(
      Functions.Proc4 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4));
  }

  public static  CompletableFuture execute(
      Functions.Proc5 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5));
  }

  public static  CompletableFuture execute(
      Functions.Proc6 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5,
      A6 arg6) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5, arg6));
  }

  @SuppressWarnings("unchecked")
  public static  CompletableFuture execute(Functions.Func workflow) {
    return (CompletableFuture)
        execute(
            () -> {
              // Need {} to call execute(Proc...)
              workflow.apply();
            });
  }

  public static  CompletableFuture execute(Functions.Func1 workflow, A1 arg1) {
    return execute(() -> workflow.apply(arg1));
  }

  public static  CompletableFuture execute(
      Functions.Func2 workflow, A1 arg1, A2 arg2) {
    return execute(() -> workflow.apply(arg1, arg2));
  }

  public static  CompletableFuture execute(
      Functions.Func3 workflow, A1 arg1, A2 arg2, A3 arg3) {
    return execute(() -> workflow.apply(arg1, arg2, arg3));
  }

  public static  CompletableFuture execute(
      Functions.Func4 workflow, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4));
  }

  public static  CompletableFuture execute(
      Functions.Func5 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5));
  }

  public static  CompletableFuture execute(
      Functions.Func6 workflow,
      A1 arg1,
      A2 arg2,
      A3 arg3,
      A4 arg4,
      A5 arg5,
      A6 arg6) {
    return execute(() -> workflow.apply(arg1, arg2, arg3, arg4, arg5, arg6));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy