Skip to content
This repository was archived by the owner on Oct 3, 2021. It is now read-only.

Commit bfbe14e

Browse files
author
Krystian Panek
committed
Callable scripts
1 parent 5b1a008 commit bfbe14e

7 files changed

+223
-32
lines changed

build.gradle.kts

+15-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,17 @@ allprojects {
2727
}
2828

2929
dependencies {
30-
compileOnly("org.osgi:osgi.cmpn:6.0.0")
31-
compileOnly("org.osgi:org.osgi.core:6.0.0")
30+
compileOnly("org.osgi:org.osgi.annotation.versioning:1.1.0")
31+
compileOnly("org.osgi:org.osgi.annotation.bundle:1.0.0")
32+
compileOnly("org.osgi:org.osgi.service.metatype.annotations:1.4.0")
33+
compileOnly("org.osgi:org.osgi.service.component.annotations:1.4.0")
34+
compileOnly("org.osgi:org.osgi.service.component:1.4.0")
35+
compileOnly("org.osgi:org.osgi.service.cm:1.6.0")
36+
compileOnly("org.osgi:org.osgi.service.event:1.3.1")
37+
compileOnly("org.osgi:org.osgi.service.log:1.4.0")
38+
compileOnly("org.osgi:org.osgi.framework:1.9.0")
39+
compileOnly("org.osgi:org.osgi.resource:1.0.0")
40+
3241
compileOnly("javax.servlet:servlet-api:2.5")
3342
compileOnly("javax.servlet:jsp-api:2.0")
3443
compileOnly("javax.jcr:jcr:2.0")
@@ -38,15 +47,17 @@ dependencies {
3847
compileOnly("org.apache.sling:org.apache.sling.jcr.api:2.4.0")
3948
compileOnly("org.apache.sling:org.apache.sling.models.api:1.3.6")
4049
compileOnly("org.apache.sling:org.apache.sling.settings:1.3.8")
50+
compileOnly("org.apache.sling:org.apache.sling.scripting.api:2.2.0")
51+
compileOnly("org.apache.sling:org.apache.sling.servlets.annotations:1.2.4")
4152
compileOnly("com.google.guava:guava:15.0")
4253
compileOnly("com.google.code.gson:gson:2.8.2")
4354
compileOnly("joda-time:joda-time:2.9.1")
4455

4556
compileOnly("org.jetbrains.kotlin:kotlin-script-util:1.4.0")
4657
compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.4.0")
4758
compileOnly("org.jetbrains.kotlin:kotlin-scripting-jvm-host:1.4.0")
48-
49-
compileOnly("com.adobe.aem:uber-jar:6.5.0:apis")
59+
compileOnly("org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.4.0")
60+
compileOnly("org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.4.0")
5061

5162
testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2")
5263
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.3.2")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.neva.slinkt.script.engine
2+
3+
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
4+
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
5+
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
6+
import org.jetbrains.kotlin.cli.common.repl.*
7+
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
8+
import org.jetbrains.kotlin.cli.jvm.config.addJvmSdkRoots
9+
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
10+
import org.jetbrains.kotlin.config.*
11+
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
12+
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.GenericReplCompiler
13+
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
14+
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
15+
import org.jetbrains.kotlin.utils.PathUtil
16+
import java.io.File
17+
import java.net.URLClassLoader
18+
import java.util.concurrent.locks.ReentrantReadWriteLock
19+
import javax.script.ScriptContext
20+
import javax.script.ScriptEngineFactory
21+
import kotlin.reflect.KClass
22+
23+
class KotlinEngine(
24+
val classLoader: ClassLoader,
25+
factory: ScriptEngineFactory,
26+
val templateClasspath: List<File>,
27+
templateClassName: String,
28+
val getScriptArgs: (ScriptContext, Array<out KClass<out Any>>?) -> ScriptArgsWithTypes?,
29+
val scriptArgsTypes: Array<out KClass<out Any>>?
30+
) : KotlinJsr223JvmScriptEngineBase(factory), KotlinJsr223JvmInvocableScriptEngine {
31+
32+
override val replCompiler: ReplCompiler by lazy {
33+
GenericReplCompiler(
34+
makeScriptDefinition(templateClasspath, templateClassName),
35+
makeCompilerConfiguration(),
36+
PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false))
37+
}
38+
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
39+
private val localEvaluator by lazy { GenericReplCompilingEvaluator(replCompiler, templateClasspath, classLoader, getScriptArgs(getContext(), scriptArgsTypes)) }
40+
41+
override val replEvaluator: ReplFullEvaluator get() = localEvaluator
42+
43+
override val state: IReplStageState<*> get() = getCurrentState(getContext())
44+
45+
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = replEvaluator.createState(lock)
46+
47+
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = getScriptArgs(context, scriptArgsTypes)
48+
49+
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
50+
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
51+
val cls = classloader.loadClass(templateClassName)
52+
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, emptyMap())
53+
}
54+
55+
private fun makeCompilerConfiguration() = CompilerConfiguration().apply {
56+
addJvmSdkRoots(PathUtil.getJdkClassesRootsFromCurrentJre())
57+
classLoader
58+
addJvmClasspathRoots(templateClasspath)
59+
put(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT, System.getProperty("user.dir")) //TODO tmp
60+
add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, ScriptingCompilerConfigurationComponentRegistrar())
61+
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
62+
languageVersionSettings = LanguageVersionSettingsImpl(
63+
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
64+
)
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.neva.slinkt.script.engine
2+
3+
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
4+
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
5+
import org.jetbrains.kotlin.script.jsr223.KotlinStandardJsr223ScriptTemplate
6+
import org.osgi.framework.FrameworkUtil
7+
import org.osgi.framework.wiring.BundleWiring
8+
import java.io.File
9+
import javax.script.Bindings
10+
import javax.script.ScriptContext
11+
import javax.script.ScriptEngine
12+
13+
class KotlinEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
14+
15+
override fun getScriptEngine(): ScriptEngine {
16+
System.setProperty("project.structure.add.tools.jar.to.new.jdk", "false")
17+
18+
return KotlinEngine(
19+
FrameworkUtil.getBundle(javaClass).adapt(BundleWiring::class.java).classLoader,
20+
this,
21+
listOf(File("/Users/krystian.panek/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-util/1.4.0/7a46a84420efbeff02a9e2cb7306bbe288bf01cc/kotlin-script-util-1.4.0.jar")),
22+
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
23+
{ ctx, types ->
24+
ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray())
25+
},
26+
arrayOf(Bindings::class)
27+
)
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.neva.slinkt.script.engine
2+
3+
import org.apache.sling.api.SlingHttpServletRequest
4+
import org.apache.sling.api.SlingHttpServletResponse
5+
import org.apache.sling.api.servlets.ServletResolverConstants
6+
import org.apache.sling.api.servlets.SlingSafeMethodsServlet
7+
import org.osgi.service.component.annotations.Component
8+
import org.osgi.service.component.annotations.Reference
9+
import javax.servlet.Servlet
10+
11+
@Component(
12+
service = [Servlet::class],
13+
immediate = true,
14+
property = [
15+
ServletResolverConstants.SLING_SERVLET_PATHS + "=/bin/slinkt/script/engine",
16+
ServletResolverConstants.SLING_SERVLET_METHODS + "=GET",
17+
]
18+
)
19+
class KotlinEngineServlet : SlingSafeMethodsServlet() {
20+
21+
@Reference
22+
private lateinit var factory: KotlinScriptEngineFactory
23+
24+
override fun doGet(request: SlingHttpServletRequest, response: SlingHttpServletResponse) {
25+
val engine = factory.scriptEngine
26+
val result = engine.eval("""
27+
val a = "Hello World!"
28+
System.out.println(a)
29+
""".trimIndent())
30+
31+
response.contentType = "text/plain"
32+
response.writer.write(result.toString())
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.neva.slinkt.script.engine
2+
3+
import org.apache.sling.scripting.api.AbstractScriptEngineFactory
4+
import org.osgi.service.component.annotations.Component
5+
import javax.script.ScriptEngine
6+
import javax.script.ScriptEngineFactory
7+
8+
@Component(
9+
immediate = true,
10+
service = [ScriptEngineFactory::class, KotlinScriptEngineFactory::class]
11+
)
12+
class KotlinScriptEngineFactory : AbstractScriptEngineFactory() {
13+
14+
private val factory = KotlinEngineFactory()
15+
16+
override fun getLanguageName() = "kts"
17+
18+
override fun getLanguageVersion(): String = "1.4"
19+
20+
override fun getScriptEngine(): ScriptEngine = factory.scriptEngine
21+
}

src/main/kotlin/com/neva/slinkt/KotlinScriptEvaluator.kt src/main/kotlin/com/neva/slinkt/script/host/KotlinScriptEvaluator.kt

+21-28
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
package com.neva.slinkt
1+
package com.neva.slinkt.script.host
22

33
import org.osgi.framework.FrameworkUtil
44
import org.osgi.framework.wiring.BundleWiring
5-
import org.osgi.service.component.annotations.Activate
65
import org.osgi.service.component.annotations.Component
76
import org.slf4j.LoggerFactory
8-
import kotlin.script.experimental.api.compilerOptions
9-
import kotlin.script.experimental.api.valueOrNull
10-
import kotlin.script.experimental.host.StringScriptSource
7+
import kotlin.script.experimental.api.*
118
import kotlin.script.experimental.jvm.dependenciesFromClassloader
129
import kotlin.script.experimental.jvm.jvm
1310
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
@@ -17,38 +14,34 @@ import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTe
1714
@Component(immediate = true, service = [KotlinScriptEvaluator::class])
1815
class KotlinScriptEvaluator {
1916

20-
@Activate
21-
fun activate() {
22-
val host = BasicJvmScriptingHost().apply {
23-
24-
}
25-
val scriptSource = StringScriptSource("""
26-
println("Hello World!")
27-
"abecadlo!"
28-
""".trimIndent())
17+
fun eval(
18+
sourceCode: SourceCode,
19+
compilationOptions: ScriptCompilationConfiguration.Builder.() -> Unit = {},
20+
evaluationOptions: ScriptEvaluationConfiguration.Builder.() -> Unit = {}
21+
): ResultWithDiagnostics<EvaluationResult> {
22+
val host = BasicJvmScriptingHost().apply {}
2923

3024
val bundle = FrameworkUtil.getBundle(javaClass)
3125
val bundleWiring = bundle.adapt(BundleWiring::class.java)
3226
val classLoader = bundleWiring.classLoader
3327

3428
val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<Any> {
35-
jvm {
36-
dependenciesFromClassloader(
37-
wholeClasspath = true,
38-
classLoader = classLoader
39-
)
40-
compilerOptions.append("-Xintellij-plugin-root", System.getProperty("user.dir"))
41-
}
29+
jvm {
30+
dependenciesFromClassloader(
31+
wholeClasspath = true,
32+
classLoader = classLoader
33+
)
34+
compilerOptions.append("-Xintellij-plugin-root", System.getProperty("user.dir"))
35+
}
36+
compilationOptions()
4237
}
4338
val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<Any> {
44-
jvm {
45-
// mainArguments()
46-
}
39+
jvm {
40+
// mainArguments()
41+
}
42+
evaluationOptions()
4743
}
48-
val result = host.eval(scriptSource, compilationConfiguration, evaluationConfiguration)
49-
50-
LOG.error("Kotlin result object:\n{}", result)
51-
LOG.error("Kotlin result value\n{}", result.valueOrNull())
44+
return host.eval(sourceCode, compilationConfiguration, evaluationConfiguration)
5245
}
5346

5447
companion object {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.neva.slinkt.script.host
2+
3+
import org.apache.sling.api.SlingHttpServletRequest
4+
import org.apache.sling.api.SlingHttpServletResponse
5+
import org.apache.sling.api.servlets.ServletResolverConstants
6+
import org.apache.sling.api.servlets.SlingSafeMethodsServlet
7+
import org.osgi.service.component.annotations.Component
8+
import org.osgi.service.component.annotations.Reference
9+
import javax.servlet.Servlet
10+
import kotlin.script.experimental.api.valueOrNull
11+
import kotlin.script.experimental.host.StringScriptSource
12+
13+
@Component(
14+
service = [Servlet::class],
15+
immediate = true,
16+
property = [
17+
ServletResolverConstants.SLING_SERVLET_PATHS + "=/bin/slinkt/script/evaluator",
18+
ServletResolverConstants.SLING_SERVLET_METHODS + "=GET",
19+
]
20+
)
21+
class SimpleServlet : SlingSafeMethodsServlet() {
22+
23+
@Reference
24+
private lateinit var evaluator: KotlinScriptEvaluator
25+
26+
override fun doGet(request: SlingHttpServletRequest, response: SlingHttpServletResponse) {
27+
val scriptSource = StringScriptSource("""
28+
println("Hello World!")
29+
"abecadlo!"
30+
""".trimIndent())
31+
32+
val result = evaluator.eval(scriptSource)
33+
34+
response.contentType = "text/plain"
35+
response.writer.write(result.valueOrNull().toString())
36+
}
37+
}

0 commit comments

Comments
 (0)