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