

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 活動和工作流程用戶端
<a name="clients"></a>

框架會根據 `@Workflow` 和 `@Activities` 界面產生工作流程和活動用戶端。會產生不同的用戶端界面，其中包含只對用戶端有意義的方法和設定。如果您使用 Eclipse 進行開發，則每次儲存包含適當界面的檔案時，Amazon SWF Eclipse 外掛程式都會執行此操作。產生的程式碼會放在專案中產生的來源目錄裡，而專案位於與界面相同的套件中。

**注意**  
請注意，Eclipse 所使用的預設目錄名稱是 .apt\$1generated。Eclipse 不會在 Package Explorer (套件瀏覽器) 中顯示名稱開頭為 '.' 的目錄。如果您想要在 Project Explorer (專案瀏覽器) 中檢視產生的檔案，則請使用不同的目錄名稱。在 Eclipse 中，以滑鼠右鍵按一下 Package Explorer (套件瀏覽器) 中的套件，並選擇 **Properties** (屬性)、**Java Compiler** (Java 編譯器)、**Annotation processing** (註釋處理)，然後修改 **Generate source directory** (產生來源目錄) 設定。

## 工作流程用戶端
<a name="clients.workflow"></a>

針對工作流程所產生的成品包含三個用戶端界面及實作它們的類別。產生的用戶端包含：
+ 「非同步用戶端」**，要在提供非同步方法來啟動工作流程執行並傳送訊號的工作流程實作內使用
+ 「外部用戶端」**，可用來啟動執行、傳送訊號，並在工作流程實作範圍外部擷取工作流程狀態
+ 「自主用戶端」**，可用來建立持續工作流程

例如，針對範例 `MyWorkflow` 界面所產生的用戶端界面如下：

```
//Client for use from within a workflow
public interface MyWorkflowClient extends WorkflowClient
{
    Promise<Void> startMyWF(
       int a, String b);

    Promise<Void> startMyWF(
       int a, String b,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    void signal1(
      int a, int b, String c);
}

//External client for use outside workflows
public interface MyWorkflowClientExternal extends WorkflowClientExternal
{
    void startMyWF(
       int a, String b);

    void startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride);

    void signal1(
       int a, int b, String c);

    MyWorkflowState getState();
}

//self client for creating continuous workflows
public interface MyWorkflowSelfClient extends WorkflowSelfClient
{
    void startMyWF(
       int a, String b);

    void startMyWF(
       int a, String b,
       Promise<?>... waitFor);

    void startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       Promise<?>... waitFor);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);
```

這些界面的多載方法對應至您所宣告之 `@Workflow` 界面中的每個方法。

外部用戶端會鏡射 `@Workflow` 界面上的方法，而此界面具有採用 `StartWorkflowOptions` 之 `@Execute` 方法的一個額外多載。您可以使用此多載，以在啟動新工作流程執行時傳遞其他選項。這些選項可讓您覆寫預設任務清單、逾時設定，以及建立標籤與工作流程執行的關聯。

另一方面，非同步用戶端的方法允許非同步呼叫 `@Execute` 方法。在工作流程界面中，於 `@Execute` 方法的用戶端界面中產生下列方法多載：

1. 依原狀採用原始引數的多載。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<Void> startMyWF(int a, String b);
   ```

   在工作流程的所有引數皆可用且不需要等待時，應該使用此多載。

1. 包含原始引數及 `Promise<?>` 類型之其他變數引數的多載。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<void> startMyWF(int a, String b, Promise<?>...waitFor);
   ```

   如果工作流程的所有引數皆可用且不需要等待，但您想要等待一些其他 Promise 就緒，則應該使用此多載。變數引數可以用來傳遞 `Promise<?>` 物件，這類物件未宣告為引數，但您想要在執行呼叫之前等待。

1. 包含原始引數、`StartWorkflowOptions` 類型之其他引數及 `Promise<?>` 類型之其他變數引數的多載。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<void> startMyWF(
      int a,
      String b,
      StartWorkflowOptions optionOverrides,
      Promise<?>...waitFor);
   ```

   如果工作流程的所有引數皆可用且不需要等待、您想要覆寫用於啟動工作流程執行的預設設定，或想要等待一些其他 Promise 就緒，則應該使用此多載。變數引數可以用來傳遞 `Promise<?>` 物件，這類物件未宣告為引數，但您想要在執行呼叫之前等待。

1. 原始方法中每個引數皆取代為 `Promise<>` 包裝函式的多載。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b);
   ```

   要非同步評估要傳遞給工作流程執行的引數時，應該使用此多載。在傳遞給此方法多載的所有引數都就緒前，不會對其執行呼叫。

   如果部分引數已就緒，則會透過 `Promise.asPromise(value)` 方法將它們轉換成已處於就緒狀態的 `Promise`。例如：

   ```
   Promise<Integer> a = getA();
   String b = getB();
   startMyWF(a, Promise.asPromise(b));
   ```

1. 原始方法中每個引數皆取代為 `Promise<>` 包裝函式的多載。多載也會具有 `Promise<?>` 類型的其他變數引數。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b,
      Promise<?>...waitFor);
   ```

   如果要非同步評估要傳遞給工作流程執行的引數，而且您也想要等待一些其他 Promise 就緒，則應該使用此多載。在傳遞給此方法多載的所有引數都就緒前，不會對其執行呼叫。

1. 原始方法中每個引數皆取代為 `Promise<?>` 包裝函式的多載。多載也會具有 `StartWorkflowOptions` 類型的其他引數以及 `Promise<?>` 類型的變數引數。如果原始方法已傳回 `void`，則此多載的傳回類型會是 `Promise<Void>`；否則會是原始方法中所宣告的 `Promise<>`。例如：

   原始方法：

   ```
   void startMyWF(int a, String b);
   ```

   產生的方法：

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b,
      StartWorkflowOptions optionOverrides,
      Promise<?>...waitFor);
   ```

   如果將會非同步評估要傳遞給工作流程執行的引數，而且您想要覆寫用以啟動工作流程執行的預設設定，則請使用此多載。在傳遞給此方法多載的所有引數都就緒前，不會對其執行呼叫。

也會產生對應至工作流程界面中每個訊號的方法，例如：

原始方法：

```
void signal1(int a, int b, String c);
```

產生的方法：

```
void signal1(int a, int b, String c);
```

非同步用戶端不會包含與原始界面中已標註 `@GetState` 之方法對應的方法。由於狀態的擷取需要 Web 服務呼叫，因此不適合在工作流程中使用。因此，它只能透過外部用戶端提供。

自主用戶端是要從工作流程內使用，以在目前執行完成時啟動新的執行。此用戶端上的方法類似非同步用戶端上的方法，但傳回 `void`。此用戶端不會具有與已標註 `@Signal` 和 `@GetState` 之方法對應的方法。如需詳細資訊，請參閱「[持續的工作流程](continuous.md)」。

產生的用戶端分別衍生自基本界面：`WorkflowClient` 和 `WorkflowClientExternal`，以提供可用來取消或終止工作流程執行的方法。如需這些界面的詳細資訊，請參閱 適用於 Java 的 AWS SDK 文件。

產生的用戶端可讓您以強類型形式與工作流程執行互動。建立之後，產生之用戶端的執行個體會繫結至特定工作流程執行，且只能用於該執行。此外，框架也會提供非工作流程類型或執行專屬的動態用戶端。產生的用戶端隱含地依賴此用戶端。您也可以直接使用這些用戶端。請參閱「[動態用戶端](#dynamicclients)」一節。

框架也會產生用於建立強類型用戶端的 Factory。針對範例 `MyWorkflow` 界面所產生的用戶端 Factory 如下：

```
//Factory for clients to be used from within a workflow
public interface MyWorkflowClientFactory
   extends WorkflowClientFactory<MyWorkflowClient>
{
}

//Factory for clients to be used outside the scope of a workflow
public interface MyWorkflowClientExternalFactory
{
   GenericWorkflowClientExternal getGenericClient();
   void setGenericClient(GenericWorkflowClientExternal genericClient);
   DataConverter getDataConverter();
   void setDataConverter(DataConverter dataConverter);
   StartWorkflowOptions getStartWorkflowOptions();
   void setStartWorkflowOptions(StartWorkflowOptions startWorkflowOptions);
   MyWorkflowClientExternal getClient();
   MyWorkflowClientExternal getClient(String workflowId);
   MyWorkflowClientExternal getClient(WorkflowExecution workflowExecution);
   MyWorkflowClientExternal getClient(
      WorkflowExecution workflowExecution,
      GenericWorkflowClientExternal genericClient,
      DataConverter dataConverter,
      StartWorkflowOptions options);
}
```

`WorkflowClientFactory` 基本界面如下：

```
public interface WorkflowClientFactory<T> {
    GenericWorkflowClient getGenericClient();
    void setGenericClient(GenericWorkflowClient genericClient);
    DataConverter getDataConverter();
    void setDataConverter(DataConverter dataConverter);
    StartWorkflowOptions getStartWorkflowOptions();
    void setStartWorkflowOptions(StartWorkflowOptions startWorkflowOptions);
    T getClient();
    T getClient(String workflowId);
    T getClient(WorkflowExecution execution);
    T getClient(WorkflowExecution execution,
                StartWorkflowOptions options);
    T getClient(WorkflowExecution execution,
                StartWorkflowOptions options,
                DataConverter dataConverter);
}
```

您應該使用這些 Factory 來建立用戶端的執行個體。Factory 可讓您設定一般用戶端 (應該使用一般用戶端來提供自訂用戶端實作)、用戶端用來封送處理資料的 `DataConverter`，以及用來啟動「工作流程執行」**的選項。如需詳細資訊，請參閱「[DataConverters](dataconverters.md)」和「[子工作流程執行](childworkflow.md)」小節。`StartWorkflowOptions` 包含的設定可用來覆寫註冊時指定的預設值，例如逾時。如需 `StartWorkflowOptions`類別的詳細資訊，請參閱 適用於 Java 的 AWS SDK 文件。

外部用戶端可以用來在工作流程範圍外部啟動工作流程執行，非同步用戶端則可用來從工作流程內的程式碼啟動工作流程執行。若要啟動執行，您只需使用產生的用戶端來呼叫與工作流程界面中已標註 `@Execute` 之方法對應的方法。

框架也會產生用戶端界面的實作類別。這些用戶端會建立並向 Amazon SWF 傳送請求，以執行適當的動作。`@Execute` 方法的用戶端版本會啟動新的工作流程執行，或使用 Amazon SWF APIs 建立子工作流程執行。同樣地， `@Signal`方法的用戶端版本會使用 Amazon SWF APIs來傳送訊號。

**注意**  
外部工作流程用戶端必須使用 Amazon SWF 用戶端和網域設定。您可以使用將它們作為參數的用戶端原廠建構函式，或傳入已使用 Amazon SWF 用戶端和網域設定的一般用戶端實作。  
框架會導覽工作流程界面的類型階層，也會產生父工作流程界面的用戶端界面並從中衍生。

## 活動用戶端
<a name="clients.activity"></a>

與工作流程用戶端類似，會針對已標註 `@Activities` 的每個界面產生用戶端。產生的成品包含用戶端界面和用戶端類別。針對上述範例 `@Activities` 界面所產生的界面 (`MyActivities`) 如下：

```
public interface MyActivitiesClient extends ActivitiesClient
{
  Promise<Integer> activity1();
  Promise<Integer> activity1(Promise<?>... waitFor);
  Promise<Integer> activity1(ActivitySchedulingOptions optionsOverride,
                             Promise<?>... waitFor);
  Promise<Void> activity2(int a);
  Promise<Void> activity2(int a,
                          Promise<?>... waitFor);
  Promise<Void> activity2(int a,
                          ActivitySchedulingOptions optionsOverride,
                          Promise<?>... waitFor);
  Promise<Void> activity2(Promise<Integer> a);
  Promise<Void> activity2(Promise<Integer> a,
                          Promise<?>... waitFor);
  Promise<Void> activity2(Promise<Integer> a,
                          ActivitySchedulingOptions optionsOverride,
                          Promise<?>... waitFor);
}
```

此界面包含對應至 `@Activities` 界面中每個活動方法的一組多載方法。這些多載可提供便利性，並可非同步呼叫活動。針對 `@Activities` 界面中的每個活動方法，在用戶端界面中產生下列方法多載：

1. 依原狀採用原始引數的多載。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise<Void> activity2(int foo);
   ```

   在工作流程的所有引數皆可用且不需要等待時，應該使用此多載。

1. 包含原始引數、`ActivitySchedulingOptions` 類型之引數及 `Promise<?>` 類型之其他變數引數的多載。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise<Void> activity2(
     int foo,
     ActivitySchedulingOptions optionsOverride,
     Promise<?>... waitFor);
   ```

   如果工作流程的所有引數皆可用且不需要等待、您想要覆寫預設設定，或想要等待其他 `Promise` 就緒，則應該使用此多載。變數引數可以用來傳遞其他 `Promise<?>` 物件，這類其他物件未宣告為引數，但您想要在執行呼叫之前等待。

1. 原始方法中每個引數皆取代為 `Promise<>` 包裝函式的多載。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise<Void> activity2(Promise<Integer> foo);
   ```

   將會非同步評估要傳遞給活動的引數時，應該使用此多載。在傳遞給此方法多載的所有引數都就緒前，不會對其執行呼叫。

1. 原始方法中每個引數皆取代為 `Promise<>` 包裝函式的多載。多載也會具有 `ActivitySchedulingOptions` 類型的其他引數以及 `Promise<?>` 類型的變數引數。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise<Void> activity2(
      Promise<Integer> foo,
      ActivitySchedulingOptions optionsOverride,
      Promise<?>...waitFor);
   ```

   如果將會非同步評估要傳遞給活動的引數、您想要覆寫已註冊之類型的預設設定，或想要等待其他 `Promise` 就緒，則應該使用此多載。在傳遞給此方法多載的所有引數都就緒前，不會對其執行呼叫。產生的用戶端類別會實作此界面。每個界面方法的實作都會建立並傳送請求給 Amazon SWF，以使用 Amazon SWF APIs 排程適當類型的活動任務。

1. 包含原始引數及 `Promise<?>` 類型之其他變數引數的多載。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise< Void > activity2(int foo,
                                Promise<?>...waitFor);
   ```

   如果有工作流程的所有引數可用而且不需要等待，但您想要等待其他 `Promise` 物件就緒，則應該使用此多載。

1. 原始方法中每個引數皆取代為 `Promise` 包裝函式且包含 `Promise<?>` 類型之其他變數引數的多載。此多載的傳回類型是 `Promise<T>`，其中 `T` 是原始方法的傳回類型。例如：

   原始方法：

   ```
   void activity2(int foo);
   ```

   產生的方法：

   ```
   Promise<Void> activity2(
     Promise<Integer> foo,
     Promise<?>... waitFor);
   ```

   如果將非同步等待活動的所有引數，而且您也想要等待一些其他 `Promise` 就緒，則應該使用此多載。所有傳遞的 `Promise` 物件都就緒時，將會非同步執行此方法多載的呼叫。

產生的活動用戶端也會有對應至所有活動多載所呼叫之每個活動方法 (名為 `{activity method name}Impl()`) 的受保護方法。您可以覆寫此方法來建立模擬用戶端實作。此方法將下列項目採用為引數：`Promise<>` 包裝函式中原始方法的所有引數、`ActivitySchedulingOptions`，以及 `Promise<?>` 類型的變數引數。例如：

原始方法：

```
void activity2(int foo);
```

產生的方法：

```
Promise<Void> activity2Impl(
   Promise<Integer> foo,
   ActivitySchedulingOptions optionsOverride,
   Promise<?>...waitFor);
```

## 排程選項
<a name="schedulingoptions"></a>

產生的活動用戶端可讓您傳入 `ActivitySchedulingOptions` 做為引數。`ActivitySchedulingOptions` 結構包含決定架構在 Amazon SWF 中排程之活動任務組態的設定。這些設定會覆寫指定為註冊選項的預設值。若要動態指定排程選項，請建立 `ActivitySchedulingOptions` 物件、視需要進行設定，並將之傳遞給活動方法。在下列範例中，我們已指定應該用於活動任務的任務清單。這將會覆寫這次活動呼叫的預設已註冊任務清單。

```
public class OrderProcessingWorkflowImpl implements OrderProcessingWorkflow {

    OrderProcessingActivitiesClient activitiesClient
            = new OrderProcessingActivitiesClientImpl();

    // Workflow entry point
    @Override
    public void processOrder(Order order) {
        Promise<Void> paymentProcessed = activitiesClient.processPayment(order);
        ActivitySchedulingOptions schedulingOptions
             = new ActivitySchedulingOptions();
        if (order.getLocation() == "Japan") {
            schedulingOptions.setTaskList("TasklistAsia");
        } else {
            schedulingOptions.setTaskList("TasklistNorthAmerica");
        }

        activitiesClient.shipOrder(order,
                                   schedulingOptions,
                                   paymentProcessed);
    }
}
```

## 動態用戶端
<a name="dynamicclients"></a>

除了產生的用戶端之外，框架還提供一般用途的用戶端`DynamicWorkflowClient``DynamicActivityClient`，以及可用來動態啟動工作流程執行、傳送訊號、排程活動等的用戶端。例如，建議您排程在設計階段類型未知的活動。您可以使用 `DynamicActivityClient` 排程這類活動任務。同樣地，您可以使用 `DynamicWorkflowClient` 動態排程子工作流程執行。在下列範例中，工作流程會從資料庫尋找活動，並使用動態活動用戶端排程該活動：

```
//Workflow entrypoint
@Override
public void start() {
   MyActivitiesClient client = new MyActivitiesClientImpl();
  Promise<ActivityType> activityType
      = client.lookUpActivityFromDB();
  Promise<String> input = client.getInput(activityType);
  scheduleDynamicActivity(activityType,
                          input);
}
@Asynchronous
void scheduleDynamicActivity(Promise<ActivityType> type,
                             Promise<String> input){
  Promise<?>[] args = new Promise<?>[1];
   args[0] = input;
   DynamicActivitiesClient activityClient
       = new DynamicActivitiesClientImpl();
   activityClient.scheduleActivity(type.get(),
                                   args,
                                   null,
                                   Void.class);
}
```

如需詳細資訊，請參閱 適用於 Java 的 AWS SDK 文件。

### 發出訊號和取消工作流程執行
<a name="executioncontext.signal"></a>

產生的工作流程用戶端具有對應至可傳送到工作流程之每個訊號的方法。您可以在工作流程內使用它們，以將訊號傳送給其他工作流程執行。這提供用來傳送訊號的類型機制。不過，有時您可能需要動態判斷訊號名稱，例如，在訊息中收到訊號名稱時。您可以使用動態工作流程用戶端，將訊號動態傳送給任何工作流程執行。同樣地，您可以使用用戶端，請求另一個工作流程執行的取消。

在下列範例中，工作流程會從資料庫尋找要傳送訊號過去的執行，並使用動態工作流程用戶端來動態傳送訊號。

```
//Workflow entrypoint
public void start()
{
  MyActivitiesClient client = new MyActivitiesClientImpl();
  Promise<WorkflowExecution> execution = client.lookUpExecutionInDB();
  Promise<String> signalName = client.getSignalToSend();
  Promise<String> input = client.getInput(signalName);
  sendDynamicSignal(execution, signalName, input);
}

@Asynchronous
void sendDynamicSignal(
   Promise<WorkflowExecution> execution,
   Promise<String> signalName,
   Promise<String> input)
{
   DynamicWorkflowClient workflowClient
      = new DynamicWorkflowClientImpl(execution.get());
   Object[] args = new Promise<?>[1];
   args[0] = input.get();
   workflowClient.signalWorkflowExecution(signalName.get(), args);
}
```