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

temporalio / sdk-java / #169

pending completion
#169

push

github-actions

web-flow
Remove use of deprecated API (#1758)

4 of 4 new or added lines in 1 file covered. (100.0%)

17345 of 21558 relevant lines covered (80.46%)

0.8 hits per line

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

71.89
/temporal-sdk/src/main/java/io/temporal/internal/sync/WorkflowInternal.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.internal.sync;
22

23
import static io.temporal.internal.sync.AsyncInternal.AsyncMarker;
24
import static io.temporal.internal.sync.DeterministicRunnerImpl.currentThreadInternal;
25

26
import com.google.common.base.Joiner;
27
import com.google.common.base.MoreObjects;
28
import com.google.common.base.Preconditions;
29
import com.uber.m3.tally.Scope;
30
import io.temporal.activity.ActivityOptions;
31
import io.temporal.activity.LocalActivityOptions;
32
import io.temporal.api.common.v1.Payload;
33
import io.temporal.api.common.v1.SearchAttributes;
34
import io.temporal.api.common.v1.WorkflowExecution;
35
import io.temporal.common.RetryOptions;
36
import io.temporal.common.converter.DataConverter;
37
import io.temporal.common.interceptors.Header;
38
import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor;
39
import io.temporal.common.metadata.POJOWorkflowImplMetadata;
40
import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata;
41
import io.temporal.common.metadata.POJOWorkflowMethodMetadata;
42
import io.temporal.internal.WorkflowThreadMarker;
43
import io.temporal.internal.common.ActivityOptionUtils;
44
import io.temporal.internal.common.NonIdempotentHandle;
45
import io.temporal.internal.common.SearchAttributesUtil;
46
import io.temporal.internal.logging.ReplayAwareLogger;
47
import io.temporal.serviceclient.CheckedExceptionWrapper;
48
import io.temporal.workflow.*;
49
import io.temporal.workflow.Functions.Func;
50
import java.lang.reflect.*;
51
import java.time.Duration;
52
import java.util.*;
53
import java.util.function.BiPredicate;
54
import java.util.function.Supplier;
55
import javax.annotation.Nonnull;
56
import javax.annotation.Nullable;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59

60
/**
61
 * Never reference directly. It is public only because Java doesn't have internal package support.
62
 */
63
public final class WorkflowInternal {
64
  public static final int DEFAULT_VERSION = -1;
65

66
  public static @Nonnull WorkflowThread newWorkflowMethodThread(Runnable runnable, String name) {
67
    Object workflowThread =
68
        currentThreadInternal()
1✔
69
            .getWorkflowContext()
1✔
70
            .getWorkflowInboundInterceptor()
1✔
71
            .newWorkflowMethodThread(runnable, name);
1✔
72
    Preconditions.checkState(
1✔
73
        workflowThread != null,
74
        "[BUG] One of the custom interceptors illegally overrode newWorkflowMethodThread result to null. "
75
            + "Check WorkflowInboundCallsInterceptor#newWorkflowMethodThread contract.");
76
    Preconditions.checkState(
1✔
77
        workflowThread instanceof WorkflowThread,
78
        "[BUG] One of the custom interceptors illegally overrode newWorkflowMethodThread result. "
79
            + "Check WorkflowInboundCallsInterceptor#newWorkflowMethodThread contract. "
80
            + "Illegal object returned from the interceptors chain: %s",
81
        workflowThread);
82
    return (WorkflowThread) workflowThread;
1✔
83
  }
84

85
  public static Promise<Void> newTimer(Duration duration) {
86
    return getWorkflowOutboundInterceptor().newTimer(duration);
1✔
87
  }
88

89
  /**
90
   * @param capacity the maximum size of the queue
91
   * @return new instance of {@link WorkflowQueue}
92
   * @deprecated this method created a deprecated implementation of the queue that has some methods
93
   *     implemented incorrectly. Please use {@link #newWorkflowQueue(int)} instead.
94
   */
95
  @Deprecated
96
  public static <E> WorkflowQueue<E> newQueue(int capacity) {
97
    return new WorkflowQueueDeprecatedImpl<>(capacity);
1✔
98
  }
99

100
  /**
101
   * Creates a {@link WorkflowQueue} implementation that can be used from workflow code.
102
   *
103
   * @param capacity the maximum size of the queue
104
   * @return new instance of {@link WorkflowQueue}
105
   */
106
  public static <E> WorkflowQueue<E> newWorkflowQueue(int capacity) {
107
    return new WorkflowQueueImpl<>(capacity);
1✔
108
  }
109

110
  public static <E> CompletablePromise<E> newCompletablePromise() {
111
    return new CompletablePromiseImpl<>();
1✔
112
  }
113

114
  public static <E> Promise<E> newPromise(E value) {
115
    CompletablePromise<E> result = Workflow.newPromise();
1✔
116
    result.complete(value);
1✔
117
    return result;
1✔
118
  }
119

120
  public static <E> Promise<E> newFailedPromise(Exception failure) {
121
    CompletablePromise<E> result = new CompletablePromiseImpl<>();
1✔
122
    result.completeExceptionally(CheckedExceptionWrapper.wrap(failure));
1✔
123
    return result;
1✔
124
  }
125

126
  /**
127
   * Register query or queries implementation object. There is no need to register top level
128
   * workflow implementation object as it is done implicitly. Only methods annotated with @{@link
129
   * QueryMethod} are registered. TODO(quinn) LIES!
130
   */
131
  public static void registerListener(Object implementation) {
132
    if (implementation instanceof DynamicSignalHandler) {
1✔
133
      getWorkflowOutboundInterceptor()
1✔
134
          .registerDynamicSignalHandler(
1✔
135
              new WorkflowOutboundCallsInterceptor.RegisterDynamicSignalHandlerInput(
136
                  (DynamicSignalHandler) implementation));
137
      return;
1✔
138
    }
139
    if (implementation instanceof DynamicQueryHandler) {
1✔
140
      getWorkflowOutboundInterceptor()
1✔
141
          .registerDynamicQueryHandler(
1✔
142
              new WorkflowOutboundCallsInterceptor.RegisterDynamicQueryHandlerInput(
143
                  (DynamicQueryHandler) implementation));
144
      return;
1✔
145
    }
146
    if (implementation instanceof DynamicUpdateHandler) {
1✔
147
      getWorkflowOutboundInterceptor()
×
148
          .registerDynamicUpdateHandler(
×
149
              new WorkflowOutboundCallsInterceptor.RegisterDynamicUpdateHandlerInput(
150
                  (DynamicUpdateHandler) implementation));
151
      return;
×
152
    }
153
    Class<?> cls = implementation.getClass();
1✔
154
    POJOWorkflowImplMetadata workflowMetadata = POJOWorkflowImplMetadata.newListenerInstance(cls);
1✔
155
    for (POJOWorkflowMethodMetadata methodMetadata : workflowMetadata.getQueryMethods()) {
1✔
156
      Method method = methodMetadata.getWorkflowMethod();
1✔
157
      getWorkflowOutboundInterceptor()
1✔
158
          .registerQuery(
1✔
159
              new WorkflowOutboundCallsInterceptor.RegisterQueryInput(
160
                  methodMetadata.getName(),
1✔
161
                  method.getParameterTypes(),
1✔
162
                  method.getGenericParameterTypes(),
1✔
163
                  (args) -> {
164
                    try {
165
                      return method.invoke(implementation, args);
1✔
166
                    } catch (Throwable e) {
×
167
                      throw CheckedExceptionWrapper.wrap(e);
×
168
                    }
169
                  }));
170
    }
1✔
171
    List<WorkflowOutboundCallsInterceptor.SignalRegistrationRequest> requests = new ArrayList<>();
1✔
172
    for (POJOWorkflowMethodMetadata methodMetadata : workflowMetadata.getSignalMethods()) {
1✔
173
      Method method = methodMetadata.getWorkflowMethod();
1✔
174
      requests.add(
1✔
175
          new WorkflowOutboundCallsInterceptor.SignalRegistrationRequest(
176
              methodMetadata.getName(),
1✔
177
              method.getParameterTypes(),
1✔
178
              method.getGenericParameterTypes(),
1✔
179
              (args) -> {
180
                try {
181
                  method.invoke(implementation, args);
1✔
182
                } catch (Throwable e) {
1✔
183
                  throw CheckedExceptionWrapper.wrap(e);
1✔
184
                }
1✔
185
              }));
1✔
186
    }
1✔
187
    if (!requests.isEmpty()) {
1✔
188
      getWorkflowOutboundInterceptor()
1✔
189
          .registerSignalHandlers(
1✔
190
              new WorkflowOutboundCallsInterceptor.RegisterSignalHandlersInput(requests));
191
    }
192

193
    // Get all validators and lazily assign them to update handlers as we see them.
194
    Map<String, POJOWorkflowMethodMetadata> validators =
1✔
195
        new HashMap<>(workflowMetadata.getUpdateValidatorMethods().size());
1✔
196
    for (POJOWorkflowMethodMetadata methodMetadata : workflowMetadata.getUpdateValidatorMethods()) {
1✔
197
      Method method = methodMetadata.getWorkflowMethod();
×
198
      UpdateValidatorMethod updateValidatorMethod =
×
199
          method.getAnnotation(UpdateValidatorMethod.class);
×
200
      if (validators.containsKey(updateValidatorMethod.updateName())) {
×
201
        throw new IllegalArgumentException(
×
202
            "Duplicate validator for update handle " + updateValidatorMethod.updateName());
×
203
      }
204
      validators.put(updateValidatorMethod.updateName(), methodMetadata);
×
205
    }
×
206

207
    List<WorkflowOutboundCallsInterceptor.UpdateRegistrationRequest> updateRequests =
1✔
208
        new ArrayList<>();
209
    for (POJOWorkflowMethodMetadata methodMetadata : workflowMetadata.getUpdateMethods()) {
1✔
210
      Method method = methodMetadata.getWorkflowMethod();
×
211
      UpdateMethod updateMethod = method.getAnnotation(UpdateMethod.class);
×
212
      String updateMethodName = updateMethod.name();
×
213
      if (updateMethodName.isEmpty()) {
×
214
        updateMethodName = method.getName();
×
215
      }
216
      // Check if any validators claim they are the validator for this update
217
      POJOWorkflowMethodMetadata validatorMethodMetadata = validators.remove(updateMethodName);
×
218
      Method validatorMethod;
219
      if (validatorMethodMetadata != null) {
×
220
        validatorMethod = validatorMethodMetadata.getWorkflowMethod();
×
221
        if (!Arrays.equals(validatorMethod.getParameterTypes(), method.getParameterTypes())) {
×
222
          throw new IllegalArgumentException(
×
223
              "Validator for: "
224
                  + updateMethodName
225
                  + " type parameters do not match the update handle");
226
        }
227
      } else {
228
        validatorMethod = null;
×
229
      }
230
      updateRequests.add(
×
231
          new WorkflowOutboundCallsInterceptor.UpdateRegistrationRequest(
232
              methodMetadata.getName(),
×
233
              method.getParameterTypes(),
×
234
              method.getGenericParameterTypes(),
×
235
              (args) -> {
236
                try {
237
                  if (validatorMethod != null) {
×
238
                    validatorMethod.invoke(implementation, args);
×
239
                  }
240
                } catch (Throwable e) {
×
241
                  throw CheckedExceptionWrapper.wrap(e);
×
242
                }
×
243
              },
×
244
              (args) -> {
245
                try {
246
                  return method.invoke(implementation, args);
×
247
                } catch (Throwable e) {
×
248
                  throw CheckedExceptionWrapper.wrap(e);
×
249
                }
250
              }));
251
    }
×
252
    if (!updateRequests.isEmpty()) {
1✔
253
      getWorkflowOutboundInterceptor()
×
254
          .registerUpdateHandlers(
×
255
              new WorkflowOutboundCallsInterceptor.RegisterUpdateHandlersInput(updateRequests));
256
    }
257
    if (!validators.isEmpty()) {
1✔
258
      throw new IllegalArgumentException(
×
259
          "Missing update methods for update validator(s): "
260
              + Joiner.on(", ").join(validators.keySet()));
×
261
    }
262
  }
1✔
263

264
  /** Should be used to get current time instead of {@link System#currentTimeMillis()} */
265
  public static long currentTimeMillis() {
266
    return getWorkflowOutboundInterceptor().currentTimeMillis();
1✔
267
  }
268

269
  public static void setDefaultActivityOptions(ActivityOptions activityOptions) {
270
    getRootWorkflowContext().setDefaultActivityOptions(activityOptions);
1✔
271
  }
1✔
272

273
  public static void applyActivityOptions(Map<String, ActivityOptions> activityTypeToOptions) {
274
    getRootWorkflowContext().applyActivityOptions(activityTypeToOptions);
1✔
275
  }
1✔
276

277
  public static void setDefaultLocalActivityOptions(LocalActivityOptions localActivityOptions) {
278
    getRootWorkflowContext().setDefaultLocalActivityOptions(localActivityOptions);
1✔
279
  }
1✔
280

281
  public static void applyLocalActivityOptions(
282
      Map<String, LocalActivityOptions> activityTypeToOptions) {
283
    getRootWorkflowContext().applyLocalActivityOptions(activityTypeToOptions);
1✔
284
  }
1✔
285

286
  /**
287
   * Creates client stub to activities that implement given interface.
288
   *
289
   * @param activityInterface interface type implemented by activities
290
   * @param options options that together with the properties of {@link
291
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters
292
   * @param activityMethodOptions activity method-specific invocation parameters
293
   */
294
  public static <T> T newActivityStub(
295
      Class<T> activityInterface,
296
      ActivityOptions options,
297
      Map<String, ActivityOptions> activityMethodOptions) {
298
    // Merge the activity options we may have received from the workflow with the options we may
299
    // have received in WorkflowImplementationOptions.
300
    SyncWorkflowContext context = getRootWorkflowContext();
1✔
301
    options = (options == null) ? context.getDefaultActivityOptions() : options;
1✔
302

303
    Map<String, ActivityOptions> mergedActivityOptionsMap;
304
    @Nonnull Map<String, ActivityOptions> predefinedActivityOptions = context.getActivityOptions();
1✔
305
    if (activityMethodOptions != null
1✔
306
        && !activityMethodOptions.isEmpty()
×
307
        && predefinedActivityOptions.isEmpty()) {
×
308
      // we need to merge only in this case
309
      mergedActivityOptionsMap = new HashMap<>(predefinedActivityOptions);
×
310
      ActivityOptionUtils.mergePredefinedActivityOptions(
×
311
          mergedActivityOptionsMap, activityMethodOptions);
312
    } else {
313
      mergedActivityOptionsMap =
1✔
314
          MoreObjects.firstNonNull(
1✔
315
              activityMethodOptions,
316
              MoreObjects.firstNonNull(predefinedActivityOptions, Collections.emptyMap()));
1✔
317
    }
318

319
    InvocationHandler invocationHandler =
1✔
320
        ActivityInvocationHandler.newInstance(
1✔
321
            activityInterface,
322
            options,
323
            mergedActivityOptionsMap,
324
            context.getWorkflowOutboundInterceptor());
1✔
325
    return ActivityInvocationHandlerBase.newProxy(activityInterface, invocationHandler);
1✔
326
  }
327

328
  /**
329
   * Creates client stub to local activities that implement given interface.
330
   *
331
   * @param activityInterface interface type implemented by activities
332
   * @param options options that together with the properties of {@link
333
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters
334
   * @param activityMethodOptions activity method-specific invocation parameters
335
   */
336
  public static <T> T newLocalActivityStub(
337
      Class<T> activityInterface,
338
      LocalActivityOptions options,
339
      @Nullable Map<String, LocalActivityOptions> activityMethodOptions) {
340
    // Merge the activity options we may have received from the workflow with the options we may
341
    // have received in WorkflowImplementationOptions.
342
    SyncWorkflowContext context = getRootWorkflowContext();
1✔
343
    options = (options == null) ? context.getDefaultLocalActivityOptions() : options;
1✔
344

345
    Map<String, LocalActivityOptions> mergedLocalActivityOptionsMap;
346
    @Nonnull
347
    Map<String, LocalActivityOptions> predefinedLocalActivityOptions =
1✔
348
        context.getLocalActivityOptions();
1✔
349
    if (activityMethodOptions != null
1✔
350
        && !activityMethodOptions.isEmpty()
×
351
        && predefinedLocalActivityOptions.isEmpty()) {
×
352
      // we need to merge only in this case
353
      mergedLocalActivityOptionsMap = new HashMap<>(predefinedLocalActivityOptions);
×
354
      ActivityOptionUtils.mergePredefinedLocalActivityOptions(
×
355
          mergedLocalActivityOptionsMap, activityMethodOptions);
356
    } else {
357
      mergedLocalActivityOptionsMap =
1✔
358
          MoreObjects.firstNonNull(
1✔
359
              activityMethodOptions,
360
              MoreObjects.firstNonNull(predefinedLocalActivityOptions, Collections.emptyMap()));
1✔
361
    }
362

363
    InvocationHandler invocationHandler =
1✔
364
        LocalActivityInvocationHandler.newInstance(
1✔
365
            activityInterface,
366
            options,
367
            mergedLocalActivityOptionsMap,
368
            WorkflowInternal.getWorkflowOutboundInterceptor());
1✔
369
    return ActivityInvocationHandlerBase.newProxy(activityInterface, invocationHandler);
1✔
370
  }
371

372
  public static ActivityStub newUntypedActivityStub(ActivityOptions options) {
373
    return ActivityStubImpl.newInstance(options, getWorkflowOutboundInterceptor());
1✔
374
  }
375

376
  public static ActivityStub newUntypedLocalActivityStub(LocalActivityOptions options) {
377
    return LocalActivityStubImpl.newInstance(options, getWorkflowOutboundInterceptor());
1✔
378
  }
379

380
  @SuppressWarnings("unchecked")
381
  public static <T> T newChildWorkflowStub(
382
      Class<T> workflowInterface, ChildWorkflowOptions options) {
383
    return (T)
1✔
384
        Proxy.newProxyInstance(
1✔
385
            workflowInterface.getClassLoader(),
1✔
386
            new Class<?>[] {workflowInterface, StubMarker.class, AsyncMarker.class},
387
            new ChildWorkflowInvocationHandler(
388
                workflowInterface, options, getWorkflowOutboundInterceptor()));
1✔
389
  }
390

391
  @SuppressWarnings("unchecked")
392
  public static <T> T newExternalWorkflowStub(
393
      Class<T> workflowInterface, WorkflowExecution execution) {
394
    return (T)
1✔
395
        Proxy.newProxyInstance(
1✔
396
            workflowInterface.getClassLoader(),
1✔
397
            new Class<?>[] {workflowInterface, StubMarker.class, AsyncMarker.class},
398
            new ExternalWorkflowInvocationHandler(
399
                workflowInterface, execution, getWorkflowOutboundInterceptor()));
1✔
400
  }
401

402
  public static Promise<WorkflowExecution> getWorkflowExecution(Object workflowStub) {
403
    if (workflowStub instanceof StubMarker) {
1✔
404
      Object stub = ((StubMarker) workflowStub).__getUntypedStub();
1✔
405
      return ((ChildWorkflowStub) stub).getExecution();
1✔
406
    }
407
    throw new IllegalArgumentException(
×
408
        "Not a workflow stub created through Workflow.newChildWorkflowStub: " + workflowStub);
409
  }
410

411
  public static ChildWorkflowStub newUntypedChildWorkflowStub(
412
      String workflowType, ChildWorkflowOptions options) {
413
    return new ChildWorkflowStubImpl(workflowType, options, getWorkflowOutboundInterceptor());
1✔
414
  }
415

416
  public static ExternalWorkflowStub newUntypedExternalWorkflowStub(WorkflowExecution execution) {
417
    return new ExternalWorkflowStubImpl(execution, getWorkflowOutboundInterceptor());
1✔
418
  }
419

420
  /**
421
   * Creates client stub that can be used to continue this workflow as new.
422
   *
423
   * @param workflowInterface interface type implemented by the next generation of workflow
424
   */
425
  @SuppressWarnings("unchecked")
426
  public static <T> T newContinueAsNewStub(
427
      Class<T> workflowInterface, ContinueAsNewOptions options) {
428
    return (T)
1✔
429
        Proxy.newProxyInstance(
1✔
430
            workflowInterface.getClassLoader(),
1✔
431
            new Class<?>[] {workflowInterface},
432
            new ContinueAsNewWorkflowInvocationHandler(
433
                workflowInterface, options, getWorkflowOutboundInterceptor()));
1✔
434
  }
435

436
  /**
437
   * Execute activity by name.
438
   *
439
   * @param name name of the activity
440
   * @param resultClass activity return type
441
   * @param args list of activity arguments
442
   * @param <R> activity return type
443
   * @return activity result
444
   */
445
  public static <R> R executeActivity(
446
      String name, ActivityOptions options, Class<R> resultClass, Type resultType, Object... args) {
447
    Promise<R> result =
448
        getWorkflowOutboundInterceptor()
×
449
            .executeActivity(
×
450
                new WorkflowOutboundCallsInterceptor.ActivityInput<>(
451
                    name, resultClass, resultType, args, options, Header.empty()))
×
452
            .getResult();
×
453
    if (AsyncInternal.isAsync()) {
×
454
      AsyncInternal.setAsyncResult(result);
×
455
      return null; // ignored
×
456
    }
457
    return result.get();
×
458
  }
459

460
  public static void await(String reason, Supplier<Boolean> unblockCondition)
461
      throws DestroyWorkflowThreadError {
462
    getWorkflowOutboundInterceptor().await(reason, unblockCondition);
1✔
463
  }
1✔
464

465
  public static boolean await(Duration timeout, String reason, Supplier<Boolean> unblockCondition)
466
      throws DestroyWorkflowThreadError {
467
    return getWorkflowOutboundInterceptor().await(timeout, reason, unblockCondition);
1✔
468
  }
469

470
  public static <R> R sideEffect(Class<R> resultClass, Type resultType, Func<R> func) {
471
    return getWorkflowOutboundInterceptor().sideEffect(resultClass, resultType, func);
1✔
472
  }
473

474
  public static <R> R mutableSideEffect(
475
      String id, Class<R> resultClass, Type resultType, BiPredicate<R, R> updated, Func<R> func) {
476
    return getWorkflowOutboundInterceptor()
1✔
477
        .mutableSideEffect(id, resultClass, resultType, updated, func);
1✔
478
  }
479

480
  public static int getVersion(String changeId, int minSupported, int maxSupported) {
481
    return getWorkflowOutboundInterceptor().getVersion(changeId, minSupported, maxSupported);
1✔
482
  }
483

484
  public static <V> Promise<Void> promiseAllOf(Iterable<Promise<V>> promises) {
485
    return new AllOfPromise(promises);
1✔
486
  }
487

488
  public static Promise<Void> promiseAllOf(Promise<?>... promises) {
489
    return new AllOfPromise(promises);
1✔
490
  }
491

492
  public static <V> Promise<V> promiseAnyOf(Iterable<Promise<V>> promises) {
493
    return CompletablePromiseImpl.promiseAnyOf(promises);
1✔
494
  }
495

496
  public static Promise<Object> promiseAnyOf(Promise<?>... promises) {
497
    return CompletablePromiseImpl.promiseAnyOf(promises);
1✔
498
  }
499

500
  public static CancellationScope newCancellationScope(boolean detached, Runnable runnable) {
501
    return new CancellationScopeImpl(detached, runnable);
1✔
502
  }
503

504
  public static CancellationScope newCancellationScope(
505
      boolean detached, Functions.Proc1<CancellationScope> proc) {
506
    return new CancellationScopeImpl(detached, proc);
1✔
507
  }
508

509
  public static CancellationScopeImpl currentCancellationScope() {
510
    return CancellationScopeImpl.current();
1✔
511
  }
512

513
  public static RuntimeException wrap(Throwable e) {
514
    return CheckedExceptionWrapper.wrap(e);
1✔
515
  }
516

517
  public static Throwable unwrap(Throwable e) {
518
    return CheckedExceptionWrapper.unwrap(e);
1✔
519
  }
520

521
  /** Returns false if not under workflow code. */
522
  public static boolean isReplaying() {
523
    Optional<WorkflowThread> thread = DeterministicRunnerImpl.currentThreadInternalIfPresent();
1✔
524
    return thread.isPresent() && getRootWorkflowContext().isReplaying();
1✔
525
  }
526

527
  public static <T> T getMemo(String key, Class<T> valueClass, Type genericType) {
528
    Payload memo = getRootWorkflowContext().getReplayContext().getMemo(key);
1✔
529
    if (memo == null) {
1✔
530
      return null;
1✔
531
    }
532

533
    return getDataConverter().fromPayload(memo, valueClass, genericType);
1✔
534
  }
535

536
  public static <R> R retry(
537
      RetryOptions options, Optional<Duration> expiration, Functions.Func<R> fn) {
538
    return WorkflowRetryerInternal.retry(
1✔
539
        options.toBuilder().validateBuildWithDefaults(), expiration, fn);
1✔
540
  }
541

542
  public static void continueAsNew(
543
      @Nullable String workflowType, @Nullable ContinueAsNewOptions options, Object[] args) {
544
    getWorkflowOutboundInterceptor()
1✔
545
        .continueAsNew(
×
546
            new WorkflowOutboundCallsInterceptor.ContinueAsNewInput(
547
                workflowType, options, args, Header.empty()));
1✔
548
  }
×
549

550
  public static void continueAsNew(
551
      @Nullable String workflowType,
552
      @Nullable ContinueAsNewOptions options,
553
      Object[] args,
554
      WorkflowOutboundCallsInterceptor outboundCallsInterceptor) {
555
    outboundCallsInterceptor.continueAsNew(
1✔
556
        new WorkflowOutboundCallsInterceptor.ContinueAsNewInput(
557
            workflowType, options, args, Header.empty()));
1✔
558
  }
×
559

560
  public static Promise<Void> cancelWorkflow(WorkflowExecution execution) {
561
    return getWorkflowOutboundInterceptor()
×
562
        .cancelWorkflow(new WorkflowOutboundCallsInterceptor.CancelWorkflowInput(execution))
×
563
        .getResult();
×
564
  }
565

566
  public static void sleep(Duration duration) {
567
    getWorkflowOutboundInterceptor().sleep(duration);
1✔
568
  }
1✔
569

570
  public static boolean isWorkflowThread() {
571
    return WorkflowThreadMarker.isWorkflowThread();
1✔
572
  }
573

574
  public static <T> T deadlockDetectorOff(Functions.Func<T> func) {
575
    if (isWorkflowThread()) {
1✔
576
      try (NonIdempotentHandle ignored = getWorkflowThread().lockDeadlockDetector()) {
1✔
577
        return func.apply();
1✔
578
      }
579
    } else {
580
      return func.apply();
1✔
581
    }
582
  }
583

584
  public static WorkflowInfo getWorkflowInfo() {
585
    return new WorkflowInfoImpl(getRootWorkflowContext().getReplayContext());
1✔
586
  }
587

588
  public static Scope getMetricsScope() {
589
    return getRootWorkflowContext().getMetricsScope();
1✔
590
  }
591

592
  private static boolean isLoggingEnabledInReplay() {
593
    return getRootWorkflowContext().isLoggingEnabledInReplay();
×
594
  }
595

596
  public static UUID randomUUID() {
597
    return getRootWorkflowContext().randomUUID();
1✔
598
  }
599

600
  public static Random newRandom() {
601
    return getRootWorkflowContext().newRandom();
1✔
602
  }
603

604
  public static Logger getLogger(Class<?> clazz) {
605
    Logger logger = LoggerFactory.getLogger(clazz);
1✔
606
    return new ReplayAwareLogger(
1✔
607
        logger, WorkflowInternal::isReplaying, WorkflowInternal::isLoggingEnabledInReplay);
608
  }
609

610
  public static Logger getLogger(String name) {
611
    Logger logger = LoggerFactory.getLogger(name);
×
612
    return new ReplayAwareLogger(
×
613
        logger, WorkflowInternal::isReplaying, WorkflowInternal::isLoggingEnabledInReplay);
614
  }
615

616
  public static <R> R getLastCompletionResult(Class<R> resultClass, Type resultType) {
617
    return getRootWorkflowContext().getLastCompletionResult(resultClass, resultType);
1✔
618
  }
619

620
  @Nullable
621
  public static <T> T getSearchAttribute(String name) {
622
    List<T> list = getSearchAttributeValues(name);
1✔
623
    if (list == null) {
1✔
624
      return null;
1✔
625
    }
626
    Preconditions.checkState(list.size() > 0);
1✔
627
    Preconditions.checkState(
1✔
628
        list.size() == 1,
1✔
629
        "search attribute with name '%s' contains a list '%s' of values instead of a single value",
630
        name,
631
        list);
632
    return list.get(0);
1✔
633
  }
634

635
  @Nullable
636
  public static <T> List<T> getSearchAttributeValues(String name) {
637
    SearchAttributes searchAttributes =
638
        getRootWorkflowContext().getReplayContext().getSearchAttributes();
1✔
639
    if (searchAttributes == null) {
1✔
640
      return null;
×
641
    }
642
    List<T> decoded = SearchAttributesUtil.decode(searchAttributes, name);
1✔
643
    return decoded != null ? Collections.unmodifiableList(decoded) : null;
1✔
644
  }
645

646
  @Nonnull
647
  public static Map<String, List<?>> getSearchAttributes() {
648
    SearchAttributes searchAttributes =
649
        getRootWorkflowContext().getReplayContext().getSearchAttributes();
1✔
650
    if (searchAttributes == null) {
1✔
651
      return Collections.emptyMap();
×
652
    }
653
    return Collections.unmodifiableMap(SearchAttributesUtil.decode(searchAttributes));
1✔
654
  }
655

656
  public static void upsertSearchAttributes(Map<String, ?> searchAttributes) {
657
    getWorkflowOutboundInterceptor().upsertSearchAttributes(searchAttributes);
1✔
658
  }
1✔
659

660
  public static DataConverter getDataConverter() {
661
    return getRootWorkflowContext().getDataConverter();
1✔
662
  }
663

664
  /**
665
   * Name of the workflow type the interface defines. It is either the interface short name * or
666
   * value of {@link WorkflowMethod#name()} parameter.
667
   *
668
   * @param workflowInterfaceClass interface annotated with @WorkflowInterface
669
   */
670
  public static String getWorkflowType(Class<?> workflowInterfaceClass) {
671
    POJOWorkflowInterfaceMetadata metadata =
1✔
672
        POJOWorkflowInterfaceMetadata.newInstance(workflowInterfaceClass);
1✔
673
    return metadata.getWorkflowType().get();
1✔
674
  }
675

676
  public static Optional<Exception> getPreviousRunFailure() {
677
    return Optional.ofNullable(getRootWorkflowContext().getReplayContext().getPreviousRunFailure())
1✔
678
        // Temporal Failure Values are additional user payload and serialized using user data
679
        // converter
680
        .map(f -> getDataConverter().failureToException(f));
1✔
681
  }
682

683
  private static WorkflowOutboundCallsInterceptor getWorkflowOutboundInterceptor() {
684
    return getRootWorkflowContext().getWorkflowOutboundInterceptor();
1✔
685
  }
686

687
  static SyncWorkflowContext getRootWorkflowContext() {
688
    return DeterministicRunnerImpl.currentThreadInternal().getWorkflowContext();
1✔
689
  }
690

691
  private static WorkflowThread getWorkflowThread() {
692
    return DeterministicRunnerImpl.currentThreadInternal();
1✔
693
  }
694

695
  /** Prohibit instantiation */
696
  private WorkflowInternal() {}
697
}
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