Use a switch expression in TypeDefinitionAwareCodec
[yangtools.git] / common / yang-common / src / main / java / org / opendaylight / yangtools / yang / common / RpcResultBuilder.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. 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.yangtools.yang.common;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.Futures;
15 import java.io.Serial;
16 import java.io.Serializable;
17 import java.util.Collection;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.yangtools.concepts.Mutable;
20
21 /**
22  * A builder for creating RpcResult instances.
23  *
24  * @author Thomas Pantelis
25  *
26  * @param <T> the result value type
27  */
28 public final class RpcResultBuilder<T> implements Mutable {
29
30     private static class RpcResultImpl<T> implements RpcResult<T>, Serializable {
31         @Serial
32         private static final long serialVersionUID = 1L;
33
34         private final ImmutableList<RpcError> errors;
35         private final T result;
36         private final boolean successful;
37
38         RpcResultImpl(final boolean successful, final T result, final ImmutableList<RpcError> errors) {
39             this.successful = successful;
40             this.result = result;
41             this.errors = requireNonNull(errors);
42         }
43
44         @Override
45         public ImmutableList<RpcError> getErrors() {
46             return errors;
47         }
48
49         @Override
50         public T getResult() {
51             return result;
52         }
53
54         @Override
55         public boolean isSuccessful() {
56             return successful;
57         }
58
59         @Override
60         public String toString() {
61             return "RpcResult [successful=" + successful + ", result="
62                     + result + ", errors=" + errors + "]";
63         }
64     }
65
66     private static class RpcErrorImpl implements RpcError, Serializable {
67         @Serial
68         private static final long serialVersionUID = 1L;
69
70         private final String applicationTag;
71         private final ErrorTag tag;
72         private final String info;
73         private final ErrorSeverity severity;
74         private final String message;
75         private final ErrorType errorType;
76         private final Throwable cause;
77
78         RpcErrorImpl(final ErrorSeverity severity, final ErrorType errorType, final ErrorTag tag, final String message,
79                 final String applicationTag, final String info, final Throwable cause) {
80             this.severity = severity;
81             this.errorType = errorType;
82             this.tag = tag;
83             this.message = message;
84             this.applicationTag = applicationTag;
85             this.info = info;
86             this.cause = cause;
87         }
88
89         @Override
90         public String getApplicationTag() {
91             return applicationTag;
92         }
93
94         @Override
95         public ErrorTag getTag() {
96             return tag;
97         }
98
99         @Override
100         public String getInfo() {
101             return info;
102         }
103
104         @Override
105         public ErrorSeverity getSeverity() {
106             return severity;
107         }
108
109         @Override
110         public String getMessage() {
111             return message;
112         }
113
114         @Override
115         public ErrorType getErrorType() {
116             return errorType;
117         }
118
119         @Override
120         public Throwable getCause() {
121             return cause;
122         }
123
124         @Override
125         public String toString() {
126             return "RpcError [message=" + message + ", severity="
127                     + severity + ", errorType=" + errorType + ", tag=" + tag
128                     + ", applicationTag=" + applicationTag + ", info=" + info
129                     + ", cause=" + cause + "]";
130         }
131     }
132
133     private ImmutableList.Builder<RpcError> errors;
134     private T result;
135     private final boolean successful;
136
137     private RpcResultBuilder(final boolean successful, final T result) {
138         this.successful = successful;
139         this.result = result;
140     }
141
142     /**
143      * Returns a builder for a successful result.
144      */
145     public static <T> @NonNull RpcResultBuilder<T> success() {
146         return new RpcResultBuilder<>(true, null);
147     }
148
149     /**
150      * Returns a builder for a successful result.
151      *
152      * @param result the result value
153      */
154     public static <T> @NonNull RpcResultBuilder<T> success(final T result) {
155         return new RpcResultBuilder<>(true, result);
156     }
157
158     /**
159      * Returns a builder for a failed result.
160      */
161     public static <T> @NonNull RpcResultBuilder<T> failed() {
162         return new RpcResultBuilder<>(false, null);
163     }
164
165     /**
166      * Returns a builder based on the given status.
167      *
168      * @param success true if successful, false otherwise.
169      */
170     public static <T> @NonNull RpcResultBuilder<T> status(final boolean success) {
171         return new RpcResultBuilder<>(success, null);
172     }
173
174     /**
175      * Returns a builder from another RpcResult.
176      *
177      * @param other the other RpcResult.
178      */
179     public static <T> @NonNull RpcResultBuilder<T> from(final RpcResult<T> other) {
180         return new RpcResultBuilder<>(other.isSuccessful(), other.getResult())
181                                                       .withRpcErrors(other.getErrors());
182     }
183
184     /**
185      * Creates an RpcError with severity ERROR for reuse.
186      *
187      * @param errorType the conceptual layer at which the error occurred.
188      * @param tag a short string that identifies the general type of error condition. See
189      *        {@link RpcError#getTag} for a list of suggested values.
190      * @param message a string suitable for human display that describes the error condition.
191      *
192      * @return an RpcError
193      */
194     public static @NonNull RpcError newError(final ErrorType errorType, final ErrorTag tag, final String message) {
195         return new RpcErrorImpl(ErrorSeverity.ERROR, errorType, tag != null ? tag : ErrorTag.OPERATION_FAILED, message,
196             null, null, null);
197     }
198
199     /**
200      * Creates an RpcError with severity ERROR for reuse.
201      *
202      * @param errorType the conceptual layer at which the error occurred.
203      * @param tag a short string that identifies the general type of error condition. See
204      *        {@link RpcError#getTag} for a list of suggested values.
205      * @param message a string suitable for human display that describes the error condition.
206      * @param applicationTag a short string that identifies the specific type of error condition.
207      * @param info a string containing additional information to provide extended
208      *        and/or implementation-specific debugging information.
209      * @param cause the exception that triggered the error.
210      *
211      * @return an RpcError
212      */
213     public static @NonNull RpcError newError(final ErrorType errorType, final ErrorTag tag, final String message,
214             final String applicationTag, final String info, final Throwable cause) {
215         return new RpcErrorImpl(ErrorSeverity.ERROR, errorType, tag != null ? tag : ErrorTag.OPERATION_FAILED, message,
216             applicationTag, info, cause);
217     }
218
219     /**
220      * Creates an RpcError with severity WARNING for reuse.
221      *
222      * @param errorType the conceptual layer at which the warning occurred.
223      * @param tag a short string that identifies the general type of warning condition. See
224      *        {@link RpcError#getTag} for a list of suggested values.
225      * @param message a string suitable for human display that describes the warning condition.
226      *
227      * @return an RpcError
228      */
229     public static @NonNull RpcError newWarning(final ErrorType errorType, final ErrorTag tag, final String message) {
230         return new RpcErrorImpl(ErrorSeverity.WARNING, errorType, tag, message, null, null, null);
231     }
232
233     /**
234      * Creates an RpcError with severity WARNING for reuse.
235      *
236      * @param errorType the conceptual layer at which the warning occurred.
237      * @param tag a short string that identifies the general type of warning condition. See
238      *        {@link RpcError#getTag} for a list of suggested values.
239      * @param message a string suitable for human display that describes the warning condition.
240      * @param applicationTag a short string that identifies the specific type of warning condition.
241      * @param info a string containing additional information to provide extended
242      *        and/or implementation-specific debugging information.
243      * @param cause the exception that triggered the warning.
244      *
245      * @return an RpcError
246      */
247     public static @NonNull RpcError newWarning(final ErrorType errorType, final ErrorTag tag, final String message,
248             final String applicationTag, final String info, final Throwable cause) {
249         return new RpcErrorImpl(ErrorSeverity.WARNING, errorType, tag, message, applicationTag, info, cause);
250     }
251
252     /**
253      * Sets the value of the result.
254      *
255      * @param result the result value
256      */
257     @SuppressWarnings("checkstyle:hiddenField")
258     public @NonNull RpcResultBuilder<T> withResult(final T result) {
259         this.result = result;
260         return this;
261     }
262
263     private void addError(final ErrorSeverity severity, final ErrorType errorType, final ErrorTag tag,
264             final String message, final String applicationTag, final String info, final Throwable cause) {
265         addError(new RpcErrorImpl(severity, errorType, tag != null ? tag : ErrorTag.OPERATION_FAILED, message,
266             applicationTag, info, cause));
267     }
268
269     private void addError(final RpcError error) {
270
271         if (errors == null) {
272             errors = new ImmutableList.Builder<>();
273         }
274
275         errors.add(error);
276     }
277
278     /**
279      * Adds a warning to the result.
280      *
281      * @param errorType the conceptual layer at which the warning occurred.
282      * @param tag a short string that identifies the general type of warning condition. See
283      *        {@link RpcError#getTag} for a list of suggested values.
284      * @param message a string suitable for human display that describes the warning condition.
285      */
286     public @NonNull RpcResultBuilder<T> withWarning(final ErrorType errorType, final ErrorTag tag,
287             final String message) {
288         addError(ErrorSeverity.WARNING, errorType, tag, message, null, null, null);
289         return this;
290     }
291
292     /**
293      * Adds a warning to the result.
294      *
295      * @param errorType the conceptual layer at which the warning occurred.
296      * @param tag a short string that identifies the general type of warning condition. See
297      *        {@link RpcError#getTag} for a list of suggested values.
298      * @param message a string suitable for human display that describes the warning condition.
299      * @param applicationTag a short string that identifies the specific type of warning condition.
300      * @param info a string containing additional information to provide extended
301      *        and/or implementation-specific debugging information.
302      * @param cause the exception that triggered the warning.
303      */
304     public @NonNull RpcResultBuilder<T> withWarning(final ErrorType errorType, final ErrorTag tag, final String message,
305             final String applicationTag, final String info, final Throwable cause) {
306         addError(ErrorSeverity.WARNING, errorType, tag, message, applicationTag, info, cause);
307         return this;
308     }
309
310     /**
311      * Adds an error to the result. The general error tag defaults to "operation-failed".
312      *
313      * @param errorType the conceptual layer at which the error occurred.
314      * @param message a string suitable for human display that describes the error condition.
315      */
316     public @NonNull RpcResultBuilder<T> withError(final ErrorType errorType, final String message) {
317         addError(ErrorSeverity.ERROR, errorType, null, message, null, null, null);
318         return this;
319     }
320
321     /**
322      * Adds an error to the result.
323      *
324      * @param errorType the conceptual layer at which the error occurred.
325      * @param tag a short string that identifies the general type of error condition. See
326      *        {@link RpcError#getTag} for a list of suggested values.
327      * @param message a string suitable for human display that describes the error condition.
328      */
329     public @NonNull RpcResultBuilder<T> withError(final ErrorType errorType, final ErrorTag tag, final String message) {
330         addError(ErrorSeverity.ERROR, errorType, tag, message, null, null, null);
331         return this;
332     }
333
334     /**
335      * Adds an error to the result. The general error tag defaults to "operation-failed".
336      *
337      * @param errorType the conceptual layer at which the error occurred.
338      * @param message a string suitable for human display that describes the error condition.
339      * @param cause the exception that triggered the error.
340      */
341     public @NonNull RpcResultBuilder<T> withError(final ErrorType errorType, final String message,
342                                           final Throwable cause) {
343         addError(ErrorSeverity.ERROR, errorType, null, message, null, null, cause);
344         return this;
345     }
346
347     /**
348      * Adds an error to the result.
349      *
350      * @param errorType the conceptual layer at which the error occurred.
351      * @param tag a short string that identifies the general type of error condition. See
352      *        {@link RpcError#getTag} for a list of suggested values.
353      * @param message a string suitable for human display that describes the error condition.
354      * @param applicationTag a short string that identifies the specific type of error condition.
355      * @param info a string containing additional information to provide extended
356      *        and/or implementation-specific debugging information.
357      * @param cause the exception that triggered the error.
358      */
359     public @NonNull RpcResultBuilder<T> withError(final ErrorType errorType, final ErrorTag tag, final String message,
360             final String applicationTag, final String info, final Throwable cause) {
361         addError(ErrorSeverity.ERROR, errorType, tag, message, applicationTag, info, cause);
362         return this;
363     }
364
365     /**
366      * Adds an RpcError.
367      *
368      * @param error the RpcError
369      */
370     public @NonNull RpcResultBuilder<T> withRpcError(final RpcError error) {
371         addError(error);
372         return this;
373     }
374
375     /**
376      * Adds RpcErrors.
377      *
378      * @param rpcErrors the list of RpcErrors
379      */
380     public RpcResultBuilder<T> withRpcErrors(final Collection<? extends RpcError> rpcErrors) {
381         if (rpcErrors != null) {
382             for (RpcError error : rpcErrors) {
383                 addError(error);
384             }
385         }
386         return this;
387     }
388
389     /**
390      * Build the resulting {@link RpcResult}.
391      *
392      * @return An RpcResult instance
393      */
394     public @NonNull RpcResult<T> build() {
395         return new RpcResultImpl<>(successful, result, errors != null ? errors.build() : ImmutableList.of());
396     }
397
398     /**
399      * Builds RpcResult and wraps it in a Future.
400      *
401      * <p>
402      * This is a convenience method to assist those writing RPCs that produce immediate results. It allows you to
403      * replace {@code FluentFuture.from(Futures.immediateFuture(rpcResult.build()))} with
404      * {@code rpcResult.buildFuture()}
405      *
406      * @return Future for RpcResult built by RpcResultBuilder
407      */
408     public @NonNull FluentFuture<RpcResult<T>> buildFuture() {
409         return FluentFuture.from(Futures.immediateFuture(build()));
410     }
411 }