From d5eb07bb5a358a467c2e9c2b2ddaaf4f8aec4b69 Mon Sep 17 00:00:00 2001 From: BT2983 Date: Mon, 23 Jul 2018 08:17:51 -0600 Subject: Adding naming micro-service code - generation. Main generation algorithm and AAI interface. Change-Id: I21eb0065358b4c9eeda85a4ae41545e864fdc627 Issue-ID: CCSDK-342 Signed-off-by: BT2983 --- .../ms/neng/core/exceptions/NengException.java | 32 ++ .../ccsdk/apps/ms/neng/core/gen/NameGenerator.java | 499 +++++++++++++++++++++ .../ccsdk/apps/ms/neng/core/gen/SeqGenData.java | 88 ++++ .../apps/ms/neng/core/gen/SequenceFormatter.java | 44 ++ .../ms/neng/core/persistence/NamePersister.java | 53 +++ .../ms/neng/core/resource/model/AaiResponse.java | 40 ++ .../interceptors/AaiAuthorizationInterceptor.java | 53 +++ .../apps/ms/neng/core/seq/SequenceGenerator.java | 101 +++++ .../ms/neng/core/validator/AaiNameValidator.java | 53 +++ .../ms/neng/core/validator/DbNameValidator.java | 43 ++ .../ccsdk/apps/ms/neng/extinf/props/AaiProps.java | 104 +++++ .../ms/neng/extinf/props/PolicyManagerProps.java | 92 ++++ .../neng/service/extinf/impl/AaiServiceImpl.java | 131 ++++++ 13 files changed, 1333 insertions(+) create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/exceptions/NengException.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SeqGenData.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatter.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/persistence/NamePersister.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/resource/model/AaiResponse.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/rs/interceptors/AaiAuthorizationInterceptor.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/seq/SequenceGenerator.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/AaiNameValidator.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/DbNameValidator.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/AaiProps.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/PolicyManagerProps.java create mode 100644 ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java (limited to 'ms/neng/src/main') diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/exceptions/NengException.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/exceptions/NengException.java new file mode 100644 index 00000000..cad15759 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/exceptions/NengException.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.exceptions; + +/** + * Represents application exceptions generated by this micro-service. + */ +public class NengException extends Exception { + static final long serialVersionUID = -3387516993124229948L; + + public NengException(String message) { + super(message); + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java new file mode 100644 index 00000000..8cfe7c88 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java @@ -0,0 +1,499 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.gen; + +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModel; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModelRelaxed; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModels; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingOperation; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingProperty; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingRecipe; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingType; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.propertyValue; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.relaxedNamingType; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.seq; +import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.value; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.onap.ccsdk.apps.ms.neng.core.exceptions.NengException; +import org.onap.ccsdk.apps.ms.neng.core.persistence.NamePersister; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyFinder; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyParameters; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicySequence; +import org.onap.ccsdk.apps.ms.neng.core.policy.PropertyOperator; +import org.onap.ccsdk.apps.ms.neng.core.policy.RecipeParser; +import org.onap.ccsdk.apps.ms.neng.core.seq.SequenceGenerator; +import org.onap.ccsdk.apps.ms.neng.core.validator.AaiNameValidator; +import org.onap.ccsdk.apps.ms.neng.core.validator.DbNameValidator; +import org.onap.ccsdk.apps.ms.neng.persistence.entity.GeneratedName; + +/** + * Generates names of network elements based on policy data. + */ +public class NameGenerator { + private static final String RESOURCE_NAME_ELEMENT_ITEM = "resource-name"; + private static final String RESOURCE_VALUE_ELEMENT_ITEM = "resource-value"; + private static final String EXTERNAL_KEY_ELEMENT_ITEM = "external-key"; + private static final String NAMING_TYPE_ELEMENT_ITEM = "naming-type"; + + private final PolicyFinder policyFinder; + private final PolicyParameters policyParams; + private final SequenceGenerator seqGenerator; + private final DbNameValidator dbValidator; + private final AaiNameValidator aaiValidator; + private final NamePersister namePersister; + private final Map requestElement; + private final List> allElements; + private final Map> earlierNames; + private final Map> policyCache; + + /** + * Constructor. + * + * @param policyFinder a way to find policies + * @param policyParams parameters related to policy + * @param seqGenerator a way to generate sequences + * @param dbValidator a way to validate generated names against DB + * @param aaiValidator a way to validate generated names against A&AI + * @param namePersister a way to persist names + * @param requestElement the request element for which the name is generated, containing data such + * as policy name, naming-type, external-key and resource-name + * @param allElements all the elements in the request (including the current request element for + * which name is generated), as this is needed to re-use names generated from other request elements + * within the same transaction + * @param earlierNames names generated earlier in the same transaction, as a map from naming-type + * to names (which is a map with keys "resource-name", "resource-value" and "external-key") + * @param policyCache cache containing policies retrieved in this transaction, to avoid repeated + * calls to policy manager within the same transaction + */ + public NameGenerator(PolicyFinder policyFinder, PolicyParameters policyParams, SequenceGenerator seqGenerator, + DbNameValidator dbValidator, AaiNameValidator aaiValidator, NamePersister namePersister, + Map requestElement, List> allElements, + Map> earlierNames, Map> policyCache) { + this.policyFinder = policyFinder; + this.policyParams = policyParams; + this.seqGenerator = seqGenerator; + this.dbValidator = dbValidator; + this.aaiValidator = aaiValidator; + this.namePersister = namePersister; + this.requestElement = requestElement; + this.allElements = allElements; + this.earlierNames = earlierNames; + this.policyCache = policyCache; + } + + /** + * Generates the name. + * + * @return the map (with keys "resource-name", "resource-value" and "external-key") containing the name. + */ + public Map generate() throws Exception { + String policyName = findElementPolicyName(); + if (policyName == null) { + throw new NengException("Could not find policy name in the request"); + } + String namingType = findElementNamingType(); + if (namingType != null) { + Map generated = this.earlierNames.get(namingType); + if (generated != null) { + return generated; + } + return generateNew(policyName, namingType); + } else { + throw new NengException("Could not find naming type in the request for policy " + policyName); + } + } + + String applyNameOperation(Map namingModel, String name) throws Exception { + String nameOperation = namingOperation(namingModel); + if (nameOperation != null && !"".equals(nameOperation)) { + name = new PropertyOperator().apply(name, nameOperation, this.policyParams); + } + return name; + } + + String applyPropertyOperation(String value, Map propertyMap) throws Exception { + return new PropertyOperator().apply(value, propertyMap, this.policyParams); + } + + static Map buildResponse(String key, String name, String value) { + Map response = new HashMap(); + response.put(EXTERNAL_KEY_ELEMENT_ITEM, key); + response.put(RESOURCE_NAME_ELEMENT_ITEM, name); + response.put(RESOURCE_VALUE_ELEMENT_ITEM, value); + return response; + } + + String buildSequenceSuffix(Map recipeValues, String recipeName, List recipe) + throws Exception { + StringBuffer buf = new StringBuffer(); + boolean postItem = false; + for (String key : recipe) { + if (postItem) { + buf.append(recipeValues.get(key).toString()); + } else if (key.equals(recipeName)) { + postItem = true; + } + } + String value = buf.toString(); + if (value.length() == 0) { + value = null; + } + return value; + } + + String buildSequencePrefix(Map recipeValues, String recipeName, List recipe) + throws Exception { + StringBuffer buf = new StringBuffer(); + for (String key : recipe) { + if (key.equals(recipeName)) { + break; + } + buf.append(recipeValues.get(key).toString()); + } + return buf.toString(); + } + + Map generateNew(String policyName, String namingType) throws Exception { + Map policy = findPolicy(policyName); + if (policy != null) { + List> namingModels = namingModels(policy); + Map namingModel = namingModel(namingModels, namingType); + if (namingModel == null) { + throw new NengException( + "Could not find the policy data for " + policyName + " and naming-type " + namingType); + } + return generateNew(policyName, namingType, namingModels, namingModel); + } else { + throw new NengException("Could not find the policy data for " + policyName); + } + } + + Map generateNew(String policyName, String namingType, + List> namingModels, Map namingModel) throws Exception { + String recipe = namingRecipe(namingModel); + if (recipe == null) { + throw new NengException("Could not find the recipe for " + + policyName + " and naming-type " + namingType); + } + List recipeItems = RecipeParser.parseRecipe(this.policyParams, recipe); + return generateNew(namingModels, policyName, namingType, namingModel, recipeItems); + } + + Map generateNew(List> namingModels, String policyName, + String namingType, Map namingModel, List recipe) throws Exception { + Map recipeValues = new LinkedHashMap<>(); + for (String recipeItem : recipe) { + Map propMap = namingProperty(namingModel, recipeItem); + if ("SEQUENCE".equals(recipeItem)) { + PolicySequence seq = seq(propMap); + recipeValues.put(recipeItem, seq); + } else { + String val = generateNonSequenceValue(namingModels, policyName, namingType, namingModel, propMap, + recipeItem); + if (val != null) { + recipeValues.put(recipeItem, val); + } + } + } + validateAllItemsPresent(policyName, namingType, recipe, recipeValues); + SeqGenData seqData = generateNameWithSequences(policyName, namingType, recipe, recipeValues, namingModel); + String name = seqData.getName(); + storeGeneratedName(findElementExternalKey(), name, namingType, seqData); + Map response = buildResponse(findElementExternalKey(), findElementResourceName(), name); + String relaxedNamingType = relaxedNamingType(namingType); + this.earlierNames.put(relaxedNamingType, response); + return response; + } + + SeqGenData generateNameWithSequences(String policyName, String namingType, List recipe, + Map recipeValues, Map namingModel) throws Exception { + int attemptCount = 0; + int maxGenAttempt = this.policyParams.getMaxGenAttempt(); + if (maxGenAttempt <= 0) { + maxGenAttempt = 1; + } + String name = null; + SeqGenData lastSeq = null; + boolean valid = false; + String additionalErrorMsg = ""; + while (attemptCount <= maxGenAttempt && !valid) { + ++attemptCount; + lastSeq = generateSequenceValues(policyName, namingType, recipe, recipeValues, lastSeq, attemptCount); + name = generateNameFromSegments(recipeValues, recipe); + boolean sequenceLess = false; + if (lastSeq == null) { + lastSeq = new SeqGenData(); + sequenceLess = true; + } + name = applyNameOperation(namingModel, name); + lastSeq.setName(name); + valid = this.dbValidator.validate(namingType, name); + if (valid) { + valid = this.aaiValidator.validate(namingType, name); + if (!valid) { + storeGeneratedName("AAI-BACKPOPULATE", name, namingType, lastSeq); + additionalErrorMsg = "AAI Name validation failed"; + } + } else { + additionalErrorMsg = "DB Name validation failed"; + } + if (sequenceLess) { + break; // handle names with no sequence in them + } + } + if (attemptCount > maxGenAttempt) { + throw new NengException("Could not generate a name successfully for policy " + policyName + + " and naming-type " + namingType + " even after " + maxGenAttempt + " attempts."); + } + if (!valid) { + throw new NengException("Could not generate a valid name successfully for policy " + policyName + + " and naming-type " + namingType + ". " + additionalErrorMsg); + } + return lastSeq; + } + + String generateNameFromSegments(Map recipeValues, List recipe) throws Exception { + StringBuffer buf = new StringBuffer(); + for (String recName : recipe) { + Object val = recipeValues.get(recName); + if (val instanceof PolicySequence) { + PolicySequence poly = (PolicySequence) val; + buf.append(poly.getValue()); + } else { + buf.append(val.toString()); + } + } + String value = buf.toString(); + return value; + } + + SeqGenData generateSequenceValues(String policyName, String namingType, List recipe, + Map recipeValues, SeqGenData lastSeq, int attemptCount) throws Exception { + SeqGenData precedSeq = generateSequenceValuesOfScope( + policyName, namingType, recipe, recipeValues, "PRECEEDING", lastSeq, attemptCount); + SeqGenData entireSeq = generateSequenceValuesOfScope( + policyName, namingType, recipe, recipeValues, "ENTIRETY", lastSeq, attemptCount); + if (entireSeq != null) { + return entireSeq; + } + return precedSeq; + } + + SeqGenData generateSequenceValuesOfScope(String policyName, String namingType, List recipe, + Map recipeValues, String scope, SeqGenData lastSeq, int attemptCount) + throws Exception { + for (String item : recipe) { + Object val = recipeValues.get(item); + if (val instanceof PolicySequence) { + PolicySequence seq = (PolicySequence) val; + if (scope.equals(seq.getScope())) { + SeqGenData seqVal = generateSequenceValue( + seq, policyName, namingType, recipeValues, item, lastSeq, attemptCount, recipe); + String seqStr = SequenceFormatter.formatSequence(seqVal.getSeq(), seq); + seqVal.setSeqEncoded(seqStr); + seq.setKey(item); + seq.setValue(seqStr); + return seqVal; + } + } + } + return null; + } + + SeqGenData generateSequenceValue(PolicySequence seq, String policyName, String namingType, + Map recipeValues, String recipeName, SeqGenData lastSeq, int attemptCount, + List recipe) throws Exception { + String prefix = buildSequencePrefix(recipeValues, recipeName, recipe); + String suffix = buildSequenceSuffix(recipeValues, recipeName, recipe); + SeqGenData seqData = new SeqGenData(); + Long lastSeqValue = null; + if (lastSeq != null) { + lastSeqValue = lastSeq.getSeq(); + } + long seqValue = this.seqGenerator.generate(prefix, suffix, seq, lastSeqValue, attemptCount); + seqData.setSeq(seqValue); + seqData.setPrefix(prefix); + seqData.setSuffix(suffix); + return seqData; + } + + String generateNonSequenceValue(List> namingModels, String policyName, String namingType, + Map namingModel, Map propMap, String recipeItem) throws Exception { + String val = propertyValue(propMap); + if (val == null) { + val = value(this.requestElement, recipeItem); + } + if (val == null) { + val = value(this.requestElement, recipeItem, true); + } + if (val == null) { + val = generateValueRecursively(namingModels, policyName, recipeItem); + } + if (val != null) { + val = applyPropertyOperation(val, propMap); + } + return val; + } + + String generateValueRecursively(List> namingModels, String policyName, String recipeItem) + throws Exception { + String val = null; + String relaxedVal = relaxedNamingType(recipeItem); + Map generated = this.earlierNames.get(relaxedVal); + if (generated != null) { + return generated.get("resource-value"); + } + Map relaxedModel = namingModelRelaxed(namingModels, recipeItem); + if (relaxedModel != null) { + String relaxedNamingType = namingType(relaxedModel); + Map relaxedElement = findElement(relaxedNamingType); + if (relaxedElement != null) { + relaxedElement = new HashMap<>(relaxedElement); + relaxedElement.put(NAMING_TYPE_ELEMENT_ITEM, relaxedNamingType); + } else { + relaxedElement = new HashMap<>(this.requestElement); + relaxedElement.put(NAMING_TYPE_ELEMENT_ITEM, relaxedNamingType); + relaxedElement.remove(EXTERNAL_KEY_ELEMENT_ITEM); + relaxedElement.remove(RESOURCE_NAME_ELEMENT_ITEM); + } + if (relaxedElement != null) { + NameGenerator recursive = new NameGenerator(policyFinder, policyParams, seqGenerator, dbValidator, + aaiValidator, namePersister, relaxedElement, allElements, earlierNames, policyCache); + Map gen = + recursive.generateNew(policyName, relaxedNamingType, namingModels, relaxedModel); + if (gen != null) { + val = value(gen, RESOURCE_VALUE_ELEMENT_ITEM); + } + } + } + return val; + } + + Map findElement(String namingType) throws Exception { + Map theElement = null; + for (Map anElement : this.allElements) { + String oneNamingType = namingType(anElement); + if (namingType.equals(oneNamingType)) { + theElement = anElement; + break; + } + } + return theElement; + } + + String findElementPolicyName() throws Exception { + return value(this.requestElement, "policy-instance-name"); + } + + String findElementNamingType() throws Exception { + return value(this.requestElement, NAMING_TYPE_ELEMENT_ITEM); + } + + String findElementResourceName() throws Exception { + return value(this.requestElement, RESOURCE_NAME_ELEMENT_ITEM); + } + + String findElementExternalKey() throws Exception { + return value(this.requestElement, EXTERNAL_KEY_ELEMENT_ITEM); + } + + Map findPolicy(String name) throws Exception { + Map policy = null; + if (name != null) { + policy = this.policyCache.get(name); + if (policy == null) { + policy = this.policyFinder.findPolicy(name); + if (policy != null) { + this.policyCache.put(name, policy); + } + } + } + return policy; + } + + void storeGeneratedName(String key, String name, String namingType, + SeqGenData seqData) throws Exception { + String prefix = null; + String suffix = null; + Long seqNum = null; + String seqEncoded = null; + if (seqData != null) { + prefix = seqData.getPrefix(); + suffix = seqData.getSuffix(); + seqNum = seqData.getSeq(); + seqEncoded = seqData.getSeqEncoded(); + } + GeneratedName record = new GeneratedName(); + GeneratedName releasedName = namePersister.findBy(namingType, name, "Y"); + if (releasedName != null) { + record = releasedName; + record.setLastUpdatedTime(new Timestamp(System.currentTimeMillis())); + record.setIsReleased(null); + } + record.setName(name); + record.setExternalId(key); + record.setElementType(namingType); + record.setPrefix(prefix); + record.setSuffix(suffix); + if (seqNum != null) { + record.setSequenceNumber(seqNum); + } + record.setSequenceNumberEnc(seqEncoded); + this.namePersister.persist(record); + } + + void validateAllItemsPresent(String policyName, String namingType, List recipe, + Map recipeValues) throws Exception { + List missing = new ArrayList<>(); + for (String item : recipe) { + Object val = recipeValues.get(item); + if (val == null) { + missing.add(item); + } + } + if (missing.size() > 0) { + StringBuffer msg = new StringBuffer(); + for (int i = 0; i < missing.size(); ++i) { + String item = missing.get(i); + if (i > 0) { + String separator = ", "; + if (i == missing.size() - 1) { + separator = " and "; + } + msg.append(separator); + } + msg.append(item); + } + String itemString = "items"; + if (missing.size() == 1) { + itemString = "item"; + } + throw new NengException("Could not find data for recipe " + itemString + " " + msg.toString() + + " in policy " + policyName + " and naming-type " + namingType); + } + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SeqGenData.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SeqGenData.java new file mode 100644 index 00000000..1fe4dd1f --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SeqGenData.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.gen; + +/** + * POJO representing a 'sequence' object defined in the policy, that controls the behavior + * of sequences used as part of a generated name. + */ +public class SeqGenData { + private String prefix; + private String suffix; + private long seq; + private String seqEncoded; + private String name; + + /** + * Prefix for the sequence. + */ + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + /** + * Suffix for the sequence. + */ + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + /** + * The sequence item as an integer. + */ + public long getSeq() { + return seq; + } + + public void setSeq(long seq) { + this.seq = seq; + } + + /** + * The name generated from the sequence. + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The sequence item encoded into the appropriate form. + */ + public String getSeqEncoded() { + return seqEncoded; + } + + public void setSeqEncoded(String seqEncoded) { + this.seqEncoded = seqEncoded; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatter.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatter.java new file mode 100644 index 00000000..c25f101a --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatter.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.gen; + +import org.apache.commons.lang.StringUtils; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicySequence; + +/** + * Utility for formatting a sequence. + */ +public class SequenceFormatter { + /** + * Format the given sequence item/value per the given sequence policy, and return the result + * as a string. + */ + public static String formatSequence(long seqVal, PolicySequence seqPoly) throws Exception { + if (seqPoly.getType() == PolicySequence.Type.ALPHA) { + String val = Long.toString(seqVal, 36); + return StringUtils.leftPad(val, (int) seqPoly.getLength(), '0'); + } else { + String format = "%0" + seqPoly.getLength() + "d"; + String strVal = String.format(format, seqVal); + return strVal; + } + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/persistence/NamePersister.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/persistence/NamePersister.java new file mode 100644 index 00000000..4875052b --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/persistence/NamePersister.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.persistence; + +import org.onap.ccsdk.apps.ms.neng.persistence.entity.GeneratedName; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.GeneratedNameRespository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Manages the persistence of generated names using a DB. + */ +@Component +public class NamePersister { + @Autowired + GeneratedNameRespository repository; + + /** + * Persist the given name. + */ + public void persist(GeneratedName name) throws Exception { + repository.save(name); + } + + /** + * Finds a name stored in the DB of the given type, name, and the 'isReleased' flag. + * + * @param elementType The type of the name + * @param name A name + * @param isReleased An Y/N flag indicating if the name is released or not + */ + public GeneratedName findBy(String elementType, String name, String isReleased) { + return repository.findByElementTypeAndNameAndIsReleased(elementType, name, isReleased); + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/resource/model/AaiResponse.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/resource/model/AaiResponse.java new file mode 100644 index 00000000..431f57b8 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/resource/model/AaiResponse.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.resource.model; + +/** + * POJO encapsulating response from A&AI query. + */ +public class AaiResponse { + + private boolean recFound = false; + + /** + * Indicates if an entry is found in A&AI for a name. + */ + public boolean isRecFound() { + return recFound; + } + + public void setRecFound(boolean recFound) { + this.recFound = recFound; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/rs/interceptors/AaiAuthorizationInterceptor.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/rs/interceptors/AaiAuthorizationInterceptor.java new file mode 100644 index 00000000..e91ee331 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/rs/interceptors/AaiAuthorizationInterceptor.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.rs.interceptors; + +import java.io.IOException; +import org.onap.ccsdk.apps.ms.neng.extinf.props.AaiProps; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.stereotype.Component; + +/** + * Interceptor for adding authorization headers in the request to A&AI. + */ +@Component +public class AaiAuthorizationInterceptor implements ClientHttpRequestInterceptor { + @Autowired + AaiProps aaiProps; + + /** + * Intercepts the given request and adds additional headers, mainly for authorization. + */ + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, ClientHttpRequestExecution executionChain) + throws IOException { + httpRequest.getHeaders().clear(); + httpRequest.getHeaders().add("x-FromAppId", aaiProps.getFromAppId()); + httpRequest.getHeaders().add("x-TransactionId", aaiProps.getTransactionId()); + httpRequest.getHeaders().add("Accept", "application/json"); + httpRequest.getHeaders().add("Content-Type", "application/json"); + return executionChain.execute(httpRequest, body); + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/seq/SequenceGenerator.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/seq/SequenceGenerator.java new file mode 100644 index 00000000..d69345f9 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/seq/SequenceGenerator.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.seq; + +import java.util.regex.Pattern; +import org.onap.ccsdk.apps.ms.neng.core.exceptions.NengException; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicySequence; +import org.onap.ccsdk.apps.ms.neng.persistence.entity.ServiceParameter; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.GeneratedNameRespository; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.ServiceParameterRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Generates the sequence number part of the name. + */ +@Component +public class SequenceGenerator { + @Autowired + GeneratedNameRespository genNameRepo; + + @Autowired + ServiceParameterRepository servParamRepo; + + /** + * Returns the next free item in the sequence that can be used for a generated name. + * + * @param prefix the prefix for the generated name + * @param suffix the suffix for the generated name + * @param seqParams the sequence parameters as defined in the policy + * @param lastSequenceNumber the last sequence number used for name generation + * @param attemptCount the number of times a free sequence item was requested in this transaction + */ + public long generate(String prefix, String suffix, PolicySequence seqParams, + Long lastSequenceNumber, int attemptCount) throws Exception { + Long newSeqNum = null; + long nextIncrement = 1; + if (seqParams.getLastReleaseSeqNumTried() != null) { + newSeqNum = genNameRepo.findNextReleasedSeq(seqParams.getLastReleaseSeqNumTried(), prefix, suffix); + if (newSeqNum == null) { + throw new Exception("Name generation failed since all available sequence numbers are already used."); + } + return newSeqNum; + } + String dbMaxSeqNum = genNameRepo.findMaxByPrefixAndSuffix(prefix, suffix); + if (attemptCount == 1) { + if (dbMaxSeqNum != null) { + newSeqNum = Long.parseLong(dbMaxSeqNum) + seqParams.getIncrement(); + } else { + newSeqNum = seqParams.getStartValue(); + } + } else { + if (dbMaxSeqNum == null) { + ServiceParameter incrementParam = servParamRepo.findByName("initial_increment"); + if (incrementParam != null) { + String[] increments = Pattern.compile(",").split(incrementParam.getValue()); + if (attemptCount <= increments.length) { + nextIncrement = Long.parseLong(increments[attemptCount - 2]); + } else { + nextIncrement = Long.parseLong(increments[increments.length - 1]); + } + newSeqNum = lastSequenceNumber + nextIncrement; + } else { + throw new NengException( + "Name generation failed since initial_increment parameter was not found."); + } + } else { + newSeqNum = lastSequenceNumber + seqParams.getIncrement(); + } + } + if (newSeqNum > seqParams.getMaxValue()) { + newSeqNum = genNameRepo.findNextReleasedSeq(seqParams.getStartValue(), prefix, suffix); + if (newSeqNum != null) { + seqParams.setLastReleaseSeqNumTried(newSeqNum); + return newSeqNum; + } else { + throw new NengException( + "Name generation failed since all available sequence numbers are already used."); + } + } + return newSeqNum; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/AaiNameValidator.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/AaiNameValidator.java new file mode 100644 index 00000000..32f3df6a --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/AaiNameValidator.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.validator; + +import java.util.logging.Logger; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.ExternalInterfaceRespository; +import org.onap.ccsdk.apps.ms.neng.service.extinf.impl.AaiServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Validates that a generated name is valid, by comparing against A&AI. + */ +@Component +public class AaiNameValidator { + @Autowired + AaiServiceImpl aaiImpl; + @Autowired + ExternalInterfaceRespository dbStuff; + + private static Logger log = Logger.getLogger(AaiNameValidator.class.getName()); + + /** + * Returns true if the given name, of the given type, is valid. + */ + public boolean validate(String namingType, String name) throws Exception { + log.info("AAI Validation called for " + namingType + " - " + name); + String url = dbStuff.getUriByNameType(namingType); + if (url == null) { + return true; + } + log.info("AAI URL " + url); + return aaiImpl.validate(url, name); + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/DbNameValidator.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/DbNameValidator.java new file mode 100644 index 00000000..131144b9 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/DbNameValidator.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.core.validator; + +import org.onap.ccsdk.apps.ms.neng.persistence.entity.GeneratedName; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.GeneratedNameRespository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Validates that a generated name is valid, by comparing against the internal DB of this micro-service. + */ +@Component +public class DbNameValidator { + @Autowired + GeneratedNameRespository genNameRepo; + + /** + * Returns true if the given name, of the given type, is valid. + */ + public boolean validate(String namingType, String name) throws Exception { + GeneratedName genName = genNameRepo.findUnReleased(namingType, name); + return (genName == null) ? true : false; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/AaiProps.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/AaiProps.java new file mode 100644 index 00000000..dd831e87 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/AaiProps.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.extinf.props; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * POJO representing properties of the interface with A&AI. + */ +@Configuration +@ConfigurationProperties(prefix = "aai") +public class AaiProps { + String certPassword; + String cert; + String uriBase; + String fromAppId; + String transactionId; + String accept; + + /** + * The certificate password. + */ + public String getCertPassword() { + return certPassword; + } + + public void setCertPassword(String certPassword) { + this.certPassword = certPassword; + } + + /** + * The certificate. + */ + public String getCert() { + return cert; + } + + public void setCert(String cert) { + this.cert = cert; + } + + /** + * Base/initial part of the A&AI URL. + */ + public String getUriBase() { + return uriBase; + } + + public void setUriBase(String auriBase) { + this.uriBase = auriBase; + } + + /** + * The value to be used in the X-FromAppId header in the request to A&AI. + */ + public String getFromAppId() { + return fromAppId; + } + + public void setFromAppId(String fromAppId) { + this.fromAppId = fromAppId; + } + + /** + * The value to be used in the X-TransactionId header in the request to A&AI. + */ + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + /** + * The value to be used in the Accept header in the request to A&AI. + */ + public String getAccept() { + return accept; + } + + public void setAccept(String accept) { + this.accept = accept; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/PolicyManagerProps.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/PolicyManagerProps.java new file mode 100644 index 00000000..bd06f76c --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/PolicyManagerProps.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.extinf.props; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * POJO for representing properties related to policy manager. + */ +@Configuration +@ConfigurationProperties(prefix = "policymgr") +public class PolicyManagerProps { + String clientAuth; + String basicAuth; + String url; + String environment; + String ecompRequestId; + + /** + * Property passed to policy manager in the ClientAuth header. + */ + public String getClientAuth() { + return clientAuth; + } + + public void setClientAuth(String clientAuth) { + this.clientAuth = clientAuth; + } + + /** + * Property passed to policy manager in the BasicAuth header. + */ + public String getBasicAuth() { + return basicAuth; + } + + public void setBasicAuth(String basicAuth) { + this.basicAuth = basicAuth; + } + + /** + * URL of the policy manager. + */ + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + /** + * Property passed to policy manager in the Environment header. + */ + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + /** + * Property passed to policy manager in the X-ECOMP-RequestID header. + */ + public String getEcompRequestId() { + return ecompRequestId; + } + + public void setEcompRequestId(String ecompRequestId) { + this.ecompRequestId = ecompRequestId; + } +} diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java new file mode 100644 index 00000000..a401d214 --- /dev/null +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java @@ -0,0 +1,131 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK.apps + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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========================================================= + */ + +package org.onap.ccsdk.apps.ms.neng.service.extinf.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URI; +import java.security.KeyStore; +import java.util.logging.Logger; +import javax.net.ssl.SSLContext; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.onap.ccsdk.apps.ms.neng.core.exceptions.NengException; +import org.onap.ccsdk.apps.ms.neng.core.resource.model.AaiResponse; +import org.onap.ccsdk.apps.ms.neng.core.rs.interceptors.AaiAuthorizationInterceptor; +import org.onap.ccsdk.apps.ms.neng.extinf.props.AaiProps; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.ResourceUtils; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +/** + * Implements interface with A&AI. + */ +@Service +public class AaiServiceImpl { + private static final Logger log = Logger.getLogger(AaiServiceImpl.class.getName()); + + @Autowired AaiProps aaiProps; + RestTemplate restTemplate; + @Autowired AaiAuthorizationInterceptor authInt; + + @Autowired + @Qualifier("aaiRestTempBuilder") + RestTemplateBuilder aaiRestTempBuilder; + + /** + * Validates the given network element name against A&AI, using the given URL. + * @param url the URL for A&AI + * @param name a generated network element name + * @return true if the element name is valid + */ + public boolean validate(String url, String name) throws Exception { + AaiResponse resp = makeOutboundCall(url, name); + return !resp.isRecFound(); + } + + AaiResponse makeOutboundCall(String url, String name) throws Exception { + String uri = aaiProps.getUriBase() + url + name; + log.info("AAI URI - " + uri); + ResponseEntity resp = null; + try { + RequestEntity re = RequestEntity.get(new URI(uri)).build(); + resp = getRestTemplate().exchange(re, Object.class); + if (HttpStatus.OK.equals(resp.getStatusCode())) { + ObjectMapper objectmapper = new ObjectMapper(); + log.info(objectmapper.writeValueAsString(resp.getBody())); + return buildResponse(true); + } else if (HttpStatus.NOT_FOUND.equals(resp.getStatusCode())) { + log.warning(resp.toString()); + return buildResponse(false); + } else { + log.warning(resp.toString()); + throw new NengException("Error while validating name with A&AI"); + } + } catch (HttpClientErrorException e) { + log.warning(e.getStatusCode().name() + " -- " + e.getResponseBodyAsString()); + if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { + return buildResponse(false); + } + throw new NengException("Error while validating name with AAI"); + } + } + + AaiResponse buildResponse(boolean found) { + AaiResponse aaiResp = new AaiResponse(); + aaiResp.setRecFound(found); + return aaiResp; + } + + RestTemplate getRestTemplate() throws Exception { + if (this.restTemplate == null) { + char[] password = aaiProps.getCertPassword().toCharArray(); + KeyStore ks = keyStore(aaiProps.getCert(), password); + SSLContextBuilder builder = SSLContextBuilder.create().loadKeyMaterial(ks, password); + SSLContext sslContext = builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(); + HttpClient client = HttpClients.custom().setSSLContext(sslContext).build(); + RestTemplateBuilder restBld = aaiRestTempBuilder.additionalInterceptors(authInt); + this.restTemplate = restBld.requestFactory(new HttpComponentsClientHttpRequestFactory(client)).build(); + } + return this.restTemplate; + } + + KeyStore keyStore(String file, char[] password) throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + File key = ResourceUtils.getFile(file); + try (InputStream in = new FileInputStream(key)) { + keyStore.load(in, password); + } + return keyStore; + } +} -- cgit 1.2.3-korg