• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #339

22 Oct 2024 04:40PM UTC coverage: 78.687% (+0.03%) from 78.658%
#339

push

github

web-flow
Fix UpdateWithStart untyped operation (#2288)

15 of 17 new or added lines in 2 files covered. (88.24%)

2 existing lines in 1 file now uncovered.

22687 of 28832 relevant lines covered (78.69%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.95
/temporal-sdk/src/main/java/io/temporal/client/UpdateWithStartWorkflowOperation.java
1
/*
2
 * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3
 *
4
 * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
 *
6
 * Modifications copyright (C) 2017 Uber Technologies, Inc.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this material except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *   http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
package io.temporal.client;
22

23
import io.temporal.common.Experimental;
24
import io.temporal.workflow.Functions;
25
import java.lang.reflect.Type;
26
import java.util.Arrays;
27
import java.util.concurrent.*;
28
import java.util.concurrent.atomic.AtomicBoolean;
29
import javax.annotation.Nullable;
30

31
/**
32
 * UpdateWithStartWorkflowOperation is an update workflow request that can be executed together with
33
 * a start workflow request.
34
 */
35
@Experimental
36
public final class UpdateWithStartWorkflowOperation<R> {
37

38
  private final AtomicBoolean invoked = new AtomicBoolean(false);
1✔
39

40
  /**
41
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a zero argument
42
   * request.
43
   *
44
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
45
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
46
   */
47
  public static <R> Builder<R> newBuilder(Functions.Func<R> request) {
48
    return new Builder<>(
1✔
49
        () -> {
50
          request.apply();
×
51
        });
×
52
  }
53

54
  /**
55
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a one argument
56
   * request.
57
   *
58
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
59
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
60
   * @param arg1 first request function parameter
61
   */
62
  public static <A1, R> Builder<R> newBuilder(Functions.Func1<A1, R> request, A1 arg1) {
63
    return new Builder<>(() -> request.apply(arg1));
1✔
64
  }
65

66
  /**
67
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a two argument
68
   * request.
69
   *
70
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
71
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
72
   * @param arg1 first request function parameter
73
   * @param arg2 second request function parameter
74
   */
75
  public static <A1, A2, R> Builder<R> newBuilder(
76
      Functions.Func2<A1, A2, R> request, A1 arg1, A2 arg2) {
77
    return new Builder<>(() -> request.apply(arg1, arg2));
1✔
78
  }
79

80
  /**
81
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a three argument
82
   * request.
83
   *
84
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
85
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
86
   * @param arg1 first request function parameter
87
   * @param arg2 second request function parameter
88
   * @param arg3 third request function parameter
89
   */
90
  public static <A1, A2, A3, R> Builder<R> newBuilder(
91
      Functions.Func3<A1, A2, A3, R> request, A1 arg1, A2 arg2, A3 arg3) {
92
    return new Builder<>(() -> request.apply(arg1, arg2, arg3));
×
93
  }
94

95
  /**
96
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a four argument
97
   * request.
98
   *
99
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
100
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
101
   * @param arg1 first request function parameter
102
   * @param arg2 second request function parameter
103
   * @param arg3 third request function parameter
104
   * @param arg4 fourth request function parameter
105
   */
106
  public static <A1, A2, A3, A4, R> Builder<R> newBuilder(
107
      Functions.Func4<A1, A2, A3, A4, R> request, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
108
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4));
×
109
  }
110

111
  /**
112
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a five argument
113
   * request.
114
   *
115
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
116
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
117
   * @param arg1 first request function parameter
118
   * @param arg2 second request function parameter
119
   * @param arg3 third request function parameter
120
   * @param arg4 fourth request function parameter
121
   * @param arg5 fifth request function parameter
122
   */
123
  public static <A1, A2, A3, A4, A5, R> Builder<R> newBuilder(
124
      Functions.Func5<A1, A2, A3, A4, A5, R> request, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
125
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4, arg5));
×
126
  }
127

128
  /**
129
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a six argument
130
   * request.
131
   *
132
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
133
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
134
   * @param arg1 first request function parameter
135
   * @param arg2 second request function parameter
136
   * @param arg3 third request function parameter
137
   * @param arg4 fourth request function parameter
138
   * @param arg5 fifth request function parameter
139
   * @param arg6 sixth request function parameter
140
   */
141
  public static <A1, A2, A3, A4, A5, A6, R> Builder<R> newBuilder(
142
      Functions.Func6<A1, A2, A3, A4, A5, A6, R> request,
143
      A1 arg1,
144
      A2 arg2,
145
      A3 arg3,
146
      A4 arg4,
147
      A5 arg5,
148
      A6 arg6) {
149
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4, arg5, arg6));
×
150
  }
151

152
  /**
153
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a zero argument
154
   * request.
155
   *
156
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
157
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
158
   */
159
  public static Builder<Void> newBuilder(Functions.Proc request) {
160
    return new Builder<>(
×
161
        () -> {
162
          request.apply();
×
163
        });
×
164
  }
165

166
  /**
167
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a one argument
168
   * request.
169
   *
170
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
171
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
172
   * @param arg1 first request function parameter
173
   */
174
  public static <A1> Builder<Void> newBuilder(Functions.Proc1<A1> request, A1 arg1) {
175
    return new Builder<>(() -> request.apply(arg1));
1✔
176
  }
177

178
  /**
179
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a two argument
180
   * request.
181
   *
182
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
183
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
184
   * @param arg1 first request function parameter
185
   * @param arg2 second request function parameter
186
   */
187
  public static <A1, A2> Builder<Void> newBuilder(
188
      Functions.Proc2<A1, A2> request, A1 arg1, A2 arg2) {
189
    return new Builder<>(() -> request.apply(arg1, arg2));
×
190
  }
191

192
  /**
193
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a three argument
194
   * request.
195
   *
196
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
197
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
198
   * @param arg1 first request function parameter
199
   * @param arg2 second request function parameter
200
   * @param arg3 third request function parameter
201
   */
202
  public static <A1, A2, A3> Builder<Void> newBuilder(
203
      Functions.Proc3<A1, A2, A3> request, A1 arg1, A2 arg2, A3 arg3) {
204
    return new Builder<>(() -> request.apply(arg1, arg2, arg3));
×
205
  }
206

207
  /**
208
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a four argument
209
   * request.
210
   *
211
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
212
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
213
   * @param arg1 first request function parameter
214
   * @param arg2 second request function parameter
215
   * @param arg3 third request function parameter
216
   * @param arg4 fourth request function parameter
217
   */
218
  public static <A1, A2, A3, A4> Builder<Void> newBuilder(
219
      Functions.Proc4<A1, A2, A3, A4> request, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
220
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4));
×
221
  }
222

223
  /**
224
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a five argument
225
   * request.
226
   *
227
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
228
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
229
   * @param arg1 first request function parameter
230
   * @param arg2 second request function parameter
231
   * @param arg3 third request function parameter
232
   * @param arg4 fourth request function parameter
233
   * @param arg5 fifth request function parameter
234
   */
235
  public static <A1, A2, A3, A4, A5> Builder<Void> newBuilder(
236
      Functions.Proc5<A1, A2, A3, A4, A5> request, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
237
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4, arg5));
×
238
  }
239

240
  /**
241
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation} for a six argument
242
   * request.
243
   *
244
   * @param request method reference annotated with @UpdateMethod of a proxy created through {@link
245
   *     WorkflowClient#newWorkflowStub(Class, WorkflowOptions)}.
246
   * @param arg1 first request function parameter
247
   * @param arg2 second request function parameter
248
   * @param arg3 third request function parameter
249
   * @param arg4 fourth request function parameter
250
   * @param arg5 fifth request function parameter
251
   * @param arg6 sixth request function parameter
252
   */
253
  public static <A1, A2, A3, A4, A5, A6> Builder<Void> newBuilder(
254
      Functions.Proc6<A1, A2, A3, A4, A5, A6> request,
255
      A1 arg1,
256
      A2 arg2,
257
      A3 arg3,
258
      A4 arg4,
259
      A5 arg5,
260
      A6 arg6) {
261
    return new Builder<>(() -> request.apply(arg1, arg2, arg3, arg4, arg5, arg6));
×
262
  }
263

264
  /**
265
   * Returns a new builder for an {@link UpdateWithStartWorkflowOperation}.
266
   *
267
   * @param updateName name of the update handler
268
   * @param resultClass class of the update return value
269
   * @param args update request arguments
270
   */
271
  public static <R> Builder<R> newBuilder(String updateName, Class<R> resultClass, Object[] args) {
272
    return new Builder<>(
1✔
273
        UpdateOptions.<R>newBuilder().setResultClass(resultClass).setUpdateName(updateName), args);
1✔
274
  }
275

276
  private WorkflowStub stub;
277

278
  private UpdateOptions<R> options;
279

280
  // set by constructor (untyped) or `prepareUpdate` (typed)
281
  private Object[] updateArgs;
282

283
  // set by `prepareStart`
284
  private Object[] workflowArgs;
285

286
  private final CompletableFuture<WorkflowUpdateHandle<R>> handle;
287

288
  @Nullable private final Functions.Proc updateRequest;
289

290
  private UpdateWithStartWorkflowOperation(
291
      UpdateOptions<R> options, Functions.Proc updateRequest, Object[] updateArgs) {
1✔
292
    this.options = options;
1✔
293
    this.updateArgs = updateArgs;
1✔
294
    this.handle = new CompletableFuture<>();
1✔
295
    this.updateRequest = updateRequest;
1✔
296
  }
1✔
297

298
  WorkflowUpdateHandle<R> invoke(Functions.Proc workflowRequest) {
299
    WorkflowInvocationHandler.initAsyncInvocation(
1✔
300
        WorkflowInvocationHandler.InvocationType.UPDATE_WITH_START, this);
301
    try {
302
      // invokes `prepareStart` via WorkflowInvocationHandler.UpdateWithStartInvocationHandler
303
      workflowRequest.apply();
1✔
304

305
      if (updateRequest != null) { // only present when using typed API
1✔
306
        // invokes `prepareUpdate` via WorkflowInvocationHandler.UpdateWithStartInvocationHandler
307
        updateRequest.apply();
1✔
308
      }
309
      stub.updateWithStart(this, this.workflowArgs);
1✔
310
      return this.handle.get();
1✔
311
    } catch (InterruptedException e) {
×
312
      Thread.currentThread().interrupt();
×
313
      throw new RuntimeException(e);
×
314
    } catch (ExecutionException e) {
×
315
      Throwable cause = e.getCause();
×
316
      throw (cause instanceof RuntimeException
×
317
          ? (RuntimeException) cause
×
318
          : new RuntimeException(cause));
×
319
    } finally {
320
      WorkflowInvocationHandler.closeAsyncInvocation();
1✔
321
    }
322
  }
323

324
  /** Invoked by {@link WorkflowInvocationHandler.UpdateWithStartInvocationHandler}. */
325
  void prepareUpdate(
326
      WorkflowStub stub, String updateName, Class resultClass, Type resultType, Object[] args) {
327
    setStub(stub);
1✔
328
    this.updateArgs = args;
1✔
329
    this.options =
1✔
330
        this.options.toBuilder()
1✔
331
            .setUpdateName(updateName)
1✔
332
            .setResultClass(resultClass)
1✔
333
            .setResultType(resultType)
1✔
334
            .build();
1✔
335
  }
1✔
336

337
  /** Invoked by {@link WorkflowInvocationHandler.UpdateWithStartInvocationHandler}. */
338
  void prepareStart(WorkflowStub stub, Object[] args) {
339
    setStub(stub);
1✔
340
    this.workflowArgs = args;
1✔
341
  }
1✔
342

343
  /** Returns the result of the update request. */
344
  public R getResult() throws ExecutionException, InterruptedException {
345
    return this.getUpdateHandle().get().getResultAsync().get();
1✔
346
  }
347

348
  public Future<WorkflowUpdateHandle<R>> getUpdateHandle() {
349
    return this.handle;
1✔
350
  }
351

352
  void setUpdateHandle(WorkflowUpdateHandle<R> updateHandle) {
353
    this.handle.complete(updateHandle);
1✔
354
  }
1✔
355

356
  public UpdateOptions<R> getOptions() {
357
    return this.options;
1✔
358
  }
359

360
  public Object[] getUpdateArgs() {
361
    return this.updateArgs;
1✔
362
  }
363

364
  // equals/hashCode intentionally left as default
365

366
  @Override
367
  public String toString() {
368
    StringBuilder sb = new StringBuilder();
×
369
    sb.append("UpdateWithStartWorkflowOperation{options=").append(options);
×
NEW
370
    if (updateRequest != null) {
×
NEW
371
      sb.append(", updateRequest=").append(updateRequest);
×
372
    }
373
    if (updateArgs != null) {
×
374
      sb.append(", updateArgs=").append(Arrays.toString(updateArgs));
×
375
    }
376
    return sb.toString();
×
377
  }
378

379
  private void setStub(WorkflowStub stub) {
380
    if (this.stub != null && stub != this.stub) {
1✔
381
      throw new IllegalArgumentException(
1✔
382
          "UpdateWithStartWorkflowOperation invoked on different workflow stubs");
383
    }
384
    this.stub = stub;
1✔
385
  }
1✔
386

387
  /**
388
   * Mark the operation as having been invoked.
389
   *
390
   * @return false if the operation was already invoked
391
   */
392
  boolean markInvoked() {
393
    return invoked.compareAndSet(false, true);
1✔
394
  }
395

396
  public static final class Builder<R> {
397
    private UpdateOptions.Builder<R> options;
398
    private Functions.Proc request;
399
    private Object[] args;
400

401
    private Builder() {}
402

403
    private Builder(UpdateOptions.Builder<R> options, Object[] args) {
1✔
404
      this.options = options;
1✔
405
      this.request = null;
1✔
406
      this.args = args;
1✔
407
    }
1✔
408

409
    private Builder(Functions.Proc request) {
1✔
410
      this.options = UpdateOptions.newBuilder();
1✔
411
      this.request = request;
1✔
412
    }
1✔
413

414
    public Builder<R> setWaitForStage(WorkflowUpdateStage waitForStage) {
415
      this.options.setWaitForStage(waitForStage);
1✔
416
      return this;
1✔
417
    }
418

419
    public Builder<R> setUpdateId(String updateId) {
420
      this.options.setUpdateId(updateId);
×
421
      return this;
×
422
    }
423

424
    public UpdateWithStartWorkflowOperation<R> build() {
425
      return new UpdateWithStartWorkflowOperation<>(this.options.build(), this.request, this.args);
1✔
426
    }
427
  }
428
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc