-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(java-sdk): Create Java Host SDK #122
Conversation
We now resolve the extism library dynamically based on the rules defined in com.sun.jna.NativeLibrary. For tests we resolve the library relative to the cwd based on the jna.library.path system property set to ../target/release. Improves #117
- Refactor Plugin - Make `Plugin` and `Context` `AutoClosable` to automatically free resources in TWR blocks - Add missing javadoc - Upgrade to Junit 5 - Reorganize packages - Use more meaningful names - Introduce `ExtismException` - Make JSON serialization pluggable - Lower required java version to Java 17 Improves #117
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before finishing this, we could address the following points:
public List<String> allowedHosts; | ||
public Map<String, String> config; | ||
|
||
private static Gson _gson; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static Gson _gson; | |
private static final Gson _gson; |
@@ -0,0 +1,15 @@ | |||
package org.extism.sdk; | |||
|
|||
public class ExtismException extends RuntimeException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add some javadoc here
* @param pluginIndex | ||
* @param json | ||
* @param jsonLength | ||
* @return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does the boolean return mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same goes for what I wrote for #call
* @param withWASI | ||
* @return | ||
*/ | ||
boolean extism_plugin_update(Pointer contextPointer, int pluginIndex, byte[] wasm, int length, boolean withWASI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the boolean return means?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same goes for what I wrote for #call
* | ||
* @param contextPointer | ||
* @param pluginIndex | ||
* @return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. return the length of the output data in bytes.
} | ||
|
||
public static String toJson(Manifest manifest) { | ||
return GSON.toJson(manifest); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could remove the GSON dependency and implement a simple hand-crafted JSON serialization for the Manifest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the fence about it. I think eventually we will need to parse too. I'd be open to removing it but I can't say how long that will be feasible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick idea:
- Introduce a
JsonConverter
interface that can be used whenever we need to read / write json data. An instance ofJsonConverter
could be made available to thePlugin
via theContext
.
interface JsonConverter {
<T> String toJson(T object);
<T> T fromJson(String json, Class<T> type);
}
-
Keep the gson library as dependency, but allow it to be excluded via dependency-excludes on the consumer side.
-
Implement a
GsonJsonConverter
implementation based onJsonSerializer
-
Introduce a
ContextFactory
where aJsonConverter
can be configured centrally with a#setJsonConverter(..)
method. Then offer something likeContextFactory#newContext()
to create newContext
classes.
With this in place, if users prefer another JSON library and don't want to pull in gson, they could exclude it with a maven dependency exclude and simply configure their own JsonConverter
implementation, e.g. based on
fasterxml jackson.
Perhaps this looks a bit over-engineered, but I think having a ContextFactory
to control creation of Context
which could allow to share
some additional information might be useful.
Alternative:
Keep the JsonSerializer class as is and only use it internally. If we need to read json data, just add another method like:
public <T> T fromJson(String json, Class<T> object) {
return GSON.fromJson(json, object);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea. I know how complex dependency clashing can get in Java. But I think it's fine to wait until after the first release. It should not affect the interface.
* @param data the byte array representing the WASM code | ||
* @param hash | ||
*/ | ||
public record ByteArrayWasmSource(String name, byte[] data, String hash) implements WasmSource { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the hash? What hash should be used here?
*/ | ||
public interface WasmSource { | ||
|
||
String name(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will every implementation of WasmSource have a String hash
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a json schema for the manifest and a page explaining the fields: https://extism.org/docs/concepts/manifest/
hash is optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'll take a look.
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class ExtismTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to add more tests for the remaining functions.
@Test | ||
public void shouldInvokeNamedFunction() { | ||
|
||
var wasmFile = Paths.get("src", "test", "resources", "code.wasm").toFile(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of copying the code.wasm in the java project, we could also refer to "../wasm/code.wasm".
java/pom.xml
Outdated
<groupId>org.extism.sdk</groupId> | ||
<artifactId>extism</artifactId> | ||
<packaging>jar</packaging> | ||
<version>1.0-SNAPSHOT</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the version be aligned with the overall project version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the Host SDKs will be versioned independently based on semver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, then I'd recommend to follow a semver approach and use 3 component version number.
java/pom.xml
Outdated
<version>5.12.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.code.gson</groupId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually need an JSON serialization library at all? If we only need to serialize the Manifest to JSON, perhaps a hand-crafted helper method will be sufficient.
* @param plugin | ||
* @return | ||
*/ | ||
public String error(Plugin plugin) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps an additional method like public String error()
that explicitly returns the context error would be useful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be an internal method I think. I'm going to capture these errors then turn them into exceptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, then protected is fine, the error can be used as the message of ExtismException
.
@thomasdarimont in the past, i've published java libraries to OSSRH: https://central.sonatype.org/publish/publish-guide/#releasing-to-central Is this still the best place to publish? |
@bhelx Yes, releasing to maven central is still current, btw. the process of publishing releases can be simplified a lot by using a tool like jreleaser which makes publishing libraries to maven central a breeze. |
I think it would also make sense to use a common source code formatter to format the code properly, otherwise a slightly diffenent IDE setup will cause formatting noise in pull requests. Perhaps a tool like maven-checkstyle could help here. |
java/pom.xml
Outdated
<artifactId>maven-assembly-plugin</artifactId> | ||
<configuration> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's usually recommended to let libraries pull in their dependencies explicitly, instead of creating a jar-with-dependencies.
java/pom.xml
Outdated
</configuration> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-assembly-plugin</artifactId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the maven-assembly-plugin needed at all? The jar builds fine without it.
java/pom.xml
Outdated
<packaging>jar</packaging> | ||
<version>1.0-SNAPSHOT</version> | ||
<name>extism</name> | ||
<url>https://github.com/extism/extism</url> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The project is lacking some metadata (organization, licensing, description, developer information) etc. that I think is necessary for releasing to maven central.
See here for a more complete library with complete maven metadata
Good to know. It was a pain last time.
…On Dec 6, 2022 at 2:49 PM -0600, Thomas Darimont ***@***.***>, wrote:
@bhelx Yes, releasing to maven central is still current, btw. the process of publishing releases can be simplified a lot by using a tool like jreleaser which makes publishing libraries to maven central a breeze.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
I think I addressed most of the points I raised in the PR #147. |
For additional tests I need a few more example wasm files:
Perhaps you could create a generic "test" wasm file with multiple functions that could be used by all modules for consistent testing instead of having |
- Context#error is now protected and used to extract the error message for the ExtismException - ByteArrayWasmSource is now correctly serialized (wasm data is now encoded base64) - Renamed ManifestMemory to MemoryOptions to align with rust codebase - Introduced WasmSourceResolver to load wasm source - Added unit tests - Revised Unit tests - Polished javadoc - Added necessary metadata for release to maven central - Removed maven-assembly-plugin as we want to allow consumers to control the dependencies
It seems as the ci fails due to unrelated issues in the Python SDK, perhaps a rebase with main would solve that. |
Just added another PR: #150 I think the libray is now in good shape, however I recommend to address the ``FIXME` comments (in the non-test) code before releasing it. I think the |
Btw. the current state of the java-sdk requires, that users manually obtain the matching native extism library for their platform and store the library in a folder. This folder then needs to provided to the JVM via a System property e.g. This should be documented in the readme.md of the SDK. Alternatively, we could package the matching library for various platforms directly in the jar and use a tool like native-lib-loader to load the proper library for the given OS dynamically. Would it be possible to provide the extism libraries for multiple os/platforms before the maven build runs? How do we communicate to the user which version of the extism library is needed for the given java-sdk version? |
So this branch has been hanging our CI on the python jobs. We think it was just something with this branch and not the code. hoping that merging will fix the problem. If not we may revert |
Wow it's going green now: #175 Thanks @thomasdarimont ! I'm going to work on docs now and some final cleanup items and push this out tomorrow |
Closes #117