Migrate netconf-client-mdsal/api tests to JUnit5
[netconf.git] / restconf / restconf-common / src / main / java / org / opendaylight / restconf / common / errors / RestconfFuture.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.common.errors;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.Throwables;
13 import com.google.common.util.concurrent.AbstractFuture;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.concurrent.ExecutionException;
18 import java.util.function.Function;
19 import org.eclipse.jdt.annotation.NonNull;
20
21 /**
22  * A {@link ListenableFuture} specialization, which fails only with {@link RestconfDocumentedException} and does not
23  * produce {@code null} values.
24  *
25  * @param <V> resulting value type
26  */
27 public sealed class RestconfFuture<V> extends AbstractFuture<@NonNull V> permits SettableRestconfFuture {
28     RestconfFuture() {
29         // Hidden on purpose
30     }
31
32     public static <V> @NonNull RestconfFuture<V> of(final V value) {
33         final var future = new RestconfFuture<V>();
34         future.set(requireNonNull(value));
35         return future;
36     }
37
38     public static <V> @NonNull RestconfFuture<V> failed(final RestconfDocumentedException cause) {
39         final var future = new RestconfFuture<V>();
40         future.setException(requireNonNull(cause));
41         return future;
42     }
43
44     @Override
45     public final boolean cancel(final boolean mayInterruptIfRunning) {
46         return false;
47     }
48
49     /**
50      * Add a callback to invoke when this future completes, or immediately if it is already complete.
51      *
52      * @param callback Callback to invoke
53      * @return This future
54      * @throws NullPointerException if {@code callback} is {@code null}
55      */
56     public final @NonNull RestconfFuture<V> addCallback(final RestconfCallback<? super V> callback) {
57         Futures.addCallback(this, callback, MoreExecutors.directExecutor());
58         return this;
59     }
60
61     /**
62      * Transform the result of this future using the specified function.
63      *
64      * @param <T> Resulting type
65      * @param function Function to apply
66      * @return Transformed future
67      * @throws NullPointerException if {@code function} is {@code null}
68      */
69     public final <T> @NonNull RestconfFuture<T> transform(final Function<@NonNull V, @NonNull T> function) {
70         final var fun = requireNonNull(function);
71         final var ret = new RestconfFuture<T>();
72         addCallback(new RestconfCallback<>() {
73             @Override
74             public void onSuccess(final V result) {
75                 ret.set(requireNonNull(fun.apply(result)));
76             }
77
78             @Override
79             protected void onFailure(final RestconfDocumentedException failure) {
80                 ret.setException(failure);
81             }
82         });
83         return ret;
84     }
85
86     /**
87      * Get the result.
88      *
89      * @return The result
90      * @throws RestconfDocumentedException if this future failed or this call is interrupted.
91      */
92     public final @NonNull V getOrThrow() {
93         try {
94             return get();
95         } catch (InterruptedException e) {
96             Thread.currentThread().interrupt();
97             throw new RestconfDocumentedException("Interrupted while waiting", e);
98         } catch (ExecutionException e) {
99             Throwables.throwIfInstanceOf(e.getCause(), RestconfDocumentedException.class);
100             throw new RestconfDocumentedException("Operation failed", e);
101         }
102     }
103 }