+ * This interface provides methods to log messages at different levels and to retrieve the current + * log level. + */ public interface LogHandler { - LogHandler DEFAULT = new LogHandler() {}; + /** + * A default, no-operation {@code LogHandler}. + * It ignores all log messages and reports {@link LogLevel#CRITICAL} as the current log level, + * effectively disabling logging. + * + *
Useful as a placeholder or when logging is explicitly disabled. + */ + LogHandler DEFAULT = + new LogHandler() { + @Override + public LogLevel getLogLevel() throws WasmException { + // since we are not logging anything, we can return the highest log level + return LogLevel.CRITICAL; + } + }; + /** + * A simple {@code LogHandler} that logs all messages to {@link System#out}. + * Messages are prefixed with their corresponding {@link LogLevel}. + * The effective log level for this handler is {@link LogLevel#TRACE}, + * meaning all messages will be printed. + */ LogHandler SYSTEM = new LogHandler() { @Override @@ -12,8 +38,21 @@ public void log(LogLevel level, String message) throws WasmException { } }; + /** + * Logs a message at the specified log level. + * + * @param level the log level + * @param message the message to log + * @throws WasmException the result to provide the plugin + */ default void log(LogLevel level, String message) throws WasmException {} + /** + * Gets the current log level. + * + * @return the current log level + * @throws WasmException the result to provide the plugin + */ default LogLevel getLogLevel() throws WasmException { return LogLevel.TRACE; } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogLevel.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogLevel.java index 18d9874..d87c096 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogLevel.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogLevel.java @@ -1,43 +1,57 @@ package io.roastedroot.proxywasm; /** - * Represents log levels for proxy WASM. - * Converted from Go's LogLevel type. + * Represents log levels used within the Proxy-WASM ABI specification. + * These levels correspond to the values expected by the host environment + * when logging messages from a WASM module. + *
+ * Converted from Go's LogLevel type in the proxy-wasm-go-sdk. */ public enum LogLevel { - // The values follow the same order as in the Go code using iota (0-based incrementing) + + /** Trace log level. Value: 0 */ TRACE(0), + /** Debug log level. Value: 1 */ DEBUG(1), + /** Info log level. Value: 2 */ INFO(2), + /** Warn log level. Value: 3 */ WARN(3), + /** Error log level. Value: 4 */ ERROR(4), + /** Critical log level. Value: 5 */ CRITICAL(5); + /** The integer representation of the log level, as defined by the Proxy-WASM ABI. */ private final int value; /** * Constructor for LogLevel enum. * - * @param value The integer value of the log level + * @param value The integer value corresponding to the log level in the ABI. */ LogLevel(int value) { this.value = value; } /** - * Get the integer value of this log level. + * Get the integer value of this log level as defined by the Proxy-WASM ABI. * - * @return The integer value + * @return The integer value representing the log level. */ public int value() { return value; } /** - * Convert an integer value to a LogLevel. + * Convert an integer value to its corresponding LogLevel enum constant. + * This is useful for interpreting log level values received from the host + * or specified in configurations. * - * @param value The integer value to convert - * @return The corresponding LogLevel, or null if not found + * @param value The integer value to convert. + * @return The corresponding LogLevel enum constant. + * @throws IllegalArgumentException if the provided integer value does not + * match any known LogLevel. */ public static LogLevel fromInt(int value) { for (LogLevel level : values()) { diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricType.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricType.java index 441a7df..b6396e7 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricType.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricType.java @@ -1,38 +1,54 @@ package io.roastedroot.proxywasm; /** - * Represents the type of metric in proxy WASM. + * Represents the types of metrics that can be defined and manipulated + * via the Proxy-WASM ABI. */ public enum MetricType { + /** + * A metric that only increments. + * Value: 0 + */ COUNTER(0), + /** + * A metric that can be arbitrarily set. + * Value: 1 + */ GAUGE(1), + /** + * A metric that accumulates observations into predefined buckets + * and a sum of observations. + * Value: 2 + */ HISTOGRAM(2); + /** The integer representation of the metric type, as defined by the Proxy-WASM ABI. */ private final int value; /** * Constructor for MetricType enum. * - * @param value The integer value of the metric type + * @param value The integer value corresponding to the metric type in the ABI. */ MetricType(int value) { this.value = value; } /** - * Get the integer value of this metric type. + * Get the integer value of this metric type as defined by the Proxy-WASM ABI. * - * @return The integer value + * @return The integer value representing the metric type. */ public int getValue() { return value; } /** - * Convert an integer value to a MetricType. + * Convert an integer value to its corresponding MetricType enum constant. * - * @param value The integer value to convert - * @return The corresponding MetricType or null if the value doesn't match any MetricType + * @param value The integer value to convert. + * @return The corresponding MetricType enum constant, or {@code null} if the + * provided integer value does not match any known MetricType. */ public static MetricType fromInt(int value) { for (MetricType type : values()) { diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java index cb2ef98..ec062b9 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java @@ -1,25 +1,79 @@ package io.roastedroot.proxywasm; +import io.roastedroot.proxywasm.internal.WasmResult; + +/** + * Defines the contract for handling metrics operations initiated by a Proxy-WASM module. + * Implementations of this interface are responsible for interacting with the underlying + * metrics system of the host environment (Prometheus etc.). + * + *
The host environment provides implementations of these methods to allow WASM modules + * to define, manipulate, and retrieve metric values. + */ public interface MetricsHandler { + /** + * A default, non-functional instance of {@code MetricsHandler}. + * This instance throws {@link WasmException} with {@link WasmResult#UNIMPLEMENTED} + * for methods that define or retrieve metrics, and returns {@link WasmResult#UNIMPLEMENTED} + * for methods that modify or remove metrics. + * Useful as a placeholder or base when only a subset of metrics functionality is needed. + */ MetricsHandler DEFAULT = new MetricsHandler() {}; + /** + * Defines a new metric. + * + * @param metricType The type of the metric (e.g., Counter, Gauge, Histogram). + * @param name The name of the metric. + * @return A unique identifier (metric ID) for the newly defined metric. + * @throws WasmException If the metric cannot be defined (e.g., name conflict, unsupported type, + * or if the operation is unimplemented by the host). + */ default int defineMetric(MetricType metricType, String name) throws WasmException { throw new WasmException(WasmResult.UNIMPLEMENTED); } + /** + * Removes or deletes a previously defined metric. + * + * @param metricId The unique identifier of the metric to remove. + * @return A {@link WasmResult} indicating the outcome of the operation (e.g., OK, NOT_FOUND, UNIMPLEMENTED). + */ default WasmResult removeMetric(int metricId) { return WasmResult.UNIMPLEMENTED; } + /** + * Records a value for a metric (typically used for Gauges or Histograms). + * + * @param metricId The unique identifier of the metric. + * @param value The value to record. + * @return A {@link WasmResult} indicating the outcome of the operation (e.g., OK, BAD_ARGUMENT, UNIMPLEMENTED). + */ default WasmResult recordMetric(int metricId, long value) { return WasmResult.UNIMPLEMENTED; } + /** + * Increments a metric's value (typically used for Counters). + * + * @param metricId The unique identifier of the metric. + * @param value The amount to increment by (can be negative to decrement, although convention is usually positive). + * @return A {@link WasmResult} indicating the outcome of the operation (e.g., OK, BAD_ARGUMENT, UNIMPLEMENTED). + */ default WasmResult incrementMetric(int metricId, long value) { return WasmResult.UNIMPLEMENTED; } + /** + * Retrieves the current value of a metric. + * + * @param metricId The unique identifier of the metric. + * @return The current value of the metric. + * @throws WasmException If the metric cannot be retrieved (e.g., metric not found, type mismatch, + * or if the operation is unimplemented by the host). + */ default long getMetric(int metricId) throws WasmException { throw new WasmException(WasmResult.UNIMPLEMENTED); } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Plugin.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Plugin.java new file mode 100644 index 0000000..21a225a --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Plugin.java @@ -0,0 +1,365 @@ +package io.roastedroot.proxywasm; + +import static io.roastedroot.proxywasm.internal.Helpers.bytes; + +import com.dylibso.chicory.runtime.ImportMemory; +import com.dylibso.chicory.runtime.Instance; +import com.dylibso.chicory.runtime.Machine; +import com.dylibso.chicory.wasi.WasiOptions; +import com.dylibso.chicory.wasm.WasmModule; +import io.roastedroot.proxywasm.internal.ProxyWasm; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +/** + * Represents an instantiated Proxy-WASM plugin, providing the bridge between the host + * environment and the WASM module. + * + *
This abstract class defines the core structure and lifecycle of a plugin.
+ * Concrete plugin instances are created using the {@link Builder}.
+ * The actual WASM instance and interaction logic are managed internally.
+ */
+public abstract class Plugin {
+
+ /**
+ * Protected constructor for subclasses.
+ */
+ protected Plugin() {}
+
+ /**
+ * Returns the configured name of this plugin instance.
+ *
+ * @return the plugin name, which might be null if not explicitly set via the builder.
+ */
+ public abstract String name();
+
+ /**
+ * Creates a new {@link Builder} to configure and construct a {@link Plugin} instance
+ * from the given WASM module.
+ *
+ * @param module the compiled {@link WasmModule} representing the plugin's code.
+ * @return a new {@link Plugin.Builder} instance.
+ */
+ public static Plugin.Builder builder(WasmModule module) {
+ return new Plugin.Builder(module);
+ }
+
+ /**
+ * Builder for creating a Plugin instance.
+ */
+ public static final class Builder {
+
+ private final WasmModule module;
+ private final ProxyWasm.Builder proxyWasmBuilder = ProxyWasm.builder().withStart(false);
+ private boolean shared;
+ private String name;
+ private HashMap If {@code strictUpstreams} is {@code true}, attempting to use an undefined upstream name
+ * will result in an error being reported back to the plugin.
+ *
+ * If {@code strictUpstreams} is {@code false} (the default behavior if this method is not called),
+ * the host will try to parse the upstream name as URI.
+ *
+ * @param strictUpstreams {@code true} to enforce that all used upstream names must be explicitly mapped,
+ * {@code false} to allow fallback resolution.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withStrictUpstreams(boolean strictUpstreams) {
+ this.strictUpstreams = strictUpstreams;
+ return this;
+ }
+
+ /**
+ * Sets a minimum interval for the plugin's periodic timer ticks ({@code proxy_on_tick}).
+ * The Proxy-WASM ABI allows plugins to request a timer tick period. This setting enforces
+ * a lower bound on that period to prevent plugins from requesting excessively frequent ticks,
+ * which could overload the host.
+ *
+ * If the plugin requests a tick period shorter than this minimum, the host will use
+ * this minimum value instead.
+ *
+ * @param minTickPeriodMilliseconds the minimum allowed tick period in milliseconds. A value of 0 or less
+ * implies no minimum enforcement (host default behavior).
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withMinTickPeriodMilliseconds(int minTickPeriodMilliseconds) {
+ this.minTickPeriodMilliseconds = minTickPeriodMilliseconds;
+ return this;
+ }
+
+ /**
+ * Provides a {@link LogHandler} implementation for the plugin to use.
+ * This handler receives log messages generated by the WASM module via the {@code proxy_log} ABI call.
+ * If no logger is provided, {@link LogHandler#DEFAULT} (a no-op logger) is used.
+ *
+ * @param logger the {@link LogHandler} implementation to handle plugin logs.
+ * @return this {@code Builder} instance for method chaining.
+ * @see LogHandler
+ */
+ public Builder withLogger(LogHandler logger) {
+ this.logger = logger;
+ return this;
+ }
+
+ /**
+ * Provides a {@link MetricsHandler} implementation for the plugin to use.
+ * This handler manages metric definition, recording, and retrieval requested by the WASM module
+ * via the relevant {@code proxy_*} ABI calls (e.g., {@code proxy_define_metric}).
+ * If no handler is provided, {@link MetricsHandler#DEFAULT} (which returns UNIMPLEMENTED)
+ * might be used implicitly.
+ *
+ * @param metricsHandler the {@link MetricsHandler} implementation to manage plugin metrics.
+ * @return this {@code Builder} instance for method chaining.
+ * @see MetricsHandler
+ */
+ public Builder withMetricsHandler(MetricsHandler metricsHandler) {
+ this.metricsHandler = metricsHandler;
+ return this;
+ }
+
+ /**
+ * Provides a {@link SharedQueueHandler} implementation for the plugin to use.
+ * This handler manages operations on shared message queues requested by the WASM module
+ * via the relevant {@code proxy_*} ABI calls (e.g., {@code proxy_register_shared_queue}).
+ * If no handler is provided, {@link SharedQueueHandler#DEFAULT} (which returns UNIMPLEMENTED)
+ * might be used implicitly.
+ *
+ * @param sharedQueueHandler the {@link SharedQueueHandler} implementation to manage shared queues.
+ * @return this {@code Builder} instance for method chaining.
+ * @see SharedQueueHandler
+ */
+ public Builder withSharedQueueHandler(SharedQueueHandler sharedQueueHandler) {
+ this.sharedQueueHandler = sharedQueueHandler;
+ return this;
+ }
+
+ /**
+ * Provides a {@link SharedDataHandler} implementation for the plugin to use.
+ * This handler manages operations on shared key-value data requested by the WASM module
+ * via the relevant {@code proxy_*} ABI calls (e.g., {@code proxy_get_shared_data}).
+ * If no handler is provided, {@link SharedDataHandler#DEFAULT} (which returns UNIMPLEMENTED)
+ * might be used implicitly.
+ *
+ * @param sharedDataHandler the {@link SharedDataHandler} implementation to manage shared data.
+ * @return this {@code Builder} instance for method chaining.
+ * @see SharedDataHandler
+ */
+ public Builder withSharedDataHandler(SharedDataHandler sharedDataHandler) {
+ this.sharedDataHandler = sharedDataHandler;
+ return this;
+ }
+
+ /**
+ * Configures whether the plugin instance should be shared across multiple host requests or contexts.
+ *
+ * If {@code shared} is {@code true}, a single WASM instance will be created and reused.
+ * across multiple concurrent requests. Since Proxy-Wasm plugins are not thread-safe, the requests will
+ * contend on an access lock for the plugin. Using a shared plugin allows the plugin to maintain state
+ * between the requests. It will use less memory but will have a performance impact due to the contention.
+ *
+ * If {@code shared} is {@code false} (the default), the host will create a new, separate WASM instance for each
+ * request or context (depending on the host implementation and threading model). This provides better
+ * isolation, eliminates contention, but consumes more memory.
+ *
+ * @param shared {@code true} to indicate the plugin instance can be shared, {@code false} otherwise.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withShared(boolean shared) {
+ this.shared = shared;
+ return this;
+ }
+
+ /**
+ * Sets the Virtual Machine (VM) configuration data for the plugin.
+ * This configuration is typically provided once when the VM (and the plugin) is initialized.
+ * It's accessible to the plugin via the {@code proxy_get_vm_configuration} ABI call.
+ *
+ * @param vmConfig A byte array containing the VM configuration data.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withVmConfig(byte[] vmConfig) {
+ this.vmConfig = vmConfig;
+ return this;
+ }
+
+ /**
+ * Sets the Virtual Machine (VM) configuration data for the plugin using a String.
+ * The string will be converted to bytes using the platform's default charset.
+ * This configuration is accessible via the {@code proxy_get_vm_configuration} ABI call.
+ *
+ * @param vmConfig A String containing the VM configuration data.
+ * @return this {@code Builder} instance for method chaining.
+ * @see #withVmConfig(byte[])
+ */
+ public Builder withVmConfig(String vmConfig) {
+ this.vmConfig = bytes(vmConfig);
+ return this;
+ }
+
+ /**
+ * Sets the specific configuration data for this plugin instance.
+ * This configuration is provided during the plugin's initialization phase
+ * (via {@code proxy_on_configure}) and allows tailoring the plugin's behavior.
+ * It's accessible to the plugin via the {@code proxy_get_plugin_configuration} ABI call.
+ *
+ * @param pluginConfig A byte array containing the plugin-specific configuration data.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withPluginConfig(byte[] pluginConfig) {
+ this.pluginConfig = pluginConfig;
+ return this;
+ }
+
+ /**
+ * Sets the specific configuration data for this plugin instance using a String.
+ * The string will be converted to bytes using the platform's default charset.
+ * This configuration is accessible via the {@code proxy_get_plugin_configuration} ABI call.
+ *
+ * @param pluginConfig A String containing the plugin-specific configuration data.
+ * @return this {@code Builder} instance for method chaining.
+ * @see #withPluginConfig(byte[])
+ */
+ public Builder withPluginConfig(String pluginConfig) {
+ this.pluginConfig = bytes(pluginConfig);
+ return this;
+ }
+
+ /**
+ * Provides an explicit memory instance to be used by the WASM module.
+ *
+ * @param memory The {@link ImportMemory} instance to be used by the WASM module.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withImportMemory(ImportMemory memory) {
+ proxyWasmBuilder.withImportMemory(memory);
+ return this;
+ }
+
+ /**
+ * Configures a custom factory for creating the {@link Machine} used to execute the WASM code.
+ * The {@link Machine} controls the low-level execution of WASM instructions.
+ * By default, an interpreter-based machine is used.
+ * Providing a custom factory allows using alternative execution strategies, such as
+ * Ahead-Of-Time (AOT) compilation to improve execution performance.
+ *
+ * See the Chicory documentation (https://chicory.dev/docs/experimental/aot) for more details on Aot compilation.
+ *
+ * @param machineFactory A function that takes a WASM {@link Instance} and returns a {@link Machine}.
+ * @return this {@code Builder} instance for method chaining.
+ */
+ public Builder withMachineFactory(Function This involves setting up the WASM environment, linking host functions, applying configurations,
+ * and calling the necessary Proxy-WASM lifecycle functions (like {@code _start} and
+ * {@code proxy_on_vm_start}).
+ *
+ * @return The fully configured and initialized {@link Plugin} instance.
+ * @throws StartException If any error occurs during the plugin initialization process
+ * (e.g., WASM instantiation failure, error during {@code proxy_on_vm_start}).
+ */
+ public Plugin build() throws StartException {
+ return new io.roastedroot.proxywasm.internal.Plugin(
+ proxyWasmBuilder.build(module),
+ shared,
+ name,
+ foreignFunctions,
+ upstreams,
+ strictUpstreams,
+ minTickPeriodMilliseconds,
+ logger,
+ vmConfig,
+ pluginConfig,
+ metricsHandler,
+ sharedQueueHandler,
+ sharedDataHandler);
+ }
+ }
+}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginFactory.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginFactory.java
new file mode 100644
index 0000000..879b131
--- /dev/null
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginFactory.java
@@ -0,0 +1,23 @@
+package io.roastedroot.proxywasm;
+
+/**
+ * A functional interface representing a factory for creating {@link Plugin} instances.
+ *
+ * This is typically used in scenarios where plugin instantiation needs to be deferred
+ * or customized, potentially based on configuration or context available at runtime.
+ * Implementations might handle loading WASM modules, configuring builders, and returning
+ * the ready-to-use plugin.
+ */
+@FunctionalInterface
+public interface PluginFactory {
+ /**
+ * Creates and returns a new {@link Plugin} instance.
+ * Implementations are responsible for all necessary setup, including potentially
+ * loading the WASM module and configuring it using {@link Plugin#builder(com.dylibso.chicory.wasm.WasmModule)}.
+ *
+ * @return A newly created {@link Plugin} instance.
+ * @throws Exception If any error occurs during plugin creation (e.g., file loading, WASM instantiation,
+ * initialization errors within the plugin's start lifecycle).
+ */
+ Plugin create() throws Exception;
+}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/QueueName.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/QueueName.java
index 03c0508..2547298 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/QueueName.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/QueueName.java
@@ -2,13 +2,34 @@
import java.util.Objects;
+/**
+ * Represents the identifier for a shared queue within the Proxy-WASM environment.
+ * A queue name is typically composed of a Virtual Machine (VM) identifier and a
+ * queue-specific name string.
+ *
+ * The VM ID provides a namespace, allowing different VMs (potentially running
+ * different WASM modules or configurations) to define queues with the same name string
+ * without collision.
+ *
+ * Instances of this class are immutable.
+ */
public class QueueName {
+
private final String vmId;
private final String name;
+ /**
+ * Constructs a new QueueName.
+ *
+ * @param vmId The identifier of the VM context associated with this queue.
+ * Cannot be null.
+ * @param name The specific name of the queue within the VM context.
+ * Cannot be null.
+ * @throws NullPointerException if either {@code vmId} or {@code name} is null.
+ */
public QueueName(String vmId, String name) {
- this.vmId = vmId;
- this.name = name;
+ this.vmId = Objects.requireNonNull(vmId, "vmId cannot be null");
+ this.name = Objects.requireNonNull(name, "name cannot be null");
}
@Override
@@ -25,10 +46,20 @@ public int hashCode() {
return Objects.hash(vmId, name);
}
+ /**
+ * Gets the VM identifier part of the queue name.
+ *
+ * @return The non-null VM ID string.
+ */
public String vmId() {
return vmId;
}
+ /**
+ * Gets the specific name string part of the queue name.
+ *
+ * @return The non-null queue name string.
+ */
public String name() {
return name;
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java
index 791b623..7478876 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java
@@ -1,18 +1,49 @@
package io.roastedroot.proxywasm;
+/**
+ * Represents a unit of shared data retrieved from the host environment via
+ * {@link SharedDataHandler#getSharedData(String)}.
+ *
+ * This class encapsulates the data itself (as a byte array) and its associated
+ * Compare-And-Swap (CAS) value. The CAS value acts as a version identifier, enabling
+ * optimistic concurrency control when updating shared data using
+ * {@link SharedDataHandler#setSharedData(String, byte[], int)}.
+ */
public class SharedData {
private final byte[] data;
private final int cas;
+ /**
+ * Constructs a new SharedData instance.
+ *
+ * @param data The raw byte data retrieved from the shared data store.
+ * This might be {@code null} if the key was found but had no associated value,
+ * depending on the {@link SharedDataHandler} implementation.
+ * @param cas The Compare-And-Swap (version) value associated with this data.
+ * A value of 0 typically indicates the key did not exist or CAS is not supported/applicable.
+ */
public SharedData(byte[] data, int cas) {
this.data = data;
this.cas = cas;
}
+ /**
+ * Gets the raw data bytes.
+ *
+ * @return The byte array representing the shared data's value.
+ * May be {@code null}.
+ */
public byte[] data() {
return data;
}
+ /**
+ * Gets the Compare-And-Swap (CAS) value associated with this data.
+ * This value should be passed back to {@link SharedDataHandler#setSharedData(String, byte[], int)}
+ * when performing a conditional update.
+ *
+ * @return The integer CAS value.
+ */
public int cas() {
return cas;
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java
index 1079813..2a6209a 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java
@@ -1,13 +1,60 @@
package io.roastedroot.proxywasm;
+import io.roastedroot.proxywasm.internal.WasmResult;
+
+/**
+ * Defines the contract for handling shared key-value data accessible by Proxy-WASM modules.
+ * Implementations of this interface manage the storage, retrieval, and conditional update
+ * (using CAS - Compare-And-Swap) of data that can be shared across different WASM module
+ * instances or even different VMs, depending on the host environment's implementation.
+ *
+ * Shared data provides a mechanism for state sharing, caching, or coordination between plugins.
+ */
public interface SharedDataHandler {
+ /**
+ * A default, non-functional instance of {@code SharedDataHandler}.
+ * This instance throws {@link WasmException} with {@link WasmResult#UNIMPLEMENTED}
+ * for {@link #getSharedData(String)} and returns {@link WasmResult#UNIMPLEMENTED}
+ * for {@link #setSharedData(String, byte[], int)}.
+ * Useful as a placeholder or base when shared data functionality is not supported or needed.
+ */
SharedDataHandler DEFAULT = new SharedDataHandler() {};
+ /**
+ * Retrieves the shared data associated with the given key.
+ * The result includes the data itself and a CAS (Compare-And-Swap) value, which represents
+ * the version of the data. The CAS value is used for optimistic concurrency control
+ * during updates via {@link #setSharedData(String, byte[], int)}.
+ *
+ * @param key The key identifying the shared data item.
+ * @return A {@link SharedData} object containing the value and its CAS.
+ * @throws WasmException If the key is not found ({@link WasmResult#NOT_FOUND}),
+ * or if the operation is unimplemented by the host.
+ */
default SharedData getSharedData(String key) throws WasmException {
throw new WasmException(WasmResult.UNIMPLEMENTED);
}
+ /**
+ * Sets or updates the shared data associated with the given key.
+ * This operation can be conditional based on the provided CAS value.
+ *
+ * The {@code cas} parameter enables Compare-And-Swap:
+ * Shared queues provide a mechanism for inter-plugin communication or for passing data
+ * between different processing stages involving WASM modules.
+ */
public interface SharedQueueHandler {
+ /**
+ * A default, non-functional instance of {@code SharedQueueHandler}.
+ * This instance throws {@link WasmException} with {@link WasmResult#UNIMPLEMENTED}
+ * for methods that register, resolve, or dequeue from queues, and returns
+ * {@link WasmResult#UNIMPLEMENTED} for enqueue operations.
+ * Useful as a placeholder or base when shared queue functionality is not supported or needed.
+ */
SharedQueueHandler DEFAULT = new SharedQueueHandler() {};
+ /**
+ * Registers a shared queue with the given name, creating it if it doesn't exist,
+ * and returns its unique identifier (queue ID).
+ *
+ * @param name The {@link QueueName} uniquely identifying the queue (VM ID + queue name string).
+ * @return The unique integer ID assigned to the queue.
+ * @throws WasmException If the queue cannot be registered (e.g., resource limits, invalid name)
+ * or if the operation is unimplemented by the host.
+ */
default int registerSharedQueue(QueueName name) throws WasmException {
throw new WasmException(WasmResult.UNIMPLEMENTED);
}
+ /**
+ * Resolves the unique identifier (queue ID) for a shared queue given its name.
+ * This does not create the queue if it doesn't exist.
+ *
+ * @param name The {@link QueueName} uniquely identifying the queue (VM ID + queue name string).
+ * @return The unique integer ID of the existing queue.
+ * @throws WasmException If the queue cannot be found ({@link WasmResult#NOT_FOUND}),
+ * or if the operation is unimplemented by the host.
+ */
default int resolveSharedQueue(QueueName name) throws WasmException {
throw new WasmException(WasmResult.UNIMPLEMENTED);
}
+ /**
+ * Removes and returns the next available message (byte array) from the front of the specified queue.
+ *
+ * @param queueId The unique integer ID of the target queue.
+ * @return The dequeued message data as a byte array.
+ * @throws WasmException If the queue is empty ({@link WasmResult#EMPTY}), the queue ID is invalid
+ * ({@link WasmResult#NOT_FOUND}), or the operation is unimplemented by the host.
+ */
default byte[] dequeueSharedQueue(int queueId) throws WasmException {
throw new WasmException(WasmResult.UNIMPLEMENTED);
}
+ /**
+ * Adds a message (byte array) to the end of the specified shared queue.
+ *
+ * @param queueId The unique integer ID of the target queue.
+ * @param value The message data to enqueue.
+ * @return A {@link WasmResult} indicating the outcome (e.g., {@link WasmResult#OK},
+ * {@link WasmResult#NOT_FOUND}, {@link WasmResult#UNIMPLEMENTED}).
+ */
default WasmResult enqueueSharedQueue(int queueId, byte[] value) {
return WasmResult.UNIMPLEMENTED;
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleMetricsHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleMetricsHandler.java
new file mode 100644
index 0000000..8cd2961
--- /dev/null
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleMetricsHandler.java
@@ -0,0 +1,174 @@
+package io.roastedroot.proxywasm;
+
+import io.roastedroot.proxywasm.internal.WasmResult;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A basic, in-memory implementation of the {@link MetricsHandler} interface.
+ *
+ * This handler manages metrics entirely within the host's memory using standard Java collections.
+ * It supports Counter, Gauge, and Histogram types in a simplified manner (e.g., Histograms are
+ * treated like Gauges for storage). It is suitable for single-process environments or testing
+ * scenarios where integration with a real metrics backend (like Prometheus, StatsD) is not required.
+ *
+ * All operations on this handler are synchronized to ensure thread safety within a single JVM.
+ */
+public class SimpleMetricsHandler implements MetricsHandler {
+
+ /**
+ * Represents an individual metric managed by {@link SimpleMetricsHandler}.
+ * Stores the metric's ID, type, name, and its current value.
+ * Note: Histograms are stored as a single value (like a Gauge) in this simple implementation.
+ */
+ public static class Metric {
+
+ private final int id;
+ private final MetricType type;
+ private final String name;
+ private long value; // Represents counter/gauge value, or potentially sum for histograms
+
+ /**
+ * Constructs a new Metric instance.
+ *
+ * @param id The unique integer ID assigned by the handler.
+ * @param type The {@link MetricType} (Counter, Gauge, Histogram).
+ * @param name The name of the metric.
+ */
+ public Metric(int id, MetricType type, String name) {
+ this.id = id;
+ this.type = type;
+ this.name = name;
+ }
+
+ /**
+ * @return The unique integer ID of the metric.
+ */
+ public int id() {
+ return id;
+ }
+
+ /**
+ * @return The {@link MetricType} of the metric.
+ */
+ public MetricType type() {
+ return type;
+ }
+
+ /**
+ * @return The name of the metric.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * @return The current value of the metric.
+ */
+ public long getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the current value of the metric.
+ * Used internally by {@link SimpleMetricsHandler#recordMetric(int, long)} and
+ * {@link SimpleMetricsHandler#incrementMetric(int, long)}.
+ *
+ * @param value The new value for the metric.
+ */
+ public void setValue(long value) {
+ this.value = value;
+ }
+ }
+
+ private final AtomicInteger lastMetricId = new AtomicInteger(0);
+ private final HashMap This handler manages shared key-value data entirely within the host's memory using a
+ * {@link HashMap}. It supports Compare-And-Swap (CAS) operations for optimistic concurrency control.
+ * It is suitable for single-process environments or testing scenarios where data persistence or
+ * cross-process sharing is not required.
+ *
+ * All operations on this handler are synchronized to ensure thread safety within a single JVM.
+ */
+public class SimpleSharedDataHandler implements SharedDataHandler {
+
+ private final HashMap CAS behavior:
+ * This handler manages shared queues entirely within the host's memory using standard Java collections.
+ * It is suitable for single-process environments or testing scenarios where queue persistence or
+ * cross-process sharing is not required.
+ *
+ * All operations on this handler are synchronized to ensure thread safety within a single JVM.
+ */
+public class SimpleSharedQueueHandler implements SharedQueueHandler {
+
+ /**
+ * Represents an individual shared queue managed by {@link SimpleSharedQueueHandler}.
+ * Each queue has a unique name (within its VM), a host-assigned ID, and holds its data
+ * in an in-memory list.
+ */
+ public static class SharedQueue {
+ /** The name identifying this queue, composed of a VM ID and queue name string. */
+ public final QueueName queueName;
+
+ /** The underlying list holding the byte array messages in the queue (FIFO order). */
+ public final LinkedList This typically happens during the execution of the {@link Plugin.Builder#build()} method,
+ * encompassing issues such as WASM module instantiation failures, errors within the WASM
+ * {@code _start} function, or failures during the initial {@code proxy_on_vm_start} or
+ * {@code proxy_on_configure} calls within the plugin.
+ */
public class StartException extends Exception {
+ /**
+ * Constructs a new StartException with the specified detail message.
+ *
+ * @param message the detail message.
+ */
public StartException(String message) {
super(message);
}
+ /**
+ * Constructs a new StartException with the specified detail message and cause.
+ *
+ * @param message the detail message.
+ * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
+ * (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.)
+ */
public StartException(String message, Throwable cause) {
super(message, cause);
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WasmException.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WasmException.java
index 215f430..7a02a19 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WasmException.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WasmException.java
@@ -1,18 +1,42 @@
package io.roastedroot.proxywasm;
+import io.roastedroot.proxywasm.internal.WasmResult;
+
/**
- * Represents WebAssembly result codes.
- * Converted from Go's WasmResult type.
+ * An exception used to signal specific outcomes or errors from host functions
+ * back to the calling Proxy-WASM module.
+ *
+ * This exception wraps a {@link WasmResult} enum value, which corresponds to the
+ * standard result codes defined in the Proxy-WASM ABI specification. When a host function
+ * (like those defined in {@link MetricsHandler}, {@link SharedQueueHandler}, etc.) needs
+ * to return a status other than simple success (which is often indicated by a void return
+ * or a non-exceptional return value), it throws a {@code WasmException} containing the
+ * appropriate {@code WasmResult}.
+ *
+ * The runtime catches this exception and translates its contained {@code WasmResult}
+ * into the integer value expected by the WASM module according to the ABI.
*/
public class WasmException extends Exception {
+ /** The specific Proxy-WASM result code associated with this exception. */
private final WasmResult result;
+ /**
+ * Constructs a new WasmException with the specified result code.
+ * The exception message is automatically set to the description of the {@link WasmResult}.
+ *
+ * @param result The {@link WasmResult} representing the outcome or error condition.
+ */
public WasmException(WasmResult result) {
super(result.description());
this.result = result;
}
+ /**
+ * Gets the underlying {@link WasmResult} code associated with this exception.
+ *
+ * @return The non-null {@link WasmResult} enum value.
+ */
public WasmResult result() {
return result;
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ABI.java
similarity index 99%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ABI.java
index fb05194..16fddca 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ABI.java
@@ -1,9 +1,9 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
-import static io.roastedroot.proxywasm.Helpers.bytes;
-import static io.roastedroot.proxywasm.Helpers.replaceBytes;
-import static io.roastedroot.proxywasm.Helpers.split;
-import static io.roastedroot.proxywasm.Helpers.string;
+import static io.roastedroot.proxywasm.internal.Helpers.bytes;
+import static io.roastedroot.proxywasm.internal.Helpers.replaceBytes;
+import static io.roastedroot.proxywasm.internal.Helpers.split;
+import static io.roastedroot.proxywasm.internal.Helpers.string;
import com.dylibso.chicory.experimental.hostmodule.annotations.HostModule;
import com.dylibso.chicory.experimental.hostmodule.annotations.WasmExport;
@@ -12,6 +12,11 @@
import com.dylibso.chicory.runtime.Memory;
import com.dylibso.chicory.runtime.WasmRuntimeException;
import com.dylibso.chicory.wasm.InvalidException;
+import io.roastedroot.proxywasm.LogLevel;
+import io.roastedroot.proxywasm.MetricType;
+import io.roastedroot.proxywasm.QueueName;
+import io.roastedroot.proxywasm.SharedData;
+import io.roastedroot.proxywasm.WasmException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Action.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Action.java
similarity index 94%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Action.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Action.java
index 278add4..46dec7d 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Action.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Action.java
@@ -1,7 +1,9 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
/**
* Action represents the action which Wasm contexts expects hosts to take.
+ *
+ * @hidden
*/
public enum Action {
CONTINUE(0),
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayBytesProxyMap.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayBytesProxyMap.java
similarity index 93%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayBytesProxyMap.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayBytesProxyMap.java
index af6c8a7..4cfadc2 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayBytesProxyMap.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayBytesProxyMap.java
@@ -1,8 +1,8 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
-import static io.roastedroot.proxywasm.Helpers.bytes;
-import static io.roastedroot.proxywasm.Helpers.len;
-import static io.roastedroot.proxywasm.Helpers.string;
+import static io.roastedroot.proxywasm.internal.Helpers.bytes;
+import static io.roastedroot.proxywasm.internal.Helpers.len;
+import static io.roastedroot.proxywasm.internal.Helpers.string;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayProxyMap.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayProxyMap.java
similarity index 97%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayProxyMap.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayProxyMap.java
index a98db45..3073b2a 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ArrayProxyMap.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ArrayProxyMap.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
import java.util.ArrayList;
import java.util.Map;
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/BufferType.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/BufferType.java
similarity index 96%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/BufferType.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/BufferType.java
index 61a2835..9ec9fe4 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/BufferType.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/BufferType.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
/**
* Represents the type of buffer in proxy WASM.
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ChainedHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ChainedHandler.java
similarity index 96%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ChainedHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ChainedHandler.java
index df4ef20..df80f6d 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ChainedHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ChainedHandler.java
@@ -1,5 +1,11 @@
-package io.roastedroot.proxywasm;
-
+package io.roastedroot.proxywasm.internal;
+
+import io.roastedroot.proxywasm.ForeignFunction;
+import io.roastedroot.proxywasm.LogLevel;
+import io.roastedroot.proxywasm.MetricType;
+import io.roastedroot.proxywasm.QueueName;
+import io.roastedroot.proxywasm.SharedData;
+import io.roastedroot.proxywasm.WasmException;
import java.util.List;
/**
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Context.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Context.java
similarity index 97%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Context.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Context.java
index e44554d..593660c 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Context.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Context.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
import java.io.Closeable;
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ContextHandler.java
similarity index 92%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ContextHandler.java
index 5af83c5..810c7a9 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/ContextHandler.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
public interface ContextHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/CustomHandler.java
similarity index 95%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/CustomHandler.java
index 8ced4ba..a7ca11a 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/CustomHandler.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
public interface CustomHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/FFIHandler.java
similarity index 86%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/FFIHandler.java
index 76c58e4..67e1660 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/FFIHandler.java
@@ -1,4 +1,6 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
+
+import io.roastedroot.proxywasm.ForeignFunction;
public interface FFIHandler {
/**
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GRPCContextHandler.java
similarity index 94%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GRPCContextHandler.java
index 08ca2dc..9ed28aa 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GRPCContextHandler.java
@@ -1,4 +1,6 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
+
+import io.roastedroot.proxywasm.WasmException;
public interface GRPCContextHandler extends StreamContextHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/GrpcCallResponseHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GrpcCallResponseHandler.java
similarity index 69%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/GrpcCallResponseHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GrpcCallResponseHandler.java
index fdb2949..6c4ff64 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/GrpcCallResponseHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/GrpcCallResponseHandler.java
@@ -1,6 +1,4 @@
-package io.roastedroot.proxywasm.plugin;
-
-import io.roastedroot.proxywasm.ArrayBytesProxyMap;
+package io.roastedroot.proxywasm.internal;
public interface GrpcCallResponseHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Handler.java
similarity index 68%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Handler.java
index c8b8179..d946cf2 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Handler.java
@@ -1,4 +1,9 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
+
+import io.roastedroot.proxywasm.LogHandler;
+import io.roastedroot.proxywasm.MetricsHandler;
+import io.roastedroot.proxywasm.SharedDataHandler;
+import io.roastedroot.proxywasm.SharedQueueHandler;
public interface Handler
extends ContextHandler,
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Helpers.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Helpers.java
similarity index 99%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Helpers.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Helpers.java
index 7008775..a644401 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Helpers.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/Helpers.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
import com.dylibso.chicory.runtime.HostFunction;
import java.nio.ByteBuffer;
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallHandler.java
similarity index 93%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallHandler.java
index 3bbd8e3..d7fb81c 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallHandler.java
@@ -1,4 +1,6 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
+
+import io.roastedroot.proxywasm.WasmException;
public interface HttpCallHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallResponseHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallResponseHandler.java
new file mode 100644
index 0000000..63417e3
--- /dev/null
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpCallResponseHandler.java
@@ -0,0 +1,5 @@
+package io.roastedroot.proxywasm.internal;
+
+public interface HttpCallResponseHandler {
+ void call(int statusCode, ProxyMap headers, byte[] body);
+}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContext.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContext.java
similarity index 95%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContext.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContext.java
index defdb93..6ddfa88 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContext.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContext.java
@@ -1,6 +1,6 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
-import static io.roastedroot.proxywasm.Helpers.len;
+import static io.roastedroot.proxywasm.internal.Helpers.len;
public class HttpContext extends Context {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContextHandler.java
similarity index 97%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContextHandler.java
index e07b52d..79b044a 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpContextHandler.java
@@ -1,4 +1,4 @@
-package io.roastedroot.proxywasm;
+package io.roastedroot.proxywasm.internal;
public interface HttpContextHandler extends StreamContextHandler {
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/HttpRequestAdaptor.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpRequestAdaptor.java
similarity index 65%
rename from proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/HttpRequestAdaptor.java
rename to proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpRequestAdaptor.java
index ff920b2..5896366 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/HttpRequestAdaptor.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/internal/HttpRequestAdaptor.java
@@ -1,8 +1,6 @@
-package io.roastedroot.proxywasm.plugin;
+package io.roastedroot.proxywasm.internal;
-import io.roastedroot.proxywasm.ProxyMap;
import io.roastedroot.proxywasm.WasmException;
-import io.roastedroot.proxywasm.WasmResult;
import java.util.List;
/**
@@ -32,7 +30,7 @@ public interface HttpRequestAdaptor {
ProxyMap getGrpcReceiveTrailerMetaData();
- byte[] getProperty(HttpContext pluginRequest, List
+ *
+ *
+ * @param key The key identifying the shared data item.
+ * @param value The new data value to store (can be null or empty, depending on implementation). A null value might signify deletion.
+ * @param cas The Compare-And-Swap value expected for a conditional update, or 0 for an unconditional update.
+ * @return A {@link WasmResult} indicating the outcome (e.g., {@link WasmResult#OK},
+ * {@link WasmResult#CAS_MISMATCH}, {@link WasmResult#UNIMPLEMENTED}).
+ */
default WasmResult setSharedData(String key, byte[] value, int cas) {
return WasmResult.UNIMPLEMENTED;
}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java
index e94c32c..abb1efb 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java
@@ -1,21 +1,73 @@
package io.roastedroot.proxywasm;
+import io.roastedroot.proxywasm.internal.WasmResult;
+
+/**
+ * Defines the contract for handling shared message queues accessible by Proxy-WASM modules.
+ * Implementations of this interface manage the registration, resolution, and data manipulation
+ * (enqueue/dequeue) of queues that can potentially be accessed by multiple WASM modules
+ * or different instances of the same module, depending on the host environment's implementation.
+ *
+ *
+ *
+ *
+ * Setting {@code value} to {@code null} effectively removes the key if the CAS check passes
+ * (or if cas is 0), as {@code HashMap} allows null values.
+ *
+ * @param key The key identifying the shared data item.
+ * @param value The new data value to store (can be null).
+ * @param cas The Compare-And-Swap value for conditional update, or 0 for unconditional update.
+ * @return {@link WasmResult#OK} if the update was successful, or
+ * {@link WasmResult#CAS_MISMATCH} if the CAS check failed.
+ */
+ @Override
+ public synchronized WasmResult setSharedData(String key, byte[] value, int cas) {
+ SharedData current = sharedData.get(key);
+ int nextCas = (current == null) ? 1 : current.cas() + 1; // Simple incrementing CAS
+
+ if (current == null) {
+ // Key does not exist
+ if (cas == 0) {
+ // Unconditional set/create
+ sharedData.put(key, new SharedData(value, nextCas));
+ return WasmResult.OK;
+ } else {
+ // CAS specified for a non-existent key
+ return WasmResult.CAS_MISMATCH; // Or NOT_FOUND, depending on desired semantics
+ }
+ } else {
+ // Key exists
+ if (cas == 0 || current.cas() == cas) {
+ // Unconditional update OR CAS matches
+ sharedData.put(key, new SharedData(value, nextCas));
+ return WasmResult.OK;
+ } else {
+ // CAS mismatch
+ return WasmResult.CAS_MISMATCH;
+ }
+ }
+ }
+}
diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleSharedQueueHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleSharedQueueHandler.java
new file mode 100644
index 0000000..e846bdf
--- /dev/null
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SimpleSharedQueueHandler.java
@@ -0,0 +1,136 @@
+package io.roastedroot.proxywasm;
+
+import io.roastedroot.proxywasm.internal.WasmResult;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A basic, in-memory implementation of the {@link SharedQueueHandler} interface.
+ *
+ *