2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.netconf.impl.osgi;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Maps;
12 import com.google.common.collect.Sets;
13 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
14 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
15 import org.opendaylight.controller.netconf.api.NetconfSession;
16 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
17 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
18 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
19 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
20 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
21 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
22 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
23 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
24 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
25 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
26 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
27 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
28 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
29 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.w3c.dom.Document;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.LinkedList;
40 import java.util.TreeMap;
41 import java.util.TreeSet;
43 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
45 private static final Logger logger = LoggerFactory.getLogger(NetconfOperationRouterImpl.class);
47 private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
49 private final Set<NetconfOperation> allNetconfOperations;
50 private final TreeSet<NetconfOperationFilter> allSortedFilters;
52 private final CapabilityProvider capabilityProvider;
55 public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
56 CapabilityProvider capabilityProvider,
57 DefaultCommitNotificationProducer commitNotifier) {
59 this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
61 this.capabilityProvider = capabilityProvider;
63 Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
64 defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
65 .getNetconfSessionIdForReporting()));
66 defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
67 .getNetconfSessionIdForReporting()));
68 defaultNetconfOperations.add(new DefaultStartExi(
69 netconfOperationServiceSnapshot
70 .getNetconfSessionIdForReporting()));
71 defaultNetconfOperations.add(new DefaultStopExi(
72 netconfOperationServiceSnapshot
73 .getNetconfSessionIdForReporting()));
75 allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
77 DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider,
78 netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
79 Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
80 allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
83 private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
84 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
85 Set<NetconfOperation> result = new HashSet<>();
86 result.addAll(defaultNetconfOperations);
88 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
89 final Set<NetconfOperation> netOpsFromService = netconfOperationService.getNetconfOperations();
90 for (NetconfOperation netconfOperation : netOpsFromService) {
91 Preconditions.checkState(result.contains(netconfOperation) == false,
92 "Netconf operation %s already present", netconfOperation);
93 result.add(netconfOperation);
96 return Collections.unmodifiableSet(result);
99 private static TreeSet<NetconfOperationFilter> getAllNetconfFilters(Set<NetconfOperationFilter> defaultFilters,
100 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
101 TreeSet<NetconfOperationFilter> result = new TreeSet<>(defaultFilters);
102 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
103 final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
104 for (NetconfOperationFilter filter : filtersFromService) {
105 Preconditions.checkState(result.contains(filter) == false, "Filter %s already present", filter);
112 public CapabilityProvider getCapabilityProvider() {
113 return capabilityProvider;
117 public synchronized Document onNetconfMessage(Document message,
118 NetconfSession session) throws NetconfDocumentedException {
119 NetconfOperationExecution netconfOperationExecution = null;
121 String messageAsString = XmlUtil.toString(message);
124 netconfOperationExecution = getNetconfOperationWithHighestPriority(
126 } catch (IllegalArgumentException | IllegalStateException e) {
127 logger.warn("Unable to handle rpc {} on session {}", messageAsString, session, e);
129 String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
130 Map<String, String> errorInfo = Maps.newHashMap();
132 NetconfDocumentedException.ErrorTag tag = null;
133 if (e instanceof IllegalArgumentException) {
134 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
135 tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
136 } else if (e instanceof IllegalStateException) {
137 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
138 tag = NetconfDocumentedException.ErrorTag.operation_failed;
141 throw new NetconfDocumentedException(errorMessage, e, NetconfDocumentedException.ErrorType.application,
142 tag, NetconfDocumentedException.ErrorSeverity.error, errorInfo);
145 logger.debug("Forwarding netconf message {} to {}", messageAsString,
146 netconfOperationExecution.operationWithHighestPriority);
148 final LinkedList<NetconfOperationFilterChain> chain = new LinkedList<>();
149 chain.push(netconfOperationExecution);
151 for (Iterator<NetconfOperationFilter> it = allSortedFilters.descendingIterator(); it.hasNext();) {
152 final NetconfOperationFilter filter = it.next();
153 final NetconfOperationFilterChain prevItem = chain.getFirst();
154 NetconfOperationFilterChain currentItem = new NetconfOperationFilterChain() {
156 public Document execute(Document message, NetconfOperationRouter operationRouter)
157 throws NetconfDocumentedException {
158 logger.trace("Entering {}", filter);
159 return filter.doFilter(message, operationRouter, prevItem);
162 chain.push(currentItem);
164 return chain.getFirst().execute(message, this);
167 private NetconfOperationExecution getNetconfOperationWithHighestPriority(
168 Document message, NetconfSession session) {
171 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
174 Preconditions.checkArgument(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
175 NetconfOperation.class.getName(), XmlUtil.toString(message));
177 HandlingPriority highestFoundPriority = sortedPriority.lastKey();
179 int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
181 Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
182 "Multiple %s available to handle message %s", NetconfOperation.class.getName(), message);
184 return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
187 private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(
188 Document message, NetconfSession session) {
189 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
191 for (NetconfOperation netconfOperation : allNetconfOperations) {
192 final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
193 if (netconfOperation instanceof DefaultNetconfOperation) {
194 ((DefaultNetconfOperation) netconfOperation)
195 .setNetconfSession(session);
197 if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
198 Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
199 netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
200 netconfOperations.add(netconfOperation);
203 return sortedPriority;
206 private Set<NetconfOperation> checkIfNoOperationsOnPriority(
207 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority, HandlingPriority handlingPriority,
208 Set<NetconfOperation> netconfOperations) {
209 if (netconfOperations == null) {
210 netconfOperations = Sets.newHashSet();
211 sortedPriority.put(handlingPriority, netconfOperations);
213 return netconfOperations;
217 public void close() {
218 netconfOperationServiceSnapshot.close();
221 private class NetconfOperationExecution implements NetconfOperationFilterChain {
222 private final NetconfOperation operationWithHighestPriority;
224 private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
225 this.operationWithHighestPriority = operationWithHighestPriority;
228 public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
229 HandlingPriority highestFoundPriority) {
230 operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
231 sortedPriority.remove(highestFoundPriority);
235 public Document execute(Document message, NetconfOperationRouter router) throws NetconfDocumentedException {
236 return operationWithHighestPriority.handle(message, router);
241 public String toString() {
242 return "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot