2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.ccsdk.apps.ms.neng.core.gen;
23 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModel;
24 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModelRelaxed;
25 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModels;
26 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingOperation;
27 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingProperty;
28 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingRecipe;
29 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingType;
30 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.propertyValue;
31 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.relaxedNamingType;
32 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.seq;
33 import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.value;
35 import java.sql.Timestamp;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.LinkedHashMap;
39 import java.util.List;
41 import org.onap.ccsdk.apps.ms.neng.core.exceptions.NengException;
42 import org.onap.ccsdk.apps.ms.neng.core.persistence.NamePersister;
43 import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyFinder;
44 import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyParameters;
45 import org.onap.ccsdk.apps.ms.neng.core.policy.PolicySequence;
46 import org.onap.ccsdk.apps.ms.neng.core.policy.PropertyOperator;
47 import org.onap.ccsdk.apps.ms.neng.core.policy.RecipeParser;
48 import org.onap.ccsdk.apps.ms.neng.core.seq.SequenceGenerator;
49 import org.onap.ccsdk.apps.ms.neng.core.validator.AaiNameValidator;
50 import org.onap.ccsdk.apps.ms.neng.core.validator.DbNameValidator;
51 import org.onap.ccsdk.apps.ms.neng.persistence.entity.GeneratedName;
54 * Generates names of network elements based on policy data.
56 public class NameGenerator {
57 private static final String RESOURCE_NAME_ELEMENT_ITEM = "resource-name";
58 private static final String RESOURCE_VALUE_ELEMENT_ITEM = "resource-value";
59 private static final String EXTERNAL_KEY_ELEMENT_ITEM = "external-key";
60 private static final String NAMING_TYPE_ELEMENT_ITEM = "naming-type";
62 private final PolicyFinder policyFinder;
63 private final PolicyParameters policyParams;
64 private final SequenceGenerator seqGenerator;
65 private final DbNameValidator dbValidator;
66 private final AaiNameValidator aaiValidator;
67 private final NamePersister namePersister;
68 private final Map<String, String> requestElement;
69 private final List<Map<String, String>> allElements;
70 private final Map<String, Map<String, String>> earlierNames;
71 private final Map<String, Map<String, ?>> policyCache;
72 private final List<String> earlierNamingTypes;
77 * @param policyFinder a way to find policies
78 * @param policyParams parameters related to policy
79 * @param seqGenerator a way to generate sequences
80 * @param dbValidator a way to validate generated names against DB
81 * @param aaiValidator a way to validate generated names against A&AI
82 * @param namePersister a way to persist names
83 * @param requestElement the request element for which the name is generated, containing data such
84 * as policy name, naming-type, external-key and resource-name
85 * @param allElements all the elements in the request (including the current request element for
86 * which name is generated), as this is needed to re-use names generated from other request elements
87 * within the same transaction
88 * @param earlierNames names generated earlier in the same transaction, as a map from naming-type
89 * to names (which is a map with keys "resource-name", "resource-value" and "external-key")
90 * @param policyCache cache containing policies retrieved in this transaction, to avoid repeated
91 * calls to policy manager within the same transaction
92 * @param earlierNamingTypes naming-types used earlier in the same transaction
94 public NameGenerator(PolicyFinder policyFinder, PolicyParameters policyParams, SequenceGenerator seqGenerator,
95 DbNameValidator dbValidator, AaiNameValidator aaiValidator, NamePersister namePersister,
96 Map<String, String> requestElement, List<Map<String, String>> allElements,
97 Map<String, Map<String, String>> earlierNames, Map<String, Map<String, ?>> policyCache,
98 List<String> earlierNamingTypes) {
99 this.policyFinder = policyFinder;
100 this.policyParams = policyParams;
101 this.seqGenerator = seqGenerator;
102 this.dbValidator = dbValidator;
103 this.aaiValidator = aaiValidator;
104 this.namePersister = namePersister;
105 this.requestElement = requestElement;
106 this.allElements = allElements;
107 this.earlierNames = earlierNames;
108 this.policyCache = policyCache;
109 this.earlierNamingTypes = earlierNamingTypes;
113 * Generates the name.
115 * @return the map (with keys "resource-name", "resource-value" and "external-key") containing the name.
117 public Map<String, String> generate() throws Exception {
118 String policyName = findElementPolicyName();
119 if (policyName == null) {
120 throw new NengException("Could not find policy name in the request");
122 String namingType = findElementNamingType();
123 String relaxedNamingType = relaxedNamingType(namingType);
124 Map<String,String> generated = null;
125 if (namingType != null) {
126 if (!earlierNamingTypes.contains(namingType)) {
127 generated = this.earlierNames.get(namingType);
128 if (generated == null) {
129 generated = this.earlierNames.get(relaxedNamingType);
132 if (generated != null) {
135 earlierNamingTypes.add(namingType);
136 return generateNew(policyName, namingType);
139 throw new NengException("Could not find naming type in the request for policy " + policyName);
144 * Updates a generated name.
146 * @return the map (with keys "resource-name", "resource-value" and "external-key") containing the name.
148 public Map<String, String> updateGenerateName() throws Exception {
149 String externalKey = findElementExternalKey();
150 String resourceValue = value(this.requestElement, RESOURCE_VALUE_ELEMENT_ITEM);
151 String reqNamingType = findElementNamingType();
152 String reqResourceName = findElementResourceName();
153 String namingType = (reqNamingType == null) ? reqResourceName : reqNamingType;
154 String relaxedNamingType = relaxedNamingType(namingType);
156 if (!aaiValidator.validate(namingType, resourceValue)) {
157 throw new NengException("Name already exists in AAI");
159 GeneratedName generatedName = null;
160 if (relaxedNamingType != null) {
161 generatedName = namePersister.findByExternalIdAndElementType(externalKey, relaxedNamingType);
163 throw new NengException("Resource Name or naming type must be provided");
165 if (generatedName == null) {
166 generatedName = new GeneratedName();
168 generatedName.setName(resourceValue);
169 generatedName.setExternalId(externalKey);
170 generatedName.setElementType(namingType);
171 generatedName.setSequenceNumber(null);
172 generatedName.setSequenceNumberEnc(null);
173 generatedName.setPrefix(null);
174 generatedName.setSuffix(null);
175 generatedName.setIsReleased(null);
176 namePersister.persist(generatedName);
177 Map<String, String> respMap = buildResponse(externalKey, reqResourceName, resourceValue);
178 respMap.put(externalKey, "Resource value updated successfully");
183 String applyNameOperation(Map<String, ?> namingModel, String name) throws Exception {
184 String nameOperation = namingOperation(namingModel);
185 if (nameOperation != null && !"".equals(nameOperation)) {
186 name = new PropertyOperator().apply(name, nameOperation, this.policyParams);
191 String applyPropertyOperation(String value, Map<String, ?> propertyMap, String recipeItem) throws Exception {
192 return new PropertyOperator().apply(value, propertyMap, this.policyParams, recipeItem);
195 static Map<String, String> buildResponse(String key, String name, String value) {
196 Map<String, String> response = new HashMap<String, String>();
197 response.put(EXTERNAL_KEY_ELEMENT_ITEM, key);
198 response.put(RESOURCE_NAME_ELEMENT_ITEM, name);
199 response.put(RESOURCE_VALUE_ELEMENT_ITEM, value);
203 String buildSequenceSuffix(Map<String, Object> recipeValues, String recipeName, List<String> recipe)
205 StringBuffer buf = new StringBuffer();
206 boolean postItem = false;
207 for (String key : recipe) {
209 buf.append(recipeValues.get(key).toString());
210 } else if (key.equals(recipeName)) {
214 String value = buf.toString();
215 if (value.length() == 0) {
221 String buildSequencePrefix(Map<String, Object> recipeValues, String recipeName, List<String> recipe)
223 StringBuffer buf = new StringBuffer();
224 for (String key : recipe) {
225 if (key.equals(recipeName)) {
228 buf.append(recipeValues.get(key).toString());
230 return buf.toString();
233 Map<String, String> generateNew(String policyName, String namingType) throws Exception {
234 Map<String, ?> policy = findPolicy(policyName);
235 if (policy != null) {
236 List<Map<String, ?>> namingModels = namingModels(policy);
237 Map<String, ?> namingModel = namingModel(namingModels, namingType);
238 if (namingModel == null) {
239 throw new NengException(
240 "Could not find the policy data for " + policyName + " and naming-type " + namingType);
242 return generateNew(policyName, namingType, namingModels, namingModel);
244 throw new NengException("Could not find the policy data for " + policyName);
248 Map<String, String> generateNew(String policyName, String namingType,
249 List<Map<String, ?>> namingModels, Map<String, ?> namingModel) throws Exception {
250 String recipe = namingRecipe(namingModel);
251 if (recipe == null) {
252 throw new NengException("Could not find the recipe for "
253 + policyName + " and naming-type " + namingType);
255 List<String> recipeItems = RecipeParser.parseRecipe(this.policyParams, recipe);
256 return generateNew(namingModels, policyName, namingType, namingModel, recipeItems);
259 Map<String, String> generateNew(List<Map<String, ?>> namingModels, String policyName,
260 String namingType, Map<String, ?> namingModel, List<String> recipe) throws Exception {
261 Map<String, Object> recipeValues = new LinkedHashMap<>();
262 for (String recipeItem : recipe) {
263 Map<String, ?> propMap = namingProperty(namingModel, recipeItem);
264 if ("SEQUENCE".equals(recipeItem)) {
265 String propValue = value(this.requestElement,recipeItem);
266 if (propValue != null) {
267 recipeValues.put(recipeItem, propValue);
269 PolicySequence seq = seq(propMap);
270 recipeValues.put(recipeItem, seq);
273 String val = generateNonSequenceValue(namingModels, policyName, namingType, namingModel, propMap,
276 recipeValues.put(recipeItem, val);
280 validateAllItemsPresent(policyName, namingType, recipe, recipeValues);
281 SeqGenData seqData = generateNameWithSequences(policyName, namingType, recipe, recipeValues, namingModel);
282 String name = seqData.getName();
283 storeGeneratedName(findElementExternalKey(), name, namingType, seqData);
284 Map<String, String> response = buildResponse(findElementExternalKey(), findElementResourceName(), name);
285 String relaxedNamingType = relaxedNamingType(namingType);
286 this.earlierNames.put(relaxedNamingType, response);
290 SeqGenData generateNameWithSequences(String policyName, String namingType, List<String> recipe,
291 Map<String, Object> recipeValues, Map<String, ?> namingModel) throws Exception {
292 int attemptCount = 0;
293 int maxGenAttempt = this.policyParams.getMaxGenAttempt();
294 if (maxGenAttempt <= 0) {
298 SeqGenData lastSeq = null;
299 boolean valid = false;
300 String additionalErrorMsg = "";
301 while (attemptCount <= maxGenAttempt && !valid) {
303 lastSeq = generateSequenceValues(policyName, namingType, recipe, recipeValues, lastSeq, attemptCount);
304 name = generateNameFromSegments(recipeValues, recipe);
305 boolean sequenceLess = false;
306 if (lastSeq == null) {
307 lastSeq = new SeqGenData();
310 name = applyNameOperation(namingModel, name);
311 lastSeq.setName(name);
312 valid = this.dbValidator.validate(namingType, name);
314 valid = this.aaiValidator.validate(namingType, name);
316 storeGeneratedName("AAI-BACKPOPULATE", name, namingType, lastSeq);
317 additionalErrorMsg = "AAI Name validation failed";
320 additionalErrorMsg = "DB Name validation failed";
323 break; // handle names with no sequence in them
326 if (attemptCount > maxGenAttempt) {
327 throw new NengException("Could not generate a name successfully for policy " + policyName
328 + " and naming-type " + namingType + " even after " + maxGenAttempt + " attempts.");
331 throw new NengException("Could not generate a valid name successfully for policy " + policyName
332 + " and naming-type " + namingType + ". " + additionalErrorMsg);
337 String generateNameFromSegments(Map<String, Object> recipeValues, List<String> recipe) throws Exception {
338 StringBuffer buf = new StringBuffer();
339 for (String recName : recipe) {
340 Object val = recipeValues.get(recName);
341 if (val instanceof PolicySequence) {
342 PolicySequence poly = (PolicySequence) val;
343 buf.append(poly.getValue());
345 buf.append(val.toString());
348 String value = buf.toString();
352 SeqGenData generateSequenceValues(String policyName, String namingType, List<String> recipe,
353 Map<String, Object> recipeValues, SeqGenData lastSeq, int attemptCount) throws Exception {
354 SeqGenData precedSeq = generateSequenceValuesOfScope(
355 policyName, namingType, recipe, recipeValues, "PRECEEDING", lastSeq, attemptCount);
356 SeqGenData entireSeq = generateSequenceValuesOfScope(
357 policyName, namingType, recipe, recipeValues, "ENTIRETY", lastSeq, attemptCount);
358 if (entireSeq != null) {
364 SeqGenData generateSequenceValuesOfScope(String policyName, String namingType, List<String> recipe,
365 Map<String, Object> recipeValues, String scope, SeqGenData lastSeq, int attemptCount)
367 for (String item : recipe) {
368 Object val = recipeValues.get(item);
369 if (val instanceof PolicySequence) {
370 PolicySequence seq = (PolicySequence) val;
371 if (scope.equals(seq.getScope())) {
372 SeqGenData seqVal = generateSequenceValue(seq, policyName, namingType, recipeValues, item,
373 lastSeq, attemptCount, recipe);
374 String seqStr = SequenceFormatter.formatSequence(seqVal.getSeq(), seq);
375 seqVal.setSeqEncoded(seqStr);
377 seq.setValue(seqStr);
385 SeqGenData generateSequenceValue(PolicySequence seq, String policyName, String namingType,
386 Map<String, Object> recipeValues, String recipeName, SeqGenData lastSeq, int attemptCount,
387 List<String> recipe) throws Exception {
388 String prefix = buildSequencePrefix(recipeValues, recipeName, recipe);
389 String suffix = buildSequenceSuffix(recipeValues, recipeName, recipe);
390 SeqGenData seqData = new SeqGenData();
391 Long lastSeqValue = null;
392 if (lastSeq != null) {
393 lastSeqValue = lastSeq.getSeq();
395 long seqValue = this.seqGenerator.generate(prefix, suffix, seq, lastSeqValue, attemptCount);
396 seqData.setSeq(seqValue);
397 seqData.setPrefix(prefix);
398 seqData.setSuffix(suffix);
402 String generateNonSequenceValue(List<Map<String, ?>> namingModels, String policyName, String namingType,
403 Map<String, ?> namingModel, Map<String, ?> propMap, String recipeItem) throws Exception {
404 String val = propertyValue(propMap);
406 val = value(this.requestElement, recipeItem);
409 val = value(this.requestElement, recipeItem, true);
412 val = generateValueRecursively(namingModels, policyName, recipeItem);
415 val = applyPropertyOperation(val, propMap, null);
418 val = applyPropertyOperation(val, propMap, recipeItem);
421 val = value(namingModel, recipeItem);
426 String generateValueRecursively(List<Map<String, ?>> namingModels, String policyName, String recipeItem)
429 String relaxedVal = relaxedNamingType(recipeItem);
430 Map<String, String> generated = this.earlierNames.get(relaxedVal);
431 if (generated != null) {
432 return generated.get("resource-value");
434 Map<String, ?> relaxedModel = namingModelRelaxed(namingModels, recipeItem);
435 if (relaxedModel != null) {
436 String relaxedNamingType = namingType(relaxedModel);
437 Map<String, String> relaxedElement = findElement(relaxedNamingType);
438 if (relaxedElement != null) {
439 relaxedElement = new HashMap<>(relaxedElement);
440 relaxedElement.put(NAMING_TYPE_ELEMENT_ITEM, relaxedNamingType);
442 relaxedElement = new HashMap<>(this.requestElement);
443 relaxedElement.put(NAMING_TYPE_ELEMENT_ITEM, relaxedNamingType);
444 relaxedElement.remove(EXTERNAL_KEY_ELEMENT_ITEM);
445 relaxedElement.remove(RESOURCE_NAME_ELEMENT_ITEM);
447 if (relaxedElement != null) {
448 NameGenerator recursive = new NameGenerator(policyFinder, policyParams, seqGenerator, dbValidator,
449 aaiValidator, namePersister, relaxedElement, allElements, earlierNames, policyCache,
451 Map<String, String> gen =
452 recursive.generateNew(policyName, relaxedNamingType, namingModels, relaxedModel);
454 val = value(gen, RESOURCE_VALUE_ELEMENT_ITEM);
461 Map<String, String> findElement(String namingType) throws Exception {
462 Map<String, String> theElement = null;
463 for (Map<String, String> anElement : this.allElements) {
464 String oneNamingType = namingType(anElement);
465 if (namingType.equals(oneNamingType)) {
466 theElement = anElement;
473 String findElementPolicyName() throws Exception {
474 return value(this.requestElement, "policy-instance-name");
477 String findElementNamingType() throws Exception {
478 return value(this.requestElement, NAMING_TYPE_ELEMENT_ITEM);
481 String findElementResourceName() throws Exception {
482 return value(this.requestElement, RESOURCE_NAME_ELEMENT_ITEM);
485 String findElementExternalKey() throws Exception {
486 return value(this.requestElement, EXTERNAL_KEY_ELEMENT_ITEM);
489 Map<String, ?> findPolicy(String name) throws Exception {
490 Map<String, ?> policy = null;
492 policy = this.policyCache.get(name);
493 if (policy == null) {
494 policy = this.policyFinder.findPolicy(name);
495 if (policy != null) {
496 this.policyCache.put(name, policy);
503 void storeGeneratedName(String key, String name, String namingType,
504 SeqGenData seqData) throws Exception {
505 String prefix = null;
506 String suffix = null;
508 String seqEncoded = null;
509 if (seqData != null) {
510 prefix = seqData.getPrefix();
511 suffix = seqData.getSuffix();
512 seqNum = seqData.getSeq();
513 seqEncoded = seqData.getSeqEncoded();
515 GeneratedName record = new GeneratedName();
516 GeneratedName releasedName = namePersister.findByElementTypeAndNameAndReleased(namingType, name, "Y");
517 if (releasedName != null) {
518 record = releasedName;
519 record.setLastUpdatedTime(new Timestamp(System.currentTimeMillis()));
520 record.setIsReleased(null);
522 record.setName(name);
523 record.setExternalId(key);
524 record.setElementType(namingType);
525 record.setPrefix(prefix);
526 record.setSuffix(suffix);
527 if (seqNum != null) {
528 record.setSequenceNumber(seqNum);
530 record.setSequenceNumberEnc(seqEncoded);
531 this.namePersister.persist(record);
534 void validateAllItemsPresent(String policyName, String namingType, List<String> recipe,
535 Map<String, Object> recipeValues) throws Exception {
536 List<String> missing = new ArrayList<>();
537 for (String item : recipe) {
538 Object val = recipeValues.get(item);
543 if (missing.size() > 0) {
544 StringBuffer msg = new StringBuffer();
545 for (int i = 0; i < missing.size(); ++i) {
546 String item = missing.get(i);
548 String separator = ", ";
549 if (i == missing.size() - 1) {
552 msg.append(separator);
556 String itemString = "items";
557 if (missing.size() == 1) {
560 throw new NengException("Could not find data for recipe " + itemString + " " + msg.toString()
561 + " in policy " + policyName + " and naming-type " + namingType);