Update license files, sonar plugin and fix tests
[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 }