ecd894b7ff913816f2152d117d027e65801e6979
[netconf.git] / restconf / restconf-common / src / main / java / org / opendaylight / restconf / common / errors / RestconfDocumentedException.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.restconf.common.errors;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableList;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.List;
15 import javax.ws.rs.WebApplicationException;
16 import javax.ws.rs.core.Response.Status;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
20 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
21 import org.opendaylight.yangtools.yang.common.OperationFailedException;
22 import org.opendaylight.yangtools.yang.common.RpcError;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24
25 /**
26  * Unchecked exception to communicate error information, as defined in the ietf restcong draft, to be sent to the
27  * client.
28  *
29  * <p>
30  * See also <a href="https://tools.ietf.org/html/draft-bierman-netconf-restconf-02">RESTCONF</a>
31  *
32  * @author Devin Avery
33  * @author Thomas Pantelis
34  */
35 public class RestconfDocumentedException extends WebApplicationException {
36
37     private static final long serialVersionUID = 1L;
38
39     private final ImmutableList<RestconfError> errors;
40     private final Status status;
41
42     /**
43      * Constructs an instance with an error message. The error type defaults to APPLICATION and the error tag defaults
44      * to OPERATION_FAILED.
45      *
46      * @param message
47      *            A string which provides a plain text string describing the error.
48      */
49     public RestconfDocumentedException(final String message) {
50         this(message, RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED);
51     }
52
53     /**
54      * Constructs an instance with an error message, error type, error tag and exception cause.
55      *
56      * @param message
57      *            A string which provides a plain text string describing the error.
58      * @param errorType
59      *            The enumerated type indicating the layer where the error occurred.
60      * @param errorTag
61      *            The enumerated tag representing a more specific error cause.
62      * @param cause
63      *            The underlying exception cause.
64      */
65     public RestconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
66                                        final Throwable cause) {
67         this(cause, new RestconfError(errorType, errorTag, message, null,
68                 cause.getMessage(), null));
69     }
70
71     /**
72      * Constructs an instance with an error message, error type, and error tag.
73      *
74      * @param message
75      *            A string which provides a plain text string describing the error.
76      * @param errorType
77      *            The enumerated type indicating the layer where the error occurred.
78      * @param errorTag
79      *            The enumerated tag representing a more specific error cause.
80      */
81     public RestconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag) {
82         this(null, new RestconfError(errorType, errorTag, message));
83     }
84
85     /**
86      * Constructs an instance with an error message, error type, error tag and error path.
87      *
88      * @param message
89      *            A string which provides a plain text string describing the error.
90      * @param errorType
91      *            The enumerated type indicating the layer where the error occurred.
92      * @param errorTag
93      *            The enumerated tag representing a more specific error cause.
94      * @param errorPath
95      *            The instance identifier representing error path
96      */
97     public RestconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
98                                        final YangInstanceIdentifier errorPath) {
99         this(null, new RestconfError(errorType, errorTag, message, errorPath));
100     }
101
102     /**
103      * Constructs an instance with an error message and exception cause.
104      * The underlying exception is included in the error-info.
105      *
106      * @param message
107      *            A string which provides a plain text string describing the error.
108      * @param cause
109      *            The underlying exception cause.
110      */
111     public RestconfDocumentedException(final String message, final Throwable cause) {
112         this(cause, new RestconfError(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED,
113                 message, null, cause.getMessage(), null));
114     }
115
116     /**
117      * Constructs an instance with the given error.
118      */
119     public RestconfDocumentedException(final RestconfError error) {
120         this(null, error);
121     }
122
123     /**
124      * Constructs an instance with the given errors.
125      */
126     public RestconfDocumentedException(final String message, final Throwable cause, final List<RestconfError> errors) {
127         // FIXME: We override getMessage so supplied message is lost for any public access
128         // this was lost also in original code.
129         super(cause);
130         if (!errors.isEmpty()) {
131             this.errors = ImmutableList.copyOf(errors);
132         } else {
133             this.errors = ImmutableList.of(new RestconfError(RestconfError.ErrorType.APPLICATION,
134                     RestconfError.ErrorTag.OPERATION_FAILED, message));
135         }
136
137         status = null;
138     }
139
140     /**
141      * Constructs an instance with the given RpcErrors.
142      */
143     public RestconfDocumentedException(final String message, final Throwable cause,
144                                        final Collection<? extends RpcError> rpcErrors) {
145         this(message, cause, convertToRestconfErrors(rpcErrors));
146     }
147
148     /**
149      * Constructs an instance with an HTTP status and no error information.
150      *
151      * @param status
152      *            the HTTP status.
153      */
154     public RestconfDocumentedException(final Status status) {
155         Preconditions.checkNotNull(status, "Status can't be null");
156         errors = ImmutableList.of();
157         this.status = status;
158     }
159
160     public RestconfDocumentedException(final Throwable cause, final RestconfError error) {
161         super(cause, error.getErrorTag().getStatusCode());
162         Preconditions.checkNotNull(error, "RestconfError can't be null");
163         errors = ImmutableList.of(error);
164         status = null;
165     }
166
167     public static RestconfDocumentedException decodeAndThrow(final String message,
168             final OperationFailedException cause) {
169         for (final RpcError error : cause.getErrorList()) {
170             if (error.getErrorType() == RpcError.ErrorType.TRANSPORT
171                     && error.getTag().equals(ErrorTag.RESOURCE_DENIED.getTagValue())) {
172                 throw new RestconfDocumentedException(error.getMessage(), ErrorType.TRANSPORT,
173                     ErrorTag.RESOURCE_DENIED_TRANSPORT, cause);
174             }
175         }
176         throw new RestconfDocumentedException(message, cause, cause.getErrorList());
177     }
178
179     /**
180      * Throw an instance of this exception if an expression evaluates to true. If the expression evaluates to false,
181      * this method does nothing.
182      *
183      * @param expression Expression to be evaluated
184      * @param errorType The enumerated type indicating the layer where the error occurred.
185      * @param errorTag The enumerated tag representing a more specific error cause.
186      * @param format Format string, according to {@link String#format(String, Object...)}.
187      * @param args Format string arguments, according to {@link String#format(String, Object...)}
188      * @throws RestconfDocumentedException if the expression evaluates to true.
189      */
190     public static void throwIf(final boolean expression, final ErrorType errorType, final ErrorTag errorTag,
191             final @NonNull String format, final Object... args) {
192         if (expression) {
193             throw new RestconfDocumentedException(String.format(format, args), errorType, errorTag);
194         }
195     }
196
197     /**
198      * Throw an instance of this exception if an expression evaluates to true. If the expression evaluates to false,
199      * this method does nothing.
200      *
201      * @param expression Expression to be evaluated
202      * @param message error message
203      * @param errorType The enumerated type indicating the layer where the error occurred.
204      * @param errorTag The enumerated tag representing a more specific error cause.
205      * @throws RestconfDocumentedException if the expression evaluates to true.
206      */
207     public static void throwIf(final boolean expression, final @NonNull String message,
208             final ErrorType errorType, final ErrorTag errorTag) {
209         if (expression) {
210             throw new RestconfDocumentedException(message, errorType, errorTag);
211         }
212     }
213
214     /**
215      * Throw an instance of this exception if an object is null. If the object is non-null, it will
216      * be returned as the result of this method.
217      *
218      * @param obj Object reference to be checked
219      * @param errorType The enumerated type indicating the layer where the error occurred.
220      * @param errorTag The enumerated tag representing a more specific error cause.
221      * @param format Format string, according to {@link String#format(String, Object...)}.
222      * @param args Format string arguments, according to {@link String#format(String, Object...)}
223      * @throws RestconfDocumentedException if the expression evaluates to true.
224      */
225     public static <T> @NonNull T throwIfNull(final @Nullable T obj, final ErrorType errorType, final ErrorTag errorTag,
226             final @NonNull String format, final Object... args) {
227         if (obj == null) {
228             throw new RestconfDocumentedException(String.format(format, args), errorType, errorTag);
229         }
230         return obj;
231     }
232
233     private static List<RestconfError> convertToRestconfErrors(final Collection<? extends RpcError> rpcErrors) {
234         final List<RestconfError> errorList = new ArrayList<>();
235         if (rpcErrors != null) {
236             for (RpcError rpcError : rpcErrors) {
237                 errorList.add(new RestconfError(rpcError));
238             }
239         }
240
241         return errorList;
242     }
243
244     public List<RestconfError> getErrors() {
245         return errors;
246     }
247
248     public Status getStatus() {
249         return status;
250     }
251
252     @Override
253     public String getMessage() {
254         return "errors: " + errors + (status != null ? ", status: " + status : "");
255     }
256 }