From b52a648f3c77a495539d64bba1e43fcbbdaa0364 Mon Sep 17 00:00:00 2001 From: Brinda Santh Date: Thu, 18 Jul 2019 19:13:00 -0400 Subject: Improve script file accessing through cache. Change-Id: If94e837975701dc7b2235c38acb46b3b883a424b Issue-ID: CCSDK-1503 Signed-off-by: Brinda Santh --- .../controllerblueprints/core/CustomFunctions.kt | 6 ++ .../core/data/BluePrintModel.kt | 2 + .../core/interfaces/BluePrintScriptsService.kt | 12 +++- .../core/scripts/BluePrintCompiledScript.kt | 21 +++--- .../core/scripts/BluePrintCompilerCache.kt | 74 +++++++++++++++++++ .../core/scripts/BluePrintCompilerProxy.kt | 21 ++++-- .../core/scripts/BluePrintScriptingHost.kt | 36 +++++----- .../core/scripts/BluePrintScriptsConfiguration.kt | 3 +- .../core/scripts/BluePrintScriptsServiceImpl.kt | 61 +++++++++------- .../core/utils/BluePrintFileUtils.kt | 28 ++++++-- .../core/utils/BluePrintMetadataUtils.kt | 7 +- .../scripts/BluePrintScriptsServiceImplTest.kt | 67 +++++++++++++++++ .../core/scripts/BlueprintScriptingHostTest.kt | 84 ---------------------- .../Scripts/kotlin/SampleBlueprintFunctionNode.kt | 66 +++++++++++++++++ .../resources/compile/TOSCA-Metadata/TOSCA.meta | 7 ++ .../scripts/SampleBlueprintFunctionNode.kts | 44 ------------ .../src/test/resources/scripts1/simple.cba.kts | 56 --------------- .../src/test/resources/scripts2/simple.cba.kts | 56 --------------- 18 files changed, 344 insertions(+), 307 deletions(-) create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerCache.kt create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImplTest.kt delete mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BlueprintScriptingHostTest.kt create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/Scripts/kotlin/SampleBlueprintFunctionNode.kt create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/TOSCA-Metadata/TOSCA.meta delete mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts/SampleBlueprintFunctionNode.kts delete mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts1/simple.cba.kts delete mode 100644 ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts2/simple.cba.kts (limited to 'ms/controllerblueprints') diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt index cea18ef9b..0b640d9e9 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt @@ -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 logger(clazz: T) = LoggerFactory.getLogger(clazz.javaClass)!! + +fun > logger(clazz: T) = LoggerFactory.getLogger(clazz.java)!! + + fun T.bpClone(): T { return ObjectUtils.clone(this) } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintModel.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintModel.kt index 68e5b0aec..a2cba95d9 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintModel.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintModel.kt @@ -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 } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintScriptsService.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintScriptsService.kt index 8bb0cd0ce..7912e781a 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintScriptsService.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintScriptsService.kt @@ -17,12 +17,18 @@ 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 scriptInstance(blueprintContext: BluePrintContext, scriptClassName: String, - reCompile: Boolean): T + suspend fun scriptInstance(bluePrintSourceCode: BluePrintSourceCode, scriptClassName: String): T + + suspend fun scriptInstance(blueprintBasePath: String, artifactName: String, artifactVersion: String, + scriptClassName: String, reCompile: Boolean): T + + suspend fun scriptInstance(blueprintBasePath: String, scriptClassName: String, reCompile: Boolean): T + + suspend fun scriptInstance(cacheKey: String, scriptClassName: String): T suspend fun scriptInstance(scriptClassName: String): T } \ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompiledScript.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompiledScript.kt index 03258c252..2f131f6f6 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompiledScript.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompiledScript.kt @@ -16,30 +16,25 @@ 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( - private val scriptCompilationConfiguration: ScriptCompilationConfiguration, - private val compiledJar: File) : - CompiledScript, Serializable { +open class BluePrintCompiledScript( + val cacheKey: String, + val scriptCompilationConfiguration: ScriptCompilationConfiguration) : + CompiledScript, Serializable { lateinit var scriptClassFQName: String override val compilationConfiguration: ScriptCompilationConfiguration get() = scriptCompilationConfiguration - override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics> = try { + override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?) + : ResultWithDiagnostics> = try { - val baseClassLoader = Thread.currentThread().contextClassLoader - - val urls = arrayListOf() - 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 index 000000000..73051392c --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerCache.kt @@ -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 = 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() { + + val log = logger(BluePrintClassLoader::class) + + override fun reload(key: String, oldValue: URLClassLoader): ListenableFuture { + 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() + 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 diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerProxy.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerProxy.kt index df3302518..e231f6d1c 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerProxy.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintCompilerProxy.kt @@ -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(scriptCompilationConfiguration, compiledJarFile) + checkFileExists(compiledJarFile) { "couldn't generate compiled jar(${compiledJarFile.absolutePath})" } + + val compiledScript = BluePrintCompiledScript(blueprintSourceCode.cacheKey, scriptCompilationConfiguration) - return ResultWithDiagnostics.Success(res, messageCollector.diagnostics) + return compiledScript.asSuccess() } catch (ex: Throwable) { return failure(ex.asDiagnostics()) diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptingHost.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptingHost.kt index 4fcc33d46..05a147171 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptingHost.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptingHost.kt @@ -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 = + override fun eval(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration, + configuration: ScriptEvaluationConfiguration?): ResultWithDiagnostics = 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 = 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() 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), diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsConfiguration.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsConfiguration.kt index 3ac790171..e01923723 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsConfiguration.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsConfiguration.kt @@ -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 lateinit var moduleName: String lateinit var targetJarFile: File + lateinit var cacheKey: String var regenerate: Boolean = false override val text: String diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImpl.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImpl.kt index e2c02603a..360035327 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImpl.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImpl.kt @@ -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 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 scriptInstance(bluePrintSourceCode: BluePrintSourceCode, scriptClassName: String): T { + val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() + 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 scriptInstance(blueprintBasePath: String, artifactName: String, artifactVersion: String, + scriptClassName: String, reCompile: Boolean): T { val sources: MutableList = 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() - val scriptEvaluator = BluePrintScriptEvaluator(scriptClassName) - - val compiledResponse = BlueprintScriptingHost(scriptEvaluator).eval(scriptSource, compilationConfiguration, - null) - - val returnValue = compiledResponse.resultOrNull()?.returnValue as? ResultValue.Value + override suspend fun 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 scriptInstance(cacheKey: String, scriptClassName: String): T { + val args = ArrayList() + return BluePrintCompileCache.classLoader(cacheKey).loadClass(scriptClassName).constructors + .single().newInstance(*args.toArray()) as T } override suspend fun 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 diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintFileUtils.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintFileUtils.kt index 5f9725f10..ad91d45c3 100755 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintFileUtils.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintFileUtils.kt @@ -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: " } - - 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('.') diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt index ef5cb81d9..6f090783a 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt @@ -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 index 000000000..9d4ef69bb --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BluePrintScriptsServiceImplTest.kt @@ -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>(basePath, + "cba.scripts.SampleBlueprintFunctionNode", true) + assertNotNull(instance, "failed to get compiled instance") + + val cachedInstance = bluePrintScriptsService + .scriptInstance>(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 index 2288d62c8..000000000 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/scripts/BlueprintScriptingHostTest.kt +++ /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 = arrayListOf() - sources1.add("src/test/resources/scripts1") - scriptSource1.blueprintKotlinSources = sources1 - - val scriptClassName = "Simple_cba\$SampleComponentFunction" - - val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() - - val scriptEvaluator = BluePrintScriptEvaluator(scriptClassName) - - val scriptSource2 = BluePrintSourceCode() - scriptSource2.moduleName = "blueprint-test-script" - - scriptSource2.targetJarFile = File("target/scripts2/blueprint-script-generated.jar") - val sources2: MutableList = 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 diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/Scripts/kotlin/SampleBlueprintFunctionNode.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/Scripts/kotlin/SampleBlueprintFunctionNode.kt new file mode 100644 index 000000000..aa77bc30b --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/Scripts/kotlin/SampleBlueprintFunctionNode.kt @@ -0,0 +1,66 @@ +/* + * 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 cba.scripts + +import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode + +open class SampleBlueprintFunctionNode : BlueprintFunctionNode { + + override fun getName(): String { + return "Kotlin-Script-Function-Node" + } + + override fun prepareRequest(executionRequest: String): String { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun process(executionRequest: String) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun recover(runtimeException: RuntimeException, executionRequest: String) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun prepareResponse(): String { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + 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 index 000000000..b1ffabd13 --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/compile/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,7 @@ +TOSCA-Meta-File-Version: 1.0.0 +CSAR-Version: 1.0 +Created-By: Brinda Santh +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/scripts/SampleBlueprintFunctionNode.kts b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts/SampleBlueprintFunctionNode.kts deleted file mode 100644 index 439351b05..000000000 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts/SampleBlueprintFunctionNode.kts +++ /dev/null @@ -1,44 +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. - */ - -import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode - -open class SampleBlueprintFunctionNode : BlueprintFunctionNode{ - - override fun getName(): String { - return "Kotlin-Script-Function-Node" - } - - override fun prepareRequest(executionRequest: String): String { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun process(executionRequest: String) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun recover(runtimeException: RuntimeException, executionRequest: String) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun prepareResponse(): String { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun apply(t: String): String { - return "$t-status" - } -} \ No newline at end of file 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 index 4fffda051..000000000 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts1/simple.cba.kts +++ /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 { - - 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 index 4ba56c491..000000000 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/scripts2/simple.cba.kts +++ /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 { - - 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....") -- cgit 1.2.3-korg