Bug 977: Return RpcError result on neconf failure 08/7608/9
authortpantelis <tpanteli@brocade.com>
Thu, 29 May 2014 01:36:13 +0000 (21:36 -0400)
committerTony Tkacik <ttkacik@cisco.com>
Thu, 19 Jun 2014 11:20:40 +0000 (13:20 +0200)
NetconfDocumentedException:
   - Added methods to convert to and from XML.

NetconfMessageTransformUtil:
   - Added code to convert a NetconfDocumentedException to an RpcError.
   - Modified checkSuccessReply and checkValidReply to throw
     NetconfDocumentedException instead of IllegalStateException.

NetconfDeviceCommunicator:
   - Modified processMessage to return an RpcError result for invalid
     message and netconf error reply.
   - Modified other places that previously returned an exception in the
     Future to intsead return an RpcError result.
   - Improved  synchronization by removing synchronized from method sigs
     and locking only the code that needs it.

SendErrorExceptionUtil:
   - Modified createDocument to call
     NetconfDocumentedException.toXMLDocument

XmlNetconfConstants:
   - Moved to netconf-api so NetconfDocumentedException could access it.

The rest of the changed files were to change the import for
XmlNetconfConstants.

Change-Id: Id0ef3ac91bbcb85c9a7a198ceac272fb07f4b9f9
Signed-off-by: tpantelis <tpanteli@brocade.com>
49 files changed:
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicator.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTest.java
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/ValidateTest.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/netconf-api/pom.xml
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/xml/XmlNetconfConstants.java [moved from opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java with 86% similarity]
opendaylight/netconf/netconf-api/src/test/java/org/opendaylight/controller/netconf/api/NetconfDocumentedExceptionTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommit.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStartExi.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExi.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/Get.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/exi/NetconfStartExiMessage.java
opendaylight/netconf/netconf-util/pom.xml
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XMLNetconfUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java

index e78f2b3..4da727f 100644 (file)
@@ -10,17 +10,20 @@ package org.opendaylight.controller.sal.connect.netconf.listener;
 import java.util.ArrayDeque;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Queue;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfClientSession;
 import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.controller.sal.common.util.RpcErrors;
 import org.opendaylight.controller.sal.common.util.Rpcs;
@@ -35,6 +38,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -45,12 +50,9 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceCommunicator.class);
 
-    private static final RpcResult<NetconfMessage> FAILED_RPC_RESULT = new FailedRpcResult<>(RpcErrors.getRpcError(
-            null, null, null, RpcError.ErrorSeverity.ERROR, "Netconf session disconnected",
-            RpcError.ErrorType.PROTOCOL, null));
-
     private final RemoteDevice<NetconfSessionCapabilities, NetconfMessage> remoteDevice;
     private final RemoteDeviceId id;
+    private final Lock sessionLock = new ReentrantLock();
 
     public NetconfDeviceCommunicator(final RemoteDeviceId id,
             final RemoteDevice<NetconfSessionCapabilities, NetconfMessage> remoteDevice) {
@@ -62,14 +64,21 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
     private NetconfClientSession session;
 
     @Override
-    public synchronized void onSessionUp(final NetconfClientSession session) {
-        logger.debug("{}: Session established", id);
-        this.session = session;
+    public void onSessionUp(final NetconfClientSession session) {
+        sessionLock.lock();
+        try {
+            logger.debug("{}: Session established", id);
+            this.session = session;
 
-        final NetconfSessionCapabilities netconfSessionCapabilities = NetconfSessionCapabilities.fromNetconfSession(session);
-        logger.trace("{}: Session advertised capabilities: {}", id, netconfSessionCapabilities);
+            final NetconfSessionCapabilities netconfSessionCapabilities =
+                                             NetconfSessionCapabilities.fromNetconfSession(session);
+            logger.trace("{}: Session advertised capabilities: {}", id, netconfSessionCapabilities);
 
-        remoteDevice.onRemoteSessionUp(netconfSessionCapabilities, this);
+            remoteDevice.onRemoteSessionUp(netconfSessionCapabilities, this);
+        }
+        finally {
+            sessionLock.unlock();
+        }
     }
 
     public void initializeRemoteConnection(final NetconfClientDispatcher dispatch,
@@ -77,37 +86,75 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
         dispatch.createReconnectingClient(config);
     }
 
-    private synchronized void tearDown(final Exception e) {
-        remoteDevice.onRemoteSessionDown();
-        session = null;
+    private void tearDown( String reason ) {
+        List<UncancellableFuture<RpcResult<NetconfMessage>>> futuresToCancel = Lists.newArrayList();
+        sessionLock.lock();
+        try {
+            if( session != null ) {
+                session = null;
+
+                /*
+                 * Walk all requests, check if they have been executing
+                 * or cancelled and remove them from the queue.
+                 */
+                final Iterator<Request> it = requests.iterator();
+                while (it.hasNext()) {
+                    final Request r = it.next();
+                    if (r.future.isUncancellable()) {
+                        futuresToCancel.add( r.future );
+                        it.remove();
+                    } else if (r.future.isCancelled()) {
+                        // This just does some house-cleaning
+                        it.remove();
+                    }
+                }
 
-        /*
-         * Walk all requests, check if they have been executing
-         * or cancelled and remove them from the queue.
-         */
-        final Iterator<Request> it = requests.iterator();
-        while (it.hasNext()) {
-            final Request r = it.next();
-            if (r.future.isUncancellable()) {
-                r.future.setException(e);
-                it.remove();
-            } else if (r.future.isCancelled()) {
-                // This just does some house-cleaning
-                it.remove();
+                remoteDevice.onRemoteSessionDown();
+            }
+        }
+        finally {
+            sessionLock.unlock();
+        }
+
+        // Notify pending request futures outside of the sessionLock to avoid unnecessarily
+        // blocking the caller.
+        for( UncancellableFuture<RpcResult<NetconfMessage>> future: futuresToCancel ) {
+            if( Strings.isNullOrEmpty( reason ) ) {
+                future.set( createSessionDownRpcResult() );
+            } else {
+                future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT, reason ) );
             }
         }
     }
 
+    private RpcResult<NetconfMessage> createSessionDownRpcResult()
+    {
+        return createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+                             String.format( "The netconf session to %1$s is disconnected", id.getName() ) );
+    }
+
+    private RpcResult<NetconfMessage> createErrorRpcResult( RpcError.ErrorType errorType, String message )
+    {
+        return new FailedRpcResult<NetconfMessage>( RpcErrors.getRpcError( null,
+                NetconfDocumentedException.ErrorTag.operation_failed.getTagValue(),
+                null, RpcError.ErrorSeverity.ERROR, message, errorType, null ) );
+    }
+
     @Override
     public void onSessionDown(final NetconfClientSession session, final Exception e) {
         logger.warn("{}: Session went down", id, e);
-        tearDown(e);
+        tearDown( null );
     }
 
     @Override
     public void onSessionTerminated(final NetconfClientSession session, final NetconfTerminationReason reason) {
         logger.warn("{}: Session terminated {}", id, reason);
-        tearDown(new RuntimeException(reason.getErrorMessage()));
+        tearDown( reason.getErrorMessage() );
+    }
+
+    @Override
+    public void close() {
+        tearDown( String.format( "The netconf session to %1$s has been closed", id.getName() ) );
     }
 
     @Override
@@ -123,73 +170,109 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
         }
     }
 
-    private synchronized void processMessage(final NetconfMessage message) {
-        final Request r = requests.peek();
-        if (r.future.isUncancellable()) {
-            requests.poll();
+    private void processMessage(final NetconfMessage message) {
+        Request request = null;
+        sessionLock.lock();
+        try {
+            request = requests.peek();
+            if (request.future.isUncancellable()) {
+                requests.poll();
+            }
+            else {
+                request = null;
+                logger.warn("{}: Ignoring unsolicited message {}", id, msgToS(message));
+            }
+        }
+        finally {
+            sessionLock.unlock();
+        }
+
+        if( request != null ) {
 
             logger.debug("{}: Message received {}", id, message);
 
             if(logger.isTraceEnabled()) {
-                logger.trace("{}: Matched request: {} to response: {}", id, msgToS(r.request), msgToS(message));
+                logger.trace( "{}: Matched request: {} to response: {}", id,
+                              msgToS( request.request ), msgToS( message ) );
             }
 
             try {
-                NetconfMessageTransformUtil.checkValidReply(r.request, message);
-            } catch (final IllegalStateException e) {
-                logger.warn("{}: Invalid request-reply match, reply message contains different message-id, request: {}, response: {}", id,
-                        msgToS(r.request), msgToS(message), e);
-                r.future.setException(e);
+                NetconfMessageTransformUtil.checkValidReply( request.request, message );
+            }
+            catch (final NetconfDocumentedException e) {
+                logger.warn( "{}: Invalid request-reply match, reply message contains different message-id, request: {}, response: {}",
+                             id, msgToS( request.request ), msgToS( message ), e );
+
+                request.future.set( new FailedRpcResult<NetconfMessage>(
+                                                           NetconfMessageTransformUtil.toRpcError( e ) ) );
                 return;
             }
 
             try {
                 NetconfMessageTransformUtil.checkSuccessReply(message);
-            } catch (NetconfDocumentedException | IllegalStateException e) {
-                logger.warn("{}: Error reply from remote device, request: {}, response: {}", id,
-                        msgToS(r.request), msgToS(message), e);
-                r.future.setException(e);
+            }
+            catch( NetconfDocumentedException e ) {
+                logger.warn( "{}: Error reply from remote device, request: {}, response: {}", id,
+                             msgToS( request.request ), msgToS( message ), e );
+
+                request.future.set( new FailedRpcResult<NetconfMessage>(
+                                                          NetconfMessageTransformUtil.toRpcError( e ) ) );
                 return;
             }
 
-            r.future.set(Rpcs.getRpcResult(true, message, Collections.<RpcError>emptySet()));
-        } else {
-            logger.warn("{}: Ignoring unsolicited message {}", id, msgToS(message));
+            request.future.set(Rpcs.getRpcResult( true, message, Collections.<RpcError>emptySet() ) );
         }
     }
 
-    @Override
-    public void close() {
-        tearDown(new RuntimeException("Closed"));
-    }
-
     private static String msgToS(final NetconfMessage msg) {
         return XmlUtil.toString(msg.getDocument());
     }
 
     @Override
-    public synchronized ListenableFuture<RpcResult<NetconfMessage>> sendRequest(final NetconfMessage message, final QName rpc) {
+    public ListenableFuture<RpcResult<NetconfMessage>> sendRequest(
+                                               final NetconfMessage message, final QName rpc) {
+        sessionLock.lock();
+        try {
+            return sendRequestWithLock( message, rpc );
+        }
+        finally {
+            sessionLock.unlock();
+        }
+    }
+
+    private ListenableFuture<RpcResult<NetconfMessage>> sendRequestWithLock(
+                                               final NetconfMessage message, final QName rpc) {
         if(logger.isTraceEnabled()) {
             logger.trace("{}: Sending message {}", id, msgToS(message));
         }
 
         if (session == null) {
             logger.warn("{}: Session is disconnected, failing RPC request {}", id, message);
-            return Futures.immediateFuture(FAILED_RPC_RESULT);
+            return Futures.immediateFuture( createSessionDownRpcResult() );
         }
 
-        final Request req = new Request(new UncancellableFuture<RpcResult<NetconfMessage>>(true), message, rpc);
+        final Request req = new Request( new UncancellableFuture<RpcResult<NetconfMessage>>(true),
+                                         message );
         requests.add(req);
 
         session.sendMessage(req.request).addListener(new FutureListener<Void>() {
             @Override
             public void operationComplete(final Future<Void> future) throws Exception {
-                if (!future.isSuccess()) {
+                if( !future.isSuccess() ) {
                     // We expect that a session down will occur at this point
-                    logger.debug("{}: Failed to send request {}", id, XmlUtil.toString(req.request.getDocument()), future.cause());
-                    req.future.setException(future.cause());
-                } else {
-                    logger.trace("{}: Finished sending request {}", id, req.request);
+                    logger.debug( "{}: Failed to send request {}", id,
+                                  XmlUtil.toString(req.request.getDocument()), future.cause() );
+
+                    if( future.cause() != null ) {
+                        req.future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+                                                              future.cause().getLocalizedMessage() ) );
+                    } else {
+                        req.future.set( createSessionDownRpcResult() ); // assume session is down
+                    }
+                    req.future.setException( future.cause() );
+                }
+                else {
+                    logger.trace( "Finished sending request {}", req.request );
                 }
             }
         });
@@ -215,12 +298,11 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
     private static final class Request {
         final UncancellableFuture<RpcResult<NetconfMessage>> future;
         final NetconfMessage request;
-        final QName rpc;
 
-        private Request(final UncancellableFuture<RpcResult<NetconfMessage>> future, final NetconfMessage request, final QName rpc) {
+        private Request(final UncancellableFuture<RpcResult<NetconfMessage>> future,
+                        final NetconfMessage request) {
             this.future = future;
             this.request = request;
-            this.rpc = rpc;
         }
     }
 }
index 1284d6d..08a5822 100644 (file)
@@ -12,14 +12,17 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.common.util.RpcErrors;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.Node;
@@ -36,6 +39,7 @@ import org.w3c.dom.Element;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
@@ -99,20 +103,68 @@ public class NetconfMessageTransformUtil {
         return new CompositeNodeTOImpl(argument.getNodeType(), null, list);
     }
 
-    public static void checkValidReply(final NetconfMessage input, final NetconfMessage output) {
+    public static void checkValidReply(final NetconfMessage input, final NetconfMessage output)
+        throws NetconfDocumentedException {
         final String inputMsgId = input.getDocument().getDocumentElement().getAttribute("message-id");
         final String outputMsgId = output.getDocument().getDocumentElement().getAttribute("message-id");
 
         if(inputMsgId.equals(outputMsgId) == false) {
-            final String requestXml = XmlUtil.toString(input.getDocument());
-            final String responseXml = XmlUtil.toString(output.getDocument());
-            throw new IllegalStateException(String.format("Rpc request and reply message IDs must be same. Request: %s, response: %s", requestXml, responseXml));
+            Map<String,String> errorInfo = ImmutableMap.<String,String>builder()
+                .put( "actual-message-id", outputMsgId )
+                .put( "expected-message-id", inputMsgId )
+                .build();
+
+            throw new NetconfDocumentedException( "Response message contained unknown \"message-id\"",
+                    null, NetconfDocumentedException.ErrorType.protocol,
+                    NetconfDocumentedException.ErrorTag.bad_attribute,
+                    NetconfDocumentedException.ErrorSeverity.error, errorInfo );
         }
     }
 
     public static void checkSuccessReply(final NetconfMessage output) throws NetconfDocumentedException {
         if(NetconfMessageUtil.isErrorMessage(output)) {
-            throw new IllegalStateException(String.format("Response contains error: %s", XmlUtil.toString(output.getDocument())));
+            throw NetconfDocumentedException.fromXMLDocument( output.getDocument() );
+        }
+    }
+
+    public static RpcError toRpcError( NetconfDocumentedException ex )
+    {
+        StringBuilder infoBuilder = new StringBuilder();
+        Map<String, String> errorInfo = ex.getErrorInfo();
+        if( errorInfo != null )
+        {
+            for( Entry<String,String> e: errorInfo.entrySet() ) {
+                infoBuilder.append( '<' ).append( e.getKey() ).append( '>' ).append( e.getValue() )
+                           .append( "</" ).append( e.getKey() ).append( '>' );
+
+            }
+        }
+
+        return RpcErrors.getRpcError( null, ex.getErrorTag().getTagValue(), infoBuilder.toString(),
+                                      toRpcErrorSeverity( ex.getErrorSeverity() ), ex.getLocalizedMessage(),
+                                      toRpcErrorType( ex.getErrorType() ), ex.getCause() );
+    }
+
+    private static ErrorSeverity toRpcErrorSeverity( NetconfDocumentedException.ErrorSeverity severity ) {
+        switch( severity ) {
+            case warning:
+                return RpcError.ErrorSeverity.WARNING;
+            default:
+                return RpcError.ErrorSeverity.ERROR;
+        }
+    }
+
+    private static RpcError.ErrorType toRpcErrorType( NetconfDocumentedException.ErrorType type )
+    {
+        switch( type ) {
+            case protocol:
+                return RpcError.ErrorType.PROTOCOL;
+            case rpc:
+                return RpcError.ErrorType.RPC;
+            case transport:
+                return RpcError.ErrorType.TRANSPORT;
+            default:
+                return RpcError.ErrorType.APPLICATION;
         }
     }
 
index 5ac32b5..c1b9f7b 100644 (file)
@@ -26,7 +26,7 @@ import java.util.concurrent.Executors;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.connect.api.MessageTransformer;
 import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java
new file mode 100644 (file)
index 0000000..391bf9c
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connect.netconf.listener;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+
+import java.io.ByteArrayInputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.sal.connect.api.RemoteDevice;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class NetconfDeviceCommunicatorTest {
+
+    @Mock
+    NetconfClientSession mockSession;
+
+    @Mock
+    RemoteDevice<NetconfSessionCapabilities, NetconfMessage> mockDevice;
+
+    NetconfDeviceCommunicator communicator;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks( this );
+
+        communicator = new NetconfDeviceCommunicator( new RemoteDeviceId( "test" ), mockDevice );
+    }
+
+    @SuppressWarnings("unchecked")
+    void setupSession()
+    {
+        doReturn( Collections.<String>emptySet() ).when( mockSession ).getServerCapabilities();
+        doNothing().when( mockDevice ).onRemoteSessionUp( any( NetconfSessionCapabilities.class ),
+                                                          any( RemoteDeviceCommunicator.class ) );
+        communicator.onSessionUp( mockSession );
+    }
+
+    private ListenableFuture<RpcResult<NetconfMessage>> sendRequest() throws Exception {
+        return sendRequest( UUID.randomUUID().toString() );
+    }
+
+    @SuppressWarnings("unchecked")
+    private ListenableFuture<RpcResult<NetconfMessage>> sendRequest( String messageID ) throws Exception {
+        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+        Element element = doc.createElement( "request" );
+        element.setAttribute( "message-id", messageID );
+        doc.appendChild( element );
+        NetconfMessage message = new NetconfMessage( doc );
+
+        ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+        doReturn( mockChannelFuture ).when( mockChannelFuture )
+            .addListener( any( (GenericFutureListener.class ) ) );
+        doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture =
+                                      communicator.sendRequest( message, QName.create( "mock rpc" ) );
+
+        assertNotNull( "ListenableFuture is null", resultFuture );
+        return resultFuture;
+    }
+
+    @Test
+    public void testOnSessionUp() {
+        String testCapability = "urn:opendaylight:params:xml:ns:test?module=test-module&revision=2014-06-02";
+        Collection<String> serverCapabilities =
+                Sets.newHashSet( NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString(),
+                                 NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString(),
+                                 testCapability );
+        doReturn( serverCapabilities ).when( mockSession ).getServerCapabilities();
+
+        ArgumentCaptor<NetconfSessionCapabilities> netconfSessionCapabilities =
+                                              ArgumentCaptor.forClass( NetconfSessionCapabilities.class );
+        doNothing().when( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+
+        communicator.onSessionUp( mockSession );
+
+        verify( mockSession ).getServerCapabilities();
+        verify( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+
+        NetconfSessionCapabilities actualCapabilites = netconfSessionCapabilities.getValue();
+        assertEquals( "containsCapability", true, actualCapabilites.containsCapability(
+                                NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString() ) );
+        assertEquals( "containsCapability", true, actualCapabilites.containsCapability( testCapability ) );
+        assertEquals( "getModuleBasedCaps", Sets.newHashSet(
+                            QName.create( "urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module" )),
+                      actualCapabilites.getModuleBasedCaps() );
+        assertEquals( "isRollbackSupported", true, actualCapabilites.isRollbackSupported() );
+        assertEquals( "isMonitoringSupported", true, actualCapabilites.isMonitoringSupported() );
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test(timeout=5000)
+    public void testOnSessionDown() throws Exception {
+        setupSession();
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest();
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest();
+
+        doNothing().when( mockDevice ).onRemoteSessionDown();
+
+        communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+        verifyErrorRpcResult( resultFuture1.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+        verifyErrorRpcResult( resultFuture2.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+
+        verify( mockDevice ).onRemoteSessionDown();
+
+        reset( mockDevice );
+
+        communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+        verify( mockDevice, never() ).onRemoteSessionDown();
+    }
+
+    @Test
+    public void testOnSessionTerminated() throws Exception {
+        setupSession();
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest();
+
+        doNothing().when( mockDevice ).onRemoteSessionDown();
+
+        String reasonText = "testing terminate";
+        NetconfTerminationReason reason = new NetconfTerminationReason( reasonText );
+        communicator.onSessionTerminated( mockSession, reason );
+
+        RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.TRANSPORT,
+                                                  "operation-failed" );
+        assertEquals( "RpcError message", reasonText, rpcError.getMessage() );
+
+        verify( mockDevice ).onRemoteSessionDown();
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        communicator.close();
+        verify( mockDevice, never() ).onRemoteSessionDown();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void testSendRequest() throws Exception {
+        setupSession();
+
+        NetconfMessage message = new NetconfMessage(
+                              DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+        QName rpc = QName.create( "mock rpc" );
+
+        ArgumentCaptor<GenericFutureListener> futureListener =
+                                            ArgumentCaptor.forClass( GenericFutureListener.class );
+
+        ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+        doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+        doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+        verify( mockSession ).sendMessage( same( message ) );
+
+        assertNotNull( "ListenableFuture is null", resultFuture );
+
+        verify( mockChannelFuture ).addListener( futureListener.capture() );
+        Future<Void> operationFuture = mock( Future.class );
+        doReturn( true ).when( operationFuture ).isSuccess();
+        doReturn( true ).when( operationFuture ).isDone();
+        futureListener.getValue().operationComplete( operationFuture );
+
+        try {
+            resultFuture.get( 1, TimeUnit.MILLISECONDS ); // verify it's not cancelled or has an error set
+        }
+        catch( TimeoutException e ) {} // expected
+    }
+
+    @Test
+    public void testSendRequestWithNoSession() throws Exception {
+        NetconfMessage message = new NetconfMessage(
+                              DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+        QName rpc = QName.create( "mock rpc" );
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+        assertNotNull( "ListenableFuture is null", resultFuture );
+
+        // Should have an immediate result
+        RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+        verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void testSendRequestWithWithSendFailure() throws Exception {
+        setupSession();
+
+        NetconfMessage message = new NetconfMessage(
+                              DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+        QName rpc = QName.create( "mock rpc" );
+
+        ArgumentCaptor<GenericFutureListener> futureListener =
+                                            ArgumentCaptor.forClass( GenericFutureListener.class );
+
+        ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+        doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+        doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+        assertNotNull( "ListenableFuture is null", resultFuture );
+
+        verify( mockChannelFuture ).addListener( futureListener.capture() );
+
+        Future<Void> operationFuture = mock( Future.class );
+        doReturn( false ).when( operationFuture ).isSuccess();
+        doReturn( true ).when( operationFuture ).isDone();
+        doReturn( new Exception( "mock error" ) ).when( operationFuture ).cause();
+        futureListener.getValue().operationComplete( operationFuture );
+
+        // Should have an immediate result
+        RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+        RpcError rpcError = verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+        assertEquals( "RpcError message contains \"mock error\"", true,
+                    rpcError.getMessage().contains( "mock error" ) );
+    }
+
+    private NetconfMessage createSuccessResponseMessage( String messageID ) throws ParserConfigurationException {
+        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+        Element rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
+        rpcReply.setAttribute( "message-id", messageID );
+        Element element = doc.createElementNS( "ns", "data" );
+        element.setTextContent( messageID );
+        rpcReply.appendChild( element );
+        doc.appendChild( rpcReply );
+
+        return new NetconfMessage( doc );
+    }
+
+    @Test
+    public void testOnSuccessfulResponseMessage() throws Exception {
+        setupSession();
+
+        String messageID1 = UUID.randomUUID().toString();
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest( messageID1 );
+
+        String messageID2 = UUID.randomUUID().toString();
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest( messageID2 );
+
+        communicator.onMessage( mockSession, createSuccessResponseMessage( messageID1 ) );
+        communicator.onMessage( mockSession, createSuccessResponseMessage( messageID2 ) );
+
+        verifyResponseMessage( resultFuture1.get(), messageID1 );
+        verifyResponseMessage( resultFuture2.get(), messageID2 );
+    }
+
+    @Test
+    public void testOnResponseMessageWithError() throws Exception {
+        setupSession();
+
+        String messageID = UUID.randomUUID().toString();
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+        communicator.onMessage( mockSession, createErrorResponseMessage( messageID ) );
+
+        RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.RPC,
+                                                  "missing-attribute" );
+        assertEquals( "RpcError message", "Missing attribute", rpcError.getMessage() );
+
+        String errorInfo = rpcError.getInfo();
+        assertNotNull( "RpcError info is null", errorInfo );
+        assertEquals( "Error info contains \"foo\"", true,
+                      errorInfo.contains( "<bad-attribute>foo</bad-attribute>" ) );
+        assertEquals( "Error info contains \"bar\"", true,
+                      errorInfo.contains( "<bad-element>bar</bad-element>" ) );
+    }
+
+    @Test
+    public void testOnResponseMessageWithWrongMessageID() throws Exception {
+        setupSession();
+
+        String messageID = UUID.randomUUID().toString();
+        ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+        communicator.onMessage( mockSession, createSuccessResponseMessage( UUID.randomUUID().toString() ) );
+
+        RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.PROTOCOL,
+                                                  "bad-attribute" );
+        assertEquals( "RpcError message non-empty", true,
+                      !Strings.isNullOrEmpty( rpcError.getMessage() ) );
+
+        String errorInfo = rpcError.getInfo();
+        assertNotNull( "RpcError info is null", errorInfo );
+        assertEquals( "Error info contains \"actual-message-id\"", true,
+                      errorInfo.contains( "actual-message-id" ) );
+        assertEquals( "Error info contains \"expected-message-id\"", true,
+                      errorInfo.contains( "expected-message-id" ) );
+    }
+
+    private NetconfMessage createErrorResponseMessage( String messageID ) throws Exception {
+        String xmlStr =
+            "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"" +
+            "           message-id=\"" + messageID + "\">" +
+            "  <rpc-error>" +
+            "    <error-type>rpc</error-type>" +
+            "    <error-tag>missing-attribute</error-tag>" +
+            "    <error-severity>error</error-severity>" +
+            "    <error-message>Missing attribute</error-message>" +
+            "    <error-info>" +
+            "      <bad-attribute>foo</bad-attribute>" +
+            "      <bad-element>bar</bad-element>" +
+            "    </error-info>" +
+            "  </rpc-error>" +
+            "</rpc-reply>";
+
+        ByteArrayInputStream bis = new ByteArrayInputStream( xmlStr.getBytes() );
+        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( bis );
+        return new NetconfMessage( doc );
+    }
+
+    private void verifyResponseMessage( RpcResult<NetconfMessage> rpcResult, String dataText ) {
+        assertNotNull( "RpcResult is null", rpcResult );
+        assertEquals( "isSuccessful", true, rpcResult.isSuccessful() );
+        NetconfMessage messageResult = rpcResult.getResult();
+        assertNotNull( "getResult", messageResult );
+//        List<SimpleNode<?>> nodes = messageResult.getSimpleNodesByName(
+//                                         QName.create( URI.create( "ns" ), null, "data" ) );
+//        assertNotNull( "getSimpleNodesByName", nodes );
+//        assertEquals( "List<SimpleNode<?>> size", 1, nodes.size() );
+//        assertEquals( "SimpleNode value", dataText, nodes.iterator().next().getValue() );
+    }
+
+    private RpcError verifyErrorRpcResult( RpcResult<NetconfMessage> rpcResult,
+                                           RpcError.ErrorType expErrorType, String expErrorTag ) {
+        assertNotNull( "RpcResult is null", rpcResult );
+        assertEquals( "isSuccessful", false, rpcResult.isSuccessful() );
+        assertNotNull( "RpcResult errors is null", rpcResult.getErrors() );
+        assertEquals( "Errors size", 1, rpcResult.getErrors().size() );
+        RpcError rpcError = rpcResult.getErrors().iterator().next();
+        assertEquals( "getErrorSeverity", RpcError.ErrorSeverity.ERROR, rpcError.getSeverity() );
+        assertEquals( "getErrorType", expErrorType, rpcError.getErrorType() );
+        assertEquals( "getErrorTag", expErrorTag, rpcError.getTag() );
+        assertTrue( "getMessage is empty", StringUtils.isNotEmpty( rpcError.getMessage() ) );
+        return rpcError;
+    }
+}
index 08f3c73..8720c65 100644 (file)
@@ -8,12 +8,14 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
 import com.google.common.base.Preconditions;
+
 import java.util.List;
 import java.util.Map;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 
 public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
 
index 68c8c6f..5d5721a 100644 (file)
@@ -8,9 +8,9 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
 
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index 1492066..5d41b78 100644 (file)
@@ -16,6 +16,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -23,13 +24,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index ff1d719..0b33b55 100644 (file)
@@ -11,16 +11,20 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.confi
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
+
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
@@ -33,7 +37,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attrib
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 0c2b0e2..eaab30b 100644 (file)
@@ -9,15 +9,18 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
 
 import com.google.common.base.Optional;
+
 import java.util.Date;
 import java.util.Map;
+
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index 559de7a..37ad2bb 100644 (file)
@@ -11,16 +11,18 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.confi
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
+
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
index b9518dc..b1df316 100644 (file)
@@ -12,14 +12,17 @@ import com.google.common.base.Optional;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index d49fe1a..8eaaecf 100644 (file)
@@ -13,9 +13,9 @@ import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 96a43b1..3cf702e 100644 (file)
@@ -9,14 +9,15 @@
     package org.opendaylight.controller.netconf.confignetconfconnector.operations;
 
 import com.google.common.base.Optional;
+
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 1a7d50e..f443111 100644 (file)
@@ -9,15 +9,16 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.operations;
 
 import com.google.common.base.Optional;
+
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 319f539..543a2c4 100644 (file)
@@ -13,12 +13,15 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
@@ -27,6 +30,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
@@ -39,7 +43,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.operations.edi
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
index 47220f1..a3d97b1 100644 (file)
@@ -11,10 +11,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.collect.Multimap;
+
 import java.util.Arrays;
 import java.util.Map;
+
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementDefinition;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
@@ -24,7 +27,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.operations.Dat
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 867ad60..fc95046 100644 (file)
@@ -9,14 +9,18 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.get;
 
 import com.google.common.collect.Maps;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.InstanceRuntime;
@@ -30,7 +34,6 @@ import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceExcept
 import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
index bc059d3..fee3036 100644 (file)
@@ -14,6 +14,7 @@ import javax.management.ObjectName;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
@@ -25,7 +26,6 @@ import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceExcept
 import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 98eb176..21021fe 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ru
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
+
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
@@ -18,6 +19,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.AttributeMappingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectMapper;
@@ -31,7 +33,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStore
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,6 +41,7 @@ import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
+
 import java.util.Map;
 
 public class RuntimeRpc extends AbstractConfigNetconfOperation {
index 5cf7f30..7fd8928 100644 (file)
@@ -11,11 +11,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ru
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
+
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 
 import javax.management.ObjectName;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.regex.Matcher;
index 4130154..e41b174 100644 (file)
@@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -42,10 +43,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
 import javax.xml.parsers.ParserConfigurationException;
+
 import org.custommonkey.xmlunit.AbstractNodeTester;
 import org.custommonkey.xmlunit.NodeTest;
 import org.custommonkey.xmlunit.NodeTestException;
@@ -80,6 +83,7 @@ import org.opendaylight.controller.config.yang.test.impl.Peers;
 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
@@ -96,7 +100,6 @@ import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
index d393121..b5c5dd3 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Element;
 
index 957db50..8d85a35 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
@@ -33,7 +34,6 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.util.NetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 061fbd7..815acec 100644 (file)
@@ -48,6 +48,7 @@
           <instructions>
             <Private-Package></Private-Package>
             <Import-Package>javax.management,
+                            javax.xml.parsers,
                             org.opendaylight.controller.config.api,
                             org.opendaylight.controller.config.api.jmx,
                             org.opendaylight.protocol.framework,
@@ -62,6 +63,7 @@
                             com.google.common.base,</Import-Package>
             <Export-Package>org.opendaylight.controller.netconf.api,
                             org.opendaylight.controller.netconf.api.jmx,
+                            org.opendaylight.controller.netconf.api.xml,
                             org.opendaylight.controller.netconf.api.monitoring,</Export-Package>
           </instructions>
         </configuration>
index 1ecbc55..0c365b9 100644 (file)
@@ -8,12 +8,30 @@
 
 package org.opendaylight.controller.netconf.api;
 
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_INFO;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_MESSAGE;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_SEVERITY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TAG;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TYPE;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_ERROR;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Checked exception to communicate an error that needs to be sent to the
@@ -23,7 +41,17 @@ public class NetconfDocumentedException extends Exception {
 
     private static final long serialVersionUID = 1L;
 
+    private final static Logger LOG = LoggerFactory.getLogger( NetconfDocumentedException.class );
 
+    private static final DocumentBuilderFactory BUILDER_FACTORY;
+
+    static {
+        BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+        BUILDER_FACTORY.setNamespaceAware(true);
+        BUILDER_FACTORY.setCoalescing(true);
+        BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
+        BUILDER_FACTORY.setIgnoringComments(true);
+    }
 
     public enum ErrorType {
         transport, rpc, protocol, application;
@@ -31,12 +59,37 @@ public class NetconfDocumentedException extends Exception {
         public String getTagValue() {
             return name();
         }
+
+        public static ErrorType from( String text ) {
+            try {
+                return valueOf( text );
+            }
+            catch( Exception e ) {
+                return application;
+            }
+        }
     }
 
     public enum ErrorTag {
-        missing_attribute("missing-attribute"), unknown_element("unknown-element"), operation_not_supported(
-                "operation-not-supported"), bad_attribute("bad-attribute"), data_missing("data-missing"), operation_failed(
-                "operation-failed"), invalid_value("invalid-value"), malformed_message("malformed-message");
+        access_denied("access-denied"),
+        bad_attribute("bad-attribute"),
+        bad_element("bad-element"),
+        data_exists("data-exists"),
+        data_missing("data-missing"),
+        in_use("in-use"),
+        invalid_value("invalid-value"),
+        lock_denied("lock-denied"),
+        malformed_message("malformed-message"),
+        missing_attribute("missing-attribute"),
+        missing_element("missing-element"),
+        operation_failed("operation-failed"),
+        operation_not_supported("operation-not-supported"),
+        resource_denied("resource-denied"),
+        rollback_failed("rollback-failed"),
+        too_big("too-big"),
+        unknown_attribute("unknown-attribute"),
+        unknown_element("unknown-element"),
+        unknown_namespace("unknown-namespace");
 
         private final String tagValue;
 
@@ -47,6 +100,17 @@ public class NetconfDocumentedException extends Exception {
         public String getTagValue() {
             return this.tagValue;
         }
+
+        public static ErrorTag from( String text ) {
+            for( ErrorTag e: values() )
+            {
+                if( e.getTagValue().equals( text ) ) {
+                    return e;
+                }
+            }
+
+            return operation_failed;
+        }
     }
 
     public enum ErrorSeverity {
@@ -55,6 +119,15 @@ public class NetconfDocumentedException extends Exception {
         public String getTagValue() {
             return name();
         }
+
+        public static ErrorSeverity from( String text ) {
+            try {
+                return valueOf( text );
+            }
+            catch( Exception e ) {
+                return error;
+            }
+        }
     }
 
     private final ErrorType errorType;
@@ -118,6 +191,64 @@ public class NetconfDocumentedException extends Exception {
                 ErrorSeverity.error, errorInfo);
     }
 
+    public static NetconfDocumentedException fromXMLDocument( Document fromDoc ) {
+
+        ErrorType errorType = ErrorType.application;
+        ErrorTag errorTag = ErrorTag.operation_failed;
+        ErrorSeverity errorSeverity = ErrorSeverity.error;
+        Map<String, String> errorInfo = null;
+        String errorMessage = "";
+
+        Node rpcReply = fromDoc.getDocumentElement();
+
+        // FIXME: BUG? - we only handle one rpc-error.
+
+        NodeList replyChildren = rpcReply.getChildNodes();
+        for( int i = 0; i < replyChildren.getLength(); i++ ) {
+            Node replyChild = replyChildren.item( i );
+            if( RPC_ERROR.equals( replyChild.getNodeName() ) )
+            {
+                NodeList rpcErrorChildren = replyChild.getChildNodes();
+                for( int j = 0; j < rpcErrorChildren.getLength(); j++ )
+                {
+                    Node rpcErrorChild = rpcErrorChildren.item( j );
+                    if( ERROR_TYPE.equals( rpcErrorChild.getNodeName() ) ) {
+                        errorType = ErrorType.from( rpcErrorChild.getTextContent() );
+                    }
+                    else if( ERROR_TAG.equals( rpcErrorChild.getNodeName() ) ) {
+                        errorTag = ErrorTag.from( rpcErrorChild.getTextContent() );
+                    }
+                    else if( ERROR_SEVERITY.equals( rpcErrorChild.getNodeName() ) ) {
+                        errorSeverity = ErrorSeverity.from( rpcErrorChild.getTextContent() );
+                    }
+                    else if( ERROR_MESSAGE.equals( rpcErrorChild.getNodeName() ) ) {
+                        errorMessage = rpcErrorChild.getTextContent();
+                    }
+                    else if( ERROR_INFO.equals( rpcErrorChild.getNodeName() ) ) {
+                        errorInfo = parseErrorInfo( rpcErrorChild );
+                    }
+                }
+
+                break;
+            }
+        }
+
+        return new NetconfDocumentedException( errorMessage, errorType, errorTag, errorSeverity, errorInfo );
+    }
+
+    private static Map<String, String> parseErrorInfo( Node node ) {
+        Map<String, String> infoMap = new HashMap<>();
+        NodeList children = node.getChildNodes();
+        for( int i = 0; i < children.getLength(); i++ ) {
+            Node child = children.item( i );
+            if( child.getNodeType() == Node.ELEMENT_NODE ) {
+                infoMap.put( child.getNodeName(), child.getTextContent() );
+            }
+        }
+
+        return infoMap;
+    }
+
     public ErrorType getErrorType() {
         return this.errorType;
     }
@@ -134,6 +265,53 @@ public class NetconfDocumentedException extends Exception {
         return this.errorInfo;
     }
 
+    public Document toXMLDocument() {
+        Document doc = null;
+        try {
+            doc = BUILDER_FACTORY.newDocumentBuilder().newDocument();
+
+            Node rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
+            doc.appendChild( rpcReply );
+
+            Node rpcError = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_ERROR );
+            rpcReply.appendChild( rpcError );
+
+            rpcError.appendChild( createTextNode( doc, ERROR_TYPE, getErrorType().getTagValue() ) );
+            rpcError.appendChild( createTextNode( doc, ERROR_TAG, getErrorTag().getTagValue() ) );
+            rpcError.appendChild( createTextNode( doc, ERROR_SEVERITY, getErrorSeverity().getTagValue() ) );
+            rpcError.appendChild( createTextNode( doc, ERROR_MESSAGE, getLocalizedMessage() ) );
+
+            Map<String, String> errorInfoMap = getErrorInfo();
+            if( errorInfoMap != null && !errorInfoMap.isEmpty() ) {
+                /*
+                 * <error-info>
+                 *   <bad-attribute>message-id</bad-attribute>
+                 *   <bad-element>rpc</bad-element>
+                 * </error-info>
+                 */
+
+                Node errorInfoNode = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, ERROR_INFO );
+                errorInfoNode.setPrefix( rpcReply.getPrefix() );
+                rpcError.appendChild( errorInfoNode );
+
+                for ( Entry<String, String> entry : errorInfoMap.entrySet() ) {
+                    errorInfoNode.appendChild( createTextNode( doc, entry.getKey(), entry.getValue() ) );
+                }
+            }
+        }
+        catch( ParserConfigurationException e ) {
+            LOG.error( "Error outputting to XML document", e ); // this shouldn't happen
+        }
+
+        return doc;
+    }
+
+    private Node createTextNode( Document doc, String tag, String textContent ) {
+        Node node = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, tag );
+        node.setTextContent( textContent );
+        return node;
+    }
+
     @Override
     public String toString() {
         return "NetconfDocumentedException{" + "message=" + getMessage() + ", errorType=" + this.errorType
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.netconf.util.xml;
+package org.opendaylight.controller.netconf.api.xml;
 
 public final class XmlNetconfConstants {
 
@@ -34,6 +34,13 @@ public final class XmlNetconfConstants {
     public static final String RPC_KEY = "rpc";
     public static final String RPC_REPLY_KEY = "rpc-reply";
     public static final String RPC_ERROR = "rpc-error";
+    public static final String ERROR_TYPE = "error-type";
+    public static final String ERROR_TAG = "error-tag";
+    public static final String ERROR_SEVERITY = "error-severity";
+    public static final String ERROR_APP_TAG = "error-app-tag";
+    public static final String ERROR_PATH = "error-path";
+    public static final String ERROR_MESSAGE = "error-message";
+    public static final String ERROR_INFO = "error-info";
     public static final String NAME_KEY = "name";
     public static final String NOTIFICATION_ELEMENT_NAME = "notification";
 
diff --git a/opendaylight/netconf/netconf-api/src/test/java/org/opendaylight/controller/netconf/api/NetconfDocumentedExceptionTest.java b/opendaylight/netconf/netconf-api/src/test/java/org/opendaylight/controller/netconf/api/NetconfDocumentedExceptionTest.java
new file mode 100644 (file)
index 0000000..cdf8b91
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+
+
+/**
+ * Unit tests for NetconfDocumentedException.
+ *
+ * @author Thomas Pantelis
+ */
+public class NetconfDocumentedExceptionTest {
+
+    private XPath xpath;
+
+    @Before
+    public void setUp() throws Exception {
+        XPathFactory xPathfactory = XPathFactory.newInstance();
+        xpath = xPathfactory.newXPath();
+        xpath.setNamespaceContext( new NamespaceContext() {
+            @Override
+            public Iterator<?> getPrefixes( String namespaceURI ) {
+                return Collections.singletonList( "netconf" ).iterator();
+            }
+
+            @Override
+            public String getPrefix( String namespaceURI ) {
+                return "netconf";
+            }
+
+            @Override
+            public String getNamespaceURI( String prefix ) {
+                return XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+            }
+        } );
+    }
+
+    @Test
+    public void testToAndFromXMLDocument() throws XPathExpressionException {
+        String errorMessage = "mock error message";
+        NetconfDocumentedException ex = new NetconfDocumentedException( errorMessage, null,
+                                                                        ErrorType.protocol,
+                                                                        ErrorTag.data_exists,
+                                                                        ErrorSeverity.warning,
+                                                                        ImmutableMap.of( "foo", "bar" ) );
+
+        Document doc = ex.toXMLDocument();
+        assertNotNull( "Document is null", doc );
+
+        Node rootNode = doc.getDocumentElement();
+
+        assertEquals( "getNamespaceURI", "urn:ietf:params:xml:ns:netconf:base:1.0", rootNode.getNamespaceURI() );
+        assertEquals( "getLocalName", "rpc-reply", rootNode.getLocalName() );
+
+        Node rpcErrorNode = getNode( "/netconf:rpc-reply/netconf:rpc-error", rootNode );
+        assertNotNull( "rpc-error not found", rpcErrorNode );
+
+        Node errorTypeNode = getNode( "netconf:error-type", rpcErrorNode );
+        assertNotNull( "error-type not found", errorTypeNode );
+        assertEquals( "error-type", ErrorType.protocol.getTagValue(),
+                      errorTypeNode.getTextContent() );
+
+        Node errorTagNode = getNode( "netconf:error-tag", rpcErrorNode );
+        assertNotNull( "error-tag not found", errorTagNode );
+        assertEquals( "error-tag", ErrorTag.data_exists.getTagValue(),
+                      errorTagNode.getTextContent() );
+
+        Node errorSeverityNode = getNode( "netconf:error-severity", rpcErrorNode );
+        assertNotNull( "error-severity not found", errorSeverityNode );
+        assertEquals( "error-severity", ErrorSeverity.warning.getTagValue(),
+                      errorSeverityNode.getTextContent() );
+
+        Node errorInfoNode = getNode( "netconf:error-info/netconf:foo", rpcErrorNode );
+        assertNotNull( "foo not found", errorInfoNode );
+        assertEquals( "foo", "bar", errorInfoNode.getTextContent() );
+
+        Node errorMsgNode = getNode( "netconf:error-message", rpcErrorNode );
+        assertNotNull( "error-message not found", errorMsgNode );
+        assertEquals( "error-message", errorMessage, errorMsgNode.getTextContent() );
+
+        // Test fromXMLDocument
+
+        ex = NetconfDocumentedException.fromXMLDocument( doc );
+
+        assertNotNull( "NetconfDocumentedException is null", ex );
+        assertEquals( "getErrorSeverity", ErrorSeverity.warning, ex.getErrorSeverity() );
+        assertEquals( "getErrorTag", ErrorTag.data_exists, ex.getErrorTag() );
+        assertEquals( "getErrorType", ErrorType.protocol, ex.getErrorType() );
+        assertEquals( "getLocalizedMessage", errorMessage, ex.getLocalizedMessage() );
+        assertEquals( "getErrorInfo", ImmutableMap.of( "foo", "bar" ), ex.getErrorInfo() );
+    }
+
+    @SuppressWarnings("unchecked")
+    <T> T getNode( String xpathExp, Node node ) throws XPathExpressionException {
+        return (T)xpath.compile( xpathExp ).evaluate( node, XPathConstants.NODE );
+    }
+}
+
index eaa3589..004a22f 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.controller.netconf.nettyutil.handler.NetconfXMLToMessage
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
+public class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
     private final Collection<String> capabilities;
index bb6ea61..971ea39 100644 (file)
@@ -15,19 +15,22 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
 import java.util.Collection;
+
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpression;
+
 import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer;
 import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSessionNegotiator;
 import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 4c993ac..3b1de34 100644 (file)
@@ -11,16 +11,18 @@ package org.opendaylight.controller.netconf.client;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
+
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
 import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
index 54ad18a..4f2f65c 100644 (file)
@@ -11,16 +11,17 @@ package org.opendaylight.controller.netconf.impl;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index d5a34d1..487ffd6 100644 (file)
@@ -12,16 +12,17 @@ import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationPr
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
+
 import java.util.Set;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
@@ -31,6 +32,7 @@ import com.google.common.collect.Sets;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index bfc7df5..6e81584 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.controller.netconf.impl;
 import com.google.common.base.Optional;
 import java.io.IOException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index f312339..b7a98ba 100644 (file)
@@ -9,9 +9,9 @@
 package org.opendaylight.controller.netconf.impl.mapping.operations;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index d454543..67b782c 100644 (file)
@@ -9,7 +9,9 @@
 package org.opendaylight.controller.netconf.impl.mapping.operations;
 
 import com.google.common.base.Preconditions;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
@@ -17,7 +19,6 @@ import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index beceb8d..6db74ea 100644 (file)
@@ -10,12 +10,13 @@ package org.opendaylight.controller.netconf.impl.mapping.operations;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index b9b30a5..cccb1a3 100644 (file)
@@ -11,12 +11,12 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;\r
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;\r
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;\r
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;\r
 import org.opendaylight.controller.netconf.api.NetconfMessage;\r
 import org.opendaylight.controller.netconf.impl.NetconfServerSession;\r
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;\r
 import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;\r
 import org.opendaylight.controller.netconf.util.xml.XmlElement;\r
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;\r
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
index 22caeff..2a24ae3 100644 (file)
@@ -8,10 +8,10 @@
 package org.opendaylight.controller.netconf.impl.mapping.operations;\r
 \r
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;\r
 import org.opendaylight.controller.netconf.impl.NetconfServerSession;\r
 import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;\r
 import org.opendaylight.controller.netconf.util.xml.XmlElement;\r
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;\r
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
index ea2bb9c..c5281d0 100644 (file)
@@ -18,11 +18,13 @@ import static org.mockito.Mockito.mock;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.GlobalEventExecutor;
+
 import java.io.DataOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -40,6 +42,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicLong;
+
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -50,6 +53,7 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
@@ -68,7 +72,6 @@ import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExi
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 import org.slf4j.Logger;
index c277e20..fa78fa4 100644 (file)
@@ -8,15 +8,16 @@
 package org.opendaylight.controller.netconf.monitoring;
 
 import com.google.common.collect.Maps;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.monitoring.xml.JaxBSerializer;
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 9e287f9..1b0a34d 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.nettyutil.handler.exi;
 import java.util.List;
 
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.openexi.proc.common.EXIOptions;
 import org.w3c.dom.Document;
index d9d957c..f3b35ce 100644 (file)
@@ -59,7 +59,8 @@
             <Import-Package>com.google.common.base, com.google.common.collect, io.netty.channel,
               io.netty.util.concurrent, javax.annotation, javax.xml.namespace, javax.xml.parsers, javax.xml.transform,
               javax.xml.transform.dom, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath,
-              org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.mapping.api,
+              org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.api.xml,
+              org.opendaylight.controller.netconf.mapping.api,
               org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax,io.netty.channel.local</Import-Package>
             <Export-Package>org.opendaylight.controller.netconf.util.*</Export-Package>
           </instructions>
index 640596d..0269bcc 100644 (file)
@@ -8,9 +8,10 @@
 package org.opendaylight.controller.netconf.util;
 
 import com.google.common.base.Preconditions;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 8837c74..25e0f79 100644 (file)
@@ -11,11 +11,11 @@ package org.opendaylight.controller.netconf.util.mapping;
 import java.util.Map;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index 86b2ba1..33934d1 100644 (file)
@@ -13,9 +13,9 @@ import org.opendaylight.controller.netconf.api.NetconfMessage;
 import java.util.Set;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
index 49395d5..3e8040a 100644 (file)
@@ -10,15 +10,17 @@ package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
 import javax.annotation.Nullable;
+
 import java.util.Collection;
 import java.util.List;
 
index fdcaa2a..4c4ff2f 100644 (file)
@@ -9,14 +9,15 @@
 package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Preconditions;
+
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
+
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,12 +25,6 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.io.InputStream;
-import java.util.Map.Entry;
 
 public final class SendErrorExceptionUtil {
     private static final Logger logger = LoggerFactory.getLogger(SendErrorExceptionUtil.class);
@@ -86,56 +81,8 @@ public final class SendErrorExceptionUtil {
         }
     }
 
-    private static XPathExpression rpcErrorExpression = XMLNetconfUtil
-            .compileXPath("/netconf:rpc-reply/netconf:rpc-error");
-    private static XPathExpression errorTypeExpression = XMLNetconfUtil.compileXPath("netconf:error-type");
-    private static XPathExpression errorTagExpression = XMLNetconfUtil.compileXPath("netconf:error-tag");
-    private static XPathExpression errorSeverityExpression = XMLNetconfUtil.compileXPath("netconf:error-severity");
-
     private static Document createDocument(final NetconfDocumentedException sendErrorException) {
-
-        final InputStream errIS = SendErrorExceptionUtil.class.getResourceAsStream("server_error.xml");
-        Document originalErrorDocument;
-        try {
-            originalErrorDocument = XmlUtil.readXmlToDocument(errIS);
-        } catch (final Exception e) {
-            throw new IllegalStateException(e);
-        }
-
-        final Document errorDocument = XmlUtil.createDocumentCopy(originalErrorDocument);
-        final Node rootNode = errorDocument.getFirstChild();
-
-        final Node rpcErrorNode = (Node) XmlUtil.evaluateXPath(rpcErrorExpression, rootNode, XPathConstants.NODE);
-
-        final Node errorTypeNode = (Node) XmlUtil.evaluateXPath(errorTypeExpression, rpcErrorNode, XPathConstants.NODE);
-        errorTypeNode.setTextContent(sendErrorException.getErrorType().getTagValue());
-
-        final Node errorTagNode = (Node) XmlUtil.evaluateXPath(errorTagExpression, rpcErrorNode, XPathConstants.NODE);
-        errorTagNode.setTextContent(sendErrorException.getErrorTag().getTagValue());
-
-        final Node errorSeverityNode = (Node) XmlUtil.evaluateXPath(errorSeverityExpression, rpcErrorNode,
-                XPathConstants.NODE);
-        errorSeverityNode.setTextContent(sendErrorException.getErrorSeverity().getTagValue());
-
-        if (sendErrorException.getErrorInfo() != null && !sendErrorException.getErrorInfo().isEmpty()) {
-            /*
-             * <error-info> <bad-attribute>message-id</bad-attribute>
-             * <bad-element>rpc</bad-element> </error-info>
-             */
-            final Node errorInfoNode = errorDocument.createElementNS(
-                    XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, "error-info");
-
-            errorInfoNode.setPrefix(rootNode.getPrefix());
-            rpcErrorNode.appendChild(errorInfoNode);
-            for (final Entry<String, String> errorInfoEntry : sendErrorException.getErrorInfo().entrySet()) {
-                final Node node = errorDocument.createElementNS(
-                        XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, errorInfoEntry.getKey());
-                node.setTextContent(errorInfoEntry.getValue());
-                errorInfoNode.appendChild(node);
-            }
-
-        }
-        return errorDocument;
+        return sendErrorException.toXMLDocument();
     }
 
     /**
index 02ced96..e7ce454 100644 (file)
@@ -13,6 +13,8 @@ import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+
 public final class XMLNetconfUtil {
 
     private XMLNetconfUtil() {}
index b2b202b..01b1c8d 100644 (file)
@@ -10,12 +10,14 @@ package org.opendaylight.controller.netconf.util.xml;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Optional;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
+
 import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
 import javax.xml.parsers.DocumentBuilder;
@@ -33,6 +35,8 @@ import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
+
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.