checkForError(document);
document.getDocumentElement().setAttribute(XmlNetconfConstants.MESSAGE_ID, msgId);
return document;
- } else if (subsequentOperation.isExecutionTermination()) {
+ } else if (subsequentOperation != null) {
+ return subsequentOperation.execute(requestMessage);
+ } else {
throw new DocumentedException("Mapping not found " + XmlUtil.toString(requestMessage),
ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
- } else {
- return subsequentOperation.execute(requestMessage);
}
}
@Override
public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation)
throws DocumentedException {
- if (subsequentOperation.isExecutionTermination()) {
+ if (subsequentOperation == null) {
throw new DocumentedException(String.format("Subsequent netconf operation expected by %s", this),
ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, ErrorSeverity.ERROR);
}
checkForError(document);
document.getDocumentElement().setAttribute(XmlNetconfConstants.MESSAGE_ID, msgId);
return document;
- } else if (subsequentOperation.isExecutionTermination()) {
- throw new DocumentedException("Mapping not found " + XmlUtil.toString(requestMessage),
- ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
- } else {
+ } else if (subsequentOperation != null) {
return subsequentOperation.execute(requestMessage);
+ } else {
+ throw new DocumentedException("Mapping not found " + XmlUtil.toString(requestMessage),
+ ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
}
}
import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStoreFactory;
import org.opendaylight.netconf.api.xml.XmlUtil;
import org.opendaylight.netconf.server.api.operations.NetconfOperation;
-import org.opendaylight.netconf.server.api.operations.NetconfOperationChainedExecution;
import org.opendaylight.netconf.server.mdsal.CurrentSchemaContext;
import org.opendaylight.netconf.server.mdsal.TransactionProvider;
import org.opendaylight.netconf.test.util.NetconfXmlUnitRecursiveQualifier;
}
protected static Document executeOperation(final NetconfOperation op, final Document request) throws Exception {
- final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+ final Document response = op.handle(request, null);
LOG.debug("Got response {}", response);
return response;
}
import org.opendaylight.netconf.api.DocumentedException;
import org.opendaylight.netconf.api.xml.XmlUtil;
import org.opendaylight.netconf.server.api.operations.HandlingPriority;
-import org.opendaylight.netconf.server.api.operations.NetconfOperationChainedExecution;
import org.opendaylight.netconf.server.mdsal.CurrentSchemaContext;
import org.opendaylight.netconf.test.util.XmlFileLoader;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
final HandlingPriority priority = rpc.canHandle(rpcDocument);
assertNotNull(priority);
- final Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+ final Document response = rpc.handle(rpcDocument, null);
verifyResponse(response, RPC_REPLY_OK);
}
final HandlingPriority priority = rpc.canHandle(rpcDocument);
assertNotNull(priority);
- final Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+ final Document response = rpc.handle(rpcDocument, null);
verifyResponse(response, XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-nonvoid-control.xml"));
}
final HandlingPriority priority = rpc.canHandle(rpcDocument);
assertNotNull(priority);
- final Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+ final Document response = rpc.handle(rpcDocument, null);
verifyResponse(response, XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-container-control.xml"));
}
final HandlingPriority priority = rpc.canHandle(rpcDocument);
assertNotNull(priority);
- final DocumentedException e = assertThrows(DocumentedException.class,
- () -> rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT));
+ final DocumentedException e = assertThrows(DocumentedException.class, () -> rpc.handle(rpcDocument, null));
assertEquals(e.getErrorSeverity(), ErrorSeverity.ERROR);
assertEquals(e.getErrorTag(), ErrorTag.OPERATION_FAILED);
final HandlingPriority priority = rpc.canHandle(rpcDocument);
assertNotNull(priority);
- final Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+ final Document response = rpc.handle(rpcDocument, null);
verifyResponse(response, RPC_REPLY_OK);
}
final RuntimeRpc rpc = new RuntimeRpc(SESSION_ID_FOR_REPORTING, currentSchemaContext, RPC_SERVICE_VOID_INVOKER);
final Document rpcDocument = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-bad-namespace.xml");
- final DocumentedException e = assertThrows(DocumentedException.class,
- () -> rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT));
+ final DocumentedException e = assertThrows(DocumentedException.class, () -> rpc.handle(rpcDocument, null));
assertEquals(e.getErrorSeverity(), ErrorSeverity.ERROR);
assertEquals(e.getErrorTag(), ErrorTag.BAD_ELEMENT);
@Override
protected Element handle(final Document document, final XmlElement operationElement,
final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
- if (!subsequentOperation.isExecutionTermination()) {
- throw new DocumentedException(String.format(
- "No netconf operation expected to be subsequent to %s, but is %s", this, subsequentOperation),
- ErrorType.APPLICATION, ErrorTag.MALFORMED_MESSAGE, ErrorSeverity.ERROR);
+ if (subsequentOperation != null) {
+ throw new DocumentedException(
+ "No netconf operation expected to be subsequent to %s, but is %s".formatted(this, subsequentOperation),
+ ErrorType.APPLICATION, ErrorTag.MALFORMED_MESSAGE, ErrorSeverity.ERROR);
}
-
return handleWithNoSubsequentOperations(document, operationElement);
}
import static java.util.Objects.requireNonNull;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.netconf.api.DocumentedException;
import org.opendaylight.netconf.api.NamespaceURN;
import org.opendaylight.netconf.api.messages.RpcMessage;
protected abstract String getOperationName();
@Override
- public Document handle(final Document requestMessage,
- final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
+ public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation)
+ throws DocumentedException {
final var requestElement = getRequestElementWithCheck(requestMessage);
final var document = XmlUtil.newDocument();
final var operationElement = requestElement.getOnlyChildElement();
}
protected abstract Element handle(Document document, XmlElement message,
- NetconfOperationChainedExecution subsequentOperation)
- throws DocumentedException;
+ @Nullable NetconfOperationChainedExecution subsequentOperation) throws DocumentedException;
@Override
public String toString() {
@Nullable HandlingPriority canHandle(Document message) throws DocumentedException;
/**
- * Execute current netconf operation and trigger execution of subsequent
- * operations. subsequentOperation parameter will provide information, if
- * current operation is the termination point in execution. In case of
- * last/singleton operation, subsequentOperation must indicate termination
- * point.
+ * Execute current netconf operation and trigger execution of subsequent operations, if applicable.
*
* @param requestMessage request message
- * @param subsequentOperation execution of subsequent netconf operation
+ * @param subsequentOperation execution of subsequent NETCONF operation, or {@code null}
* @return {@code document}
* @throws DocumentedException if operation fails
*/
- Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation)
+ Document handle(Document requestMessage, @Nullable NetconfOperationChainedExecution subsequentOperation)
throws DocumentedException;
}
import org.w3c.dom.Document;
/**
- * Single link in netconf operation execution chain.
- * Wraps the execution of a single netconf operation.
+ * Single link in netconf operation execution chain. Wraps the execution of a single netconf operation.
*/
public interface NetconfOperationChainedExecution {
- /**
- * Check if this is termination point in operation execution.
- *
- * @return true if this is termination point in operation execution, false
- * if there is a subsequent operation present that needs to be
- * executed.
- */
- boolean isExecutionTermination();
- /**
- * Do not execute if this is termination point.
- */
Document execute(Document requestMessage) throws DocumentedException;
-
- NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() {
- @Override
- public boolean isExecutionTermination() {
- return true;
- }
-
- @Override
- public Document execute(final Document requestMessage) {
- throw new IllegalStateException("This execution represents the termination point in operation execution "
- + "and cannot be executed itself");
- }
- };
}
}
@Override
- public Document handle(final Document message,
- final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
+ public Document handle(final Document message, final NetconfOperationChainedExecution subsequentOperation)
+ throws DocumentedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Received start-exi message {} ", XmlUtil.toString(message));
}
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document,
- final XmlElement operationElement) {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) {
final Element getSchemaResult = document.createElementNS(NamespaceURN.BASE, XmlNetconfConstants.OK);
LOG.trace("{} operation successful", START_EXI);
return getSchemaResult;
this.subsequentExecution = subsequentExecution;
}
- @Override
- public boolean isExecutionTermination() {
- return false;
- }
-
@Override
public Document execute(final Document message) throws DocumentedException {
return netconfOperation.handle(message, subsequentExecution);
final NetconfOperation netconfOperation = sortedByPriority.get(handlingPriority);
final HandlingPriority subsequentHandlingPriority = sortedByPriority.lowerKey(handlingPriority);
- NetconfOperationChainedExecution subsequentExecution = null;
-
- if (subsequentHandlingPriority != null) {
- subsequentExecution = createExecutionChain(sortedByPriority, subsequentHandlingPriority);
- } else {
- subsequentExecution = EXECUTION_TERMINATION_POINT;
- }
-
- return new NetconfOperationExecution(netconfOperation, subsequentExecution);
+ return new NetconfOperationExecution(netconfOperation, subsequentHandlingPriority == null ? null
+ : createExecutionChain(sortedByPriority, subsequentHandlingPriority));
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
@ExtendWith(MockitoExtension.class)
class ConcurrentClientsTest {
? null : HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
}
- @SuppressWarnings("checkstyle:IllegalCatch")
@Override
public Document handle(final Document requestMessage,
final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
counter.getAndIncrement();
try {
return XmlUtil.readXmlToDocument("<test/>");
- } catch (Exception e) {
+ } catch (IOException | SAXException e) {
throw new RuntimeException(e);
}
}
@Test
void testHandle() {
- NetconfOperationChainedExecution operation = mock(NetconfOperationChainedExecution.class);
+ final var operation = mock(NetconfOperationChainedExecution.class);
doReturn("").when(operation).toString();
- doReturn(false).when(operation).isExecutionTermination();
assertThrows(DocumentedException.class, () -> netconfOperation.handle(null, null, operation));
}
}
package org.opendaylight.netconf.server.osgi;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
void testOnNetconfMessage() throws Exception {
doReturn(HandlingPriority.HANDLE_WITH_MAX_PRIORITY).when(maxPrioMock).canHandle(any(Document.class));
doReturn(XmlUtil.readXmlToDocument(MAX_PRIORITY_REPLY)).when(maxPrioMock).handle(any(Document.class),
- any(NetconfOperationChainedExecution.class));
+ any());
doReturn(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY).when(defaultPrioMock).canHandle(any(Document.class));
doReturn(XmlUtil.readXmlToDocument(DEFAULT_PRIORITY_REPLY)).when(defaultPrioMock).handle(any(Document.class),
- any(NetconfOperationChainedExecution.class));
- final ArgumentCaptor<NetconfOperationChainedExecution> highPriorityChainEx =
- ArgumentCaptor.forClass(NetconfOperationChainedExecution.class);
- final ArgumentCaptor<NetconfOperationChainedExecution> defaultPriorityChainEx =
- ArgumentCaptor.forClass(NetconfOperationChainedExecution.class);
+ isNull());
+ final var highPriorityChainEx = ArgumentCaptor.forClass(NetconfOperationChainedExecution.class);
- final Document document = operationRouter.onNetconfMessage(TEST_RPC_DOC, null);
+ final var document = operationRouter.onNetconfMessage(TEST_RPC_DOC, null);
//max priority message is first in chain
verify(maxPrioMock).handle(any(Document.class), highPriorityChainEx.capture());
- final NetconfOperationChainedExecution chainedExecution = highPriorityChainEx.getValue();
- assertFalse(chainedExecution.isExecutionTermination());
+ final var chainedExecution = highPriorityChainEx.getValue();
+ assertNotNull(chainedExecution);
//execute next in chain
- final Document execute = chainedExecution.execute(XmlUtil.newDocument());
+ final var execute = chainedExecution.execute(XmlUtil.newDocument());
assertEquals(DEFAULT_PRIORITY_REPLY, XmlUtil.toString(execute).trim());
//default priority message is second and last
- verify(defaultPrioMock).handle(any(Document.class), defaultPriorityChainEx.capture());
- assertTrue(defaultPriorityChainEx.getValue().isExecutionTermination());
+ verify(defaultPrioMock).handle(any(Document.class), isNull());
assertEquals(MAX_PRIORITY_REPLY, XmlUtil.toString(document).trim());
}
@Test
void testOnNetconfMessageFail() {
- final DocumentedException ex = assertThrows(DocumentedException.class,
+ final var ex = assertThrows(DocumentedException.class,
() -> emptyOperationRouter.onNetconfMessage(TEST_RPC_DOC, null));
assertEquals(ErrorTag.OPERATION_NOT_SUPPORTED, ex.getErrorTag());
}