2 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.datarouter.util;
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;
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;
41 import java.util.Vector;
44 * Builds up a representation of the versioned entities in a way that they can be cross referenced
45 * in a data-driven way
49 public class VersionedOxmEntities {
51 private static final String REST_ROOT_ENTITY = "inventory";
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<>();
61 public void initialize(DynamicJAXBContext context) {
62 parseOxmContext(context);
63 buildCrossEntityReferenceCollections(REST_ROOT_ENTITY, new HashSet<String>());
64 populateSearchableDescriptors(context);
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.
74 * This method will build two collections:
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.
80 * For example, looking at a service-instance <=> inventory path:
86 * -> service-subscriptions (true)
87 * -> service-subscription (CER defined here in the model) (true)
88 * -> service-instances (false)
89 * -> service-instance (false)
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.
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
102 protected boolean buildCrossEntityReferenceCollections(String entityType, HashSet<String> checked) {
105 * To short-circuit infinite loops, make sure this entityType hasn't
106 * already been checked
109 if (checked.contains(entityType)) {
112 checked.add(entityType);
115 DynamicType parentType = entityTypeLookup.get(entityType);
116 DynamicType childType;
117 boolean returnValue = false;
119 if (parentType == null) {
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.
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())) {
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);
143 Vector<DatabaseField> fields = parentType.getDescriptor().getAllFields();
145 if (fields != null) {
148 for (DatabaseField f : fields) {
150 if (f instanceof XMLField) {
151 xmlField = (XMLField) f;
152 XPathFragment xpathFragment = xmlField.getXPathFragment();
153 String entityShortName = xpathFragment.getLocalName();
155 childType = entityTypeLookup.get(entityShortName);
157 if (childType != null) {
159 if (!checked.contains(entityShortName)) {
161 if (buildCrossEntityReferenceCollections(entityShortName, checked)) {
167 checked.add(entityShortName);
177 crossEntityReferenceContainerLookup.put(entityType, Boolean.valueOf(returnValue));
181 private void populateSearchableDescriptors(DynamicJAXBContext oxmContext) {
182 List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
183 OxmEntityDescriptor newOxmEntity;
185 for (Descriptor desc : descriptorsList) {
187 DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
189 //LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
190 String primaryKeyAttributeNames = null;
192 //Not all fields have key attributes
193 if (desc.getPrimaryKeyFields() != null) {
194 primaryKeyAttributeNames = desc.getPrimaryKeyFields()
195 .toString().replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", "");
198 String entityName = desc.getDefaultRootElement();
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())) {
206 * we can do all the work here, we don't have a create additional collections for
209 newOxmEntity = new OxmEntityDescriptor();
210 newOxmEntity.setEntityName(entityName);
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<>();
222 for (DatabaseMapping descMap : descriptorMaps) {
223 if (descMap.isAbstractDirectMapping()) {
225 if (descMap.getProperties().get("suggestibleOnSearch") != null) {
226 String suggestableOnSearchString = String.valueOf(
227 descMap.getProperties().get("suggestibleOnSearch"));
229 boolean isSuggestibleOnSearch = Boolean.valueOf(suggestableOnSearchString);
231 if (isSuggestibleOnSearch) {
232 /* Grab attribute types for suggestion */
233 String attributeName = descMap.getField().getName()
234 .replaceAll("/text\\(\\)", "");
235 listOfSuggestableAttributes.add(attributeName);
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);
255 public Map<String, OxmEntityDescriptor> getSearchableEntityDescriptors() {
256 return searchableEntityDescriptors;
259 public OxmEntityDescriptor getSearchableEntityDescriptor(String entityType) {
260 return searchableEntityDescriptors.get(entityType);
264 public HashMap<String, Boolean> getCrossEntityReferenceContainers() {
265 return crossEntityReferenceContainerLookup;
268 public HashMap<String, CrossEntityReference> getCrossEntityReferences() {
269 return crossEntityReferenceLookup;
273 private void parseOxmContext(DynamicJAXBContext oxmContext) {
274 List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
276 for (Descriptor desc : descriptorsList) {
278 DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
280 String entityName = desc.getDefaultRootElement();
282 entityTypeLookup.put(entityName, entity);
288 public boolean entityModelContainsCrossEntityReference(String containerEntityType) {
289 Boolean v = crossEntityReferenceContainerLookup.get(containerEntityType);
298 public boolean entityContainsCrossEntityReference(String entityType) {
299 return crossEntityReferenceLookup.get(entityType) != null;
302 public CrossEntityReference getCrossEntityReference(String entityType) {
303 return crossEntityReferenceLookup.get(entityType);
306 public Map<String, OxmEntityDescriptor> getSuggestableEntityDescriptors() {
307 return suggestableEntityDescriptors;
310 public void setSuggestableEntityDescriptors(
311 Map<String, OxmEntityDescriptor> suggestableEntityDescriptors) {
312 this.suggestableEntityDescriptors = suggestableEntityDescriptors;
315 public Map<String, OxmEntityDescriptor> getEntityAliasDescriptors() {
316 return entityAliasDescriptors;
319 public void setEntityAliasDescriptors(Map<String, OxmEntityDescriptor> entityAliasDescriptors) {
320 this.entityAliasDescriptors = entityAliasDescriptors;
323 public void extractEntities(String entityType, DynamicJAXBContext context, Collection<DynamicType> entities) {
328 public String dumpCrossEntityReferenceContainers() {
330 Set<String> keys = crossEntityReferenceContainerLookup.keySet();
331 StringBuilder sb = new StringBuilder(128);
333 for (String key : keys) {
335 if (crossEntityReferenceContainerLookup.get(key)) {
336 sb.append("\n").append("Entity-Type = '" + key + "' contains a Cross-Entity-Reference.");
341 return sb.toString();
345 public Map<String, DynamicType> getEntityTypeLookup() {
346 return entityTypeLookup;