2 * Copyright (c) 2013 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.netconf.api;
11 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_INFO;
12 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_MESSAGE;
13 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_SEVERITY;
14 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TAG;
15 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TYPE;
16 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_ERROR;
17 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
18 import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
20 import java.util.Collections;
21 import java.util.HashMap;
23 import java.util.Map.Entry;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
26 import org.opendaylight.controller.config.api.ConflictingVersionException;
27 import org.opendaylight.controller.config.api.ValidationException;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Node;
32 import org.w3c.dom.NodeList;
35 * Checked exception to communicate an error that needs to be sent to the
38 public class NetconfDocumentedException extends Exception {
40 private static final long serialVersionUID = 1L;
42 private final static Logger LOG = LoggerFactory.getLogger( NetconfDocumentedException.class );
44 private static final DocumentBuilderFactory BUILDER_FACTORY;
47 BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
49 BUILDER_FACTORY.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
50 BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-general-entities", false);
51 BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
52 BUILDER_FACTORY.setXIncludeAware(false);
53 BUILDER_FACTORY.setExpandEntityReferences(false);
54 } catch (ParserConfigurationException e) {
55 throw new ExceptionInInitializerError(e);
57 BUILDER_FACTORY.setNamespaceAware(true);
58 BUILDER_FACTORY.setCoalescing(true);
59 BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
60 BUILDER_FACTORY.setIgnoringComments(true);
63 public enum ErrorType {
64 transport, rpc, protocol, application;
66 public String getTagValue() {
70 public static ErrorType from( String text ) {
72 return valueOf( text );
74 catch( Exception e ) {
80 public enum ErrorTag {
81 access_denied("access-denied"),
82 bad_attribute("bad-attribute"),
83 bad_element("bad-element"),
84 data_exists("data-exists"),
85 data_missing("data-missing"),
87 invalid_value("invalid-value"),
88 lock_denied("lock-denied"),
89 malformed_message("malformed-message"),
90 missing_attribute("missing-attribute"),
91 missing_element("missing-element"),
92 operation_failed("operation-failed"),
93 operation_not_supported("operation-not-supported"),
94 resource_denied("resource-denied"),
95 rollback_failed("rollback-failed"),
97 unknown_attribute("unknown-attribute"),
98 unknown_element("unknown-element"),
99 unknown_namespace("unknown-namespace");
101 private final String tagValue;
103 ErrorTag(final String tagValue) {
104 this.tagValue = tagValue;
107 public String getTagValue() {
108 return this.tagValue;
111 public static ErrorTag from( String text ) {
112 for( ErrorTag e: values() )
114 if( e.getTagValue().equals( text ) ) {
119 return operation_failed;
123 public enum ErrorSeverity {
126 public String getTagValue() {
130 public static ErrorSeverity from( String text ) {
132 return valueOf( text );
134 catch( Exception e ) {
140 private final ErrorType errorType;
141 private final ErrorTag errorTag;
142 private final ErrorSeverity errorSeverity;
143 private final Map<String, String> errorInfo;
145 public NetconfDocumentedException(String message) {
147 NetconfDocumentedException.ErrorType.application,
148 NetconfDocumentedException.ErrorTag.invalid_value,
149 NetconfDocumentedException.ErrorSeverity.error
153 public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
154 final ErrorSeverity errorSeverity) {
155 this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
158 public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
159 final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
161 this.errorType = errorType;
162 this.errorTag = errorTag;
163 this.errorSeverity = errorSeverity;
164 this.errorInfo = errorInfo;
167 public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType,
168 final ErrorTag errorTag, final ErrorSeverity errorSeverity) {
169 this(message, cause, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
172 public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType,
173 final ErrorTag errorTag, final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
174 super(message, cause);
175 this.errorType = errorType;
176 this.errorTag = errorTag;
177 this.errorSeverity = errorSeverity;
178 this.errorInfo = errorInfo;
181 public static <E extends Exception> NetconfDocumentedException wrap(E exception) throws NetconfDocumentedException {
182 final Map<String, String> errorInfo = new HashMap<>();
183 errorInfo.put(ErrorTag.operation_failed.name(), "Exception thrown");
184 throw new NetconfDocumentedException(exception.getMessage(), exception, ErrorType.application, ErrorTag.operation_failed,
185 ErrorSeverity.error, errorInfo);
187 public static NetconfDocumentedException wrap(ValidationException e) throws NetconfDocumentedException {
188 final Map<String, String> errorInfo = new HashMap<>();
189 errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
190 throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
191 ErrorSeverity.error, errorInfo);
194 public static NetconfDocumentedException wrap(ConflictingVersionException e) throws NetconfDocumentedException {
195 final Map<String, String> errorInfo = new HashMap<>();
196 errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed");
197 throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
198 ErrorSeverity.error, errorInfo);
201 public static NetconfDocumentedException fromXMLDocument( Document fromDoc ) {
203 ErrorType errorType = ErrorType.application;
204 ErrorTag errorTag = ErrorTag.operation_failed;
205 ErrorSeverity errorSeverity = ErrorSeverity.error;
206 Map<String, String> errorInfo = null;
207 String errorMessage = "";
209 Node rpcReply = fromDoc.getDocumentElement();
211 // FIXME: BUG? - we only handle one rpc-error.
213 NodeList replyChildren = rpcReply.getChildNodes();
214 for( int i = 0; i < replyChildren.getLength(); i++ ) {
215 Node replyChild = replyChildren.item( i );
216 if( RPC_ERROR.equals( replyChild.getNodeName() ) )
218 NodeList rpcErrorChildren = replyChild.getChildNodes();
219 for( int j = 0; j < rpcErrorChildren.getLength(); j++ )
221 Node rpcErrorChild = rpcErrorChildren.item( j );
222 if( ERROR_TYPE.equals( rpcErrorChild.getNodeName() ) ) {
223 errorType = ErrorType.from( rpcErrorChild.getTextContent() );
225 else if( ERROR_TAG.equals( rpcErrorChild.getNodeName() ) ) {
226 errorTag = ErrorTag.from( rpcErrorChild.getTextContent() );
228 else if( ERROR_SEVERITY.equals( rpcErrorChild.getNodeName() ) ) {
229 errorSeverity = ErrorSeverity.from( rpcErrorChild.getTextContent() );
231 else if( ERROR_MESSAGE.equals( rpcErrorChild.getNodeName() ) ) {
232 errorMessage = rpcErrorChild.getTextContent();
234 else if( ERROR_INFO.equals( rpcErrorChild.getNodeName() ) ) {
235 errorInfo = parseErrorInfo( rpcErrorChild );
243 return new NetconfDocumentedException( errorMessage, errorType, errorTag, errorSeverity, errorInfo );
246 private static Map<String, String> parseErrorInfo( Node node ) {
247 Map<String, String> infoMap = new HashMap<>();
248 NodeList children = node.getChildNodes();
249 for( int i = 0; i < children.getLength(); i++ ) {
250 Node child = children.item( i );
251 if( child.getNodeType() == Node.ELEMENT_NODE ) {
252 infoMap.put( child.getNodeName(), child.getTextContent() );
259 public ErrorType getErrorType() {
260 return this.errorType;
263 public ErrorTag getErrorTag() {
264 return this.errorTag;
267 public ErrorSeverity getErrorSeverity() {
268 return this.errorSeverity;
271 public Map<String, String> getErrorInfo() {
272 return this.errorInfo;
275 public Document toXMLDocument() {
278 doc = BUILDER_FACTORY.newDocumentBuilder().newDocument();
280 Node rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
281 doc.appendChild( rpcReply );
283 Node rpcError = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_ERROR );
284 rpcReply.appendChild( rpcError );
286 rpcError.appendChild( createTextNode( doc, ERROR_TYPE, getErrorType().getTagValue() ) );
287 rpcError.appendChild( createTextNode( doc, ERROR_TAG, getErrorTag().getTagValue() ) );
288 rpcError.appendChild( createTextNode( doc, ERROR_SEVERITY, getErrorSeverity().getTagValue() ) );
289 rpcError.appendChild( createTextNode( doc, ERROR_MESSAGE, getLocalizedMessage() ) );
291 Map<String, String> errorInfoMap = getErrorInfo();
292 if( errorInfoMap != null && !errorInfoMap.isEmpty() ) {
295 * <bad-attribute>message-id</bad-attribute>
296 * <bad-element>rpc</bad-element>
300 Node errorInfoNode = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, ERROR_INFO );
301 errorInfoNode.setPrefix( rpcReply.getPrefix() );
302 rpcError.appendChild( errorInfoNode );
304 for ( Entry<String, String> entry : errorInfoMap.entrySet() ) {
305 errorInfoNode.appendChild( createTextNode( doc, entry.getKey(), entry.getValue() ) );
309 catch( ParserConfigurationException e ) {
310 LOG.error( "Error outputting to XML document", e ); // this shouldn't happen
316 private Node createTextNode( Document doc, String tag, String textContent ) {
317 Node node = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, tag );
318 node.setTextContent( textContent );
323 public String toString() {
324 return "NetconfDocumentedException{" + "message=" + getMessage() + ", errorType=" + this.errorType
325 + ", errorTag=" + this.errorTag + ", errorSeverity=" + this.errorSeverity + ", errorInfo="
326 + this.errorInfo + '}';