Merge "Add support for enums as configuration attributes in config and netconf subsys...
[controller.git] / opendaylight / netconf / config-persister-impl / src / main / java / org / opendaylight / controller / netconf / persist / impl / CapabilityStrippingConfigSnapshotHolder.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.persist.impl;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
12 import org.opendaylight.controller.netconf.util.xml.XmlElement;
13 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.w3c.dom.Attr;
17 import org.w3c.dom.Element;
18
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.Map.Entry;
23 import java.util.Set;
24 import java.util.SortedSet;
25 import java.util.TreeSet;
26 import java.util.regex.Pattern;
27
28 import static com.google.common.base.Preconditions.checkState;
29
30 public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHolder {
31     private static final Logger logger = LoggerFactory.getLogger(CapabilityStrippingConfigSnapshotHolder.class);
32
33     private final String configSnapshot;
34     private final StripCapabilitiesResult stripCapabilitiesResult;
35
36     public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set<String> capabilities, Pattern ignoredMissingCapabilityRegex) {
37         final XmlElement configElement = XmlElement.fromDomElement(snapshot);
38         configSnapshot = XmlUtil.toString(configElement.getDomElement());
39         stripCapabilitiesResult = stripCapabilities(configElement, capabilities, ignoredMissingCapabilityRegex);
40     }
41
42     private static class StripCapabilitiesResult {
43         private final SortedSet<String> requiredCapabilities, missingNamespaces;
44
45         private StripCapabilitiesResult(SortedSet<String> requiredCapabilities, SortedSet<String> missingNamespaces) {
46             this.requiredCapabilities = Collections.unmodifiableSortedSet(requiredCapabilities);
47             this.missingNamespaces = Collections.unmodifiableSortedSet(missingNamespaces);
48         }
49     }
50
51
52     @VisibleForTesting
53     static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set<String> allCapabilitiesFromHello,
54                                                      Pattern ignoredMissingCapabilityRegex) {
55         // collect all namespaces
56         Set<String> foundNamespacesInXML = getNamespaces(configElement);
57         logger.trace("All capabilities {}\nFound namespaces in XML {}", allCapabilitiesFromHello, foundNamespacesInXML);
58         // required are referenced both in xml and hello
59         SortedSet<String> requiredCapabilities = new TreeSet<>();
60         // can be removed
61         Set<String> obsoleteCapabilities = new HashSet<>();
62         // are in xml but not in hello
63         SortedSet<String> missingNamespaces = new TreeSet<>(foundNamespacesInXML);
64         for (String capability : allCapabilitiesFromHello) {
65             String namespace = capability.replaceAll("\\?.*","");
66             if (foundNamespacesInXML.contains(namespace)) {
67                 requiredCapabilities.add(capability);
68                 checkState(missingNamespaces.remove(namespace));
69             } else {
70                 obsoleteCapabilities.add(capability);
71             }
72         }
73
74         logger.trace("Required capabilities {}, \nObsolete capabilities {}",
75                 requiredCapabilities, obsoleteCapabilities);
76
77         for(Iterator<String> iterator = missingNamespaces.iterator();iterator.hasNext(); ){
78             String capability = iterator.next();
79             if (ignoredMissingCapabilityRegex.matcher(capability).matches()){
80                 logger.trace("Ignoring missing capability {}", capability);
81                 iterator.remove();
82             }
83         }
84         if (missingNamespaces.size() > 0) {
85             logger.warn("Some capabilities are missing: {}", missingNamespaces);
86         }
87         return new StripCapabilitiesResult(requiredCapabilities, missingNamespaces);
88     }
89
90     static Set<String> getNamespaces(XmlElement element){
91         Set<String> result = new HashSet<>();
92         for (Entry<String,Attr> attribute : element.getAttributes().entrySet()) {
93             if  (attribute.getKey().startsWith("xmlns")){
94                 result.add(attribute.getValue().getValue());
95             }
96         }
97         //element.getAttributes()
98         for(XmlElement child: element.getChildElements()) {
99             result.addAll(getNamespaces(child));
100         }
101         return result;
102     }
103
104     @Override
105     public SortedSet<String> getCapabilities() {
106         return stripCapabilitiesResult.requiredCapabilities;
107     }
108
109     @VisibleForTesting
110     Set<String> getMissingNamespaces(){
111         return stripCapabilitiesResult.missingNamespaces;
112     }
113
114     @Override
115     public String getConfigSnapshot() {
116         return configSnapshot;
117     }
118 }