a9bea344c9471853bc1654f708f8f9d99a61e619
[controller.git] / opendaylight / netconf / netconf-impl / src / main / java / org / opendaylight / controller / netconf / impl / osgi / NetconfOperationRouterImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.netconf.impl.osgi;
9
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.impl.DefaultCommitNotificationProducer;
16 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
17 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
18 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
19 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
20 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
21 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
22 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
23 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
24 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
25 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 import org.w3c.dom.Document;
29
30 import java.util.Collections;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.LinkedList;
34 import java.util.Set;
35 import java.util.TreeMap;
36 import java.util.TreeSet;
37
38 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
39
40     private static final Logger logger = LoggerFactory.getLogger(NetconfOperationRouterImpl.class);
41
42     private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
43
44     private final Set<NetconfOperation> allNetconfOperations;
45     private final TreeSet<NetconfOperationFilter> allSortedFilters;
46
47     private final CapabilityProvider capabilityProvider;
48
49     public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
50             CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
51
52         this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
53
54         this.capabilityProvider = capabilityProvider;
55
56         Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
57         defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
58                 .getNetconfSessionIdForReporting()));
59         defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
60                 .getNetconfSessionIdForReporting()));
61
62         allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
63
64         DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider,
65                 netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
66         Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
67         allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
68     }
69
70     private static Set<NetconfOperation> getAllNetconfOperations(Set<NetconfOperation> defaultNetconfOperations,
71             NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
72         Set<NetconfOperation> result = new HashSet<>();
73         result.addAll(defaultNetconfOperations);
74
75         for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
76             final Set<NetconfOperation> netOpsFromService = netconfOperationService.getNetconfOperations();
77             for (NetconfOperation netconfOperation : netOpsFromService) {
78                 Preconditions.checkState(result.contains(netconfOperation) == false,
79                         "Netconf operation %s already present", netconfOperation);
80                 result.add(netconfOperation);
81             }
82         }
83         return Collections.unmodifiableSet(result);
84     }
85
86     private static TreeSet<NetconfOperationFilter> getAllNetconfFilters(Set<NetconfOperationFilter> defaultFilters,
87             NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
88         TreeSet<NetconfOperationFilter> result = new TreeSet<>(defaultFilters);
89         for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
90             final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
91             for (NetconfOperationFilter filter : filtersFromService) {
92                 Preconditions.checkState(result.contains(filter) == false, "Filter %s already present", filter);
93                 result.add(filter);
94             }
95         }
96         return result;
97     }
98
99     public CapabilityProvider getCapabilityProvider() {
100         return capabilityProvider;
101     }
102
103     @Override
104     public synchronized Document onNetconfMessage(Document message) throws NetconfDocumentedException {
105         NetconfOperationExecution netconfOperationExecution = getNetconfOperationWithHighestPriority(message);
106         logger.debug("Forwarding netconf message {} to {}", XmlUtil.toString(message),
107                 netconfOperationExecution.operationWithHighestPriority);
108
109         final LinkedList<NetconfOperationFilterChain> chain = new LinkedList<>();
110         chain.push(netconfOperationExecution);
111
112         for (Iterator<NetconfOperationFilter> it = allSortedFilters.descendingIterator(); it.hasNext();) {
113             final NetconfOperationFilter filter = it.next();
114             final NetconfOperationFilterChain prevItem = chain.getFirst();
115             NetconfOperationFilterChain currentItem = new NetconfOperationFilterChain() {
116                 @Override
117                 public Document execute(Document message, NetconfOperationRouter operationRouter)
118                         throws NetconfDocumentedException {
119                     logger.trace("Entering {}", filter);
120                     return filter.doFilter(message, operationRouter, prevItem);
121                 }
122             };
123             chain.push(currentItem);
124         }
125         return chain.getFirst().execute(message, this);
126     }
127
128     private NetconfOperationExecution getNetconfOperationWithHighestPriority(Document message) {
129
130         // TODO test
131         TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(message);
132
133         Preconditions.checkState(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
134                 NetconfOperation.class.getName(), XmlUtil.toString(message));
135
136         HandlingPriority highestFoundPriority = sortedPriority.lastKey();
137
138         int netconfOperationsWithHighestPriority = sortedPriority.get(highestFoundPriority).size();
139
140         Preconditions.checkState(netconfOperationsWithHighestPriority == 1,
141                 "Multiple %s available to handle message %s", NetconfOperation.class.getName(), message);
142
143         return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
144     }
145
146     private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(Document message) {
147         TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
148
149         for (NetconfOperation netconfOperation : allNetconfOperations) {
150             final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
151
152             if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
153                 Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
154                 netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
155                 netconfOperations.add(netconfOperation);
156             }
157         }
158         return sortedPriority;
159     }
160
161     private Set<NetconfOperation> checkIfNoOperationsOnPriority(
162             TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority, HandlingPriority handlingPriority,
163             Set<NetconfOperation> netconfOperations) {
164         if (netconfOperations == null) {
165             netconfOperations = Sets.newHashSet();
166             sortedPriority.put(handlingPriority, netconfOperations);
167         }
168         return netconfOperations;
169     }
170
171     @Override
172     public void close() {
173         netconfOperationServiceSnapshot.close();
174     }
175
176     private class NetconfOperationExecution implements NetconfOperationFilterChain {
177         private final NetconfOperation operationWithHighestPriority;
178
179         private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
180             this.operationWithHighestPriority = operationWithHighestPriority;
181         }
182
183         public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
184                 HandlingPriority highestFoundPriority) {
185             operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
186             sortedPriority.remove(highestFoundPriority);
187         }
188
189         @Override
190         public Document execute(Document message, NetconfOperationRouter router) throws NetconfDocumentedException {
191             return operationWithHighestPriority.handle(message, router);
192         }
193     }
194
195     @Override
196     public String toString() {
197         return "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot
198                 + '}';
199     }
200 }