Capabilities check to include both namespace and revision
[ccsdk/features.git] / sdnr / wt / netconfnode-state-service / model / src / main / java / org / onap / ccsdk / features / sdnr / wt / netconfnodestateservice / Capabilities.java
1 /*
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18 /**
19  * Convert capabilities of netconfnode into internal format. Boron and Carbon are providing
20  * different versions
21  */
22 package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice;
23
24 import java.text.DateFormat;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.Optional;
30 import javax.annotation.Nullable;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilities;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilities;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Wrapper class for capabilites for Boron and later releases. Uses generics because yang model was changed from Boron
42  * to later version. Interface class:
43  * org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability
44  */
45 public class Capabilities {
46
47     private static final Logger LOG = LoggerFactory.getLogger(Capabilities.class);
48
49     private static final String UNSUPPORTED = "Unsupported";
50     private final List<String> capabilities = new ArrayList<>();
51     private final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
52
53     private Capabilities() {}
54
55     public static Capabilities getAvailableCapabilities(@Nullable NetconfNode nnode) {
56         LOG.info("GetAvailableCapabilities for node");
57         Capabilities capabilities = new Capabilities();
58         if (nnode != null) {
59             AvailableCapabilities availableCapabilites = nnode.getAvailableCapabilities();
60             if (availableCapabilites != null) {
61                 capabilities.constructor(availableCapabilites.getAvailableCapability());
62             } else {
63                 LOG.debug("empty capabilites");
64             }
65         } else {
66             LOG.debug("No node provided");
67         }
68         return capabilities;
69     }
70
71     public static Capabilities getUnavailableCapabilities(NetconfNode nnode) {
72         LOG.info("GetUnavailableCapabilities for node");
73         Capabilities capabilities = new Capabilities();
74         if (nnode != null) {
75             UnavailableCapabilities availableCapabilites = nnode.getUnavailableCapabilities();
76             if (availableCapabilites != null) {
77                 capabilities.constructor2(availableCapabilites.getUnavailableCapability());
78             } else {
79                 LOG.debug("empty capabilites");
80             }
81         } else {
82             LOG.debug("No node provided");
83         }
84         return capabilities;
85     }
86
87
88     /**
89      * Does all construction steps
90      *
91      * @param pcapabilities with a list of capabilities.
92      */
93     private void constructor(List<AvailableCapability> pcapabilities) {
94         if (pcapabilities != null) {
95             for (AvailableCapability capability : pcapabilities) {
96                 this.capabilities.add(capability.getCapability());
97             }
98         }
99     }
100
101     private void constructor2(List<UnavailableCapability> pcapabilities) {
102         if (pcapabilities != null) {
103             for (UnavailableCapability capability : pcapabilities) {
104                 this.capabilities.add(capability.getCapability());
105             }
106         }
107     }
108
109     /**
110      * Get Capabilites
111      *
112      * @return List<String> with capabilites
113      */
114     public List<String> getCapabilities() {
115         return capabilities;
116     }
117
118     /**
119      * Verify if the namespace is supported
120      *
121      * @param qCapability from model
122      * @return true if namespace is supported
123      */
124     public boolean isSupportingNamespace(QName qCapability) {
125         String namespace = qCapability.getNamespace().toString();
126         return isSupportingNamespaceAndRevision(namespace, null);
127     }
128
129     /**
130      * Verify if the namespace is supported
131      *
132      * @param namespace
133      * @return
134      */
135     public boolean isSupportingNamespace(String namespace) {
136         return isSupportingNamespaceAndRevision(namespace, null);
137     }
138
139     /**
140      * check if the namespace and its revision are supported by the given capabilities
141      *
142      * @param qCapability capability from the model
143      * @return true if supporting the model AND revision<br>
144      *         false if revision not available or both not found.
145      */
146     public boolean isSupportingNamespaceAndRevision(QName qCapability) {
147         String namespace = qCapability.getNamespace().toString();
148         String revision = getRevisionString(qCapability);
149         return revision == null ? false : isSupportingNamespaceAndRevision(namespace, revision);
150     }
151
152     /**
153      *
154      * @param namespace requested
155      * @param revision request or null for any revision
156      * @return true if existing
157      */
158     public boolean isSupportingNamespaceAndRevision(String namespace, @Nullable String revision) {
159         LOG.trace("isSupportingNamespaceAndRevision: Model namespace {}?[revision {}]", namespace, revision);
160
161         final String nsAndRev = String.format("%s?revision=%s", namespace, revision);
162         for (String capability : capabilities) {
163             //if (capability.contains(namespace) && (revision == null || capability.contains(revision))) {
164             if (capability.contains(revision != null ? nsAndRev : namespace)) {
165                 LOG.trace("Verify true with: {}", capability);
166                 return true;
167             } else {
168                 LOG.trace("Verify false with: {}", capability);
169             }
170         }
171         return false;
172     }
173
174     /**
175      * Provide revision as String from QName, considering older formats.
176      *
177      * @param qCapability that specifies the revision
178      * @return String with revisiondate or null
179      */
180     private String getRevisionString(QName qCapability) {
181         Object revisionObject = qCapability.getRevision();
182         String revision = null;
183         if (revisionObject instanceof Optional) {
184             if (((Optional<?>) revisionObject).isPresent()) {
185                 revisionObject = ((Optional<?>) revisionObject).get();
186                 LOG.info("Unwrapp Optional: {}", revisionObject != null ? revisionObject.getClass() : null);
187             }
188         }
189         if (revisionObject == null) {
190             // Cover null case
191         } else if (revisionObject instanceof String) {
192             revision = (String) revisionObject;
193         } else if (revisionObject instanceof Date) {
194             revision = formatter.format((Date) revisionObject);
195         } else {
196             revision = revisionObject.toString();
197             LOG.debug("Revision number type not supported. Use toString().String:{} Class:{} ", revisionObject,
198                     revisionObject.getClass().getName());
199         }
200         return revision;
201     }
202
203     /**
204      * Get revision of first entry of related capability
205      *
206      * @param qCapability that specifies the namespace
207      * @return String with date or
208      */
209     public String getRevisionForNamespace(QName qCapability) {
210         String namespace = qCapability.getNamespace().toString();
211         for (String capability : capabilities) {
212             if (capability.contains(namespace)) {
213                 return QName.create(capability).getRevision().get().toString();
214             }
215         }
216         return UNSUPPORTED;
217     }
218
219     /**
220      * Verify if QName namespace is supported by capabilities
221      *
222      * @param revision result of getRevisionForNamespace()
223      * @return true if namespace is supported.
224      */
225     static public boolean isNamespaceSupported(String revision) {
226         return revision != UNSUPPORTED;
227     }
228
229     @Override
230     public String toString() {
231         return "Capabilities [capabilities=" + capabilities + "]";
232     }
233
234 }