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