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;
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;
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) {
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,
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
}
}
- 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 );
}
}
});
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;
}
}
}
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;
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;
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;
}
}
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;
--- /dev/null
+/*
+ * 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;
+ }
+}
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 {
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
import javax.management.ObjectName;
import javax.management.openmbean.OpenType;
+
import java.util.Map;
public class RuntimeRpc extends AbstractConfigNetconfOperation {
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;
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;
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;
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;
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;
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;
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;
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;
<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,
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>
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
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;
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;
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 {
public String getTagValue() {
return name();
}
+
+ public static ErrorSeverity from( String text ) {
+ try {
+ return valueOf( text );
+ }
+ catch( Exception e ) {
+ return error;
+ }
+ }
}
private final ErrorType errorType;
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;
}
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
* 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 {
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";
--- /dev/null
+/*
+ * 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 );
+ }
+}
+
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;
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;
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;
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;
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;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
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;
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;
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;
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;
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
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
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;
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;
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;
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;
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;
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;
<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>
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;
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;
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;
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;
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;
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);
}
}
- 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();
}
/**
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+
public final class XMLNetconfUtil {
private XMLNetconfUtil() {}
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;
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;