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