0e5b4bcd678ae2d35205fd9f35eb9d1bdd2581d7
[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()))) {
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                 }
177                 
178                 if (!relationshipChain.contains(obj.getDbName())) {
179                         this.currentDepth++;
180                 }
181
182         }
183
184         /**
185          * {@inheritDoc}
186          */
187         @Override
188         public void processPrimitive(String propName, Introspector obj) {
189                 //NO OP
190         }
191
192         /**
193          * {@inheritDoc}
194          */
195         @Override
196         public void processPrimitiveList(String propName, Introspector obj) {
197                 //NO OP
198         }
199
200         /**
201          * {@inheritDoc}
202          */
203         @Override
204         public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) {
205                 //NO OP
206         }
207         
208         
209         /**
210          * Builds the message.
211          *
212          * @param severity the severity
213          * @param error the error
214          * @param detail the detail
215          * @return the issue
216          */
217         private Issue buildMessage(Severity severity, IssueType error, String detail) {
218                 Issue message = new Issue();
219                 message.setSeverity(severity);
220                 message.setType(error);
221                 message.setDetail(detail);
222                 
223                 return message;
224         }
225
226         /**
227          * {@inheritDoc}
228          */
229         @Override
230         public boolean createComplexObjIfNull() {
231                 return false;
232         }
233
234         /**
235          * {@inheritDoc}
236          */
237         @Override
238         public int createComplexListSize(Introspector parent, Introspector child) {
239                 return 0;
240         }
241         
242         public static class Builder {
243                 
244                 private boolean validateRequired = true;
245                 private List<IssueResolver> issueResolvers = null;
246                 private int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
247                 /**
248                  * Instantiates a new builder.
249                  *
250                  * @param llBuilder the ll builder
251                  */
252                 public Builder() {
253                         issueResolvers = new ArrayList<IssueResolver>();
254                 }
255                 
256                 /**
257                  * Validate required.
258                  *
259                  * @param validateRequired the validate required
260                  * @return the builder
261                  */
262                 public Builder validateRequired(boolean validateRequired) {
263                         this.validateRequired = validateRequired;
264                         return this;
265                 }
266                 
267                 public Builder restrictDepth(int depth) {
268                         this.maximumDepth = depth; 
269                         return this;
270                 }
271                 /**
272                  * Adds the resolver.
273                  *
274                  * @param resolver the resolver
275                  * @return the builder
276                  */
277                 public Builder addResolver(IssueResolver resolver) {
278                         issueResolvers.add(resolver);
279                         return this;
280                 }
281                 
282                 /**
283                  * Builds the.
284                  *
285                  * @return the introspector validator
286                  */
287                 public IntrospectorValidator build() {
288                         return new IntrospectorValidator(this);
289                 }
290                 
291                 /**
292                  * Gets the validate required.
293                  *
294                  * @return the validate required
295                  */
296                 public boolean getValidateRequired() {
297                         return this.validateRequired;
298                 }
299                 
300                 /**
301                  * Gets the resolvers.
302                  *
303                  * @return the resolvers
304                  */
305                 public List<IssueResolver> getResolvers() {
306                         return this.issueResolvers;
307                 }
308                 
309                 public int getMaximumDepth() {
310                         return this.maximumDepth;
311                 }
312         }
313         
314 }