2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.openecomp.datarouter.util;
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;
36 import java.util.Vector;
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;
50 * Builds up a representation of the versioned entities in a way that they can be cross referenced
51 * in a data-driven way
54 public class VersionedOxmEntities {
56 private static final Logger logger = LoggerFactory.getLogger(VersionedOxmEntities.class);
57 private static final String REST_ROOT_ENTITY = "inventory";
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>();
67 public void initialize(DynamicJAXBContext context) {
68 parseOxmContext(context);
69 buildCrossEntityReferenceCollections(REST_ROOT_ENTITY, new HashSet<String>());
70 populateSearchableDescriptors(context);
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.
80 * This method will build two collections:
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.
86 * For example, looking at a service-instance <=> inventory path:
92 * -> service-subscriptions (true)
93 * -> service-subscription (CER defined here in the model) (true)
94 * -> service-instances (false)
95 * -> service-instance (false)
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.
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.
108 protected boolean buildCrossEntityReferenceCollections(String entityType, HashSet<String> checked) {
111 * To short-circuit infinite loops, make sure this entityType hasn't
112 * already been checked
115 if(checked.contains(entityType)) {
119 checked.add(entityType);
122 DynamicType parentType = entityTypeLookup.get(entityType);
123 DynamicType childType = null;
124 boolean returnValue = false;
126 if(parentType == null) {
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.
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")) {
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);
150 Vector<DatabaseField> fields = parentType.getDescriptor().getAllFields();
154 XMLField xmlField = null;
155 for(DatabaseField f : fields) {
157 if(f instanceof XMLField) {
158 xmlField = (XMLField)f;
159 XPathFragment xpathFragment = xmlField.getXPathFragment();
160 String entityShortName = xpathFragment.getLocalName();
162 childType = entityTypeLookup.get(entityShortName);
164 if(childType != null) {
166 if(!checked.contains(entityShortName)) {
168 if(buildCrossEntityReferenceCollections(entityShortName,checked)) {
174 checked.add(entityShortName);
184 crossEntityReferenceContainerLookup.put(entityType, Boolean.valueOf(returnValue));
188 private void populateSearchableDescriptors(DynamicJAXBContext oxmContext) {
189 List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
190 OxmEntityDescriptor newOxmEntity = null;
192 for (Descriptor desc: descriptorsList) {
194 DynamicType entity = (DynamicType) oxmContext.getDynamicType(desc.getAlias());
196 //LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
197 String primaryKeyAttributeNames = null;
199 //Not all fields have key attributes
200 if (desc.getPrimaryKeyFields() != null) {
201 primaryKeyAttributeNames = desc.getPrimaryKeyFields().toString().replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", "");
204 String entityName = desc.getDefaultRootElement();
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")) {
212 * we can do all the work here, we don't have a create additional collections for
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>();
227 for (DatabaseMapping descMap : descriptorMaps) {
228 if (descMap.isAbstractDirectMapping()) {
230 if (descMap.getProperties().get("suggestibleOnSearch") != null) {
231 String suggestableOnSearchString = String.valueOf(
232 descMap.getProperties().get("suggestibleOnSearch"));
234 boolean isSuggestibleOnSearch = Boolean.valueOf(suggestableOnSearchString);
236 if (isSuggestibleOnSearch) {
237 /* Grab attribute types for suggestion */
238 String attributeName = descMap.getField().getName()
239 .replaceAll("/text\\(\\)", "");
240 listOfSuggestableAttributes.add(attributeName);
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);
260 public Map<String, OxmEntityDescriptor> getSearchableEntityDescriptors() {
261 return searchableEntityDescriptors;
264 public OxmEntityDescriptor getSearchableEntityDescriptor(String entityType) {
265 return searchableEntityDescriptors.get(entityType);
269 public HashMap<String,Boolean> getCrossEntityReferenceContainers() {
270 return crossEntityReferenceContainerLookup;
273 public HashMap<String,CrossEntityReference> getCrossEntityReferences() {
274 return crossEntityReferenceLookup;
278 private void parseOxmContext(DynamicJAXBContext oxmContext) {
279 List<Descriptor> descriptorsList = oxmContext.getXMLContext().getDescriptors();
281 for(Descriptor desc : descriptorsList) {
283 DynamicType entity = (DynamicType)oxmContext.getDynamicType(desc.getAlias());
285 String entityName = desc.getDefaultRootElement();
287 entityTypeLookup.put(entityName, entity);
293 public boolean entityModelContainsCrossEntityReference(String containerEntityType) {
294 Boolean v = crossEntityReferenceContainerLookup.get(containerEntityType);
303 public boolean entityContainsCrossEntityReference(String entityType) {
304 return (crossEntityReferenceLookup.get(entityType) != null);
307 public CrossEntityReference getCrossEntityReference(String entityType) {
308 return crossEntityReferenceLookup.get(entityType);
311 public Map<String, OxmEntityDescriptor> getSuggestableEntityDescriptors() {
312 return suggestableEntityDescriptors;
315 public void setSuggestableEntityDescriptors(
316 Map<String, OxmEntityDescriptor> suggestableEntityDescriptors) {
317 this.suggestableEntityDescriptors = suggestableEntityDescriptors;
320 public Map<String, OxmEntityDescriptor> getEntityAliasDescriptors() {
321 return entityAliasDescriptors;
324 public void setEntityAliasDescriptors(Map<String, OxmEntityDescriptor> entityAliasDescriptors) {
325 this.entityAliasDescriptors = entityAliasDescriptors;
328 public void extractEntities(String entityType, DynamicJAXBContext context, Collection<DynamicType> entities) {
335 public String dumpCrossEntityReferenceContainers() {
337 Set<String> keys = crossEntityReferenceContainerLookup.keySet();
338 StringBuilder sb = new StringBuilder(128);
340 for ( String key : keys ) {
342 if ( crossEntityReferenceContainerLookup.get(key) ) {
343 sb.append("\n").append("Entity-Type = '" + key + "' contains a Cross-Entity-Reference.");
348 return sb.toString();