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