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