Merge "Fix file stream closing"
[aai/data-router.git] / src / main / java / org / onap / aai / datarouter / util / VersionedOxmEntities.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.aai.datarouter.util;
22
23 import org.eclipse.persistence.dynamic.DynamicType;
24 import org.eclipse.persistence.internal.helper.DatabaseField;
25 import org.eclipse.persistence.internal.oxm.XPathFragment;
26 import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
27 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
28 import org.eclipse.persistence.mappings.DatabaseMapping;
29 import org.eclipse.persistence.oxm.XMLField;
30 import org.onap.aai.datarouter.entity.OxmEntityDescriptor;
31
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.LinkedHashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.Vector;
42
43 /**
44  * Builds up a representation of the versioned entities in a way that they can be cross referenced
45  * in a data-driven way
46  *
47  * @author DAVEA
48  */
49 public class VersionedOxmEntities {
50
51     private static final String REST_ROOT_ENTITY = "inventory";
52
53     private HashMap<String, Boolean> crossEntityReferenceContainerLookup = new HashMap<>();
54     private HashMap<String, CrossEntityReference> crossEntityReferenceLookup = new HashMap<>();
55     private Map<String, DynamicType> entityTypeLookup = new LinkedHashMap<>();
56     private Map<String, OxmEntityDescriptor> searchableEntityDescriptors = new HashMap<>();
57     private Map<String, OxmEntityDescriptor> suggestableEntityDescriptors = new HashMap<>();
58     private Map<String, OxmEntityDescriptor> entityAliasDescriptors = new HashMap<>();
59
60
61     public void initialize(DynamicJAXBContext context) {
62         parseOxmContext(context);
63         buildCrossEntityReferenceCollections(REST_ROOT_ENTITY, new HashSet<String>());
64         populateSearchableDescriptors(context);
65     }
66
67     /**
68      * The big goal for these methods is to make the processing as generic and model driven as possible.
69      * There are only two exceptions to this rule, at the moment.  I needed to hard-coded the top level REST data
70      * model entity type, which is "inventory" for now.   And as this class is heavily focused and coupled towards
71      * building a version specific set of lookup structures for the "crossEntityReference" model attribute, it possesses
72      * knowledge of that attribute whether it exists or not in the DynamicJAXBContext we are currently analyzing.
73      * <p>
74      * This method will build two collections:
75      * <p>
76      * 1)  A list of entity types that can have nested entities containing cross entity reference definitions.
77      * The purpose of this collection is a fail-fast test when processing UEB events so we can quickly determine if
78      * it is necessary to deeply parse the event looking for cross entity reference attributes which not exist.
79      * <p>
80      * For example, looking at a service-instance <=> inventory path:
81      * <p>
82      * inventory (true)
83      * -> business (true)
84      * -> customers  (true)
85      * -> customer  (true)
86      * -> service-subscriptions (true)
87      * -> service-subscription (CER defined here in the model)   (true)
88      * -> service-instances    (false)
89      * -> service-instance   (false)
90      * <p>
91      * Because service-subscription contains a model definition of CER, in the first collection all the types in the
92      * tree will indicate that it possesses one or more contained entity types with a cross-entity-reference definition.
93      * <p>
94      * 2)  A lookup for { entityType => CrossEntityReference } so we can quickly access the model definition of a CER
95      * for a specific entity type when we begin extracting parent attributes for transposition into nested child entity
96      * types.
97      *
98      * @param entityType
99      * @param checked
100      * @return
101      */
102     protected boolean buildCrossEntityReferenceCollections(String entityType, HashSet<String> checked) {
103
104       /*
105        * To short-circuit infinite loops, make sure this entityType hasn't
106        * already been checked
107        */
108
109         if (checked.contains(entityType)) {
110             return false;
111         } else {
112             checked.add(entityType);
113         }
114
115         DynamicType parentType = entityTypeLookup.get(entityType);
116         DynamicType childType;
117         boolean returnValue = false;
118
119         if (parentType == null) {
120             return returnValue;
121         }
122
123       /*
124        * Check if current descriptor contains the cross-entity-reference
125        * attribute. If it does not walk the entity model looking for nested
126        * entity types that may contain the reference.
127        */
128
129         Map<String, String> properties = parentType.getDescriptor().getProperties();
130         if (properties != null) {
131             for (Map.Entry<String, String> entry : properties.entrySet()) {
132                 if ("crossEntityReference".equalsIgnoreCase(entry.getKey())) {
133                     returnValue = true;
134                     CrossEntityReference cer = new CrossEntityReference();
135                     cer.initialize(entry.getValue());
136                     crossEntityReferenceLookup.put(entityType, cer);
137                     //System.out.println("entityType = " + entityType + " contains a CER instance = " + returnValue);
138                     // return true;
139                 }
140             }
141         }
142
143         Vector<DatabaseField> fields = parentType.getDescriptor().getAllFields();
144
145         if (fields != null) {
146
147             XMLField xmlField;
148             for (DatabaseField f : fields) {
149
150                 if (f instanceof XMLField) {
151                     xmlField = (XMLField) f;
152                     XPathFragment xpathFragment = xmlField.getXPathFragment();
153                     String entityShortName = xpathFragment.getLocalName();
154
155                     childType = entityTypeLookup.get(entityShortName);
156
157                     if (childType != null) {
158
159                         if (!checked.contains(entityShortName)) {
160
161                             if (buildCrossEntityReferenceCollections(entityShortName, checked)) {
162                                 returnValue = true;
163                             }
164
165                         }
166
167                         checked.add(entityShortName);
168
169                     }
170
171                 }
172
173             }
174
175         }
176
177         crossEntityReferenceContainerLookup.put(entityType, Boolean.valueOf(returnValue));
178         return returnValue;
179     }
180
181     private void populateSearchableDescriptors(DynamicJAXBContext oxmContext) {
182         List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
183         OxmEntityDescriptor newOxmEntity;
184
185         for (Descriptor desc : descriptorsList) {
186
187             DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
188
189             //LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
190             String primaryKeyAttributeNames = null;
191
192             //Not all fields have key attributes
193             if (desc.getPrimaryKeyFields() != null) {
194                 primaryKeyAttributeNames = desc.getPrimaryKeyFields()
195                         .toString().replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", "");
196             }
197
198             String entityName = desc.getDefaultRootElement();
199
200             Map<String, String> properties = entity.getDescriptor().getProperties();
201             if (properties != null) {
202                 for (Map.Entry<String, String> entry : properties.entrySet()) {
203                     if ("searchable".equalsIgnoreCase(entry.getKey())) {
204                   
205                   /*
206                    * we can do all the work here, we don't have a create additional collections for 
207                    * subsequent passes
208                    */
209                         newOxmEntity = new OxmEntityDescriptor();
210                         newOxmEntity.setEntityName(entityName);
211                         newOxmEntity
212                                 .setPrimaryKeyAttributeName(Arrays.asList(primaryKeyAttributeNames.split(",")));
213                         newOxmEntity.setSearchableAttributes(Arrays.asList(entry.getValue().split(",")));
214                         searchableEntityDescriptors.put(entityName, newOxmEntity);
215                     } else if ("containsSuggestibleProps".equalsIgnoreCase(entry.getKey())) {
216                         newOxmEntity = new OxmEntityDescriptor();
217                         newOxmEntity.setEntityName(entityName);
218                         newOxmEntity.setSuggestableEntity(true);
219                         Vector<DatabaseMapping> descriptorMaps = entity.getDescriptor().getMappings();
220                         List<String> listOfSuggestableAttributes = new ArrayList<>();
221
222                         for (DatabaseMapping descMap : descriptorMaps) {
223                             if (descMap.isAbstractDirectMapping()) {
224
225                                 if (descMap.getProperties().get("suggestibleOnSearch") != null) {
226                                     String suggestableOnSearchString = String.valueOf(
227                                             descMap.getProperties().get("suggestibleOnSearch"));
228
229                                     boolean isSuggestibleOnSearch = Boolean.valueOf(suggestableOnSearchString);
230
231                                     if (isSuggestibleOnSearch) {
232                          /* Grab attribute types for suggestion */
233                                         String attributeName = descMap.getField().getName()
234                                                 .replaceAll("/text\\(\\)", "");
235                                         listOfSuggestableAttributes.add(attributeName);
236                                     }
237                                 }
238                             }
239                         }
240                         newOxmEntity.setSuggestableAttributes(listOfSuggestableAttributes);
241                         suggestableEntityDescriptors.put(entityName, newOxmEntity);
242                     } else if ("suggestionAliases".equalsIgnoreCase(entry.getKey())) {
243                         newOxmEntity = new OxmEntityDescriptor();
244                         newOxmEntity.setEntityName(entityName);
245                         newOxmEntity.setAlias(Arrays.asList(entry.getValue().split(",")));
246                         entityAliasDescriptors.put(entityName, newOxmEntity);
247                     }
248                 }
249             }
250
251         }
252
253     }
254
255     public Map<String, OxmEntityDescriptor> getSearchableEntityDescriptors() {
256         return searchableEntityDescriptors;
257     }
258
259     public OxmEntityDescriptor getSearchableEntityDescriptor(String entityType) {
260         return searchableEntityDescriptors.get(entityType);
261     }
262
263
264     public HashMap<String, Boolean> getCrossEntityReferenceContainers() {
265         return crossEntityReferenceContainerLookup;
266     }
267
268     public HashMap<String, CrossEntityReference> getCrossEntityReferences() {
269         return crossEntityReferenceLookup;
270     }
271
272
273     private void parseOxmContext(DynamicJAXBContext oxmContext) {
274         List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
275
276         for (Descriptor desc : descriptorsList) {
277
278             DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
279
280             String entityName = desc.getDefaultRootElement();
281
282             entityTypeLookup.put(entityName, entity);
283
284         }
285
286     }
287
288     public boolean entityModelContainsCrossEntityReference(String containerEntityType) {
289         Boolean v = crossEntityReferenceContainerLookup.get(containerEntityType);
290
291         if (v == null) {
292             return false;
293         }
294
295         return v;
296     }
297
298     public boolean entityContainsCrossEntityReference(String entityType) {
299         return crossEntityReferenceLookup.get(entityType) != null;
300     }
301
302     public CrossEntityReference getCrossEntityReference(String entityType) {
303         return crossEntityReferenceLookup.get(entityType);
304     }
305
306     public Map<String, OxmEntityDescriptor> getSuggestableEntityDescriptors() {
307         return suggestableEntityDescriptors;
308     }
309
310     public void setSuggestableEntityDescriptors(
311             Map<String, OxmEntityDescriptor> suggestableEntityDescriptors) {
312         this.suggestableEntityDescriptors = suggestableEntityDescriptors;
313     }
314
315     public Map<String, OxmEntityDescriptor> getEntityAliasDescriptors() {
316         return entityAliasDescriptors;
317     }
318
319     public void setEntityAliasDescriptors(Map<String, OxmEntityDescriptor> entityAliasDescriptors) {
320         this.entityAliasDescriptors = entityAliasDescriptors;
321     }
322
323     public void extractEntities(String entityType, DynamicJAXBContext context, Collection<DynamicType> entities) {
324
325
326     }
327
328     public String dumpCrossEntityReferenceContainers() {
329
330         Set<String> keys = crossEntityReferenceContainerLookup.keySet();
331         StringBuilder sb = new StringBuilder(128);
332
333         for (String key : keys) {
334
335             if (crossEntityReferenceContainerLookup.get(key)) {
336                 sb.append("\n").append("Entity-Type = '" + key + "' contains a Cross-Entity-Reference.");
337             }
338         }
339
340
341         return sb.toString();
342
343     }
344     
345     public Map<String, DynamicType> getEntityTypeLookup() {
346       return entityTypeLookup;
347     }
348
349 }