d6208553d9155ea57db59e5d2d6949f0a3c0ceba
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.models.acm.document.base;
22
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import lombok.AccessLevel;
28 import lombok.NoArgsConstructor;
29 import lombok.NonNull;
30 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaEntity;
31 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate;
32 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaTopologyTemplate;
33 import org.onap.policy.common.parameters.BeanValidationResult;
34 import org.onap.policy.common.parameters.ValidationStatus;
35 import org.onap.policy.models.base.PfUtils;
36
37 @NoArgsConstructor(access = AccessLevel.PRIVATE)
38 public final class ToscaServiceTemplateValidation {
39
40     private static final String ROOT_KEY_NAME_SUFFIX = ".Root";
41     private static final String TOPOLOGY_TEMPLATE = "TopologyTemplate";
42     private static final String NOT_FOUND = "not found";
43
44     /**
45      * validate a serviceTemplate.
46      *
47      * @param result the result
48      * @param serviceTemplate the serviceTemplate to validate
49      */
50     public static void validate(final @NonNull BeanValidationResult result, DocToscaServiceTemplate serviceTemplate,
51                                 String toscaCompositionName) {
52
53         var references = DocUtil.getToscaReferences(serviceTemplate);
54
55         validEntityTypeAncestors(serviceTemplate.getDataTypes(), references.get(DocUtil.REF_DATA_TYPES), result);
56         validEntityTypeAncestors(serviceTemplate.getCapabilityTypes(), references.get(DocUtil.REF_CAPABILITY_TYPES),
57                 result);
58         validEntityTypeAncestors(serviceTemplate.getNodeTypes(), references.get(DocUtil.REF_NODE_TYPES), result);
59         validEntityTypeAncestors(serviceTemplate.getRelationshipTypes(), references.get(DocUtil.REF_RELATIONSHIP_TYPES),
60                 result);
61         validEntityTypeAncestors(serviceTemplate.getPolicyTypes(), references.get(DocUtil.REF_POLICY_TYPES), result);
62
63         if (serviceTemplate.getNodeTypes() != null) {
64             for (var nodeType : serviceTemplate.getNodeTypes().values()) {
65                 validEntityTypeAncestors(nodeType.getRequirements(), references.get(DocUtil.REF_REQUIREMENTS), result);
66             }
67         }
68
69         validateToscaTopologyTemplate(result, serviceTemplate.getToscaTopologyTemplate(), toscaCompositionName);
70
71         if (serviceTemplate.getToscaTopologyTemplate() != null) {
72             validEntityTypeAncestors(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates(),
73                     references.get(DocUtil.REF_NODE_TEMPLATES), result);
74             validEntityTypeAncestors(serviceTemplate.getToscaTopologyTemplate().getPolicies(),
75                     references.get(DocUtil.REF_POLICIES), result);
76
77             if (serviceTemplate.getToscaTopologyTemplate().getNodeTemplates() != null) {
78                 for (var nodeTemplate : serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().values()) {
79                     validEntityTypeAncestors(nodeTemplate.getCapabilities(), references.get(DocUtil.REF_CAPABILITIES),
80                             result);
81                     validEntityTypeAncestors(nodeTemplate.getRequirements(), references.get(DocUtil.REF_REQUIREMENTS),
82                             result);
83                 }
84             }
85         }
86
87         validateReferencedDataTypes(result, serviceTemplate, references);
88
89         validatePolicyTypesInPolicies(result, serviceTemplate, references);
90
91     }
92
93     /**
94      * Validate ToscaTopologyTemplate.
95      *
96      * @param result the BeanValidationResult
97      * @param topologyTemplate the ToscaServiceTemplate
98      * @param toscaCompositionName the name of the ToscaComposition
99      */
100     public static void validateToscaTopologyTemplate(final @NonNull BeanValidationResult result,
101             DocToscaTopologyTemplate topologyTemplate, String toscaCompositionName) {
102         String acNodeTypeNotPresent =
103                 "NodeTemplate with type " + toscaCompositionName + " must exist!";
104
105         if (topologyTemplate != null && topologyTemplate.getNodeTemplates() != null) {
106             var nodeTemplates = topologyTemplate.getNodeTemplates();
107             var acNumber = nodeTemplates.values().stream().filter(
108                     nodeTemplate -> toscaCompositionName.equals(nodeTemplate.getType()))
109                     .count();
110             if (acNumber == 0) {
111                 result.addResult(TOPOLOGY_TEMPLATE, nodeTemplates, ValidationStatus.INVALID, acNodeTypeNotPresent);
112             }
113             if (acNumber > 1) {
114                 result.addResult(TOPOLOGY_TEMPLATE, nodeTemplates, ValidationStatus.INVALID, "NodeTemplate with type "
115                         + toscaCompositionName + " not allowed to be more than one!");
116             }
117         } else {
118             result.addResult(TOPOLOGY_TEMPLATE, topologyTemplate, ValidationStatus.INVALID, acNodeTypeNotPresent);
119         }
120     }
121
122     /**
123      * Validate that all data types referenced in policy types exist.
124      *
125      * @param result where the results are added
126      */
127     private static void validateReferencedDataTypes(final BeanValidationResult result,
128             DocToscaServiceTemplate serviceTemplate, Map<String, Set<String>> references) {
129         if (serviceTemplate.getDataTypes() != null) {
130             for (var dataType : serviceTemplate.getDataTypes().values()) {
131                 validateReferencedDataTypesExists(result, dataType.getReferencedDataTypes(), references);
132             }
133         }
134
135         if (serviceTemplate.getPolicyTypes() != null) {
136             for (var policyType : serviceTemplate.getPolicyTypes().values()) {
137                 validateReferencedDataTypesExists(result, policyType.getReferencedDataTypes(), references);
138             }
139         }
140         if (serviceTemplate.getNodeTypes() != null) {
141             for (var nodeType : serviceTemplate.getNodeTypes().values()) {
142                 validateReferencedDataTypesExists(result, nodeType.getReferencedDataTypes(), references);
143             }
144         }
145     }
146
147     /**
148      * Validate that the referenced data types exist for a collection of data type keys.
149      *
150      * @param dataTypeKeyCollection the data type key collection
151      * @param result where the results are added
152      */
153     private static void validateReferencedDataTypesExists(final BeanValidationResult result,
154             final Collection<DocConceptKey> dataTypeKeyCollection, Map<String, Set<String>> references) {
155         for (DocConceptKey dataTypeKey : dataTypeKeyCollection) {
156             if (!isTypePresent(dataTypeKey, references.get(DocUtil.REF_DATA_TYPES))) {
157                 result.addResult(
158                         "data type", PfUtils.getId(dataTypeKey), ValidationStatus.INVALID, NOT_FOUND);
159             }
160         }
161     }
162
163     /**
164      * Validate that all policy types referenced in policies exist.
165      *
166      * @param result where the results are added
167      */
168     private static void validatePolicyTypesInPolicies(final BeanValidationResult result,
169             DocToscaServiceTemplate serviceTemplate, Map<String, Set<String>> references) {
170         if (serviceTemplate.getToscaTopologyTemplate() == null) {
171             return;
172         }
173
174         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() != null) {
175             for (var policy : serviceTemplate.getToscaTopologyTemplate().getPolicies().values()) {
176                 var key = policy.getTypeDocConceptKey();
177                 if (!isTypePresent(key, references.get(DocUtil.REF_POLICY_TYPES))) {
178                     result.addResult("policy type", key, ValidationStatus.INVALID, NOT_FOUND);
179                 }
180             }
181         }
182         if (serviceTemplate.getToscaTopologyTemplate().getNodeTemplates() != null) {
183             for (var nodeTemplate : serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().values()) {
184                 var key = nodeTemplate.getTypeDocConceptKey();
185                 if (!isTypePresent(key, references.get(DocUtil.REF_NODE_TYPES))) {
186                     result.addResult("node Template", key, ValidationStatus.INVALID, NOT_FOUND);
187                 }
188             }
189         }
190     }
191
192     private static boolean isTypePresent(String key, Set<String> reference) {
193         if (reference.isEmpty()) {
194             return false;
195         }
196         return reference.contains(key);
197     }
198
199     private static boolean isTypePresent(DocConceptKey key, Set<String> reference) {
200         if (reference.isEmpty()) {
201             return false;
202         }
203         return reference.contains(PfUtils.getId(key));
204     }
205
206     private static String extractDerivedFrom(DocToscaEntity<?> entityType, final BeanValidationResult result) {
207         if (entityType.getDerivedFrom() == null) {
208             return null;
209         }
210         var parentEntityTypeKey = entityType.getDerivedFrom();
211
212         if (parentEntityTypeKey.endsWith(ROOT_KEY_NAME_SUFFIX)) {
213             return null;
214         }
215         if (entityType.getName().equals(parentEntityTypeKey)) {
216             result.addResult("entity type", PfUtils.getId(entityType.getDocConceptKey()), ValidationStatus.INVALID,
217                     "ancestor of itself");
218             return null;
219         }
220         return parentEntityTypeKey;
221     }
222
223     /**
224      * validate all the ancestors of an entity type.
225      *
226      * @param entityTypes the set of entity types that exist
227      * @param result the result of the ancestor search with any warnings or errors
228      */
229     private static void validEntityTypeAncestors(Map<String, ? extends DocToscaEntity<?>> entityTypes,
230             Set<String> reference, final BeanValidationResult result) {
231         if (entityTypes != null) {
232             for (var entityType : entityTypes.values()) {
233                 var parentEntityTypeKey = extractDerivedFrom(entityType, result);
234                 if (parentEntityTypeKey == null) {
235                     continue;
236                 }
237                 if (!isTypePresent(parentEntityTypeKey, reference)) {
238                     result.addResult("parent", parentEntityTypeKey, ValidationStatus.INVALID, NOT_FOUND);
239                 }
240             }
241         }
242     }
243
244     /**
245      * validate all the ancestors of an entity type.
246      *
247      * @param entityTypesList the set of entity types that exist
248      * @param result the result of the ancestor search with any warnings or errors
249      */
250     private static <T extends DocToscaEntity<?>> void validEntityTypeAncestors(List<Map<String, T>> entityTypesList,
251             Set<String> reference, final BeanValidationResult result) {
252         if (entityTypesList != null) {
253             for (var entityTypes : entityTypesList) {
254                 for (var entityType : entityTypes.values()) {
255                     var parentEntityTypeKey = extractDerivedFrom(entityType, result);
256                     if (parentEntityTypeKey == null) {
257                         continue;
258                     }
259                     if (!isTypePresent(parentEntityTypeKey, reference)) {
260                         result.addResult("parent", parentEntityTypeKey, ValidationStatus.INVALID, NOT_FOUND);
261                     }
262                 }
263             }
264         }
265     }
266
267 }