Adding naming micro-service code - generation. 75/57175/1
authorBT2983 <BT2983@att.com>
Mon, 23 Jul 2018 14:17:51 +0000 (08:17 -0600)
committerBT2983 <BT2983@att.com>
Mon, 23 Jul 2018 14:17:51 +0000 (08:17 -0600)
Main generation algorithm and AAI interface.

Change-Id: I21eb0065358b4c9eeda85a4ae41545e864fdc627
Issue-ID: CCSDK-342
Signed-off-by: BT2983 <BT2983@att.com>
13 files changed:
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/exceptions/NengException.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SeqGenData.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatter.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/persistence/NamePersister.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/resource/model/AaiResponse.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/rs/interceptors/AaiAuthorizationInterceptor.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/seq/SequenceGenerator.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/AaiNameValidator.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/validator/DbNameValidator.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/AaiProps.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/extinf/props/PolicyManagerProps.java [new file with mode: 0644]
ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java [new file with mode: 0644]

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 (file)
index 0000000..cad1575
--- /dev/null
@@ -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 (file)
index 0000000..8cfe7c8
--- /dev/null
@@ -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<String, String> requestElement;
+    private final List<Map<String, String>> allElements;
+    private final Map<String, Map<String, String>> earlierNames;
+    private final Map<String, Map<String, ?>> 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<String, String> requestElement, List<Map<String, String>> allElements,
+                    Map<String, Map<String, String>> earlierNames, Map<String, Map<String, ?>> 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<String, String> 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<String, String> 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<String, ?> 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<String, ?> propertyMap) throws Exception {
+        return new PropertyOperator().apply(value, propertyMap, this.policyParams);
+    }
+
+    static Map<String, String> buildResponse(String key, String name, String value) {
+        Map<String, String> response = new HashMap<String, String>();
+        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<String, Object> recipeValues, String recipeName, List<String> 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<String, Object> recipeValues, String recipeName, List<String> 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<String, String> generateNew(String policyName, String namingType) throws Exception {
+        Map<String, ?> policy = findPolicy(policyName);
+        if (policy != null) {
+            List<Map<String, ?>> namingModels = namingModels(policy);
+            Map<String, ?> 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<String, String> generateNew(String policyName, String namingType, 
+                    List<Map<String, ?>> namingModels, Map<String, ?> 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<String> recipeItems = RecipeParser.parseRecipe(this.policyParams, recipe);
+        return generateNew(namingModels, policyName, namingType, namingModel, recipeItems);
+    }
+
+    Map<String, String> generateNew(List<Map<String, ?>> namingModels, String policyName, 
+                    String namingType, Map<String, ?> namingModel, List<String> recipe) throws Exception {
+        Map<String, Object> recipeValues = new LinkedHashMap<>();
+        for (String recipeItem : recipe) {
+            Map<String, ?> 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<String, String> response = buildResponse(findElementExternalKey(), findElementResourceName(), name);
+        String relaxedNamingType = relaxedNamingType(namingType);
+        this.earlierNames.put(relaxedNamingType, response);
+        return response;
+    }
+
+    SeqGenData generateNameWithSequences(String policyName, String namingType, List<String> recipe,
+                    Map<String, Object> recipeValues, Map<String, ?> 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<String, Object> recipeValues, List<String> 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<String> recipe,
+                    Map<String, Object> 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<String> recipe,
+                    Map<String, Object> 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<String, Object> recipeValues, String recipeName, SeqGenData lastSeq, int attemptCount,
+                    List<String> 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<Map<String, ?>> namingModels, String policyName, String namingType,
+                    Map<String, ?> namingModel, Map<String, ?> 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<Map<String, ?>> namingModels, String policyName, String recipeItem)
+                    throws Exception {
+        String val = null;
+        String relaxedVal = relaxedNamingType(recipeItem);
+        Map<String, String> generated = this.earlierNames.get(relaxedVal);
+        if (generated != null) {
+            return generated.get("resource-value");
+        }
+        Map<String, ?> relaxedModel = namingModelRelaxed(namingModels, recipeItem);
+        if (relaxedModel != null) {
+            String relaxedNamingType = namingType(relaxedModel);
+            Map<String, String> 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<String, String> gen =
+                                recursive.generateNew(policyName, relaxedNamingType, namingModels, relaxedModel);
+                if (gen != null) {
+                    val = value(gen, RESOURCE_VALUE_ELEMENT_ITEM);
+                }
+            }
+        }
+        return val;
+    }
+
+    Map<String, String> findElement(String namingType) throws Exception {
+        Map<String, String> theElement = null;
+        for (Map<String, String> 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<String, ?> findPolicy(String name) throws Exception {
+        Map<String, ?> 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<String> recipe,
+                    Map<String, Object> recipeValues) throws Exception {
+        List<String> 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 (file)
index 0000000..1fe4dd1
--- /dev/null
@@ -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 (file)
index 0000000..c25f101
--- /dev/null
@@ -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 (file)
index 0000000..4875052
--- /dev/null
@@ -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 (file)
index 0000000..431f57b
--- /dev/null
@@ -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 (file)
index 0000000..e91ee33
--- /dev/null
@@ -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 (file)
index 0000000..d69345f
--- /dev/null
@@ -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 (file)
index 0000000..32f3df6
--- /dev/null
@@ -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 (file)
index 0000000..131144b
--- /dev/null
@@ -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 (file)
index 0000000..dd831e8
--- /dev/null
@@ -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 (file)
index 0000000..bd06f76
--- /dev/null
@@ -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 (file)
index 0000000..a401d21
--- /dev/null
@@ -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<Object> resp = null;
+        try {
+            RequestEntity<Void> 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;
+    }
+}