Loosen RpcResultBuilder argument
[yangtools.git] / yang / 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
9 package org.opendaylight.yangtools.yang.common;
10
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.io.Serializable;
15 import java.util.Collection;
16 import java.util.Collections;
17 import org.opendaylight.yangtools.concepts.Builder;
18 import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
19 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
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 Builder<RpcResult<T>> {
29
30     private static class RpcResultImpl<T> implements RpcResult<T>, Serializable {
31         private static final long serialVersionUID = 1L;
32
33         private final Collection<RpcError> errors;
34         private final T result;
35         private final boolean successful;
36
37         RpcResultImpl(final boolean successful, final T result,
38                        final Collection<RpcError> errors) {
39             this.successful = successful;
40             this.result = result;
41             this.errors = errors;
42         }
43
44         @Override
45         public Collection<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         private static final long serialVersionUID = 1L;
68
69         private final String applicationTag;
70         private final String tag;
71         private final String info;
72         private final ErrorSeverity severity;
73         private final String message;
74         private final ErrorType errorType;
75         private final Throwable cause;
76
77         RpcErrorImpl(final ErrorSeverity severity, final ErrorType errorType,
78                 final String tag, final String message, final String applicationTag, final String info,
79                 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 String 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> 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> RpcResultBuilder<T> success(final T result) {
155         return new RpcResultBuilder<>(true, result);
156     }
157
158     /**
159      * Returns a builder for a successful result.
160      *
161      * @param builder builder for the result value
162      */
163     public static <T> RpcResultBuilder<T> success(final Builder<T> builder) {
164         return success(builder.build());
165     }
166
167     /**
168      * Returns a builder for a failed result.
169      */
170     public static <T> RpcResultBuilder<T> failed() {
171         return new RpcResultBuilder<>(false, null);
172     }
173
174     /**
175      * Returns a builder based on the given status.
176      *
177      * @param success true if successful, false otherwise.
178      */
179     public static <T> RpcResultBuilder<T> status(final boolean success) {
180         return new RpcResultBuilder<>(success, null);
181     }
182
183     /**
184      * Returns a builder from another RpcResult.
185      *
186      * @param other the other RpcResult.
187      */
188     public static <T> RpcResultBuilder<T> from(final RpcResult<T> other) {
189         return new RpcResultBuilder<>(other.isSuccessful(), other.getResult())
190                                                       .withRpcErrors(other.getErrors());
191     }
192
193     /**
194      * Creates an RpcError with severity ERROR for reuse.
195      *
196      * @param errorType the conceptual layer at which the error occurred.
197      * @param tag a short string that identifies the general type of error condition. See
198      *        {@link RpcError#getTag} for a list of suggested values.
199      * @param message a string suitable for human display that describes the error condition.
200      *
201      * @return an RpcError
202      */
203     public static RpcError newError(final ErrorType errorType, final String tag, final String message) {
204         return new RpcErrorImpl(ErrorSeverity.ERROR, errorType,
205                 tag != null ? tag : "operation-failed", message, null, null, null);
206     }
207
208     /**
209      * Creates an RpcError with severity ERROR for reuse.
210      *
211      * @param errorType the conceptual layer at which the error occurred.
212      * @param tag a short string that identifies the general type of error condition. See
213      *        {@link RpcError#getTag} for a list of suggested values.
214      * @param message a string suitable for human display that describes the error condition.
215      * @param applicationTag a short string that identifies the specific type of error condition.
216      * @param info a string containing additional information to provide extended
217      *        and/or implementation-specific debugging information.
218      * @param cause the exception that triggered the error.
219      *
220      * @return an RpcError
221      */
222     public static RpcError newError(final ErrorType errorType, final String tag, final String message,
223             final String applicationTag, final String info, final Throwable cause) {
224         return new RpcErrorImpl(ErrorSeverity.ERROR, errorType,
225                 tag != null ? tag : "operation-failed", message, applicationTag, info, cause);
226     }
227
228     /**
229      * Creates an RpcError with severity WARNING for reuse.
230      *
231      * @param errorType the conceptual layer at which the warning occurred.
232      * @param tag a short string that identifies the general type of warning condition. See
233      *        {@link RpcError#getTag} for a list of suggested values.
234      * @param message a string suitable for human display that describes the warning condition.
235      *
236      * @return an RpcError
237      */
238     public static RpcError newWarning(final ErrorType errorType, final String tag, final String message) {
239         return new RpcErrorImpl(ErrorSeverity.WARNING, errorType, tag, message, null, null, null);
240     }
241
242     /**
243      * Creates an RpcError with severity WARNING for reuse.
244      *
245      * @param errorType the conceptual layer at which the warning occurred.
246      * @param tag a short string that identifies the general type of warning condition. See
247      *        {@link RpcError#getTag} for a list of suggested values.
248      * @param message a string suitable for human display that describes the warning condition.
249      * @param applicationTag a short string that identifies the specific type of warning condition.
250      * @param info a string containing additional information to provide extended
251      *        and/or implementation-specific debugging information.
252      * @param cause the exception that triggered the warning.
253      *
254      * @return an RpcError
255      */
256     public static RpcError newWarning(final ErrorType errorType, final String tag, final String message,
257             final String applicationTag, final String info, final Throwable cause) {
258         return new RpcErrorImpl(ErrorSeverity.WARNING, errorType, tag, message,
259                                  applicationTag, info, cause);
260     }
261
262     /**
263      * Sets the value of the result.
264      *
265      * @param result the result value
266      */
267     @SuppressWarnings("checkstyle:hiddenField")
268     public RpcResultBuilder<T> withResult(final T result) {
269         this.result = result;
270         return this;
271     }
272
273     /**
274      * Sets the value of the result.
275      *
276      * @param builder builder for the result value
277      */
278     public RpcResultBuilder<T> withResult(final Builder<T> builder) {
279         return withResult(builder.build());
280     }
281
282     private void addError(final ErrorSeverity severity, final ErrorType errorType,
283             final String tag, final String message, final String applicationTag, final String info,
284             final Throwable cause) {
285
286         addError(new RpcErrorImpl(severity, errorType,
287                                     tag != null ? tag : "operation-failed", message,
288                                     applicationTag, info, cause));
289     }
290
291     private void addError(final RpcError error) {
292
293         if (errors == null) {
294             errors = new ImmutableList.Builder<>();
295         }
296
297         errors.add(error);
298     }
299
300     /**
301      * Adds a warning to the result.
302      *
303      * @param errorType the conceptual layer at which the warning occurred.
304      * @param tag a short string that identifies the general type of warning condition. See
305      *        {@link RpcError#getTag} for a list of suggested values.
306      * @param message a string suitable for human display that describes the warning condition.
307      */
308     public RpcResultBuilder<T> withWarning(final ErrorType errorType, final String tag, final String message) {
309         addError(ErrorSeverity.WARNING, errorType, tag, message, null, null, null);
310         return this;
311     }
312
313     /**
314      * Adds a warning to the result.
315      *
316      * @param errorType the conceptual layer at which the warning occurred.
317      * @param tag a short string that identifies the general type of warning condition. See
318      *        {@link RpcError#getTag} for a list of suggested values.
319      * @param message a string suitable for human display that describes the warning condition.
320      * @param applicationTag a short string that identifies the specific type of warning condition.
321      * @param info a string containing additional information to provide extended
322      *        and/or implementation-specific debugging information.
323      * @param cause the exception that triggered the warning.
324      */
325     public RpcResultBuilder<T> withWarning(final ErrorType errorType, final String tag, final String message,
326             final String applicationTag, final String info, final Throwable cause) {
327         addError(ErrorSeverity.WARNING, errorType, tag, message, applicationTag, info, cause);
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      */
337     public RpcResultBuilder<T> withError(final ErrorType errorType, final String message) {
338         addError(ErrorSeverity.ERROR, errorType, null, message, null, null, null);
339         return this;
340     }
341
342     /**
343      * Adds an error to the result.
344      *
345      * @param errorType the conceptual layer at which the error occurred.
346      * @param tag a short string that identifies the general type of error condition. See
347      *        {@link RpcError#getTag} for a list of suggested values.
348      * @param message a string suitable for human display that describes the error condition.
349      */
350     public RpcResultBuilder<T> withError(final ErrorType errorType, final String tag, final String message) {
351         addError(ErrorSeverity.ERROR, errorType, tag, message, null, null, null);
352         return this;
353     }
354
355     /**
356      * Adds an error to the result. The general error tag defaults to "operation-failed".
357      *
358      * @param errorType the conceptual layer at which the error occurred.
359      * @param message a string suitable for human display that describes the error condition.
360      * @param cause the exception that triggered the error.
361      */
362     public RpcResultBuilder<T> withError(final ErrorType errorType, final String message,
363                                           final Throwable cause) {
364         addError(ErrorSeverity.ERROR, errorType, null, message, null, null, cause);
365         return this;
366     }
367
368     /**
369      * Adds an error to the result.
370      *
371      * @param errorType the conceptual layer at which the error occurred.
372      * @param tag a short string that identifies the general type of error condition. See
373      *        {@link RpcError#getTag} for a list of suggested values.
374      * @param message a string suitable for human display that describes the error condition.
375      * @param applicationTag a short string that identifies the specific type of error condition.
376      * @param info a string containing additional information to provide extended
377      *        and/or implementation-specific debugging information.
378      * @param cause the exception that triggered the error.
379      */
380     public RpcResultBuilder<T> withError(final ErrorType errorType, final String tag, final String message,
381             final String applicationTag, final String info, final Throwable cause) {
382         addError(ErrorSeverity.ERROR, errorType, tag, message, applicationTag, info, cause);
383         return this;
384     }
385
386     /**
387      * Adds an RpcError.
388      *
389      * @param error the RpcError
390      */
391     public RpcResultBuilder<T> withRpcError(final RpcError error) {
392         addError(error);
393         return this;
394     }
395
396     /**
397      * Adds RpcErrors.
398      *
399      * @param rpcErrors the list of RpcErrors
400      */
401     public RpcResultBuilder<T> withRpcErrors(final Collection<? extends RpcError> rpcErrors) {
402         if (rpcErrors != null) {
403             for (RpcError error : rpcErrors) {
404                 addError(error);
405             }
406         }
407         return this;
408     }
409
410     @Override
411     public RpcResult<T> build() {
412
413         return new RpcResultImpl<>(successful, result,
414                 errors != null ? errors.build() : Collections.emptyList());
415     }
416
417     /**
418      * Builds RpcResult and wraps it in a Future
419      *
420      * <p>
421      * This is a convenience method to assist those writing rpcs
422      * that produce immediate results.  It allows you to replace
423      *
424      * {@code Futures.immediateFuture(rpcResult.build())}
425      * with
426      * {@code rpcResult.buildFuture();}
427      *
428      * @return Future for RpcResult built by RpcResultBuilder
429      *
430      */
431     public ListenableFuture<RpcResult<T>> buildFuture() {
432         return Futures.immediateFuture(build());
433     }
434 }