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