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