AAI-1523 Batch reformat aai-core
[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
21 package org.onap.aai.introspection.tools;
22
23 import java.util.*;
24
25 import org.onap.aai.db.props.AAIProperties;
26 import org.onap.aai.exceptions.AAIException;
27 import org.onap.aai.introspection.Introspector;
28 import org.onap.aai.introspection.IntrospectorWalker;
29 import org.onap.aai.introspection.Visibility;
30 import org.onap.aai.introspection.Wanderer;
31 import org.onap.aai.schema.enums.PropertyMetadata;
32
33 public class IntrospectorValidator implements Wanderer {
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     /**
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      * 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 = this.buildMessage(Severity.CRITICAL, IssueType.EXCEEDED_ALLOWED_DEPTH,
134                     "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 = this.buildMessage(Severity.CRITICAL, IssueType.MISSING_KEY_PROP,
147                             "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 = this.buildMessage(Severity.CRITICAL, IssueType.MISSING_REQUIRED_PROP,
155                             "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()))
164                     && obj.getValue(prop) != null) {
165                 Issue message = this.buildMessage(Severity.ERROR, IssueType.PROPERTY_NOT_VISIBLE,
166                         "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 = this.buildMessage(Severity.CRITICAL, IssueType.DEPENDENT_PROP_NOT_FOUND,
175                         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,
209             Introspector child) {
210         // NO OP
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         /**
253          * Instantiates a new builder.
254          *
255          * @param llBuilder the ll builder
256          */
257         public Builder() {
258             issueResolvers = new ArrayList<IssueResolver>();
259         }
260
261         /**
262          * Validate required.
263          *
264          * @param validateRequired the validate required
265          * @return the builder
266          */
267         public Builder validateRequired(boolean validateRequired) {
268             this.validateRequired = validateRequired;
269             return this;
270         }
271
272         public Builder restrictDepth(int depth) {
273             this.maximumDepth = depth;
274             return this;
275         }
276
277         /**
278          * Adds the resolver.
279          *
280          * @param resolver the resolver
281          * @return the builder
282          */
283         public Builder addResolver(IssueResolver resolver) {
284             issueResolvers.add(resolver);
285             return this;
286         }
287
288         /**
289          * Builds the.
290          *
291          * @return the introspector validator
292          */
293         public IntrospectorValidator build() {
294             return new IntrospectorValidator(this);
295         }
296
297         /**
298          * Gets the validate required.
299          *
300          * @return the validate required
301          */
302         public boolean getValidateRequired() {
303             return this.validateRequired;
304         }
305
306         /**
307          * Gets the resolvers.
308          *
309          * @return the resolvers
310          */
311         public List<IssueResolver> getResolvers() {
312             return this.issueResolvers;
313         }
314
315         public int getMaximumDepth() {
316             return this.maximumDepth;
317         }
318     }
319
320 }