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