12d545d2cffcfef47eaa424607387634df6b5aae
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / introspection / IntrospectorWalker.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;
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.openecomp.aai.exceptions.AAIException;
29 import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
30 import com.att.eelf.configuration.EELFLogger;
31 import com.att.eelf.configuration.EELFManager;
32
33 public class IntrospectorWalker {
34
35         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IntrospectorWalker.class);
36
37         private Wanderer w = null;
38         private Set<String> blacklist = null;
39         private boolean preventCycles = false;
40         private final PropertyPredicate<Introspector, String> propVisibility;
41         
42         /**
43          * Instantiates a new introspector walker.
44          *
45          * @param w the w
46          * @param llBuilder the ll builder
47          */
48         public IntrospectorWalker(Wanderer w) {
49                 this.w = w;
50                 this.blacklist = new HashSet<>();
51                 this.propVisibility = null;
52         }
53         
54         public IntrospectorWalker(Wanderer w, PropertyPredicate<Introspector, String> p) {
55                 this.w = w;
56                 this.blacklist = new HashSet<>();
57                 this.propVisibility = p;
58         }
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)", 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("Skipping property " + prop + " (Unknown Object)", e);
162                                                 }
163                                         } else if (!isComplexType){
164                                                 w.processPrimitiveList(prop, obj);
165                                         }
166                                 }
167                         
168                         } else if (obj.isComplexType(prop) && !stopRecursion) {
169                                 Introspector child = null;
170                                 if (obj.getValue(prop) != null) {
171                                         child = IntrospectorFactory.newInstance(obj.getModelType(), obj.getValue(prop));
172                                 } else {
173                                         if (w.createComplexObjIfNull()) {
174                                                 try {
175                                                         child = obj.newIntrospectorInstanceOfProperty(prop);
176                                                         obj.setValue(prop, child.getUnderlyingObject());
177                                                 } catch (AAIUnknownObjectException e) {
178                                                         LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e);
179                                                 }
180                                         }
181                                 }
182                                 if (child != null) {
183                                         walk(child, obj, localVisited);
184                                 }
185                         }
186                         
187                 }
188                 /*
189                 if (preventCycles && !obj.isContainer()) {
190                         visited.remove(obj.getName()); //so we can see it down another path that isn't in danger of recursing over it
191                 }*/
192         }
193 }