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 java.util.Collections;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.LinkedList;
16 import java.util.TreeMap;
17 import java.util.TreeSet;
19 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
20 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
21 import org.opendaylight.controller.netconf.api.NetconfSession;
22 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
23 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
24 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
25 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
26 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
27 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
28 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
29 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
30 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
31 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
32 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
33 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
34 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
35 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.w3c.dom.Document;
40 import com.google.common.base.Preconditions;
41 import com.google.common.collect.Maps;
42 import com.google.common.collect.Sets;
44 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
46 private static final Logger logger = LoggerFactory.getLogger(NetconfOperationRouterImpl.class);
48 private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
50 private final Set<NetconfOperation> allNetconfOperations;
51 private final TreeSet<NetconfOperationFilter> allSortedFilters;
53 private final CapabilityProvider capabilityProvider;
56 public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
57 CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
59 this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
60 this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider);
62 final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
63 final Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
64 defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId));
65 defaultNetconfOperations.add(new DefaultCloseSession(sessionId));
66 defaultNetconfOperations.add(new DefaultStartExi(sessionId));
67 defaultNetconfOperations.add(new DefaultStopExi(sessionId));
69 allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
71 DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId);
72 Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
73 allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
76 private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
77 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
78 Set<NetconfOperation> result = new HashSet<>();
79 result.addAll(defaultNetconfOperations);
81 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
82 final Set<NetconfOperation> netOpsFromService = netconfOperationService.getNetconfOperations();
83 for (NetconfOperation netconfOperation : netOpsFromService) {
84 Preconditions.checkState(result.contains(netconfOperation) == false,
85 "Netconf operation %s already present", netconfOperation);
86 result.add(netconfOperation);
89 return Collections.unmodifiableSet(result);
92 private static TreeSet<NetconfOperationFilter> getAllNetconfFilters(Set<NetconfOperationFilter> defaultFilters,
93 NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
94 TreeSet<NetconfOperationFilter> result = new TreeSet<>(defaultFilters);
95 for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
96 final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
97 for (NetconfOperationFilter filter : filtersFromService) {
98 Preconditions.checkState(result.contains(filter) == false,
99 "Filter %s already present, all filters so far: %s", filter, result);
106 public CapabilityProvider getCapabilityProvider() {
107 return capabilityProvider;
111 public synchronized Document onNetconfMessage(Document message,
112 NetconfSession session) throws NetconfDocumentedException {
113 NetconfOperationExecution netconfOperationExecution;
115 String messageAsString = XmlUtil.toString(message);
118 netconfOperationExecution = getNetconfOperationWithHighestPriority(message, session);
119 } catch (IllegalArgumentException | IllegalStateException e) {
120 logger.warn("Unable to handle rpc {} on session {}", messageAsString, session, e);
122 String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
123 Map<String, String> errorInfo = Maps.newHashMap();
125 NetconfDocumentedException.ErrorTag tag = null;
126 if (e instanceof IllegalArgumentException) {
127 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
128 tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
129 } else if (e instanceof IllegalStateException) {
130 errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
131 tag = NetconfDocumentedException.ErrorTag.operation_failed;
134 throw new NetconfDocumentedException(errorMessage, e, NetconfDocumentedException.ErrorType.application,
135 tag, NetconfDocumentedException.ErrorSeverity.error, errorInfo);
136 } catch (RuntimeException e) {
137 throw handleUnexpectedEx("Unexpected exception during netconf operation sort", e);
141 return executeOperationWithHighestPriority(message, netconfOperationExecution, messageAsString);
142 } catch (RuntimeException e) {
143 throw handleUnexpectedEx("Unexpected exception during netconf operation execution", e);
147 private NetconfDocumentedException handleUnexpectedEx(String s, Exception e) throws NetconfDocumentedException {
150 Map<String, String> info = Maps.newHashMap();
151 info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.toString());
152 return new NetconfDocumentedException("Unexpected error",
153 NetconfDocumentedException.ErrorType.application,
154 NetconfDocumentedException.ErrorTag.operation_failed,
155 NetconfDocumentedException.ErrorSeverity.error, info);
158 private Document executeOperationWithHighestPriority(Document message, NetconfOperationExecution netconfOperationExecution, String messageAsString) throws NetconfDocumentedException {
159 logger.debug("Forwarding netconf message {} to {}", messageAsString,
160 netconfOperationExecution.operationWithHighestPriority);
162 final LinkedList<NetconfOperationFilterChain> chain = new LinkedList<>();
163 chain.push(netconfOperationExecution);
165 for (Iterator<NetconfOperationFilter> it = allSortedFilters.descendingIterator(); it.hasNext();) {
166 final NetconfOperationFilter filter = it.next();
167 final NetconfOperationFilterChain prevItem = chain.getFirst();
168 NetconfOperationFilterChain currentItem = new NetconfOperationFilterChain() {
170 public Document execute(Document message, NetconfOperationRouter operationRouter)
171 throws NetconfDocumentedException {
172 logger.trace("Entering {}", filter);
173 return filter.doFilter(message, operationRouter, prevItem);
176 chain.push(currentItem);
178 return chain.getFirst().execute(message, this);
181 private NetconfOperationExecution getNetconfOperationWithHighestPriority(
182 Document message, NetconfSession session) {
184 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
187 Preconditions.checkArgument(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
188 NetconfOperation.class.getName(), XmlUtil.toString(message));
190 HandlingPriority highestFoundPriority = sortedPriority.lastKey();
192 int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
194 Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
195 "Multiple %s available to handle message %s", NetconfOperation.class.getName(), message);
197 return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
200 private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(
201 Document message, NetconfSession session) {
202 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
204 for (NetconfOperation netconfOperation : allNetconfOperations) {
205 final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
206 if (netconfOperation instanceof DefaultNetconfOperation) {
207 ((DefaultNetconfOperation) netconfOperation)
208 .setNetconfSession(session);
210 if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
211 Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
212 netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
213 netconfOperations.add(netconfOperation);
216 return sortedPriority;
219 private Set<NetconfOperation> checkIfNoOperationsOnPriority(
220 TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority, HandlingPriority handlingPriority,
221 Set<NetconfOperation> netconfOperations) {
222 if (netconfOperations == null) {
223 netconfOperations = Sets.newHashSet();
224 sortedPriority.put(handlingPriority, netconfOperations);
226 return netconfOperations;
230 public void close() {
231 netconfOperationServiceSnapshot.close();
234 private class NetconfOperationExecution implements NetconfOperationFilterChain {
235 private final NetconfOperation operationWithHighestPriority;
237 public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
238 HandlingPriority highestFoundPriority) {
239 operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
240 sortedPriority.remove(highestFoundPriority);
244 public Document execute(Document message, NetconfOperationRouter router) throws NetconfDocumentedException {
245 return operationWithHighestPriority.handle(message, router);
250 public String toString() {
251 return "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot