[AAI-178 Amsterdam] Make Edge Properties to be
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / introspection / tools / IntrospectorValidator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.aai.introspection.tools;
22
23 import org.openecomp.aai.db.props.AAIProperties;
24 import org.openecomp.aai.exceptions.AAIException;
25 import org.openecomp.aai.introspection.Introspector;
26 import org.openecomp.aai.introspection.IntrospectorWalker;
27 import org.openecomp.aai.introspection.Visibility;
28 import org.openecomp.aai.introspection.Wanderer;
29 import org.openecomp.aai.schema.enums.PropertyMetadata;
30
31 import java.util.*;
32
33 public class IntrospectorValidator implements Wanderer {
34
35         
36         private List<Issue> issues = null;
37         private List<IssueResolver> issueResolvers = null; 
38         private boolean validateRequired = true;
39         private final int maximumDepth;
40         private int currentDepth = 0;
41         
42         private final Set<String> relationshipChain;
43         /**
44          * Instantiates a new introspector validator.
45          *
46          * @param builder the builder
47          */
48         private IntrospectorValidator(Builder builder) {
49                 this.validateRequired = builder.getValidateRequired();
50                 this.issueResolvers = builder.getResolvers();
51                 this.maximumDepth = builder.getMaximumDepth();
52                 issues = new ArrayList<>();
53                 
54                 relationshipChain = new HashSet<>();
55                 
56                 relationshipChain.add("relationship-list");
57                 relationshipChain.add("relationship");
58                 relationshipChain.add("relationship-data");
59                 relationshipChain.add("related-to-property");
60
61
62         }
63         
64         /**
65          * Validate.
66          *
67          * @param obj the obj
68          * @return true, if successful
69          * @throws AAIException 
70          */
71         public boolean validate(Introspector obj) throws AAIException {
72                 IntrospectorWalker walker = new IntrospectorWalker(this);
73                 this.currentDepth = 0;
74                 walker.walk(obj);
75                 
76                 for (Issue m : issues) {
77                         if (!m.getSeverity().equals(Severity.WARNING)) {
78                                 return false;
79                         }
80                 }
81                 
82                 return true;
83         }
84         
85         /**
86          * Gets the issues.
87          *
88          * @return the issues
89          */
90         public List<Issue> getIssues() {
91                 return this.issues;
92         }
93         
94         /**
95          * Sets the issue resolvers.
96          *
97          * @param resolvers the new issue resolvers
98          */
99         public void setIssueResolvers(List<IssueResolver> resolvers) {
100                 issueResolvers = new ArrayList<>();
101                 for (IssueResolver resolver : resolvers) {
102                         issueResolvers.add(resolver);
103                 }
104         }
105         
106         /**
107          * Resolve issues.
108          *
109          * @return true, if successful
110          */
111         public boolean resolveIssues() {
112                 boolean result = true;
113                 for (Issue issue : issues) {
114                         for (IssueResolver resolver : issueResolvers) {
115                                 if (resolver.resolveIssue(issue)) {
116                                         issue.setResolved(true);
117                                 }
118                         }
119                         if (!issue.isResolved()) {
120                                 result = false;
121                         }
122                 }
123                 
124                 return result;
125         }
126         
127         /**
128          * {@inheritDoc}
129          */
130         @Override
131         public void processComplexObj(Introspector obj) {
132                                 
133                 if (this.currentDepth > this.maximumDepth && !relationshipChain.contains(obj.getDbName())) {
134                         Issue message = 
135                                         this.buildMessage(Severity.CRITICAL, IssueType.EXCEEDED_ALLOWED_DEPTH, "Maximum allowed depth of this object has been exceeded on: " + obj.getDbName());
136                         message.setIntrospector(obj);
137                         issues.add(message);
138                 }
139                 Set<String> requiredProps = obj.getRequiredProperties();
140                 Set<String> keys = obj.getKeys();
141                 Set<String> props = obj.getProperties();
142                 
143                 for (String prop : props) {
144                         Object value = obj.getValue(prop);
145                         if (keys.contains(prop)) {
146                                 if (value == null) {
147                                         Issue message = 
148                                                         this.buildMessage(Severity.CRITICAL, IssueType.MISSING_KEY_PROP, "Missing key property: " + prop);
149                                         message.setIntrospector(obj);
150                                         message.setPropName(prop);
151                                         issues.add(message);
152                                 }
153                         } else if (requiredProps.contains(prop)) {
154                                 if (value == null && validateRequired) {
155                                         Issue message = 
156                                                         this.buildMessage(Severity.CRITICAL, IssueType.MISSING_REQUIRED_PROP, "Missing required property: " + prop);
157                                         message.setIntrospector(obj);
158                                         message.setPropName(prop);
159                                         issues.add(message);
160                                 }
161                         }
162                         
163                         final Optional<String> visibility = obj.getPropertyMetadata(prop, PropertyMetadata.VISIBILITY);
164                         if(visibility.isPresent() && Visibility.internal.equals(Visibility.valueOf(visibility.get())) && obj.getValue(prop) != null) {
165                                 Issue message =
166                                                 this.buildMessage(Severity.ERROR, IssueType.PROPERTY_NOT_VISIBLE, "client attemptted to set property not visible: " + prop);
167                                 message.setIntrospector(obj);
168                                 message.setPropName(prop);
169                                 issues.add(message);
170                                 
171                         }
172                         final Optional<String> requires = obj.getPropertyMetadata(prop, PropertyMetadata.REQUIRES);
173                         if (requires.isPresent() && (obj.getValue(prop) != null && obj.getValue(requires.get()) == null)) {
174                                 Issue message =
175                                                 this.buildMessage(Severity.CRITICAL, IssueType.DEPENDENT_PROP_NOT_FOUND, prop + " requires " + requires.get() + " to also be popluated.");
176                                 message.setIntrospector(obj);
177                                 message.setPropName(prop);
178                                 issues.add(message);
179                         }
180                 }
181                 
182                 if (!relationshipChain.contains(obj.getDbName())) {
183                         this.currentDepth++;
184                 }
185
186         }
187
188         /**
189          * {@inheritDoc}
190          */
191         @Override
192         public void processPrimitive(String propName, Introspector obj) {
193                 //NO OP
194         }
195
196         /**
197          * {@inheritDoc}
198          */
199         @Override
200         public void processPrimitiveList(String propName, Introspector obj) {
201                 //NO OP
202         }
203
204         /**
205          * {@inheritDoc}
206          */
207         @Override
208         public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) {
209                 //NO OP
210         }
211         
212         
213         /**
214          * Builds the message.
215          *
216          * @param severity the severity
217          * @param error the error
218          * @param detail the detail
219          * @return the issue
220          */
221         private Issue buildMessage(Severity severity, IssueType error, String detail) {
222                 Issue message = new Issue();
223                 message.setSeverity(severity);
224                 message.setType(error);
225                 message.setDetail(detail);
226                 
227                 return message;
228         }
229
230         /**
231          * {@inheritDoc}
232          */
233         @Override
234         public boolean createComplexObjIfNull() {
235                 return false;
236         }
237
238         /**
239          * {@inheritDoc}
240          */
241         @Override
242         public int createComplexListSize(Introspector parent, Introspector child) {
243                 return 0;
244         }
245         
246         public static class Builder {
247                 
248                 private boolean validateRequired = true;
249                 private List<IssueResolver> issueResolvers = null;
250                 private int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
251                 /**
252                  * Instantiates a new builder.
253                  *
254                  * @param llBuilder the ll builder
255                  */
256                 public Builder() {
257                         issueResolvers = new ArrayList<IssueResolver>();
258                 }
259                 
260                 /**
261                  * Validate required.
262                  *
263                  * @param validateRequired the validate required
264                  * @return the builder
265                  */
266                 public Builder validateRequired(boolean validateRequired) {
267                         this.validateRequired = validateRequired;
268                         return this;
269                 }
270                 
271                 public Builder restrictDepth(int depth) {
272                         this.maximumDepth = depth; 
273                         return this;
274                 }
275                 /**
276                  * Adds the resolver.
277                  *
278                  * @param resolver the resolver
279                  * @return the builder
280                  */
281                 public Builder addResolver(IssueResolver resolver) {
282                         issueResolvers.add(resolver);
283                         return this;
284                 }
285                 
286                 /**
287                  * Builds the.
288                  *
289                  * @return the introspector validator
290                  */
291                 public IntrospectorValidator build() {
292                         return new IntrospectorValidator(this);
293                 }
294                 
295                 /**
296                  * Gets the validate required.
297                  *
298                  * @return the validate required
299                  */
300                 public boolean getValidateRequired() {
301                         return this.validateRequired;
302                 }
303                 
304                 /**
305                  * Gets the resolvers.
306                  *
307                  * @return the resolvers
308                  */
309                 public List<IssueResolver> getResolvers() {
310                         return this.issueResolvers;
311                 }
312                 
313                 public int getMaximumDepth() {
314                         return this.maximumDepth;
315                 }
316         }
317         
318 }