2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.config.util.xml;
11 import static org.opendaylight.controller.config.util.xml.XmlMappingConstants.RPC_REPLY_KEY;
12 import static org.opendaylight.controller.config.util.xml.XmlMappingConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
14 import java.util.Collections;
15 import java.util.HashMap;
17 import java.util.Map.Entry;
18 import javax.xml.parsers.DocumentBuilderFactory;
19 import javax.xml.parsers.ParserConfigurationException;
20 import org.opendaylight.controller.config.api.ConflictingVersionException;
21 import org.opendaylight.controller.config.api.ValidationException;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Node;
26 import org.w3c.dom.NodeList;
29 * Checked exception to communicate an error that needs to be sent to the
32 public class DocumentedException extends Exception {
34 public static final String RPC_ERROR = "rpc-error";
35 public static final String ERROR_TYPE = "error-type";
36 public static final String ERROR_TAG = "error-tag";
37 public static final String ERROR_SEVERITY = "error-severity";
38 public static final String ERROR_APP_TAG = "error-app-tag";
39 public static final String ERROR_PATH = "error-path";
40 public static final String ERROR_MESSAGE = "error-message";
41 public static final String ERROR_INFO = "error-info";
43 private static final long serialVersionUID = 1L;
45 private final static Logger LOG = LoggerFactory.getLogger( DocumentedException.class );
47 private static final DocumentBuilderFactory BUILDER_FACTORY;
50 BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
52 BUILDER_FACTORY.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
53 BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-general-entities", false);
54 BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
55 BUILDER_FACTORY.setXIncludeAware(false);
56 BUILDER_FACTORY.setExpandEntityReferences(false);
57 } catch (ParserConfigurationException e) {
58 throw new ExceptionInInitializerError(e);
60 BUILDER_FACTORY.setNamespaceAware(true);
61 BUILDER_FACTORY.setCoalescing(true);
62 BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
63 BUILDER_FACTORY.setIgnoringComments(true);
66 public enum ErrorType {
67 transport, rpc, protocol, application;
69 public String getTagValue() {
73 public static ErrorType from( String text ) {
75 return valueOf( text );
77 catch( Exception e ) {
83 public enum ErrorTag {
84 access_denied("access-denied"),
85 bad_attribute("bad-attribute"),
86 bad_element("bad-element"),
87 data_exists("data-exists"),
88 data_missing("data-missing"),
90 invalid_value("invalid-value"),
91 lock_denied("lock-denied"),
92 malformed_message("malformed-message"),
93 missing_attribute("missing-attribute"),
94 missing_element("missing-element"),
95 operation_failed("operation-failed"),
96 operation_not_supported("operation-not-supported"),
97 resource_denied("resource-denied"),
98 rollback_failed("rollback-failed"),
100 unknown_attribute("unknown-attribute"),
101 unknown_element("unknown-element"),
102 unknown_namespace("unknown-namespace");
104 private final String tagValue;
106 ErrorTag(final String tagValue) {
107 this.tagValue = tagValue;
110 public String getTagValue() {
111 return this.tagValue;
114 public static ErrorTag from( String text ) {
115 for( ErrorTag e: values() )
117 if( e.getTagValue().equals( text ) ) {
122 return operation_failed;
126 public enum ErrorSeverity {
129 public String getTagValue() {
133 public static ErrorSeverity from( String text ) {
135 return valueOf( text );
137 catch( Exception e ) {
143 private final ErrorType errorType;
144 private final ErrorTag errorTag;
145 private final ErrorSeverity errorSeverity;
146 private final Map<String, String> errorInfo;
148 public DocumentedException(String message) {
150 DocumentedException.ErrorType.application,
151 DocumentedException.ErrorTag.invalid_value,
152 DocumentedException.ErrorSeverity.error
156 public DocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
157 final ErrorSeverity errorSeverity) {
158 this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
161 public DocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
162 final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
164 this.errorType = errorType;
165 this.errorTag = errorTag;
166 this.errorSeverity = errorSeverity;
167 this.errorInfo = errorInfo;
170 public DocumentedException(final String message, final Exception cause, final ErrorType errorType,
171 final ErrorTag errorTag, final ErrorSeverity errorSeverity) {
172 this(message, cause, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
175 public DocumentedException(final String message, final Exception cause, final ErrorType errorType,
176 final ErrorTag errorTag, final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
177 super(message, cause);
178 this.errorType = errorType;
179 this.errorTag = errorTag;
180 this.errorSeverity = errorSeverity;
181 this.errorInfo = errorInfo;
184 public static <E extends Exception> DocumentedException wrap(E exception) throws DocumentedException {
185 final Map<String, String> errorInfo = new HashMap<>();
186 errorInfo.put(ErrorTag.operation_failed.name(), "Exception thrown");
187 throw new DocumentedException(exception.getMessage(), exception, ErrorType.application, ErrorTag.operation_failed,
188 ErrorSeverity.error, errorInfo);
190 public static DocumentedException wrap(ValidationException e) throws DocumentedException {
191 final Map<String, String> errorInfo = new HashMap<>();
192 errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
193 throw new DocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
194 ErrorSeverity.error, errorInfo);
197 public static DocumentedException wrap(ConflictingVersionException e) throws DocumentedException {
198 final Map<String, String> errorInfo = new HashMap<>();
199 errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed");
200 throw new DocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
201 ErrorSeverity.error, errorInfo);
204 public static DocumentedException fromXMLDocument( Document fromDoc ) {
206 ErrorType errorType = ErrorType.application;
207 ErrorTag errorTag = ErrorTag.operation_failed;
208 ErrorSeverity errorSeverity = ErrorSeverity.error;
209 Map<String, String> errorInfo = null;
210 String errorMessage = "";
212 Node rpcReply = fromDoc.getDocumentElement();
214 // FIXME: BUG? - we only handle one rpc-error.
216 NodeList replyChildren = rpcReply.getChildNodes();
217 for( int i = 0; i < replyChildren.getLength(); i++ ) {
218 Node replyChild = replyChildren.item( i );
219 if( RPC_ERROR.equals( replyChild.getNodeName() ) )
221 NodeList rpcErrorChildren = replyChild.getChildNodes();
222 for( int j = 0; j < rpcErrorChildren.getLength(); j++ )
224 Node rpcErrorChild = rpcErrorChildren.item( j );
225 if( ERROR_TYPE.equals( rpcErrorChild.getNodeName() ) ) {
226 errorType = ErrorType.from(rpcErrorChild.getTextContent());
228 else if( ERROR_TAG.equals( rpcErrorChild.getNodeName() ) ) {
229 errorTag = ErrorTag.from(rpcErrorChild.getTextContent());
231 else if( ERROR_SEVERITY.equals( rpcErrorChild.getNodeName() ) ) {
232 errorSeverity = ErrorSeverity.from(rpcErrorChild.getTextContent());
234 else if( ERROR_MESSAGE.equals( rpcErrorChild.getNodeName() ) ) {
235 errorMessage = rpcErrorChild.getTextContent();
237 else if( ERROR_INFO.equals( rpcErrorChild.getNodeName() ) ) {
238 errorInfo = parseErrorInfo( rpcErrorChild );
246 return new DocumentedException( errorMessage, errorType, errorTag, errorSeverity, errorInfo );
249 private static Map<String, String> parseErrorInfo( Node node ) {
250 Map<String, String> infoMap = new HashMap<>();
251 NodeList children = node.getChildNodes();
252 for( int i = 0; i < children.getLength(); i++ ) {
253 Node child = children.item( i );
254 if( child.getNodeType() == Node.ELEMENT_NODE ) {
255 infoMap.put( child.getNodeName(), child.getTextContent() );
262 public ErrorType getErrorType() {
263 return this.errorType;
266 public ErrorTag getErrorTag() {
267 return this.errorTag;
270 public ErrorSeverity getErrorSeverity() {
271 return this.errorSeverity;
274 public Map<String, String> getErrorInfo() {
275 return this.errorInfo;
278 public Document toXMLDocument() {
281 doc = BUILDER_FACTORY.newDocumentBuilder().newDocument();
283 Node rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY);
284 doc.appendChild( rpcReply );
286 Node rpcError = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_ERROR );
287 rpcReply.appendChild( rpcError );
289 rpcError.appendChild( createTextNode( doc, ERROR_TYPE, getErrorType().getTagValue() ) );
290 rpcError.appendChild( createTextNode( doc, ERROR_TAG, getErrorTag().getTagValue() ) );
291 rpcError.appendChild( createTextNode( doc, ERROR_SEVERITY, getErrorSeverity().getTagValue() ) );
292 rpcError.appendChild( createTextNode( doc, ERROR_MESSAGE, getLocalizedMessage() ) );
294 Map<String, String> errorInfoMap = getErrorInfo();
295 if( errorInfoMap != null && !errorInfoMap.isEmpty() ) {
298 * <bad-attribute>message-id</bad-attribute>
299 * <bad-element>rpc</bad-element>
303 Node errorInfoNode = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, ERROR_INFO );
304 errorInfoNode.setPrefix( rpcReply.getPrefix() );
305 rpcError.appendChild( errorInfoNode );
307 for ( Entry<String, String> entry : errorInfoMap.entrySet() ) {
308 errorInfoNode.appendChild( createTextNode( doc, entry.getKey(), entry.getValue() ) );
312 catch( ParserConfigurationException e ) {
313 LOG.error( "Error outputting to XML document", e ); // this shouldn't happen
319 private Node createTextNode( Document doc, String tag, String textContent ) {
320 Node node = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, tag );
321 node.setTextContent( textContent );
326 public String toString() {
327 return "NetconfDocumentedException{" + "message=" + getMessage() + ", errorType=" + this.errorType
328 + ", errorTag=" + this.errorTag + ", errorSeverity=" + this.errorSeverity + ", errorInfo="
329 + this.errorInfo + '}';