2  *  Copyright © 2017-2018 AT&T Intellectual Property.
 
   3  *  Modifications Copyright © 2018 IBM.
 
   5  *  Licensed under the Apache License, Version 2.0 (the "License");
 
   6  *  you may not use this file except in compliance with the License.
 
   7  *  You may obtain a copy of the License at
 
   9  *      http://www.apache.org/licenses/LICENSE-2.0
 
  11  *  Unless required by applicable law or agreed to in writing, software
 
  12  *  distributed under the License is distributed on an "AS IS" BASIS,
 
  13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  *  See the License for the specific language governing permissions and
 
  15  *  limitations under the License.
 
  18 package org.onap.ccsdk.apps.controllerblueprints.resource.dict.service
 
  20 import com.att.eelf.configuration.EELFLogger
 
  21 import com.att.eelf.configuration.EELFManager
 
  22 import org.apache.commons.collections.CollectionUtils
 
  23 import org.apache.commons.lang3.StringUtils
 
  24 import org.apache.commons.lang3.text.StrBuilder
 
  25 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException
 
  26 import org.onap.ccsdk.apps.controllerblueprints.core.utils.TopologicalSortingUtils
 
  27 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceAssignment
 
  28 import java.io.Serializable
 
  31  * ResourceAssignmentValidationService.
 
  33  * @author Brinda Santh
 
  35 interface ResourceAssignmentValidationService : Serializable {
 
  37     @Throws(BluePrintException::class)
 
  38     fun validate(resourceAssignments: List<ResourceAssignment>): Boolean
 
  42  * ResourceAssignmentValidationServiceImpl.
 
  44  * @author Brinda Santh
 
  46 open class ResourceAssignmentValidationServiceImpl : ResourceAssignmentValidationService {
 
  47     private val log: EELFLogger = EELFManager.getInstance().getLogger(ResourceAssignmentValidationServiceImpl::class.java)
 
  49     open var resourceAssignmentMap: Map<String, ResourceAssignment> = hashMapOf()
 
  50     open val validationMessage = StrBuilder()
 
  52     override fun validate(resourceAssignments: List<ResourceAssignment>): Boolean {
 
  54             validateTemplateNDictionaryKeys(resourceAssignments)
 
  55             validateCyclicDependency(resourceAssignments)
 
  56             if (StringUtils.isNotBlank(validationMessage)) {
 
  57                 throw BluePrintException("Resource Assignment Validation Failure")
 
  59         } catch (e: Exception) {
 
  60             throw BluePrintException("Resource Assignment Validation :" + validationMessage.toString(), e)
 
  66     open fun validateTemplateNDictionaryKeys(resourceAssignments: List<ResourceAssignment>) {
 
  68         resourceAssignmentMap = resourceAssignments.map { it.name to it }.toMap()
 
  70         // Check the Resource Assignment has Duplicate Key Names
 
  71         val duplicateKeyNames = resourceAssignments.groupBy { it.name }
 
  72                 .filter { it.value.size > 1 }
 
  75         if (duplicateKeyNames.isNotEmpty()) {
 
  76             validationMessage.appendln(String.format("Duplicate Assignment Template Keys (%s) is Present", duplicateKeyNames))
 
  79         // Check the Resource Assignment has Duplicate Dictionary Names
 
  80         val duplicateDictionaryKeyNames = resourceAssignments.groupBy { it.dictionaryName }
 
  81                 .filter { it.value.size > 1 }
 
  83         if (duplicateDictionaryKeyNames.isNotEmpty()) {
 
  84             validationMessage.appendln(String.format("Duplicate Assignment Dictionary Keys (%s) is Present", duplicateDictionaryKeyNames))
 
  87         // Collect all the dependencies as a single list
 
  88         val dependenciesNames = resourceAssignments.mapNotNull { it.dependencies }.flatten()
 
  90         // Check all the dependencies keys have Resource Assignment mappings.
 
  91         val notPresentDictionaries = dependenciesNames.filter { !resourceAssignmentMap.containsKey(it) }.distinct()
 
  92         if (notPresentDictionaries.isNotEmpty()) {
 
  93             validationMessage.appendln(String.format("No assignments for Dictionary Keys (%s)", notPresentDictionaries))
 
  96         if (StringUtils.isNotBlank(validationMessage)) {
 
  97             throw BluePrintException("Resource Assignment Validation Failure")
 
 101     open fun validateCyclicDependency(resourceAssignments: List<ResourceAssignment>) {
 
 102         val startResourceAssignment = ResourceAssignment()
 
 103         startResourceAssignment.name = "*"
 
 105         val topologySorting = TopologicalSortingUtils<ResourceAssignment>()
 
 107         resourceAssignmentMap.map { it.value }.map { resourceAssignment ->
 
 108             if (CollectionUtils.isNotEmpty(resourceAssignment.dependencies)) {
 
 109                 resourceAssignment.dependencies!!.map {
 
 110                     log.trace("Topological Graph link from {} to {}", it, resourceAssignment.name)
 
 111                     topologySorting.add(resourceAssignmentMap[it]!!, resourceAssignment)
 
 114                 topologySorting.add(startResourceAssignment, resourceAssignment)
 
 118         if (!topologySorting.isDag) {
 
 119             val graph = getTopologicalGraph(topologySorting)
 
 120             validationMessage.appendln("Cyclic Dependency :$graph")
 
 124     open fun getTopologicalGraph(topologySorting: TopologicalSortingUtils<ResourceAssignment>): String {
 
 125         val s = StringBuilder()
 
 126         val neighbors = topologySorting.getNeighbors()
 
 128         neighbors.forEach { v, vs ->
 
 130                 s.append("\n    * -> [")
 
 131                 for (resourceAssignment in vs) {
 
 132                     s.append("(" + resourceAssignment.dictionaryName + ":" + resourceAssignment.name
 
 137                 s.append("\n    (" + v.dictionaryName + ":" + v.name + ") -> [")
 
 138                 for (resourceAssignment in vs) {
 
 139                     s.append("(" + resourceAssignment.dictionaryName + ":" + resourceAssignment.name