package org.opendaylight.controller.netconf.confignetconfconnector.operations;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
-public abstract class AbstractConfigNetconfOperation extends AbstractNetconfOperation {
+public abstract class AbstractConfigNetconfOperation extends AbstractLastNetconfOperation {
protected final ConfigRegistryClient configRegistryClient;
super(netconfSessionIdForReporting);
this.configRegistryClient = configRegistryClient;
}
-
- @Override
- protected HandlingPriority canHandle(String operationName, String operationNamespace) {
- // TODO check namespace
- return operationName.equals(getOperationName()) ? HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY
- : HandlingPriority.CANNOT_HANDLE;
- }
-
- protected abstract String getOperationName();
-
- @Override
- protected Element handle(Document document, XmlElement operationElement, NetconfOperationRouter opRouter)
- throws NetconfDocumentedException {
- return handle(document, operationElement);
- }
-
- protected abstract Element handle(Document document, XmlElement operationElement) throws NetconfDocumentedException;
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
+import java.util.HashMap;
+import java.util.Map;
+
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.HashMap;
-import java.util.Map;
-
public class Commit extends AbstractConfigNetconfOperation {
private static final Logger logger = LoggerFactory.getLogger(Commit.class);
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
checkXml(xml);
CommitStatus status;
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
+import java.util.HashMap;
+import java.util.Map;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.HashMap;
-import java.util.Map;
-
public class DiscardChanges extends AbstractConfigNetconfOperation {
public static final String DISCARD = "discard-changes";
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
try {
fromXml(xml);
} catch (final IllegalArgumentException e) {
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
-import com.google.common.base.Preconditions;
+import java.util.HashMap;
+import java.util.Map;
+
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.HashMap;
-import java.util.Map;
+import com.google.common.base.Preconditions;
public class Validate extends AbstractConfigNetconfOperation {
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
try {
checkXml(xml);
} catch (IllegalStateException e) {
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import com.google.common.annotations.VisibleForTesting;
-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.Map.Entry;
+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.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
public class EditConfig extends AbstractConfigNetconfOperation {
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
EditConfigXmlParser.EditConfigExecution editConfigExecution;
Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot);
package org.opendaylight.controller.netconf.confignetconfconnector.operations.get;
-import com.google.common.collect.Maps;
+import java.util.HashMap;
+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.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.management.ObjectName;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.collect.Maps;
public class Get extends AbstractConfigNetconfOperation {
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
try {
checkXml(xml);
} catch (final IllegalArgumentException e) {
package org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig;
-import com.google.common.base.Optional;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.ObjectName;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.management.ObjectName;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.base.Optional;
public class GetConfig extends AbstractConfigNetconfOperation {
}
@Override
- public Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ public Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
Datastore source;
try {
source = fromXml(xml);
package org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
+import java.util.Map;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.OpenType;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.management.ObjectName;
-import javax.management.openmbean.OpenType;
-import java.util.Map;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
public class RuntimeRpc extends AbstractConfigNetconfOperation {
}
@Override
- protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
// TODO exception handling
// TODO check for namespaces and unknown elements
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.yangtools.yang.model.api.Module;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
/**
* Manages life cycle of {@link YangStoreSnapshot}.
return operationProvider.getOperations();
}
- @Override
- public Set<NetconfOperationFilter> getFilters() {
- return Collections.emptySet();
- }
-
private static Set<Capability> setupCapabilities(YangStoreSnapshot yangStoreSnapshot) {
Set<Capability> capabilities = new HashSet<>();
// [RFC6241] 8.3. Candidate Configuration Capability
package org.opendaylight.controller.netconf.confignetconfconnector;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Ignore;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
public class NetconfMappingTest extends AbstractConfigTest {
YangStoreSnapshot yangStoreSnapshot;
@Mock
NetconfOperationRouter netconfOperationRouter;
+ @Mock
+ NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
private TransactionProvider transactionProvider;
MockitoAnnotations.initMocks(this);
doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
+ doNothing().when(netconfOperationServiceSnapshot).close();
this.factory = new NetconfTestImplModuleFactory();
this.factory2 = new DepTestImplModuleFactory();
assertEquals(expectedResult, responseFromCandidate);
edit("netconfMessages/editConfig_none.xml");
- doNothing().when(netconfOperationRouter).close();
closeSession();
- verify(netconfOperationRouter).close();
+ verify(netconfOperationServiceSnapshot).close();
verifyNoMoreInteractions(netconfOperationRouter);
+ verifyNoMoreInteractions(netconfOperationServiceSnapshot);
}
private void checkBigDecimal(Element response) {
private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
IOException {
- DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID);
+ DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID, netconfOperationServiceSnapshot);
executeOp(closeOp, "netconfMessages/closeSession.xml");
}
Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE);
- final Document response = op.handle(request, netconfOperationRouter);
+ final Document response = op.handle(request, NetconfOperationRouterImpl.EXECUTION_TERMINATION_POINT);
logger.debug("Got response\n{}", XmlUtil.toString(response));
return response.getDocumentElement();
}
public void test() throws Exception {
final XmlElement xml = XmlElement.fromString("<abc></abc>");
final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test(expected = NetconfDocumentedException.class)
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 + "\"/>");
final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test(expected = NetconfDocumentedException.class)
public void testNoNamespace() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate/>");
final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test(expected = NetconfDocumentedException.class)
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0
+ "\"><source><running></running></source></validate>");
final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test(expected = NetconfDocumentedException.class)
final TransactionProvider transactionProvider = mock(TransactionProvider.class);
doThrow(IllegalStateException.class).when(transactionProvider).validateTransaction();
final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test(expected = NetconfDocumentedException.class)
final TransactionProvider transactionProvider = mock(TransactionProvider.class);
doThrow(ValidationException.class).when(transactionProvider).validateTransaction();
final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
- validate.handle(null, xml);
+ validate.handleWithNoSubsequentOperations(null, xml);
}
@Test
final Element okElement = XmlUtil.readXmlToElement("<ok/>");
doNothing().when(transactionProvider).validateTransaction();
final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
- Element ok = validate.handle(XmlUtil.newDocument(), xml);
+ Element ok = validate.handleWithNoSubsequentOperations(XmlUtil.newDocument(), xml);
assertEquals(XmlUtil.toString(okElement), XmlUtil.toString(ok));
}
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.api.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class);
private final SessionMonitoringService monitoringService;
- private final NetconfOperationRouterImpl operationRouter;
+ private final NetconfOperationRouter operationRouter;
- public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, SessionMonitoringService monitoringService) {
+ public NetconfServerSessionListener(NetconfOperationRouter operationRouter, SessionMonitoringService monitoringService) {
this.operationRouter = operationRouter;
this.monitoringService = monitoringService;
}
package org.opendaylight.controller.netconf.impl;
+import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
- NetconfOperationRouterImpl operationRouter = new NetconfOperationRouterImpl(
+ NetconfOperationRouter operationRouter = NetconfOperationRouterImpl.createOperationRouter(
netconfOperationServiceSnapshot, capabilityProvider,
commitNotifier);
package org.opendaylight.controller.netconf.impl.mapping.operations;
+import java.util.Collections;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
+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.w3c.dom.Document;
import org.w3c.dom.Element;
-public class DefaultCloseSession extends AbstractNetconfOperation {
+public class DefaultCloseSession extends AbstractSingletonNetconfOperation {
public static final String CLOSE_SESSION = "close-session";
+ private final AutoCloseable sessionResources;
- public DefaultCloseSession(String netconfSessionIdForReporting) {
+ public DefaultCloseSession(String netconfSessionIdForReporting, AutoCloseable sessionResources) {
super(netconfSessionIdForReporting);
+ this.sessionResources = sessionResources;
}
@Override
- protected HandlingPriority canHandle(String operationName, String netconfOperationNamespace) {
- if (operationName.equals(CLOSE_SESSION) == false)
- return HandlingPriority.CANNOT_HANDLE;
- if (netconfOperationNamespace.equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0) == false)
- return HandlingPriority.CANNOT_HANDLE;
-
- return HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
+ protected String getOperationName() {
+ return CLOSE_SESSION;
}
/**
* instances
*/
@Override
- protected Element handle(Document document, XmlElement operationElement, NetconfOperationRouter opRouter)
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement)
throws NetconfDocumentedException {
- opRouter.close();
+ try {
+ sessionResources.close();
+ } catch (Exception e) {
+ throw new NetconfDocumentedException("Unable to properly close session "
+ + getNetconfSessionIdForReporting(), NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.operation_failed,
+ NetconfDocumentedException.ErrorSeverity.error, Collections.singletonMap(
+ NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
+ }
return document.createElement(XmlNetconfConstants.OK);
}
}
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
-public class DefaultCommit implements NetconfOperationFilter {
+public class DefaultCommit extends AbstractNetconfOperation {
private static final Logger logger = LoggerFactory.getLogger(DefaultCommit.class);
private final DefaultCommitNotificationProducer notificationProducer;
private final CapabilityProvider cap;
- private final String netconfSessionIdForReporting;
+ private final NetconfOperationRouter operationRouter;
public DefaultCommit(DefaultCommitNotificationProducer notifier, CapabilityProvider cap,
- String netconfSessionIdForReporting) {
+ String netconfSessionIdForReporting, NetconfOperationRouter netconfOperationRouter) {
+ super(netconfSessionIdForReporting);
this.notificationProducer = notifier;
this.cap = cap;
- this.netconfSessionIdForReporting = netconfSessionIdForReporting;
+ this.operationRouter = netconfOperationRouter;
this.getConfigMessage = loadGetConfigMessage();
}
}
@Override
- public Document doFilter(Document message, NetconfOperationRouter operationRouter,
- NetconfOperationFilterChain filterChain) throws NetconfDocumentedException {
- OperationNameAndNamespace operationNameAndNamespace = new OperationNameAndNamespace(message);
- if (canHandle(operationNameAndNamespace)) {
- if (isCommitWithoutNotification(message)) {
- message = removePersisterAttributes(message);
- logger.debug("Skipping commit notification");
- // fall back to filter chain
- } else {
- Document innerResult = filterChain.execute(message, operationRouter);
- Element cfgSnapshot = getConfigSnapshot(operationRouter);
- logger.debug("Config snapshot retrieved successfully {}", cfgSnapshot);
- notificationProducer.sendCommitNotification("ok", cfgSnapshot, cap.getCapabilities());
- return innerResult;
- }
- }
- return filterChain.execute(message, operationRouter);
+ protected String getOperationName() {
+ return XmlNetconfConstants.COMMIT;
}
@Override
- public int getSortingOrder() {
- return 0;
+ public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ Preconditions.checkArgument(subsequentOperation.isExecutionTermination() == false,
+ "Subsequent netconf operation expected by %s", this);
+
+ if (isCommitWithoutNotification(requestMessage)) {
+ logger.debug("Skipping commit notification");
+ } else {
+ // Send commit notification if commit was not issued by persister
+ requestMessage = removePersisterAttributes(requestMessage);
+ Element cfgSnapshot = getConfigSnapshot(operationRouter);
+ logger.debug("Config snapshot retrieved successfully {}", cfgSnapshot);
+ notificationProducer.sendCommitNotification("ok", cfgSnapshot, cap.getCapabilities());
+ }
+
+ return subsequentOperation.execute(requestMessage);
}
@Override
- public int compareTo(NetconfOperationFilter o) {
- return Integer.compare(getSortingOrder(), o.getSortingOrder());
+ protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ throw new UnsupportedOperationException("Never gets called");
}
- private boolean canHandle(OperationNameAndNamespace operationNameAndNamespace) {
- if (operationNameAndNamespace.getOperationName().equals("commit") == false)
- return false;
- return operationNameAndNamespace.getNamespace().equals(
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ @Override
+ protected HandlingPriority getHandlingPriority() {
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.increasePriority(1);
}
private Document removePersisterAttributes(Document message) {
return dataElement.getDomElement();
}
- @Override
- public String toString() {
- return "DefaultCommit{" + netconfSessionIdForReporting + '}';
- }
}
import java.util.Map;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
+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 com.google.common.base.Optional;
import com.google.common.collect.Maps;
-public final class DefaultGetSchema extends AbstractNetconfOperation {
+public final class DefaultGetSchema extends AbstractLastNetconfOperation {
public static final String GET_SCHEMA = "get-schema";
public static final String IDENTIFIER = "identifier";
public static final String VERSION = "version";
}
@Override
- protected HandlingPriority canHandle(String netconfOperationName, String namespace) {
- if (netconfOperationName.equals("get-schema") == false)
- return HandlingPriority.CANNOT_HANDLE;
- if (namespace.equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING) == false)
- return HandlingPriority.CANNOT_HANDLE;
+ protected String getOperationName() {
+ return GET_SCHEMA;
+ }
- return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
+ @Override
+ protected String getOperationNamespace() {
+ return XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING;
}
@Override
- protected Element handle(Document document, XmlElement xml, NetconfOperationRouter router)
- throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
GetSchemaEntry entry;
try {
*/\r
package org.opendaylight.controller.netconf.impl.mapping.operations;\r
\r
-import org.opendaylight.controller.netconf.api.NetconfSession;\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;\r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;\r
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;\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.w3c.dom.Document;\r
import org.w3c.dom.Element;\r
\r
-public class DefaultStartExi extends AbstractNetconfOperation implements DefaultNetconfOperation {\r
+public class DefaultStartExi extends AbstractSingletonNetconfOperation implements DefaultNetconfOperation {\r
\r
public static final String START_EXI = "start-exi";\r
\r
}\r
\r
@Override\r
- protected HandlingPriority canHandle(String operationName,\r
- String netconfOperationNamespace) {\r
- if (operationName.equals(START_EXI) == false)\r
- return HandlingPriority.CANNOT_HANDLE;\r
- if (netconfOperationNamespace\r
- .equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0) == false)\r
- return HandlingPriority.CANNOT_HANDLE;\r
-\r
- return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;\r
+ protected String getOperationName() {\r
+ return START_EXI;\r
}\r
\r
@Override\r
- protected Element handle(Document document, XmlElement operationElement,\r
- NetconfOperationRouter opRouter) throws NetconfDocumentedException {\r
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {\r
\r
\r
Element getSchemaResult = document\r
*/\r
package org.opendaylight.controller.netconf.impl.mapping.operations;\r
\r
-import org.opendaylight.controller.netconf.api.NetconfSession;\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;\r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;\r
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;\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.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
import org.w3c.dom.Document;\r
import org.w3c.dom.Element;\r
\r
-public class DefaultStopExi extends AbstractNetconfOperation implements DefaultNetconfOperation {\r
+public class DefaultStopExi extends AbstractSingletonNetconfOperation implements DefaultNetconfOperation {\r
\r
public static final String STOP_EXI = "stop-exi";\r
private NetconfSession netconfSession;\r
}\r
\r
@Override\r
- protected HandlingPriority canHandle(String operationName,\r
- String netconfOperationNamespace) {\r
- if (operationName.equals(STOP_EXI) == false)\r
- return HandlingPriority.CANNOT_HANDLE;\r
- if (netconfOperationNamespace\r
- .equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0) == false)\r
- return HandlingPriority.CANNOT_HANDLE;\r
-\r
- return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;\r
+ protected String getOperationName() {\r
+ return STOP_EXI;\r
}\r
\r
@Override\r
- protected Element handle(Document document, XmlElement operationElement,\r
- NetconfOperationRouter opRouter) throws NetconfDocumentedException {\r
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement)\r
+ throws NetconfDocumentedException {\r
throw new UnsupportedOperationException("Not implemented");\r
/*\r
netconfSession.remove(ExiDecoderHandler.class);\r
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import java.util.TreeSet;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
private static final Logger logger = LoggerFactory.getLogger(NetconfOperationRouterImpl.class);
private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
+ private Set<NetconfOperation> allNetconfOperations;
- private final Set<NetconfOperation> allNetconfOperations;
- private final TreeSet<NetconfOperationFilter> allSortedFilters;
-
- private final CapabilityProvider capabilityProvider;
+ private NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
+ this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
+ }
+ private void initNetconfOperations(Set<NetconfOperation> allOperations) {
+ allNetconfOperations = allOperations;
+ }
- public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
- CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
+ /**
+ * Factory method to produce instance of NetconfOperationRouter
+ */
+ public static NetconfOperationRouter createOperationRouter(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
+ CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
+ NetconfOperationRouterImpl router = new NetconfOperationRouterImpl(netconfOperationServiceSnapshot);
- this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
- this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider);
+ Preconditions.checkNotNull(netconfOperationServiceSnapshot);
+ Preconditions.checkNotNull(capabilityProvider);
final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
+
final Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId));
- defaultNetconfOperations.add(new DefaultCloseSession(sessionId));
+ defaultNetconfOperations.add(new DefaultCloseSession(sessionId, router));
defaultNetconfOperations.add(new DefaultStartExi(sessionId));
defaultNetconfOperations.add(new DefaultStopExi(sessionId));
+ defaultNetconfOperations.add(new DefaultCommit(commitNotifier, capabilityProvider, sessionId, router));
- allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
+ router.initNetconfOperations(getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot));
- DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId);
- Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
- allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
+ return router;
}
private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
return Collections.unmodifiableSet(result);
}
- private static TreeSet<NetconfOperationFilter> getAllNetconfFilters(Set<NetconfOperationFilter> defaultFilters,
- NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
- TreeSet<NetconfOperationFilter> result = new TreeSet<>(defaultFilters);
- for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
- final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
- for (NetconfOperationFilter filter : filtersFromService) {
- Preconditions.checkState(result.contains(filter) == false,
- "Filter %s already present, all filters so far: %s", filter, result);
- result.add(filter);
- }
- }
- return result;
- }
-
- public CapabilityProvider getCapabilityProvider() {
- return capabilityProvider;
- }
-
@Override
public synchronized Document onNetconfMessage(Document message,
NetconfSession session) throws NetconfDocumentedException {
- NetconfOperationExecution netconfOperationExecution;
+ Preconditions.checkNotNull(allNetconfOperations, "Operation router was not initialized properly");
+ NetconfOperationExecution netconfOperationExecution;
String messageAsString = XmlUtil.toString(message);
try {
}
}
+ @Override
+ public void close() {
+ netconfOperationServiceSnapshot.close();
+ }
+
private NetconfDocumentedException handleUnexpectedEx(String s, Exception e) throws NetconfDocumentedException {
logger.error(s, e);
NetconfDocumentedException.ErrorSeverity.error, info);
}
- private Document executeOperationWithHighestPriority(Document message, NetconfOperationExecution netconfOperationExecution, String messageAsString) throws NetconfDocumentedException {
- logger.debug("Forwarding netconf message {} to {}", messageAsString,
- netconfOperationExecution.operationWithHighestPriority);
-
- final LinkedList<NetconfOperationFilterChain> chain = new LinkedList<>();
- chain.push(netconfOperationExecution);
-
- for (Iterator<NetconfOperationFilter> it = allSortedFilters.descendingIterator(); it.hasNext();) {
- final NetconfOperationFilter filter = it.next();
- final NetconfOperationFilterChain prevItem = chain.getFirst();
- NetconfOperationFilterChain currentItem = new NetconfOperationFilterChain() {
- @Override
- public Document execute(Document message, NetconfOperationRouter operationRouter)
- throws NetconfDocumentedException {
- logger.trace("Entering {}", filter);
- return filter.doFilter(message, operationRouter, prevItem);
- }
- };
- chain.push(currentItem);
- }
- return chain.getFirst().execute(message, this);
+ private Document executeOperationWithHighestPriority(Document message,
+ NetconfOperationExecution netconfOperationExecution, String messageAsString)
+ throws NetconfDocumentedException {
+ logger.debug("Forwarding netconf message {} to {}", messageAsString, netconfOperationExecution.netconfOperation);
+ return netconfOperationExecution.execute(message);
}
private NetconfOperationExecution getNetconfOperationWithHighestPriority(
Document message, NetconfSession session) {
- TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
+ TreeMap<HandlingPriority, NetconfOperation> sortedByPriority = getSortedNetconfOperationsWithCanHandle(
message, session);
- Preconditions.checkArgument(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
- NetconfOperation.class.getName(), XmlUtil.toString(message));
-
- HandlingPriority highestFoundPriority = sortedPriority.lastKey();
-
- int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
-
- Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
- "Multiple %s available to handle message %s", NetconfOperation.class.getName(), message);
+ Preconditions.checkArgument(sortedByPriority.isEmpty() == false,
+ "No %s available to handleWithNoSubsequentOperations message %s", NetconfOperation.class.getName(),
+ XmlUtil.toString(message));
- return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
+ return NetconfOperationExecution.createExecutionChain(sortedByPriority, sortedByPriority.lastKey());
}
- private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(
- Document message, NetconfSession session) {
- TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
+ private TreeMap<HandlingPriority, NetconfOperation> getSortedNetconfOperationsWithCanHandle(Document message,
+ NetconfSession session) {
+ TreeMap<HandlingPriority, NetconfOperation> sortedPriority = Maps.newTreeMap();
for (NetconfOperation netconfOperation : allNetconfOperations) {
final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
if (netconfOperation instanceof DefaultNetconfOperation) {
- ((DefaultNetconfOperation) netconfOperation)
- .setNetconfSession(session);
+ ((DefaultNetconfOperation) netconfOperation).setNetconfSession(session);
}
if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
- Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
- netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
- netconfOperations.add(netconfOperation);
+
+ Preconditions.checkState(sortedPriority.containsKey(handlingPriority) == false,
+ "Multiple %s available to handle message %s with priority %s",
+ NetconfOperation.class.getName(), message, handlingPriority);
+ sortedPriority.put(handlingPriority, netconfOperation);
}
}
return sortedPriority;
}
- private Set<NetconfOperation> checkIfNoOperationsOnPriority(
- TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority, HandlingPriority handlingPriority,
- Set<NetconfOperation> netconfOperations) {
- if (netconfOperations == null) {
- netconfOperations = Sets.newHashSet();
- sortedPriority.put(handlingPriority, netconfOperations);
+ public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() {
+ @Override
+ public boolean isExecutionTermination() {
+ return true;
}
- return netconfOperations;
- }
- @Override
- public void close() {
- netconfOperationServiceSnapshot.close();
- }
+ @Override
+ public Document execute(Document requestMessage) throws NetconfDocumentedException {
+ throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself");
+ }
+ };
+
+ private static class NetconfOperationExecution implements NetconfOperationChainedExecution {
+ private final NetconfOperation netconfOperation;
+ private NetconfOperationChainedExecution subsequentExecution;
- private class NetconfOperationExecution implements NetconfOperationFilterChain {
- private final NetconfOperation operationWithHighestPriority;
+ private NetconfOperationExecution(NetconfOperation netconfOperation, NetconfOperationChainedExecution subsequentExecution) {
+ this.netconfOperation = netconfOperation;
+ this.subsequentExecution = subsequentExecution;
+ }
- public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
- HandlingPriority highestFoundPriority) {
- operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
- sortedPriority.remove(highestFoundPriority);
+ @Override
+ public boolean isExecutionTermination() {
+ return false;
}
@Override
- public Document execute(Document message, NetconfOperationRouter router) throws NetconfDocumentedException {
- return operationWithHighestPriority.handle(message, router);
+ public Document execute(Document message) throws NetconfDocumentedException {
+ return netconfOperation.handle(message, subsequentExecution);
+ }
+
+ public static NetconfOperationExecution createExecutionChain(
+ TreeMap<HandlingPriority, NetconfOperation> sortedByPriority, HandlingPriority handlingPriority) {
+ NetconfOperation netconfOperation = sortedByPriority.get(handlingPriority);
+ 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 "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot
+ '}';
}
-
-
-
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-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 static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.ObjectName;
+
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
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.NetconfOperationFilter;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import javax.management.ObjectName;
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
public class ConcurrentClientsTest {
}
@Override
- public Document handle(Document message, NetconfOperationRouter operationRouter)
- throws NetconfDocumentedException {
+ public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
try {
return XmlUtil.readXmlToDocument("<test/>");
} catch (Exception e) {
});
}
- @Override
- public Set<NetconfOperationFilter> getFilters() {
- return Collections.emptySet();
- }
-
@Override
public void close() {
}
package org.opendaylight.controller.netconf.mapping.api;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
public class HandlingPriority implements Comparable<HandlingPriority> {
* @return priority number or Optional.absent otherwise
*/
public Optional<Integer> getPriority() {
- return Optional.of(priority).or(Optional.<Integer> absent());
+ return Optional.fromNullable(priority);
+ }
+
+ public HandlingPriority increasePriority(int priorityIncrease) {
+ Preconditions.checkState(priority!=null, "Unable to increase priority for %s", this);
+ Preconditions.checkArgument(priorityIncrease > 0, "Negative increase");
+ Preconditions.checkArgument(Long.valueOf(priority) + priorityIncrease < Integer.MAX_VALUE,
+ "Resulting priority cannot be higher than %s", Integer.MAX_VALUE);
+ return getHandlingPriority(priority + priorityIncrease);
}
@Override
package org.opendaylight.controller.netconf.mapping.api;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.w3c.dom.Document;
+/**
+ * NetconfOperation handles netconf requests. Multiple operations might be
+ * capable of handling one request at the same time. In such case, these
+ * operations are chained (ordered by HandlingPriority returned by canHandle
+ * method) and executed.
+ *
+ * Operation can be declared as singleton or last in chain (see abstract
+ * implementations in netconf-util). If the operation is not singleton or last,
+ * it is responsible for the execution of subsequent operation and for merging
+ * the results.
+ *
+ */
public interface NetconfOperation {
- HandlingPriority canHandle(Document message);
+ /**
+ * Singleton operations should return
+ * HandlingPriority.HANDLE_WITH_MAX_PRIORITY, last operations
+ * HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.
+ *
+ * @param requestMessage
+ * @return
+ */
+ HandlingPriority canHandle(Document requestMessage);
- Document handle(Document message, NetconfOperationRouter operationRouter) throws NetconfDocumentedException;
+ /**
+ * 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.
+ *
+ * @param requestMessage
+ * @param subsequentOperation
+ * execution of subsequent netconf operation
+ * @return
+ * @throws NetconfDocumentedException
+ */
+ Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation)
+ throws NetconfDocumentedException;
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco 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.mapping.api;
+
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.w3c.dom.Document;
+
+/**
+ * Single link in netconf operation execution chain.
+ * Wraps the execution of a single netconf operation.
+ */
+public interface NetconfOperationChainedExecution {
+
+ /**
+ * @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 NetconfDocumentedException;
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco 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.mapping.api;
-
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.w3c.dom.Document;
-
-/**
- * Filters wrap each netconf operation, if there is one found. Filters are
- * sorted and applied from the greatest to smallest sorting order.
- */
-public interface NetconfOperationFilter extends Comparable<NetconfOperationFilter> {
-
- Document doFilter(Document message, NetconfOperationRouter operationRouter, NetconfOperationFilterChain filterChain)
- throws NetconfDocumentedException;
-
- int getSortingOrder();
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco 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.mapping.api;
-
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.w3c.dom.Document;
-
-public interface NetconfOperationFilterChain {
-
- Document execute(Document message, NetconfOperationRouter operationRouter) throws NetconfDocumentedException;
-
-}
*/
Set<NetconfOperation> getNetconfOperations();
- Set<NetconfOperationFilter> getFilters();
-
/**
* Called when netconf session is destroyed.
*/
*/
package org.opendaylight.controller.netconf.monitoring;
-import com.google.common.collect.Maps;
+import java.util.Map;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
+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.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.Map;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
-public class Get implements NetconfOperationFilter {
+public class Get extends AbstractNetconfOperation {
private static final Logger logger = LoggerFactory.getLogger(Get.class);
private final NetconfMonitoringService netconfMonitor;
public Get(NetconfMonitoringService netconfMonitor) {
+ super(MonitoringConstants.MODULE_NAME);
this.netconfMonitor = netconfMonitor;
}
- @Override
- public Document doFilter(Document message, NetconfOperationRouter operationRouter,
- NetconfOperationFilterChain filterChain) throws NetconfDocumentedException {
- AbstractNetconfOperation.OperationNameAndNamespace operationNameAndNamespace = new AbstractNetconfOperation.OperationNameAndNamespace(
- message);
- if (canHandle(operationNameAndNamespace)) {
- return handle(message, operationRouter, filterChain);
+ private Element getPlaceholder(Document innerResult) {
+ try {
+ XmlElement rootElement = XmlElement.fromDomElementWithExpected(innerResult.getDocumentElement(),
+ XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+ return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
+ } catch (RuntimeException e) {
+ throw new IllegalArgumentException(String.format(
+ "Input xml in wrong format, Expecting root element %s with child element %s, but was %s",
+ XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.DATA_KEY,
+ XmlUtil.toString(innerResult.getDocumentElement())), e);
}
- return filterChain.execute(message, operationRouter);
}
- private Document handle(Document message, NetconfOperationRouter operationRouter,
- NetconfOperationFilterChain filterChain) throws NetconfDocumentedException {
+ @Override
+ protected String getOperationName() {
+ return XmlNetconfConstants.GET;
+ }
+
+ @Override
+ protected HandlingPriority getHandlingPriority() {
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.increasePriority(1);
+ }
+
+ @Override
+ public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation)
+ throws NetconfDocumentedException {
+ Preconditions.checkArgument(subsequentOperation.isExecutionTermination() == false,
+ "Subsequent netconf operation expected by %s", this);
+
try {
- Document innerResult = filterChain.execute(message, operationRouter);
+ Document innerResult = subsequentOperation.execute(requestMessage);
NetconfState netconfMonitoring = new NetconfState(netconfMonitor);
Element monitoringXmlElement = new JaxBSerializer().toXml(netconfMonitoring);
}
}
- private Element getPlaceholder(Document innerResult) {
- try {
- XmlElement rootElement = XmlElement.fromDomElementWithExpected(innerResult.getDocumentElement(),
- XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
- return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
- } catch (RuntimeException e) {
- throw new IllegalArgumentException(String.format(
- "Input xml in wrong format, Expecting root element %s with child element %s, but was %s",
- XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.DATA_KEY,
- XmlUtil.toString(innerResult.getDocumentElement())), e);
- }
- }
-
- private boolean canHandle(AbstractNetconfOperation.OperationNameAndNamespace operationNameAndNamespace) {
- if (operationNameAndNamespace.getOperationName().equals(XmlNetconfConstants.GET) == false)
- return false;
- return operationNameAndNamespace.getNamespace().equals(
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
- }
-
@Override
- public int getSortingOrder() {
- // FIXME filters for different operations cannot have same order
- return 1;
+ protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation)
+ throws NetconfDocumentedException {
+ throw new UnsupportedOperationException("Never gets called");
}
-
- @Override
- public int compareTo(NetconfOperationFilter o) {
- return Integer.compare(getSortingOrder(), o.getSortingOrder());
- }
-
}
*/
package org.opendaylight.controller.netconf.monitoring.osgi;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import com.google.common.io.Files;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.monitoring.Get;
import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
public class NetconfMonitoringOperationService implements NetconfOperationService {
@Override
public Set<NetconfOperation> getNetconfOperations() {
- return Collections.emptySet();
- }
-
- @Override
- public Set<NetconfOperationFilter> getFilters() {
- return Sets.<NetconfOperationFilter>newHashSet(new Get(monitor));
+ return Sets.<NetconfOperation>newHashSet(new Get(monitor));
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco 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.util.mapping;
+
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+public abstract class AbstractLastNetconfOperation extends AbstractNetconfOperation {
+
+ protected AbstractLastNetconfOperation(String netconfSessionIdForReporting) {
+ super(netconfSessionIdForReporting);
+ }
+
+ @Override
+ protected Element handle(Document document, XmlElement operationElement,
+ NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ Preconditions.checkArgument(subsequentOperation.isExecutionTermination(),
+ "No netconf operation expected to be subsequent to %s, but is %s", this, subsequentOperation);
+
+ return handleWithNoSubsequentOperations(document, operationElement);
+ }
+
+ @Override
+ protected HandlingPriority getHandlingPriority() {
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
+ }
+
+ protected abstract Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException;
+}
import java.util.Map;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
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;
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
- protected abstract HandlingPriority canHandle(String operationName, String netconfOperationNamespace);
+ protected HandlingPriority canHandle(String operationName, String operationNamespace) {
+ return operationName.equals(getOperationName()) && operationNamespace.equals(getOperationNamespace())
+ ? getHandlingPriority()
+ : HandlingPriority.CANNOT_HANDLE;
+ }
+
+ protected HandlingPriority getHandlingPriority() {
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
+ }
+
+ protected String getOperationNamespace() {
+ return XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+ }
+
+ protected abstract String getOperationName();
@Override
- public final Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException {
+ public Document handle(Document requestMessage,
+ NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
- XmlElement requestElement = getRequestElementWithCheck(message);
+ XmlElement requestElement = getRequestElementWithCheck(requestMessage);
Document document = XmlUtil.newDocument();
XmlElement operationElement = requestElement.getOnlyChildElement();
Map<String, Attr> attributes = requestElement.getAttributes();
- Element response = handle(document, operationElement, opRouter);
+ Element response = handle(document, operationElement, subsequentOperation);
Element rpcReply = document.createElementNS(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0,
XmlNetconfConstants.RPC_REPLY_KEY);
return document;
}
- protected abstract Element handle(Document document, XmlElement operationElement, NetconfOperationRouter opRouter)
+ protected abstract Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation)
throws NetconfDocumentedException;
@Override
public String toString() {
- return getClass() + "{" + netconfSessionIdForReporting + '}';
+ final StringBuffer sb = new StringBuffer("AbstractConfigNetconfOperation{");
+ sb.append("name=").append(getOperationName());
+ sb.append(", namespace=").append(getOperationNamespace());
+ sb.append(", session=").append(netconfSessionIdForReporting);
+ sb.append('}');
+ return sb.toString();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco 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.util.mapping;
+
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+
+public abstract class AbstractSingletonNetconfOperation extends AbstractLastNetconfOperation {
+
+ protected AbstractSingletonNetconfOperation(String netconfSessionIdForReporting) {
+ super(netconfSessionIdForReporting);
+ }
+
+ @Override
+ protected HandlingPriority getHandlingPriority() {
+ return HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
+ }
+
+}
public static final String PREFIX = "prefix";
//
- //
+ // TODO duplicate
public static final String RFC4741_TARGET_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
public static final String URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0";