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.NetconfSession;
14 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
15 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
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, DefaultCommitNotificationProducer commitNotifier) {
58 this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
60 this.capabilityProvider = capabilityProvider;
62 Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
63 defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
64 .getNetconfSessionIdForReporting()));
65 defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
66 .getNetconfSessionIdForReporting()));
67 defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot
68 .getNetconfSessionIdForReporting()));
69 defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot
70 .getNetconfSessionIdForReporting()));
72 allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
74 DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider,
75 netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
76 Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
77 allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
80 private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
81 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
82 Set<NetconfOperation> result = new HashSet<>();
83 result.addAll(defaultNetconfOperations);
85 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
86 final Set<NetconfOperation> netOpsFromService = netconfOperationService.getNetconfOperations();
87 for (NetconfOperation netconfOperation : netOpsFromService) {
88 Preconditions.checkState(result.contains(netconfOperation) == false,
89 "Netconf operation %s already present", netconfOperation);
90 result.add(netconfOperation);
93 return Collections.unmodifiableSet(result);
96 private static TreeSet<NetconfOperationFilter> getAllNetconfFilters(Set<NetconfOperationFilter> defaultFilters,
97 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
98 TreeSet<NetconfOperationFilter> result = new TreeSet<>(defaultFilters);
99 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
100 final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
101 for (NetconfOperationFilter filter : filtersFromService) {
102 Preconditions.checkState(result.contains(filter) == false,
103 "Filter %s already present, all filters so far: %s", filter, result);
110 public CapabilityProvider getCapabilityProvider() {
111 return capabilityProvider;
115 public synchronized Document onNetconfMessage(Document message,
116 NetconfSession session) throws NetconfDocumentedException {
117 NetconfOperationExecution netconfOperationExecution;
119 String messageAsString = XmlUtil.toString(message);
122 netconfOperationExecution = getNetconfOperationWithHighestPriority(message, session);
123 } catch (IllegalArgumentException | IllegalStateException e) {
124 logger.warn("Unable to handle rpc {} on session {}", messageAsString, session, e);
126 String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
127 Map<String, String> errorInfo = Maps.newHashMap();
129 NetconfDocumentedException.ErrorTag tag = null;
130 if (e instanceof IllegalArgumentException) {
131 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
132 tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
133 } else if (e instanceof IllegalStateException) {
134 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
135 tag = NetconfDocumentedException.ErrorTag.operation_failed;
138 throw new NetconfDocumentedException(errorMessage, e, NetconfDocumentedException.ErrorType.application,
139 tag, NetconfDocumentedException.ErrorSeverity.error, errorInfo);
140 } catch (RuntimeException e) {
141 throw handleUnexpectedEx("Unexpected exception during netconf operation sort", e);
145 return executeOperationWithHighestPriority(message, netconfOperationExecution, messageAsString);
146 } catch (RuntimeException e) {
147 throw handleUnexpectedEx("Unexpected exception during netconf operation execution", e);
151 private NetconfDocumentedException handleUnexpectedEx(String s, Exception e) throws NetconfDocumentedException {
154 Map<String, String> info = Maps.newHashMap();
155 info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.toString());
156 return new NetconfDocumentedException("Unexpected error",
157 NetconfDocumentedException.ErrorType.application,
158 NetconfDocumentedException.ErrorTag.operation_failed,
159 NetconfDocumentedException.ErrorSeverity.error, info);
162 private Document executeOperationWithHighestPriority(Document message, NetconfOperationExecution netconfOperationExecution, String messageAsString) throws NetconfDocumentedException {
163 logger.debug("Forwarding netconf message {} to {}", messageAsString,
164 netconfOperationExecution.operationWithHighestPriority);
166 final LinkedList<NetconfOperationFilterChain> chain = new LinkedList<>();
167 chain.push(netconfOperationExecution);
169 for (Iterator<NetconfOperationFilter> it = allSortedFilters.descendingIterator(); it.hasNext();) {
170 final NetconfOperationFilter filter = it.next();
171 final NetconfOperationFilterChain prevItem = chain.getFirst();
172 NetconfOperationFilterChain currentItem = new NetconfOperationFilterChain() {
174 public Document execute(Document message, NetconfOperationRouter operationRouter)
175 throws NetconfDocumentedException {
176 logger.trace("Entering {}", filter);
177 return filter.doFilter(message, operationRouter, prevItem);
180 chain.push(currentItem);
182 return chain.getFirst().execute(message, this);
185 private NetconfOperationExecution getNetconfOperationWithHighestPriority(
186 Document message, NetconfSession session) {
189 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
192 Preconditions.checkArgument(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
193 NetconfOperation.class.getName(), XmlUtil.toString(message));
195 HandlingPriority highestFoundPriority = sortedPriority.lastKey();
197 int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
199 Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
200 "Multiple %s available to handle message %s", NetconfOperation.class.getName(), message);
202 return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
205 private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(
206 Document message, NetconfSession session) {
207 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
209 for (NetconfOperation netconfOperation : allNetconfOperations) {
210 final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
211 if (netconfOperation instanceof DefaultNetconfOperation) {
212 ((DefaultNetconfOperation) netconfOperation)
213 .setNetconfSession(session);
215 if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
216 Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
217 netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
218 netconfOperations.add(netconfOperation);
221 return sortedPriority;
224 private Set<NetconfOperation> checkIfNoOperationsOnPriority(
225 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority, HandlingPriority handlingPriority,
226 Set<NetconfOperation> netconfOperations) {
227 if (netconfOperations == null) {
228 netconfOperations = Sets.newHashSet();
229 sortedPriority.put(handlingPriority, netconfOperations);
231 return netconfOperations;
235 public void close() {
236 netconfOperationServiceSnapshot.close();
239 private class NetconfOperationExecution implements NetconfOperationFilterChain {
240 private final NetconfOperation operationWithHighestPriority;
242 private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
243 this.operationWithHighestPriority = operationWithHighestPriority;
246 public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
247 HandlingPriority highestFoundPriority) {
248 operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
249 sortedPriority.remove(highestFoundPriority);
253 public Document execute(Document message, NetconfOperationRouter router) throws NetconfDocumentedException {
254 return operationWithHighestPriority.handle(message, router);
259 public String toString() {
260 return "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot