NETCONF-553 : Stack traces need to suppressed and error messages should
[netconf.git] / restconf / restconf-common / src / main / java / org / opendaylight / restconf / common / errors / RestconfError.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.restconf.common.errors;
10
11 import com.google.common.base.Preconditions;
12 import java.io.Serializable;
13 import java.util.Locale;
14 import org.opendaylight.yangtools.yang.common.RpcError;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
16
17 /**
18  * Encapsulates a restconf error as defined in the ietf restconf draft.
19  *
20  * <br>
21  * <br>
22  * <b>Note:</b> Enumerations defined within are provided by the ietf restconf draft.
23  *
24  * @author Devin Avery
25  *     See also <a href="https://tools.ietf.org/html/draft-bierman-netconf-restconf-02">RESTCONF</a>.
26  */
27 public class RestconfError implements Serializable {
28     private static final long serialVersionUID = 1L;
29
30     public enum ErrorType {
31         /**
32          * Errors relating to the transport layer.
33          */
34         TRANSPORT,
35         /**
36          * Errors relating to the RPC or notification layer.
37          */
38         RPC,
39         /**
40          * Errors relating to the protocol operation layer.
41          */
42         PROTOCOL,
43         /**
44          * Errors relating to the server application layer.
45          */
46         APPLICATION;
47
48         public String getErrorTypeTag() {
49             return name().toLowerCase(Locale.ROOT);
50         }
51
52         public static ErrorType valueOfCaseInsensitive(final String value) {
53             try {
54                 return ErrorType.valueOf(ErrorType.class, value.toUpperCase(Locale.ROOT));
55             } catch (IllegalArgumentException e) {
56                 return APPLICATION;
57             }
58         }
59     }
60
61     public enum ErrorTag {
62         IN_USE("in-use", 409 /* Conflict */),
63         INVALID_VALUE("invalid-value", 400 /* Bad Request */),
64         TOO_BIG("too-big", 413 /* Request Entity Too Large */),
65         MISSING_ATTRIBUTE("missing-attribute", 400 /* Bad Request */),
66         BAD_ATTRIBUTE("bad-attribute", 400 /* Bad Request */),
67         UNKNOWN_ATTRIBUTE("unknown-attribute", 400 /* Bad Request */),
68         MISSING_ELEMENT("missing-element", 400 /* Bad Request */),
69         BAD_ELEMENT("bad-element", 400 /* Bad Request */),
70         UNKNOWN_ELEMENT("unknown-element", 400 /* Bad Request */),
71         UNKNOWN_NAMESPACE("unknown-namespace", 400 /* Bad Request */),
72         ACCESS_DENIED("access-denied", 403 /* Forbidden */),
73         LOCK_DENIED("lock-denied", 409 /* Conflict */),
74         RESOURCE_DENIED("resource-denied", 409 /* Conflict */),
75         ROLLBACK_FAILED("rollback-failed", 500 /* INTERNAL_SERVER_ERROR */),
76         DATA_EXISTS("data-exists", 409 /* Conflict */),
77         DATA_MISSING("data-missing", 404 /* Resource Not Found */),
78         OPERATION_NOT_SUPPORTED("operation-not-supported", 501 /* Not Implemented */),
79         OPERATION_FAILED("operation-failed", 500 /* INTERNAL_SERVER_ERROR */),
80         PARTIAL_OPERATION("partial-operation", 500 /* INTERNAL_SERVER_ERROR */),
81         MALFORMED_MESSAGE("malformed-message", 400 /* Bad Request */),
82         RESOURCE_DENIED_TRANSPORT("resource-denied-transport", 503 /* Service Unavailable */);
83
84         private final String tagValue;
85         private final int statusCode;
86
87         ErrorTag(final String tagValue, final int statusCode) {
88             this.tagValue = tagValue;
89             this.statusCode = statusCode;
90         }
91
92         public String getTagValue() {
93             return this.tagValue.toLowerCase(Locale.ROOT);
94         }
95
96         public static ErrorTag valueOfCaseInsensitive(final String value) {
97             try {
98                 return ErrorTag.valueOf(ErrorTag.class, value.toUpperCase(Locale.ROOT).replaceAll("-", "_"));
99             } catch (IllegalArgumentException e) {
100                 return OPERATION_FAILED;
101             }
102         }
103
104         public int getStatusCode() {
105             return statusCode;
106         }
107     }
108
109     private final ErrorType errorType;
110     private final ErrorTag errorTag;
111     private final String errorInfo;
112     private final String errorAppTag;
113     private final String errorMessage;
114     private final YangInstanceIdentifier errorPath;
115
116     /**
117      * Constructs a RestConfError.
118      *
119      * @param errorType
120      *            The enumerated type indicating the layer where the error occurred.
121      * @param errorTag
122      *            The enumerated tag representing a more specific error cause.
123      * @param errorMessage
124      *            A string which provides a plain text string describing the error.
125      */
126     public RestconfError(final ErrorType errorType, final ErrorTag errorTag, final String errorMessage) {
127         this(errorType, errorTag, errorMessage, null, null, null);
128     }
129
130     /**
131      * Constructs a RestConfError object.
132      *
133      * @param errorType
134      *            The enumerated type indicating the layer where the error occurred.
135      * @param errorTag
136      *            The enumerated tag representing a more specific error cause.
137      * @param errorMessage
138      *            A string which provides a plain text string describing the error.
139      * @param errorAppTag
140      *            A string which represents an application-specific error tag that further specifies the error cause.
141      */
142     public RestconfError(final ErrorType errorType, final ErrorTag errorTag, final String errorMessage,
143                          final String errorAppTag) {
144         this(errorType, errorTag, errorMessage, errorAppTag, null, null);
145     }
146
147     /**
148      * Constructs a RestConfError object.
149      *
150      * @param errorType
151      *            The enumerated type indicating the layer where the error occurred.
152      * @param errorTag
153      *            The enumerated tag representing a more specific error cause.
154      * @param errorMessage
155      *            A string which provides a plain text string describing the error.
156      * @param errorPath
157      *            An instance identifier which contains error path
158      */
159     public RestconfError(final ErrorType errorType, final ErrorTag errorTag, final String errorMessage,
160                          final YangInstanceIdentifier errorPath) {
161         this(errorType, errorTag, errorMessage, null, null, errorPath);
162     }
163
164     /**
165      * Constructs a RestConfError object.
166      *
167      * @param errorType
168      *            The enumerated type indicating the layer where the error occurred.
169      * @param errorTag
170      *            The enumerated tag representing a more specific error cause.
171      * @param errorMessage
172      *            A string which provides a plain text string describing the error.
173      * @param errorAppTag
174      *            A string which represents an application-specific error tag that further specifies the error cause.
175      * @param errorInfo
176      *            A string, <b>formatted as XML</b>, which contains additional error information.
177      */
178     public RestconfError(final ErrorType errorType, final ErrorTag errorTag, final String errorMessage,
179                          final String errorAppTag, final String errorInfo) {
180         this(errorType, errorTag, errorMessage, errorAppTag, errorInfo, null);
181     }
182
183     /**
184      * Constructs a RestConfError object.
185      *
186      * @param errorType
187      *            The enumerated type indicating the layer where the error occurred.
188      * @param errorTag
189      *            The enumerated tag representing a more specific error cause.
190      * @param errorMessage
191      *            A string which provides a plain text string describing the error.
192      * @param errorAppTag
193      *            A string which represents an application-specific error tag that further specifies the error cause.
194      * @param errorInfo
195      *            A string, <b>formatted as XML</b>, which contains additional error information.
196      * @param errorPath
197      *            An instance identifier which contains error path
198      */
199     public RestconfError(final ErrorType errorType, final ErrorTag errorTag, final String errorMessage,
200                          final String errorAppTag, final String errorInfo, final YangInstanceIdentifier errorPath) {
201         Preconditions.checkNotNull(errorType, "Error type is required for RestConfError");
202         Preconditions.checkNotNull(errorTag, "Error tag is required for RestConfError");
203         this.errorType = errorType;
204         this.errorTag = errorTag;
205         this.errorMessage = errorMessage;
206         this.errorAppTag = errorAppTag;
207         this.errorInfo = errorInfo;
208         this.errorPath = errorPath;
209     }
210
211     /**
212      * Constructs a RestConfError object from an RpcError.
213      */
214     public RestconfError(final RpcError rpcError) {
215
216         this.errorType = rpcError.getErrorType() == null ? ErrorType.APPLICATION : ErrorType
217                 .valueOfCaseInsensitive(rpcError.getErrorType().name());
218
219         this.errorTag = rpcError.getTag() == null ? ErrorTag.OPERATION_FAILED : ErrorTag
220                 .valueOfCaseInsensitive(rpcError.getTag());
221
222         this.errorMessage = rpcError.getMessage();
223         this.errorAppTag = rpcError.getApplicationTag();
224
225         String localErrorInfo = null;
226         if (rpcError.getInfo() == null) {
227             if (rpcError.getCause() != null) {
228                 localErrorInfo = rpcError.getCause().getMessage();
229             } else if (rpcError.getSeverity() != null) {
230                 localErrorInfo = "<severity>" + rpcError.getSeverity().toString().toLowerCase(Locale.ROOT)
231                         + "</severity>";
232             }
233         } else {
234             localErrorInfo = rpcError.getInfo();
235         }
236
237         this.errorInfo = localErrorInfo;
238         this.errorPath = null;
239     }
240
241     public ErrorType getErrorType() {
242         return errorType;
243     }
244
245     public ErrorTag getErrorTag() {
246         return errorTag;
247     }
248
249     public String getErrorInfo() {
250         return errorInfo;
251     }
252
253     public String getErrorAppTag() {
254         return errorAppTag;
255     }
256
257     public String getErrorMessage() {
258         return errorMessage;
259     }
260
261     public YangInstanceIdentifier getErrorPath() {
262         return errorPath;
263     }
264
265     @Override
266     public String toString() {
267         return "RestconfError ["
268                 + "error-type: " + errorType.getErrorTypeTag() + ", error-tag: " + errorTag.getTagValue()
269                 + (errorAppTag != null ? ", error-app-tag: " + errorAppTag : "")
270                 + (errorMessage != null ? ", error-message: " + errorMessage : "")
271                 + (errorInfo != null ? ", error-info: " + errorInfo : "")
272                 + (errorPath != null ? ", error-path: " + errorPath.toString() : "")
273                 + "]";
274     }
275 }