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