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