7b5ef531c9033d191146902dd14b8cc1a292d1de
[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     public RpcResultBuilder<T> withResult( final T result ) {
268         this.result = result;
269         return this;
270     }
271
272     /**
273      * Sets the value of the result.
274      *
275      * @param builder builder for the result value
276      */
277     public RpcResultBuilder<T> withResult( final Builder<T> builder ) {
278         return withResult(builder.build());
279     }
280
281     private void addError( final ErrorSeverity severity, final ErrorType errorType,
282             final String tag, final String message, final String applicationTag, final String info,
283             final Throwable cause ) {
284
285         addError( new RpcErrorImpl( severity, errorType,
286                                     tag != null ? tag : "operation-failed", message,
287                                     applicationTag, info, cause ) );
288     }
289
290     private void addError( final RpcError error ) {
291
292         if (errors == null) {
293             errors = new ImmutableList.Builder<>();
294         }
295
296         errors.add( error );
297     }
298
299     /**
300      * Adds a warning to the result.
301      *
302      * @param errorType the conceptual layer at which the warning occurred.
303      * @param tag a short string that identifies the general type of warning condition. See
304      *        {@link RpcError#getTag} for a list of suggested values.
305      * @param message a string suitable for human display that describes the warning condition.
306      */
307     public RpcResultBuilder<T> withWarning( final ErrorType errorType, final String tag, final String message ) {
308         addError( ErrorSeverity.WARNING, errorType, tag, message, null, null, null );
309         return this;
310     }
311
312     /**
313      * Adds a warning to the result.
314      *
315      * @param errorType the conceptual layer at which the warning occurred.
316      * @param tag a short string that identifies the general type of warning condition. See
317      *        {@link RpcError#getTag} for a list of suggested values.
318      * @param message a string suitable for human display that describes the warning condition.
319      * @param applicationTag a short string that identifies the specific type of warning condition.
320      * @param info a string containing additional information to provide extended
321      *        and/or implementation-specific debugging information.
322      * @param cause the exception that triggered the warning.
323      */
324     public RpcResultBuilder<T> withWarning( final ErrorType errorType, final String tag, final String message,
325             final String applicationTag, final String info, final Throwable cause ) {
326         addError( ErrorSeverity.WARNING, errorType, tag, message, applicationTag, info, cause );
327         return this;
328     }
329
330     /**
331      * Adds an error to the result. The general error tag defaults to "operation-failed".
332      *
333      * @param errorType the conceptual layer at which the error occurred.
334      * @param message a string suitable for human display that describes the error condition.
335      */
336     public RpcResultBuilder<T> withError( final ErrorType errorType, final String message ) {
337         addError( ErrorSeverity.ERROR, errorType, null, message, null, null, null );
338         return this;
339     }
340
341     /**
342      * Adds an error to the result.
343      *
344      * @param errorType the conceptual layer at which the error occurred.
345      * @param tag a short string that identifies the general type of error condition. See
346      *        {@link RpcError#getTag} for a list of suggested values.
347      * @param message a string suitable for human display that describes the error condition.
348      */
349     public RpcResultBuilder<T> withError( final ErrorType errorType, final String tag, final String message ) {
350         addError( ErrorSeverity.ERROR, errorType, tag, message, null, null, null );
351         return this;
352     }
353
354     /**
355      * Adds an error to the result. The general error tag defaults to "operation-failed".
356      *
357      * @param errorType the conceptual layer at which the error occurred.
358      * @param message a string suitable for human display that describes the error condition.
359      * @param cause the exception that triggered the error.
360      */
361     public RpcResultBuilder<T> withError( final ErrorType errorType, final String message,
362                                           final Throwable cause ) {
363         addError( ErrorSeverity.ERROR, errorType, null, message, null, null, cause );
364         return this;
365     }
366
367     /**
368      * Adds an error to the result.
369      *
370      * @param errorType the conceptual layer at which the error occurred.
371      * @param tag a short string that identifies the general type of error condition. See
372      *        {@link RpcError#getTag} for a list of suggested values.
373      * @param message a string suitable for human display that describes the error condition.
374      * @param applicationTag a short string that identifies the specific type of error condition.
375      * @param info a string containing additional information to provide extended
376      *        and/or implementation-specific debugging information.
377      * @param cause the exception that triggered the error.
378      */
379     public RpcResultBuilder<T> withError( final ErrorType errorType, final String tag, final String message,
380             final String applicationTag, final String info, final Throwable cause ) {
381         addError( ErrorSeverity.ERROR, errorType, tag, message, applicationTag, info, cause );
382         return this;
383     }
384
385     /**
386      * Adds an RpcError.
387      *
388      * @param error the RpcError
389      */
390     public RpcResultBuilder<T> withRpcError( final RpcError error ) {
391         addError( error );
392         return this;
393     }
394
395     /**
396      * Adds RpcErrors.
397      *
398      * @param errors the list of RpcErrors
399      */
400     public RpcResultBuilder<T> withRpcErrors( final Collection<RpcError> errors ) {
401         if (errors != null) {
402             for (RpcError error : errors) {
403                 addError( error );
404             }
405         }
406         return this;
407     }
408
409     @Override
410     public RpcResult<T> build() {
411
412         return new RpcResultImpl<>(successful, result,
413                 errors != null ? errors.build() : Collections.emptyList());
414     }
415
416     /**
417      * Builds RpcResult and wraps it in a Future
418      *
419      * This is a convenience method to assist those writing rpcs
420      * that produce immediate results.  It allows you to replace
421      *
422      * Futures.immediateFuture(rpcResult.build())
423      *
424      * with
425      *
426      * 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 }