Initial ONAP Synapse commit
[aai/data-router.git] / src / main / java / org / openecomp / datarouter / util / VersionedOxmEntities.java
diff --git a/src/main/java/org/openecomp/datarouter/util/VersionedOxmEntities.java b/src/main/java/org/openecomp/datarouter/util/VersionedOxmEntities.java
new file mode 100644 (file)
index 0000000..46c4a76
--- /dev/null
@@ -0,0 +1,352 @@
+/**
+ * ============LICENSE_START=======================================================
+ * DataRouter
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.openecomp.datarouter.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.internal.oxm.XPathFragment;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.oxm.XMLField;
+import org.openecomp.datarouter.entity.OxmEntityDescriptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Builds up a representation of the versioned entities in a way that they can be cross referenced
+ * in a data-driven way
+ * @author DAVEA
+ */
+public class VersionedOxmEntities {
+
+   private static final Logger logger = LoggerFactory.getLogger(VersionedOxmEntities.class);
+   private static final String REST_ROOT_ENTITY = "inventory";
+
+   private HashMap<String,Boolean> crossEntityReferenceContainerLookup = new HashMap<String,Boolean>();
+   private HashMap<String,CrossEntityReference> crossEntityReferenceLookup = new HashMap<String,CrossEntityReference>();
+   private Map<String,DynamicType> entityTypeLookup = new LinkedHashMap<String,DynamicType>();
+   private Map<String, OxmEntityDescriptor> searchableEntityDescriptors = new HashMap<String, OxmEntityDescriptor>();
+   private Map<String, OxmEntityDescriptor> suggestableEntityDescriptors = new HashMap<String, OxmEntityDescriptor>();
+   private Map<String, OxmEntityDescriptor> entityAliasDescriptors = new HashMap<String, OxmEntityDescriptor>();
+
+   
+   public void initialize(DynamicJAXBContext context) {
+      parseOxmContext(context);
+      buildCrossEntityReferenceCollections(REST_ROOT_ENTITY, new HashSet<String>());
+      populateSearchableDescriptors(context);
+   }
+   
+   /**
+    * The big goal for these methods is to make the processing as generic and model driven as possible.  There are only two 
+    * exceptions to this rule, at the moment.  I needed to hard-coded the top level REST data model entity type, which is
+    * "inventory" for now.   And as this class is heavily focused and coupled towards building a version specific set of 
+    * lookup structures for the "crossEntityReference" model attribute, it possesses knowledge of that attribute whether it 
+    * exists or not in the DynamicJAXBContext we are currently analyzing.
+    * 
+    * This method will build two collections:
+    * 
+    * 1)  A list of entity types that can have nested entities containing cross entity reference definitions.  The purpose
+    *     of this collection is a fail-fast test when processing UEB events so we can quickly determine if it is necessary
+    *     to deeply parse the event looking for cross entity reference attributes which not exist.
+    *     
+    *     For example, looking at a service-instance <=> inventory path:
+    *     
+    *     inventory (true)
+    *     -> business (true)
+    *        -> customers  (true)
+    *           -> customer  (true)
+    *              -> service-subscriptions (true)
+    *                 -> service-subscription (CER defined here in the model)   (true)
+    *                    -> service-instances    (false)
+    *                       -> service-instance   (false)
+    *     
+    *     Because service-subscription contains a model definition of CER, in the first collection all the types in the tree will
+    *     indicate that it possesses one or more contained entity types with a cross-entity-reference definition.
+    *     
+    * 2)  A lookup for { entityType => CrossEntityReference } so we can quickly access the model definition of a CER for
+    *     a specific entity type when we begin extracting parent attributes for transposition into nested child entity types.
+    * 
+    * 
+    * @param entityType
+    * @param checked
+    * @return
+    */
+   protected boolean buildCrossEntityReferenceCollections(String entityType, HashSet<String> checked) {
+
+      /*
+       * To short-circuit infinite loops, make sure this entityType hasn't
+       * already been checked
+       */
+
+      if(checked.contains(entityType)) {
+         return false;
+      }
+      else {
+         checked.add(entityType);
+      }
+
+      DynamicType parentType = entityTypeLookup.get(entityType);
+      DynamicType childType = null;
+      boolean returnValue = false;
+
+      if(parentType == null) {
+         return returnValue;
+      }
+
+      /*
+       * Check if current descriptor contains the cross-entity-reference
+       * attribute. If it does not walk the entity model looking for nested
+       * entity types that may contain the reference.
+       */
+
+      Map<String, String> properties = parentType.getDescriptor().getProperties();
+      if(properties != null) {
+         for(Map.Entry<String, String> entry : properties.entrySet()) {
+            if(entry.getKey().equalsIgnoreCase("crossEntityReference")) {
+               returnValue = true;
+               CrossEntityReference cer = new CrossEntityReference();
+               cer.initialize(entry.getValue());
+               crossEntityReferenceLookup.put( entityType, cer);
+               //System.out.println("entityType = " + entityType + " contains a CER instance = " + returnValue);
+              // return true;
+            }
+         }
+      }
+
+      Vector<DatabaseField> fields = parentType.getDescriptor().getAllFields();
+
+      if(fields != null) {
+
+         XMLField xmlField = null;
+         for(DatabaseField f : fields) {
+
+            if(f instanceof XMLField) {
+               xmlField = (XMLField)f;
+               XPathFragment xpathFragment = xmlField.getXPathFragment();
+               String entityShortName = xpathFragment.getLocalName();
+
+               childType = entityTypeLookup.get(entityShortName);
+
+               if(childType != null) {
+
+                  if(!checked.contains(entityShortName)) {
+
+                     if(buildCrossEntityReferenceCollections(entityShortName,checked)) {
+                        returnValue = true;
+                     }
+
+                  }
+
+                  checked.add(entityShortName);
+
+               }
+
+            }
+
+         }
+
+      }
+
+      crossEntityReferenceContainerLookup.put(entityType, Boolean.valueOf(returnValue));
+      return returnValue;
+   }
+   
+   private void populateSearchableDescriptors(DynamicJAXBContext oxmContext) {
+      List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
+      OxmEntityDescriptor newOxmEntity = null;
+      
+      for (Descriptor desc: descriptorsList) {
+         
+         DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
+         
+         //LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+         String primaryKeyAttributeNames = null;
+         
+         //Not all fields have key attributes
+         if (desc.getPrimaryKeyFields() != null) {
+            primaryKeyAttributeNames = desc.getPrimaryKeyFields().toString().replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", "");
+         }
+         
+         String entityName = desc.getDefaultRootElement();
+         
+         Map<String, String> properties = entity.getDescriptor().getProperties();
+         if (properties != null) {
+            for (Map.Entry<String, String> entry : properties.entrySet()) {
+               if (entry.getKey().equalsIgnoreCase("searchable")) {
+                  
+                  /*
+                   * we can do all the work here, we don't have a create additional collections for 
+                   * subsequent passes
+                   */
+                  newOxmEntity = new OxmEntityDescriptor();
+                  newOxmEntity.setEntityName(entityName);
+                  newOxmEntity.setPrimaryKeyAttributeName(Arrays.asList(primaryKeyAttributeNames.split(",")));
+                  newOxmEntity.setSearchableAttributes(Arrays.asList(entry.getValue().split(",")));
+                  searchableEntityDescriptors.put(entityName, newOxmEntity);
+               } else if (entry.getKey().equalsIgnoreCase("containsSuggestibleProps")) {
+                 newOxmEntity = new OxmEntityDescriptor();
+                 newOxmEntity.setEntityName(entityName);
+                 newOxmEntity.setSuggestableEntity(true);
+                 Vector<DatabaseMapping> descriptorMaps = entity.getDescriptor().getMappings();
+                 List<String> listOfSuggestableAttributes = new ArrayList<String>();
+                 
+                 for (DatabaseMapping descMap : descriptorMaps) {
+                   if (descMap.isAbstractDirectMapping()) {
+                     
+                     if (descMap.getProperties().get("suggestibleOnSearch") != null) {
+                       String suggestableOnSearchString = String.valueOf(
+                           descMap.getProperties().get("suggestibleOnSearch"));
+                       
+                       boolean isSuggestibleOnSearch = Boolean.valueOf(suggestableOnSearchString);
+
+                       if (isSuggestibleOnSearch) {
+                         /* Grab attribute types for suggestion */
+                         String attributeName = descMap.getField().getName()
+                             .replaceAll("/text\\(\\)", "");
+                         listOfSuggestableAttributes.add(attributeName);
+                       }
+                     }
+                   }
+                 }
+                 newOxmEntity.setSuggestableAttributes(listOfSuggestableAttributes);
+                 suggestableEntityDescriptors.put(entityName, newOxmEntity);
+               } else if (entry.getKey().equalsIgnoreCase("suggestionAliases")) {
+                 newOxmEntity = new OxmEntityDescriptor();
+                 newOxmEntity.setEntityName(entityName);
+                 newOxmEntity.setAlias(Arrays.asList(entry.getValue().split(",")));
+                 entityAliasDescriptors.put(entityName, newOxmEntity);
+               }
+            }
+         }
+         
+      }
+      
+   }
+   
+   public Map<String, OxmEntityDescriptor> getSearchableEntityDescriptors() {
+      return searchableEntityDescriptors;
+   }
+   
+   public OxmEntityDescriptor getSearchableEntityDescriptor(String entityType) {
+      return searchableEntityDescriptors.get(entityType);
+   }
+
+
+   public HashMap<String,Boolean> getCrossEntityReferenceContainers() {
+      return crossEntityReferenceContainerLookup;
+   }
+   
+   public HashMap<String,CrossEntityReference> getCrossEntityReferences() {
+      return crossEntityReferenceLookup;
+   }
+   
+
+   private void parseOxmContext(DynamicJAXBContext oxmContext) {
+      List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
+
+      for(Descriptor desc : descriptorsList) {
+
+         DynamicType entity = (DynamicType)oxmContext.getDynamicType(desc.getAlias());
+
+         String entityName = desc.getDefaultRootElement();
+
+         entityTypeLookup.put(entityName, entity);
+
+      }
+
+   }
+
+   public boolean entityModelContainsCrossEntityReference(String containerEntityType) {
+      Boolean v = crossEntityReferenceContainerLookup.get(containerEntityType);
+
+      if(v == null) {
+         return false;
+      }
+
+      return v;
+   }
+   
+   public boolean entityContainsCrossEntityReference(String entityType) {
+      return (crossEntityReferenceLookup.get(entityType) != null);
+   }   
+
+   public CrossEntityReference getCrossEntityReference(String entityType) {
+      return crossEntityReferenceLookup.get(entityType);
+   }   
+   
+   public Map<String, OxmEntityDescriptor> getSuggestableEntityDescriptors() {
+    return suggestableEntityDescriptors;
+  }
+
+  public void setSuggestableEntityDescriptors(
+      Map<String, OxmEntityDescriptor> suggestableEntityDescriptors) {
+    this.suggestableEntityDescriptors = suggestableEntityDescriptors;
+  }
+
+  public Map<String, OxmEntityDescriptor> getEntityAliasDescriptors() {
+    return entityAliasDescriptors;
+  }
+
+  public void setEntityAliasDescriptors(Map<String, OxmEntityDescriptor> entityAliasDescriptors) {
+    this.entityAliasDescriptors = entityAliasDescriptors;
+  }
+
+  public void extractEntities(String entityType, DynamicJAXBContext context, Collection<DynamicType> entities) {
+      
+      
+      
+      
+   }
+   
+   public String dumpCrossEntityReferenceContainers() {
+      
+      Set<String> keys = crossEntityReferenceContainerLookup.keySet();
+      StringBuilder sb = new StringBuilder(128);
+      
+      for ( String key : keys ) {
+
+         if ( crossEntityReferenceContainerLookup.get(key) ) {
+            sb.append("\n").append("Entity-Type = '" + key + "' contains a Cross-Entity-Reference.");   
+         }
+      }
+      
+      
+      return sb.toString();
+      
+   }
+   
+}
\ No newline at end of file