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