Skip to content

Commit e782bac

Browse files
committed
Allow compiling the polyglot micronaut chat app to a native image
1 parent e178e7f commit e782bac

File tree

4 files changed

+53
-4
lines changed

4 files changed

+53
-4
lines changed

polyglot-chat-app/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ The application uses the Gradle build tool.
4444
[bob 💬] still loading the sentiment model I believe
4545
```
4646

47+
## Building a Native Image
48+
49+
The application can be AOT compiled using GraalVM Native Image.
50+
The Python code has to be shipped in a _resources_ directory that is kept next to the native executable.
51+
52+
1. Build a native executable with the Micronaut AOT support:
53+
```bash
54+
./gradlew nativeCompile
55+
```
56+
57+
2. Copy the venv into the output _resources_ directory:
58+
```bash
59+
cp -R src/main/resources/venv/ build/native/nativeCompile/resources/python/
60+
```
61+
62+
3. Run the native executable:
63+
```bash
64+
build/native/nativeCompile/websocket.chat
65+
```
66+
4767
### Learn More
4868

4969
Learn more about GraalVM polyglot capabilities [here](https://www.graalvm.org/latest/reference-manual/polyglot-programming/).

polyglot-chat-app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ dependencies {
3333

3434
implementation("org.graalvm.sdk:graal-sdk:23.1.1")
3535
implementation("org.graalvm.polyglot:python:23.1.1")
36+
implementation("org.graalvm.sdk:nativeimage:23.1.1")
3637
}
3738

3839

polyglot-chat-app/src/main/java/websocket/chat/PolyglotContextFactories.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@
5252
import java.net.URISyntaxException;
5353
import java.nio.file.Paths;
5454

55+
import org.graalvm.nativeimage.ImageInfo;
56+
import org.graalvm.nativeimage.ProcessProperties;
5557
import org.graalvm.polyglot.Context;
5658
import org.graalvm.polyglot.Engine;
5759
import org.graalvm.polyglot.Source;
5860

59-
6061
/**
6162
* Defines bean factories for polyglot {@link Context} and {@link Engine}
6263
* so that they can be injected into other beans. All {@link Context}
@@ -68,10 +69,26 @@ public class PolyglotContextFactories {
6869
@Singleton
6970
@Bean(preDestroy = "close")
7071
Context createContext(ResourceResolver resolver, ScriptsConfig config) throws URISyntaxException {
71-
var exe = Paths.get(resolver.getResource(config.pythonVenv).get().toURI()).resolveSibling("bin").resolve("exe");
72+
String exe;
73+
if (ImageInfo.inImageRuntimeCode()) {
74+
if (ProcessProperties.getArgumentVectorBlockSize() > 0) {
75+
exe = Paths.get(ProcessProperties.getArgumentVectorProgramName())
76+
.resolveSibling("resources")
77+
.resolve("python")
78+
.resolve("venv")
79+
.resolve("bin")
80+
.resolve("exe")
81+
.toAbsolutePath()
82+
.toString();
83+
} else {
84+
exe = "";
85+
}
86+
} else {
87+
exe = Paths.get(resolver.getResource(config.pythonVenv).get().toURI()).resolveSibling("bin").resolve("exe").toString();
88+
}
7289
var context = Context.newBuilder("python")
7390
.option("python.ForceImportSite", "true")
74-
.option("python.Executable", exe.toString())
91+
.option("python.Executable", exe)
7592
.allowAllAccess(true)
7693
.build();
7794
loadScript(context, "python", config.pythonInit);

polyglot-chat-app/src/main/java/websocket/chat/PolyglotMessageHandlerFactory.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@
5454
public class PolyglotMessageHandlerFactory {
5555
@Bean
5656
MessageHandler createPythonHandler(Context context) {
57-
return context.getPolyglotBindings().getMember("ChatMessageHandler").as(MessageHandler.class);
57+
var value = context.getPolyglotBindings().getMember("ChatMessageHandler");
58+
// we could use value.as(MessageHandler.class), but then we need a proxy config for native
59+
// image.
60+
return new MessageHandler() {
61+
public boolean isValid(String senderTopic, String receiverTopic) {
62+
return value.invokeMember("isValid", senderTopic, receiverTopic).asBoolean();
63+
}
64+
65+
public String createMessage(String sender, String message) {
66+
return value.invokeMember("createMessage", sender, message).asString();
67+
}
68+
};
5869
}
5970
}

0 commit comments

Comments
 (0)