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