Merge "Update shema for VFC"
[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 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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.introspection;
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import org.onap.aai.exceptions.AAIException;
27 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
28
29 import java.util.HashSet;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Set;
33
34 public class IntrospectorWalker {
35
36         private static final EELFLogger LOGGER = EELFManager.getInstance().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         /**
63          * Sets the blacklist.
64          *
65          * @param list the new blacklist
66          */
67         public void setBlacklist(List<String> list) {
68                 blacklist.addAll(list);
69         }
70         
71         /**
72          * Prevent cycles.
73          *
74          * @param prevent the prevent
75          */
76         public void preventCycles(boolean prevent) {
77                 this.preventCycles = prevent;
78         }
79         
80         /**
81          * Walk.
82          *
83          * @param obj the obj
84          * @throws AAIException 
85          */
86         public void walk(Introspector obj) throws AAIException {
87                 Set<String> visited = new HashSet<>();
88
89                 walk(obj, null, visited);
90         }
91         
92         /**
93          * Walk.
94          *
95          * @param obj the obj
96          * @param parent the parent
97          * @throws AAIException 
98          */
99         private void walk(Introspector obj, Introspector parent, Set<String> visited) throws AAIException {
100                 boolean stopRecursion = false;
101                 Set<String> localVisited = new HashSet<>();
102                 localVisited.addAll(visited);
103                 if (preventCycles) {
104                         if (visited.contains(obj.getName())) {
105                                 stopRecursion = true;
106                         }
107                         if (!obj.isContainer()) {
108                                 localVisited.add(obj.getName()); //so we don't recurse while walking its children
109                         }
110                 }
111                 Set<String> props;
112                 //props must duplicate the result from getProperties because
113                 //it is unmodifiable
114                 if (this.propVisibility == null) {
115                         props = new LinkedHashSet<>(obj.getProperties());
116                 } else {
117                         props = new LinkedHashSet<>(obj.getProperties(this.propVisibility));
118                 }
119
120                 w.processComplexObj(obj);
121                 props.removeAll(blacklist);
122                 if (!obj.isContainer()) {
123                         parent = obj;
124                 }
125                 for (String prop : props) {
126                         
127                         if (obj.isSimpleType(prop)) {
128                                 
129                                 w.processPrimitive(prop, obj);
130                         } else if (obj.isListType(prop) && !stopRecursion) {
131                                 
132                                 List<Object> listReference = obj.getValue(prop);
133                                 boolean isComplexType = obj.isComplexGenericType(prop);
134                                 if (isComplexType) {
135                                         List<Introspector> list = obj.getWrappedListValue(prop);
136                                         try {
137                                                 Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
138                                                 w.modifyComplexList(list, listReference, parent, child);
139                                                 for (Object item : listReference) {
140                                                         child = IntrospectorFactory.newInstance(obj.getModelType(), item);
141                                                         walk(child, parent, localVisited);
142                                                 }
143                                         } catch (AAIUnknownObjectException e) {
144                                                 LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e);
145                                         }
146                                 } else {
147                                         w.processPrimitiveList(prop, obj);
148                                 }
149                                 if (listReference.size() == 0) {
150                                         if (isComplexType) {
151                                                 try {
152                                                         Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
153                                                         int size = w.createComplexListSize(parent, child);
154                                                         for (int i = 0; i < size; i++) {
155                                                                 child = obj.newIntrospectorInstanceOfNestedProperty(prop);
156                                                                 walk(child, parent, localVisited);
157                                                                 listReference.add(child.getUnderlyingObject());
158                                                         }
159
160                                                         obj.setValue(prop, listReference);
161                                                 } catch (AAIUnknownObjectException e) {
162                                                         LOGGER.warn("Skipping property " + prop + " (Unknown Object)", 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("Skipping property " + prop + " (Unknown Object)", e);
180                                                 }
181                                         }
182                                 }
183                                 if (child != null) {
184                                         walk(child, obj, localVisited);
185                                 }
186                         }
187                         
188                 }
189                 /*
190                 if (preventCycles && !obj.isContainer()) {
191                         visited.remove(obj.getName()); //so we can see it down another path that isn't in danger of recursing over it
192                 }*/
193         }
194 }