Improve script file accessing through cache. 07/91707/2
authorBrinda Santh <brindasanth@in.ibm.com>
Thu, 18 Jul 2019 23:13:00 +0000 (19:13 -0400)
committerBrinda Santh <brindasanth@in.ibm.com>
Fri, 19 Jul 2019 14:50:25 +0000 (10:50 -0400)
Change-Id: If94e837975701dc7b2235c38acb46b3b883a424b
Issue-ID: CCSDK-1503
Signed-off-by: Brinda Santh <brindasanth@in.ibm.com>
19 files changed:
ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImpl.kt
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ComponentFunctionScriptingService.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintModel.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintScriptsService.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompiledScript.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerCache.kt [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerProxy.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptingHost.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsConfiguration.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImpl.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintFileUtils.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt
ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImplTest.kt [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BlueprintScriptingHostTest.kt [deleted file]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/Scripts/kotlin/SampleBlueprintFunctionNode.kt [moved from ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts/SampleBlueprintFunctionNode.kts with 63% similarity]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/TOSCA-Metadata/TOSCA.meta [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts1/simple.cba.kts [deleted file]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts2/simple.cba.kts [deleted file]

index 3e1f071..9faf879 100755 (executable)
@@ -26,6 +26,8 @@ import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants
 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintValidatorService
+import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
 import org.onap.ccsdk.cds.controllerblueprints.db.resources.BlueprintCatalogServiceImpl
 import org.slf4j.LoggerFactory
 import org.springframework.dao.DataIntegrityViolationException
@@ -46,12 +48,17 @@ class BlueprintProcessorCatalogServiceImpl(bluePrintRuntimeValidatorService: Blu
     private val log = LoggerFactory.getLogger(BlueprintProcessorCatalogServiceImpl::class.toString())
 
     override suspend fun delete(name: String, version: String) {
+        // Clean blueprint script cache
+        val cacheKey = BluePrintFileUtils
+                .compileCacheKey(normalizedPathName(bluePrintPathConfiguration.blueprintDeployPath, name, version))
+        BluePrintCompileCache.cleanClassLoader(cacheKey)
+        log.info("removed cba file name($name), version($version) from cache")
         // Cleaning Deployed Blueprint
         deleteNBDir(bluePrintPathConfiguration.blueprintDeployPath, name, version)
         log.info("removed cba file name($name), version($version) from deploy location")
         // Cleaning Data Base
         blueprintModelRepository
-            .deleteByArtifactNameAndArtifactVersion(name, version)
+                .deleteByArtifactNameAndArtifactVersion(name, version)
         log.info("removed cba file name($name), version($version) from database")
     }
 
@@ -60,7 +67,7 @@ class BlueprintProcessorCatalogServiceImpl(bluePrintRuntimeValidatorService: Blu
 
         val deployFile = normalizedFile(bluePrintPathConfiguration.blueprintDeployPath, name, version)
         val cbaFile = normalizedFile(bluePrintPathConfiguration.blueprintArchivePath,
-            UUID.randomUUID().toString(), "cba.zip")
+                UUID.randomUUID().toString(), "cba.zip")
 
         if (extract && deployFile.exists()) {
             log.info("cba file name($name), version($version) already present(${deployFile.absolutePath})")
@@ -110,7 +117,7 @@ class BlueprintProcessorCatalogServiceImpl(bluePrintRuntimeValidatorService: Blu
             log.info("Overwriting blueprint model :$artifactName::$artifactVersion")
             blueprintModelRepository.deleteByArtifactNameAndArtifactVersion(artifactName, artifactVersion)
             val deployFile =
-                normalizedPathName(bluePrintPathConfiguration.blueprintDeployPath, artifactName, artifactVersion)
+                    normalizedPathName(bluePrintPathConfiguration.blueprintDeployPath, artifactName, artifactVersion)
             deleteNBDir(deployFile).let {
                 if (it) log.info("Deleted deployed blueprint model :$artifactName::$artifactVersion")
                 else log.info("Fail to delete deployed blueprint model :$artifactName::$artifactVersion")
index 49a2c62..a16c520 100644 (file)
@@ -76,7 +76,8 @@ class ComponentFunctionScriptingService(private val applicationContext: Applicat
             }
             BluePrintConstants.SCRIPT_KOTLIN -> {
                 val bluePrintScriptsService: BluePrintScriptsService = BluePrintScriptsServiceImpl()
-                scriptComponent = bluePrintScriptsService.scriptInstance<T>(bluePrintContext, scriptClassReference, false)
+                scriptComponent = bluePrintScriptsService.scriptInstance<T>(bluePrintContext.rootPath,
+                        bluePrintContext.name(), bluePrintContext.version(), scriptClassReference, false)
             }
             BluePrintConstants.SCRIPT_JYTHON -> {
                 scriptComponent = blueprintJythonService.jythonComponentInstance(bluePrintContext, scriptClassReference) as T
index cea18ef..0b640d9 100644 (file)
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.node.*
 import org.apache.commons.lang3.ObjectUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.slf4j.LoggerFactory
 import org.slf4j.helpers.MessageFormatter
 import kotlin.reflect.KClass
 
@@ -30,6 +31,11 @@ import kotlin.reflect.KClass
  * @author Brinda Santh
  */
 
+fun <T : Any> logger(clazz: T) = LoggerFactory.getLogger(clazz.javaClass)!!
+
+fun <T : KClass<*>> logger(clazz: T) = LoggerFactory.getLogger(clazz.java)!!
+
+
 fun <T : Any> T.bpClone(): T {
     return ObjectUtils.clone(this)
 }
index 68e5b0a..a2cba95 100644 (file)
@@ -630,6 +630,8 @@ class ToscaMetaData {
     lateinit var csarVersion: String
     lateinit var createdBy: String
     lateinit var entityDefinitions: String
+    var templateName: String? = null
+    var templateVersion: String? = null
     var templateTags: String? = null
 }
 
index 8bb0cd0..7912e78 100644 (file)
 
 package org.onap.ccsdk.cds.controllerblueprints.core.interfaces
 
-import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
+import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintSourceCode
 
 interface BluePrintScriptsService {
 
-    suspend fun <T> scriptInstance(blueprintContext: BluePrintContext, scriptClassName: String,
-                           reCompile: Boolean): T
+    suspend fun <T> scriptInstance(bluePrintSourceCode: BluePrintSourceCode, scriptClassName: String): T
+
+    suspend fun <T> scriptInstance(blueprintBasePath: String, artifactName: String, artifactVersion: String,
+                                   scriptClassName: String, reCompile: Boolean): T
+
+    suspend fun <T> scriptInstance(blueprintBasePath: String, scriptClassName: String, reCompile: Boolean): T
+
+    suspend fun <T> scriptInstance(cacheKey: String, scriptClassName: String): T
 
     suspend fun <T> scriptInstance(scriptClassName: String): T
 }
\ No newline at end of file
index 03258c2..2f131f6 100644 (file)
 
 package org.onap.ccsdk.cds.controllerblueprints.core.scripts
 
-import java.io.File
 import java.io.Serializable
-import java.net.URL
-import java.net.URLClassLoader
 import kotlin.reflect.KClass
 import kotlin.script.experimental.api.*
 
-open class BluePrintCompiledScript<out JarFile : File>(
-        private val scriptCompilationConfiguration: ScriptCompilationConfiguration,
-        private val compiledJar: File) :
-        CompiledScript<JarFile>, Serializable {
+open class BluePrintCompiledScript<out BCS : String>(
+        val cacheKey: String,
+        val scriptCompilationConfiguration: ScriptCompilationConfiguration) :
+        CompiledScript<BCS>, Serializable {
 
     lateinit var scriptClassFQName: String
 
     override val compilationConfiguration: ScriptCompilationConfiguration
         get() = scriptCompilationConfiguration
 
-    override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>> = try {
+    override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?)
+            : ResultWithDiagnostics<KClass<*>> = try {
 
-        val baseClassLoader = Thread.currentThread().contextClassLoader
-
-        val urls = arrayListOf<URL>()
-        urls.add(compiledJar.toURI().toURL())
-        val classLoaderWithDependencies = URLClassLoader(urls.toTypedArray(), baseClassLoader)
+        /** Get the class loader from the cache */
+        val classLoaderWithDependencies = BluePrintCompileCache.classLoader(cacheKey)
 
         val clazz = classLoaderWithDependencies.loadClass(scriptClassFQName).kotlin
         clazz.asSuccess()
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerCache.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerCache.kt
new file mode 100644 (file)
index 0000000..7305139
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  Copyright © 2019 IBM.
+ *
+ *  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.
+ */
+
+package org.onap.ccsdk.cds.controllerblueprints.core.scripts
+
+import com.google.common.cache.CacheBuilder
+import com.google.common.cache.CacheLoader
+import com.google.common.cache.LoadingCache
+import com.google.common.util.concurrent.ListenableFuture
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
+import java.net.URL
+import java.net.URLClassLoader
+
+
+object BluePrintCompileCache {
+    val log = logger(BluePrintCompileCache::class)
+
+    private val classLoaderCache: LoadingCache<String, URLClassLoader> = CacheBuilder.newBuilder()
+            .maximumSize(10)
+            .build(BluePrintClassLoader)
+
+    fun classLoader(key: String): URLClassLoader {
+        return classLoaderCache.get(key)
+    }
+
+    fun cleanClassLoader(key: String) {
+        classLoaderCache.invalidate(key)
+        log.info("Cleaned script cache($key)")
+    }
+
+    fun hasClassLoader(key: String): Boolean {
+        return classLoaderCache.asMap().containsKey(key)
+    }
+}
+
+object BluePrintClassLoader : CacheLoader<String, URLClassLoader>() {
+
+    val log = logger(BluePrintClassLoader::class)
+
+    override fun reload(key: String, oldValue: URLClassLoader): ListenableFuture<URLClassLoader> {
+        return reload(key, oldValue)
+    }
+
+    override fun load(key: String): URLClassLoader {
+        log.info("loading cache key($key)")
+        val keyPath = normalizedFile(key)
+        if (!keyPath.exists()) {
+            throw BluePrintException("failed to load cache($key), missing files.")
+        }
+        val urls = arrayListOf<URL>()
+        keyPath.walkTopDown()
+                .filter { it.name.endsWith("cba-kts.jar") }
+                .forEach {
+                    log.debug("Adding (${it.absolutePath}) to cache key($key)")
+                    urls.add(it.toURI().toURL())
+                }
+        return URLClassLoader(urls.toTypedArray(), this.javaClass.classLoader)
+    }
+}
\ No newline at end of file
index df33025..e231f6d 100644 (file)
@@ -30,8 +30,8 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
 import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
 import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer
 import org.jetbrains.kotlin.config.*
+import org.onap.ccsdk.cds.controllerblueprints.core.checkFileExists
 import org.slf4j.LoggerFactory
-import java.io.File
 import kotlin.script.experimental.api.*
 import kotlin.script.experimental.host.ScriptingHostConfiguration
 import kotlin.script.experimental.jvm.util.classpathFromClasspathProperty
@@ -60,7 +60,11 @@ open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostC
 
             val compiledJarFile = blueprintSourceCode.targetJarFile
 
-            if (!compiledJarFile.exists() || blueprintSourceCode.regenerate) {
+            /** Check cache is present for the blueprint scripts */
+            val hasCompiledCache = BluePrintCompileCache.hasClassLoader(blueprintSourceCode.cacheKey)
+
+            if (!compiledJarFile.exists() || blueprintSourceCode.regenerate || !hasCompiledCache) {
+                log.info("compiling for cache key(${blueprintSourceCode.cacheKey})")
 
                 var environment: KotlinCoreEnvironment? = null
 
@@ -68,6 +72,11 @@ open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostC
 
                 try {
 
+                    // Clean the cache, if present
+                    if (hasCompiledCache) {
+                        BluePrintCompileCache.cleanClassLoader(blueprintSourceCode.cacheKey)
+                    }
+
                     val compilerConfiguration = CompilerConfiguration().apply {
 
                         put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
@@ -83,6 +92,8 @@ open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostC
 
                         // Add all Kotlin Sources
                         addKotlinSourceRoots(blueprintSourceCode.blueprintKotlinSources)
+                        // for Kotlin 1.3.30 greater
+                        //add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, ScriptingCompilerConfigurationComponentRegistrar())
 
                         languageVersionSettings = LanguageVersionSettingsImpl(
                                 LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
@@ -108,9 +119,11 @@ open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostC
                 }
             }
 
-            val res = BluePrintCompiledScript<File>(scriptCompilationConfiguration, compiledJarFile)
+            checkFileExists(compiledJarFile) { "couldn't generate compiled jar(${compiledJarFile.absolutePath})" }
+
+            val compiledScript = BluePrintCompiledScript<String>(blueprintSourceCode.cacheKey, scriptCompilationConfiguration)
 
-            return ResultWithDiagnostics.Success(res, messageCollector.diagnostics)
+            return compiledScript.asSuccess()
 
         } catch (ex: Throwable) {
             return failure(ex.asDiagnostics())
index 4fcc33d..05a1471 100644 (file)
@@ -19,6 +19,7 @@ package org.onap.ccsdk.cds.controllerblueprints.core.scripts
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
 import org.slf4j.LoggerFactory
 import java.util.*
+import kotlin.reflect.full.createInstance
 import kotlin.script.experimental.api.*
 import kotlin.script.experimental.host.BasicScriptingHost
 import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
@@ -30,19 +31,16 @@ val blueprintScriptCompiler = JvmScriptCompiler(defaultJvmScriptingHostConfigura
 
 open class BlueprintScriptingHost(evaluator: ScriptEvaluator) : BasicScriptingHost(blueprintScriptCompiler, evaluator) {
 
-    override fun eval(
-            script: SourceCode,
-            scriptCompilationConfiguration: ScriptCompilationConfiguration,
-            configuration: ScriptEvaluationConfiguration?
-    ): ResultWithDiagnostics<EvaluationResult> =
+    override fun eval(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration,
+                      configuration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<EvaluationResult> =
 
             runInCoroutineContext {
 
-                compiler(script, scriptCompilationConfiguration)
+                blueprintScriptCompiler(script, scriptCompilationConfiguration)
                         .onSuccess {
                             evaluator(it, configuration)
                         }.onFailure { failedResult ->
-                            val messages = failedResult.reports?.joinToString("\n")
+                            val messages = failedResult.reports.joinToString("\n")
                             throw BluePrintProcessorException(messages)
                         }
             }
@@ -52,21 +50,21 @@ open class BluePrintScriptEvaluator(private val scriptClassName: String) : Scrip
 
     private val log = LoggerFactory.getLogger(BluePrintScriptEvaluator::class.java)!!
 
-    override suspend operator fun invoke(
-            compiledScript: CompiledScript<*>,
-            scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
+    override suspend operator fun invoke(compiledScript: CompiledScript<*>,
+                                         scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
     ): ResultWithDiagnostics<EvaluationResult> =
             try {
                 log.debug("Getting script class name($scriptClassName) from the compiled sources ")
+
                 val bluePrintCompiledScript = compiledScript as BluePrintCompiledScript
                 bluePrintCompiledScript.scriptClassFQName = scriptClassName
 
-                val res = compiledScript.getClass(scriptEvaluationConfiguration)
-                when (res) {
-                    is ResultWithDiagnostics.Failure -> res
+                val classResult = compiledScript.getClass(scriptEvaluationConfiguration)
+                when (classResult) {
+                    is ResultWithDiagnostics.Failure -> classResult
                     is ResultWithDiagnostics.Success -> {
 
-                        val scriptClass = res.value
+                        val scriptClass = classResult.value
                         val args = ArrayList<Any?>()
                         scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.providedProperties)?.forEach {
                             args.add(it.value)
@@ -78,10 +76,14 @@ open class BluePrintScriptEvaluator(private val scriptClassName: String) : Scrip
                             args.addAll(it)
                         }
 
-                        val instance = scriptClass.java.constructors.single().newInstance(*args.toArray())
-                                ?: throw BluePrintProcessorException("failed to create instance from the script")
+                        val instance = if (args.isNotEmpty()) {
+                            scriptClass.java.constructors.single().newInstance(*args.toArray())
+                                    ?: throw BluePrintProcessorException("failed to create instance from the script")
+                        } else {
+                            scriptClass.createInstance()
+                        }
 
-                        log.info("Created script instance of type ${instance.javaClass}")
+                        log.debug("Created script instance of type ${instance.javaClass}")
 
                         ResultWithDiagnostics.Success(EvaluationResult(ResultValue.Value(scriptClass.qualifiedName!!,
                                 instance, "", instance),
index 3ac7901..e019237 100644 (file)
@@ -35,7 +35,7 @@ object BluePrintScripCompilationConfiguration : ScriptCompilationConfiguration(
                 //classpathFromClassloader(BluePrintScripCompilationConfiguration::class.java.classLoader)
                 classpathFromClasspathProperty()
             }
-            ide{
+            ide {
                 acceptedLocations(ScriptAcceptedLocation.Everywhere)
             }
 
@@ -46,6 +46,7 @@ open class BluePrintSourceCode : SourceCode {
     lateinit var blueprintKotlinSources: MutableList<String>
     lateinit var moduleName: String
     lateinit var targetJarFile: File
+    lateinit var cacheKey: String
     var regenerate: Boolean = false
 
     override val text: String
index e2c0260..3600353 100644 (file)
@@ -19,42 +19,59 @@ package org.onap.ccsdk.cds.controllerblueprints.core.scripts
 
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintScriptsService
-import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
-import java.io.File
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
 import java.util.*
 import kotlin.script.experimental.api.ResultValue
 import kotlin.script.experimental.api.resultOrNull
 import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
 
+
 open class BluePrintScriptsServiceImpl : BluePrintScriptsService {
 
-    override suspend fun <T> scriptInstance(blueprintContext: BluePrintContext, scriptClassName: String,
-                                            reCompile: Boolean): T {
+    val log = logger(BluePrintScriptsServiceImpl::class)
 
-        val kotlinScriptPath = blueprintContext.rootPath.plus(File.separator)
-                .plus(BluePrintConstants.TOSCA_SCRIPTS_KOTLIN_DIR)
+    override suspend fun <T> scriptInstance(bluePrintSourceCode: BluePrintSourceCode, scriptClassName: String): T {
+        val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<BluePrintKotlinScript>()
+        val scriptEvaluator = BluePrintScriptEvaluator(scriptClassName)
 
-        val compiledJar = kotlinScriptPath.plus(File.separator)
-                .plus(bluePrintScriptsJarName(blueprintContext))
+        val compiledResponse = BlueprintScriptingHost(scriptEvaluator)
+                .eval(bluePrintSourceCode, compilationConfiguration, null)
 
-        val scriptSource = BluePrintSourceCode()
+        val returnValue = compiledResponse.resultOrNull()?.returnValue as? ResultValue.Value
+        return returnValue?.value!! as T
+    }
+
+    override suspend fun <T> scriptInstance(blueprintBasePath: String, artifactName: String, artifactVersion: String,
+                                            scriptClassName: String, reCompile: Boolean): T {
 
         val sources: MutableList<String> = arrayListOf()
-        sources.add(kotlinScriptPath)
+        sources.add(normalizedPathName(blueprintBasePath, BluePrintConstants.TOSCA_SCRIPTS_KOTLIN_DIR))
+
+        val scriptSource = BluePrintSourceCode()
         scriptSource.blueprintKotlinSources = sources
-        scriptSource.moduleName = "${blueprintContext.name()}-${blueprintContext.version()}-cba-kts"
-        scriptSource.targetJarFile = File(compiledJar)
+        scriptSource.moduleName = "$artifactName-$artifactVersion-cba-kts"
+        scriptSource.cacheKey = BluePrintFileUtils.compileCacheKey(blueprintBasePath)
+        scriptSource.targetJarFile = BluePrintFileUtils.compileJarFile(blueprintBasePath, artifactName, artifactVersion)
         scriptSource.regenerate = reCompile
+        return scriptInstance(scriptSource, scriptClassName)
+    }
 
-        val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<BluePrintKotlinScript>()
-        val scriptEvaluator = BluePrintScriptEvaluator(scriptClassName)
-
-        val compiledResponse = BlueprintScriptingHost(scriptEvaluator).eval(scriptSource, compilationConfiguration,
-                null)
-
-        val returnValue = compiledResponse.resultOrNull()?.returnValue as? ResultValue.Value
+    override suspend fun <T> scriptInstance(blueprintBasePath: String, scriptClassName: String,
+                                            reCompile: Boolean): T {
+        val toscaMetaData = BluePrintMetadataUtils.toscaMetaData(blueprintBasePath)
+        checkNotNull(toscaMetaData.templateName) { "couldn't find 'Template-Name' key in TOSCA.meta" }
+        checkNotNull(toscaMetaData.templateVersion) { "couldn't find 'Template-Version' key in TOSCA.meta" }
+        return scriptInstance(blueprintBasePath, toscaMetaData.templateName!!, toscaMetaData.templateVersion!!,
+                scriptClassName, reCompile)
+    }
 
-        return returnValue?.value!! as T
+    override suspend fun <T> scriptInstance(cacheKey: String, scriptClassName: String): T {
+        val args = ArrayList<Any?>()
+        return BluePrintCompileCache.classLoader(cacheKey).loadClass(scriptClassName).constructors
+                .single().newInstance(*args.toArray()) as T
     }
 
     override suspend fun <T> scriptInstance(scriptClassName: String): T {
@@ -62,8 +79,4 @@ open class BluePrintScriptsServiceImpl : BluePrintScriptsService {
         return Thread.currentThread().contextClassLoader.loadClass(scriptClassName).constructors
                 .single().newInstance(*args.toArray()) as T
     }
-
-    private fun bluePrintScriptsJarName(blueprintContext: BluePrintContext): String {
-        return "${blueprintContext.name()}-${blueprintContext.version()}-cba-kts.jar"
-    }
 }
\ No newline at end of file
index 5f9725f..ad91d45 100755 (executable)
@@ -17,7 +17,6 @@
 
 package org.onap.ccsdk.cds.controllerblueprints.core.utils
 
-import org.slf4j.LoggerFactory
 import kotlinx.coroutines.runBlocking
 import org.apache.commons.io.FileUtils
 import org.apache.commons.lang3.StringUtils
@@ -26,7 +25,10 @@ import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ImportDefinition
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
+import org.slf4j.LoggerFactory
 import java.io.File
 import java.io.FileFilter
 import java.nio.file.Files
@@ -38,7 +40,7 @@ import java.nio.file.StandardOpenOption
 class BluePrintFileUtils {
     companion object {
 
-        private val log= LoggerFactory.getLogger(this::class.toString())
+        private val log = LoggerFactory.getLogger(this::class.toString())
 
         fun createEmptyBluePrint(basePath: String) {
 
@@ -216,8 +218,8 @@ class BluePrintFileUtils {
                     "\nTemplate-Tags: <TAGS>"
         }
 
-       
-        fun getBluePrintFile(fileName: String, targetPath: Path) : File {
+
+        fun getBluePrintFile(fileName: String, targetPath: Path): File {
             val filePath = targetPath.resolve(fileName).toString()
             val file = File(filePath)
             check(file.exists()) {
@@ -241,6 +243,24 @@ class BluePrintFileUtils {
             return fileStorageLocation
         }
 
+        fun compileCacheKey(basePath: String): String {
+            return normalizedPathName(basePath)
+        }
+
+        private fun compileJarFileName(artifactName: String, artifactVersion: String): String {
+            return "$artifactName-$artifactVersion-cba-kts.jar"
+        }
+
+        fun compileJarFilePathName(basePath: String, artifactName: String, artifactVersion: String): String {
+            return normalizedPathName(basePath, BluePrintConstants.TOSCA_SCRIPTS_KOTLIN_DIR,
+                    compileJarFileName(artifactName, artifactVersion))
+        }
+
+        fun compileJarFile(basePath: String, artifactName: String, artifactVersion: String): File {
+            return normalizedFile(compileJarFilePathName(basePath,
+                    artifactName, artifactVersion))
+        }
+
         fun stripFileExtension(fileName: String): String {
             val dotIndexe = fileName.lastIndexOf('.')
 
index ef5cb81..6f09078 100644 (file)
@@ -20,8 +20,11 @@ package org.onap.ccsdk.cds.controllerblueprints.core.utils
 
 import com.fasterxml.jackson.databind.JsonNode
 import kotlinx.coroutines.runBlocking
-import org.onap.ccsdk.cds.controllerblueprints.core.*
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ToscaMetaData
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
+import org.onap.ccsdk.cds.controllerblueprints.core.readNBLines
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintImportService
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
@@ -83,6 +86,8 @@ class BluePrintMetadataUtils {
                             "CSAR-Version" -> toscaMetaData.csarVersion = value
                             "Created-By" -> toscaMetaData.createdBy = value
                             "Entry-Definitions" -> toscaMetaData.entityDefinitions = value
+                            "Template-Name" -> toscaMetaData.templateName = value
+                            "Template-Version" -> toscaMetaData.templateVersion = value
                             "Template-Tags" -> toscaMetaData.templateTags = value
                         }
                     }
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImplTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImplTest.kt
new file mode 100644 (file)
index 0000000..9d4ef69
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2017-2018 AT&T Intellectual Property.
+ *
+ * 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.
+ */
+
+package org.onap.ccsdk.cds.controllerblueprints.core.scripts
+
+
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
+import kotlin.script.experimental.jvm.util.classpathFromClass
+import kotlin.script.experimental.jvm.util.classpathFromClassloader
+import kotlin.script.experimental.jvm.util.classpathFromClasspathProperty
+import kotlin.test.assertNotNull
+
+class BluePrintScriptsServiceImplTest {
+
+    private fun viewClassPathInfo() {
+
+        println(" *********** classpathFromClass  *********** ")
+        classpathFromClass(BluePrintScriptsServiceImplTest::class.java.classLoader,
+                BluePrintScriptsServiceImplTest::class)!!
+                .forEach(::println)
+
+        println(" *********** classpathFromClassloader  *********** ")
+        classpathFromClassloader(BluePrintScriptsServiceImplTest::class.java.classLoader)!!
+                .forEach(::println)
+
+        println(" *********** classpathFromClasspathProperty  *********** ")
+        classpathFromClasspathProperty()!!
+                .forEach(::println)
+    }
+
+    @Test
+    fun testCachedService() {
+        runBlocking {
+
+            val bluePrintScriptsService = BluePrintScriptsServiceImpl()
+
+            val basePath = normalizedPathName("src/test/resources/compile")
+
+            val instance = bluePrintScriptsService
+                    .scriptInstance<BlueprintFunctionNode<String, String>>(basePath,
+                            "cba.scripts.SampleBlueprintFunctionNode", true)
+            assertNotNull(instance, "failed to get compiled instance")
+
+            val cachedInstance = bluePrintScriptsService
+                    .scriptInstance<BlueprintFunctionNode<String, String>>(basePath,
+                            "cba.scripts.SampleBlueprintFunctionNode", false)
+            assertNotNull(cachedInstance, "failed to get cached compile instance")
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BlueprintScriptingHostTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BlueprintScriptingHostTest.kt
deleted file mode 100644 (file)
index 2288d62..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright © 2017-2018 AT&T Intellectual Property.
- *
- * 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.
- */
-
-package org.onap.ccsdk.cds.controllerblueprints.core.scripts
-
-
-import org.apache.commons.io.FileUtils
-import org.junit.Test
-import java.io.File
-import kotlin.script.experimental.jvm.util.classpathFromClass
-import kotlin.script.experimental.jvm.util.classpathFromClassloader
-import kotlin.script.experimental.jvm.util.classpathFromClasspathProperty
-import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
-
-class BlueprintScriptingHostTest {
-
-    private fun viewClassPathInfo() {
-
-        println(" *********** classpathFromClass  *********** ")
-        classpathFromClass(BlueprintScriptingHostTest::class.java.classLoader,
-                BlueprintScriptingHostTest::class)!!
-                .forEach(::println)
-
-        println(" *********** classpathFromClassloader  *********** ")
-        classpathFromClassloader(BlueprintScriptingHostTest::class.java.classLoader)!!
-                .forEach(::println)
-
-        println(" *********** classpathFromClasspathProperty  *********** ")
-        classpathFromClasspathProperty()!!
-                .forEach(::println)
-    }
-
-    @Test
-    fun `test same script two folders`() {
-
-        FileUtils.forceMkdir(File("target/scripts1/"))
-        FileUtils.forceMkdir(File("target/scripts2/"))
-
-        val scriptSource1 = BluePrintSourceCode()
-        scriptSource1.moduleName = "blueprint-test-script"
-
-        scriptSource1.targetJarFile = File("target/scripts1/blueprint-script-generated.jar")
-        val sources1: MutableList<String> = arrayListOf()
-        sources1.add("src/test/resources/scripts1")
-        scriptSource1.blueprintKotlinSources = sources1
-
-        val scriptClassName = "Simple_cba\$SampleComponentFunction"
-
-        val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<BluePrintKotlinScript>()
-
-        val scriptEvaluator = BluePrintScriptEvaluator(scriptClassName)
-
-        val scriptSource2 = BluePrintSourceCode()
-        scriptSource2.moduleName = "blueprint-test-script"
-
-        scriptSource2.targetJarFile = File("target/scripts2/blueprint-script-generated.jar")
-        val sources2: MutableList<String> = arrayListOf()
-        sources2.add("src/test/resources/scripts2")
-        scriptSource2.blueprintKotlinSources = sources2
-
-        for (i in 1..2) {
-            val evalResponse = BlueprintScriptingHost(scriptEvaluator).eval(scriptSource1, compilationConfiguration,
-                    null)
-        }
-
-        for (i in 1..2) {
-            val evalResponse = BlueprintScriptingHost(scriptEvaluator).eval(scriptSource2, compilationConfiguration,
-                    null)
-        }
-    }
-}
\ No newline at end of file
  * limitations under the License.
  */
 
+package cba.scripts
+
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode
 
-open class SampleBlueprintFunctionNode : BlueprintFunctionNode<String, String>{
+open class SampleBlueprintFunctionNode : BlueprintFunctionNode<String, String> {
 
     override fun getName(): String {
         return "Kotlin-Script-Function-Node"
@@ -41,4 +43,24 @@ open class SampleBlueprintFunctionNode : BlueprintFunctionNode<String, String>{
     override fun apply(t: String): String {
         return "$t-status"
     }
+
+    override suspend fun prepareRequestNB(executionRequest: String): String {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override suspend fun processNB(executionRequest: String) {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: String) {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override suspend fun prepareResponseNB(): String {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override suspend fun applyNB(t: String): String {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
 }
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/TOSCA-Metadata/TOSCA.meta b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/TOSCA-Metadata/TOSCA.meta
new file mode 100644 (file)
index 0000000..b1ffabd
--- /dev/null
@@ -0,0 +1,7 @@
+TOSCA-Meta-File-Version: 1.0.0
+CSAR-Version: 1.0
+Created-By: Brinda Santh <brindasanth@in.ibm.com>
+Entry-Definitions: cba.scripts.ActivateBlueprintDefinitions.kt
+Template-Tags: Brinda Santh, activation-blueprint
+Template-Name: activate-blueprint
+Template-Version: 1.0.0
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts1/simple.cba.kts b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts1/simple.cba.kts
deleted file mode 100644 (file)
index 4fffda0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright © 2017-2018 AT&T Intellectual Property.
- * Modifications Copyright © 2019 IBM.
- *
- * 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.
- */
-
-import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
-import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
-import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode
-import org.springframework.stereotype.Service
-
-@Service
-open class SampleComponentFunction : BlueprintFunctionNode<String, String> {
-
-    override fun getName(): String {
-        println("Printing Name....." + "sample".asJsonPrimitive())
-        return "my Name"
-    }
-
-    override suspend fun prepareRequestNB(executionRequest: String): String {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun processNB(executionRequest: String) {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: String) {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun prepareResponseNB(): String {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun applyNB(t: String): String {
-        return "Script 1 response - $t"
-    }
-}
-
-val blueprintFunction = SampleComponentFunction()
-
-val serviceTemplate = ServiceTemplate()
-
-println("Simple script printing....")
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts2/simple.cba.kts b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts2/simple.cba.kts
deleted file mode 100644 (file)
index 4ba56c4..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright © 2017-2018 AT&T Intellectual Property.
- * Modifications Copyright © 2019 IBM.
- *
- * 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.
- */
-
-import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
-import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
-import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode
-import org.springframework.stereotype.Service
-
-@Service
-open class SampleComponentFunction : BlueprintFunctionNode<String, String> {
-
-    override fun getName(): String {
-        println("Printing Name....." + "sample".asJsonPrimitive())
-        return "my Name"
-    }
-
-    override suspend fun prepareRequestNB(executionRequest: String): String {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun processNB(executionRequest: String) {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: String) {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun prepareResponseNB(): String {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override suspend fun applyNB(t: String): String {
-       return "Script 2 response - $t"
-    }
-}
-
-val blueprintFunction = SampleComponentFunction()
-
-val serviceTemplate = ServiceTemplate()
-
-println("Simple script printing....")