Merge "[AAI] Fix doc config files"
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / introspection / IntrospectorWalker.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;
22
23 import java.util.HashSet;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Set;
27
28 import org.onap.aai.exceptions.AAIException;
29 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
30 import org.onap.aai.logging.LogFormatTools;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 public class IntrospectorWalker {
35
36     private static final Logger LOGGER = LoggerFactory.getLogger(IntrospectorWalker.class);
37
38     private Wanderer w = null;
39     private Set<String> blacklist = null;
40     private boolean preventCycles = false;
41     private final PropertyPredicate<Introspector, String> propVisibility;
42
43     /**
44      * Instantiates a new introspector walker.
45      *
46      * @param w the w
47      * @param llBuilder the ll builder
48      */
49     public IntrospectorWalker(Wanderer w) {
50         this.w = w;
51         this.blacklist = new HashSet<>();
52         this.propVisibility = null;
53     }
54
55     public IntrospectorWalker(Wanderer w, PropertyPredicate<Introspector, String> p) {
56         this.w = w;
57         this.blacklist = new HashSet<>();
58         this.propVisibility = p;
59     }
60
61     /**
62      * Sets the blacklist.
63      *
64      * @param list the new blacklist
65      */
66     public void setBlacklist(List<String> list) {
67         blacklist.addAll(list);
68     }
69
70     /**
71      * Prevent cycles.
72      *
73      * @param prevent the prevent
74      */
75     public void preventCycles(boolean prevent) {
76         this.preventCycles = prevent;
77     }
78
79     /**
80      * Walk.
81      *
82      * @param obj the obj
83      * @throws AAIException
84      */
85     public void walk(Introspector obj) throws AAIException {
86         Set<String> visited = new HashSet<>();
87
88         walk(obj, null, visited);
89     }
90
91     /**
92      * Walk.
93      *
94      * @param obj the obj
95      * @param parent the parent
96      * @throws AAIException
97      */
98     private void walk(Introspector obj, Introspector parent, Set<String> visited) throws AAIException {
99         boolean stopRecursion = false;
100         Set<String> localVisited = new HashSet<>();
101         localVisited.addAll(visited);
102         if (preventCycles) {
103             if (visited.contains(obj.getName())) {
104                 stopRecursion = true;
105             }
106             if (!obj.isContainer()) {
107                 localVisited.add(obj.getName()); // so we don't recurse while walking its children
108             }
109         }
110         Set<String> props;
111         // props must duplicate the result from getProperties because
112         // it is unmodifiable
113         if (this.propVisibility == null) {
114             props = new LinkedHashSet<>(obj.getProperties());
115         } else {
116             props = new LinkedHashSet<>(obj.getProperties(this.propVisibility));
117         }
118
119         w.processComplexObj(obj);
120         props.removeAll(blacklist);
121         if (!obj.isContainer()) {
122             parent = obj;
123         }
124         for (String prop : props) {
125
126             if (obj.isSimpleType(prop)) {
127
128                 w.processPrimitive(prop, obj);
129             } else if (obj.isListType(prop) && !stopRecursion) {
130
131                 List<Object> listReference = obj.getValue(prop);
132                 boolean isComplexType = obj.isComplexGenericType(prop);
133                 if (isComplexType) {
134                     List<Introspector> list = obj.getWrappedListValue(prop);
135                     try {
136                         Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
137                         w.modifyComplexList(list, listReference, parent, child);
138                         for (Object item : listReference) {
139                             child = IntrospectorFactory.newInstance(obj.getModelType(), item);
140                             walk(child, parent, localVisited);
141                         }
142                     } catch (AAIUnknownObjectException e) {
143                         LOGGER.warn("Skipping property " + prop + " (Unknown Object) " + LogFormatTools.getStackTop(e));
144                     }
145                 } else {
146                     w.processPrimitiveList(prop, obj);
147                 }
148                 if (listReference.size() == 0) {
149                     if (isComplexType) {
150                         try {
151                             Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
152                             int size = w.createComplexListSize(parent, child);
153                             for (int i = 0; i < size; i++) {
154                                 child = obj.newIntrospectorInstanceOfNestedProperty(prop);
155                                 walk(child, parent, localVisited);
156                                 listReference.add(child.getUnderlyingObject());
157                             }
158
159                             obj.setValue(prop, listReference);
160                         } catch (AAIUnknownObjectException e) {
161                             LOGGER.warn(
162                                     "Skipping property " + prop + " (Unknown Object) " + LogFormatTools.getStackTop(e));
163                         }
164                     } else if (!isComplexType) {
165                         w.processPrimitiveList(prop, obj);
166                     }
167                 }
168
169             } else if (obj.isComplexType(prop) && !stopRecursion) {
170                 Introspector child = null;
171                 if (obj.getValue(prop) != null) {
172                     child = IntrospectorFactory.newInstance(obj.getModelType(), obj.getValue(prop));
173                 } else {
174                     if (w.createComplexObjIfNull()) {
175                         try {
176                             child = obj.newIntrospectorInstanceOfProperty(prop);
177                             obj.setValue(prop, child.getUnderlyingObject());
178                         } catch (AAIUnknownObjectException e) {
179                             LOGGER.warn(
180                                     "Skipping property " + prop + " (Unknown Object) " + LogFormatTools.getStackTop(e));
181                         }
182                     }
183                 }
184                 if (child != null) {
185                     walk(child, obj, localVisited);
186                 }
187             }
188
189         }
190         /*
191          * if (preventCycles && !obj.isContainer()) {
192          * visited.remove(obj.getName()); //so we can see it down another path that isn't in danger of recursing over it
193          * }
194          */
195     }
196 }