import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
-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.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
-import java.util.TreeSet;
public class NetconfOperationRouterImpl implements NetconfOperationRouter {
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 = netconfOperationServiceSnapshot;
+ Preconditions.checkNotNull(netconfOperationServiceSnapshot);
+ Preconditions.checkNotNull(capabilityProvider);
- this.capabilityProvider = capabilityProvider;
+ final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
- Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
- defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
+ final Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
+ defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, 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,
- netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
- Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
- allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
+ return router;
}
private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
final Set<NetconfOperation> netOpsFromService = netconfOperationService.getNetconfOperations();
for (NetconfOperation netconfOperation : netOpsFromService) {
- Preconditions.checkState(result.contains(netconfOperation) == false,
+ Preconditions.checkState(!result.contains(netconfOperation),
"Netconf operation %s already present", netconfOperation);
result.add(netconfOperation);
}
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;
+ NetconfServerSession session) throws NetconfDocumentedException {
+ Preconditions.checkNotNull(allNetconfOperations, "Operation router was not initialized properly");
- String messageAsString = XmlUtil.toString(message);
+ NetconfOperationExecution netconfOperationExecution;
+ String messageAsString = "";
try {
+ messageAsString = XmlUtil.toString(message);
netconfOperationExecution = getNetconfOperationWithHighestPriority(message, session);
} catch (IllegalArgumentException | IllegalStateException e) {
logger.warn("Unable to handle rpc {} on session {}", messageAsString, session, e);
String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
Map<String, String> errorInfo = Maps.newHashMap();
- NetconfDocumentedException.ErrorTag tag = null;
+ NetconfDocumentedException.ErrorTag tag;
if (e instanceof IllegalArgumentException) {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
- } else if (e instanceof IllegalStateException) {
+ } else {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_failed;
}
}
}
+ @Override
+ public void close() throws Exception {
+ 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) {
+ Document message, NetconfServerSession session) throws NetconfDocumentedException {
- // TODO test
- TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
+ NavigableMap<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();
+ Preconditions.checkArgument(sortedByPriority.isEmpty() == false,
+ "No %s available to handle message %s", NetconfOperation.class.getName(),
+ XmlUtil.toString(message));
- int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
-
- Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
- "Multiple %s available to handle message %s", NetconfOperation.class.getName(), 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,
+ NetconfServerSession session) throws NetconfDocumentedException {
+ 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);
+ if (!handlingPriority.equals(HandlingPriority.CANNOT_HANDLE)) {
+
+ Preconditions.checkState(!sortedPriority.containsKey(handlingPriority),
+ "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 NetconfDocumentedException("This execution represents the termination point in operation execution and cannot be executed itself",
+ NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.operation_failed,
+ NetconfDocumentedException.ErrorSeverity.error);
+ }
+ };
- private class NetconfOperationExecution implements NetconfOperationFilterChain {
- private final NetconfOperation operationWithHighestPriority;
+ private static class NetconfOperationExecution implements NetconfOperationChainedExecution {
+ private final NetconfOperation netconfOperation;
+ private NetconfOperationChainedExecution subsequentExecution;
- private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
- this.operationWithHighestPriority = 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(
+ NavigableMap<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
+ '}';
}
-
-
-
}