Kotlin Channel Messaging Public Interface¶
Interface table of contents · Java Channel
A Kotlin application doesn't directly use the Java Channel call. A
Kotlin-only client and call wrapper keep the Java call internally,
projecting regular completion as await(), and completion that returns
the current Spot turn as yield(). One-way await()'s normal result is
Unit, and failure propagates the Java stage's exception unchanged. The
typed request's reified entry method fixes KClass<TReply>.java as the
internal Java Class<TReply> when building the wrapper. The application
doesn't pass the reply type again at the terminal, or write
.submit().await().
The synchronous blocking terminator adds no Kotlin-specific wrapper and exposes the Java surface's
submit_sync() as is. A blocking call is not a suspend, so it is not wrapped in await(); it is for
application threads and fails with InvalidOperation when called from a runtime execution context
(Submit And Completion §4 F2-a).
The Kotlin filter uses the same applicable scope as the Java runtime.
It's applied to RouteMesh/ClientServer Channel send/request, Node direct
send/request, and classic fanout subscription handlers, and isn't
applied to Spot/Actor/Logical Multicast/STREAM handlers.
ZLinkHandlerFilterContext.dispatchKind() distinguishes the five paths.
RouteMesh and Node direct provide MeshName, and ClientServer and classic
fanout don't.
The handler and filter are each created once per dispatch and use the
same scoped dependency — application DI registration can't change this
lifetime. Calling next.invoke() twice is IllegalStateException, and
not calling it on a request is REJECTED. Even if the filter returns an
arbitrary value, it doesn't substitute for the handler reply. Coroutine
suspension doesn't extend the dispatch scope beyond terminal completion.
A Spot context's outbound() is used through the Kotlin wrapper that
outbound().kotlin() returns; the wrapper's calls, terminals and JVM
signature are owned by the Spot Interface.
Handler registration on the Channel Server builders follows the registration rule in Kotlin Configuration. The source and JVM signatures below declare those extensions.
Kotlin Source Signature¶
interface ZLinkSuspendingRequestHandler<TRequest, TReply> {
suspend fun handle(request: TRequest, context: ZLinkMessageContext): TReply
}
interface ZLinkSuspendingSendHandler<TMessage> {
suspend fun handle(message: TMessage, context: ZLinkMessageContext)
}
interface ZLinkSuspendingPublishHandler<TMessage> {
suspend fun handle(message: TMessage, context: ZLinkPublishMessageContext)
}
interface ZLinkSuspendingRouteRequestHandler<TRequest, TReply> {
suspend fun handle(request: TRequest, context: ZLinkRouteMessageContext): TReply
}
interface ZLinkSuspendingRouteSendHandler<TMessage> {
suspend fun handle(message: TMessage, context: ZLinkRouteMessageContext)
}
interface ZLinkKotlinMessageSendCall {
fun metadata(key: String, value: String): ZLinkKotlinMessageSendCall
suspend fun await()
}
interface ZLinkKotlinSubmissionCall {
suspend fun await()
}
interface ZLinkKotlinRequestCall<TReply : Any> {
fun metadata(key: String, value: String): ZLinkKotlinRequestCall<TReply>
fun timeout(timeout: Duration): ZLinkKotlinRequestCall<TReply>
suspend fun await(): TReply
suspend fun yield(): TReply
}
interface ZLinkKotlinClient {
fun sendToChannel(
channelName: String,
message: Any,
): ZLinkKotlinMessageSendCall
fun <TReply : Any> requestToChannel(
channelName: String,
request: Any,
replyType: KClass<TReply>,
): ZLinkKotlinRequestCall<TReply>
}
inline fun <reified TReply : Any> ZLinkKotlinClient.requestToChannel(
channelName: String,
request: Any,
): ZLinkKotlinRequestCall<TReply> =
requestToChannel(channelName, request, TReply::class)
interface ZLinkKotlinFanoutClient {
fun publish(
channelName: String,
topic: String,
event: Any,
): ZLinkKotlinSubmissionCall
fun publish(
channelName: String,
event: Any,
): ZLinkKotlinSubmissionCall
}
interface ZLinkKotlinRouteClient {
fun sendToNode(
meshName: String,
target: RoutingId,
message: Any,
): ZLinkKotlinMessageSendCall
fun <TReply : Any> requestToNode(
meshName: String,
target: RoutingId,
request: Any,
replyType: KClass<TReply>,
): ZLinkKotlinRequestCall<TReply>
fun sendToChannel(
channelName: String,
message: Any,
): ZLinkKotlinMessageSendCall
fun <TReply : Any> requestToChannel(
channelName: String,
request: Any,
replyType: KClass<TReply>,
): ZLinkKotlinRequestCall<TReply>
}
inline fun <reified TReply : Any> ZLinkKotlinRouteClient.requestToNode(
meshName: String,
target: RoutingId,
request: Any,
): ZLinkKotlinRequestCall<TReply> =
requestToNode(meshName, target, request, TReply::class)
inline fun <reified TReply : Any> ZLinkKotlinRouteClient.requestToChannel(
channelName: String,
request: Any,
): ZLinkKotlinRequestCall<TReply> =
requestToChannel(channelName, request, TReply::class)
public inline fun <reified T : Any> messageOf(value: T): ZLinkMessage
public fun messageOf(value: Any, declaredType: KClass<*>): ZLinkMessage
public inline fun <reified T> ZLinkMessage.decode(): T
The first messageOf(...) overload retains the call site's T as the
message's declared type. The codec selector uses that declared type even
when the runtime value is a subtype. Use the second overload when the
call site cannot retain T, such as Java reflection or a shared base-type
boundary.
The first decode<T>() on a received message fixes either a value or a failure. Later
calls use the same single outcome as Java's ZLinkMessage.decode(Class<T>) and do not
invoke the serializer again. Another T ends with TYPE_MISMATCH when it cannot accept
the first value, and a failure from the first call is delivered again.
ZLinkKotlinRequestCall.yield() bridges the Java call to a coroutine; Execution gate defines eligibility and admission.
Submit and completion defines one-way admission and terminal outcomes. Cancellation of a coroutine awaiting a one-way send follows Cancellation and shutdown §1. A request maps cancellation to coroutine cancellation.
A topic passed to publishToTopic(...), which takes a topic, or registered with the Java
builder's subscribe, that Channel messaging §7 forbids raises the Java runtime's
ZLinkConfigurationException. The overload
that omits topic uses the typed
event's packet name, and the same rule applies to it.
The RouteMesh DSL doesn't change the Java builder's meaning — it only provides a receiver and lambda. It configures a per-ChannelName role on one MeshNode's physical connection.
The Kotlin runtime directly uses Java's ZLinkRouteMeshRuntimeOptions.
channel(meshName, channelName) selects a target Mesh and ChannelName,
while mesh(meshName) selects the placement option. channel(channelName)
selects a ChannelName registered on exactly one Mesh. The Kotlin DSL's
routeMesh and channelName don't add a new overload to this runtime option.
So these three methods must be confirmed with the same name, arguments,
and return type in both the Java per-language interface and the Kotlin package
consumer.
RouteMesh Channel Server and ClientServer Server weight use the Java
builder's signed int. The allowed range is 0..10000, defaulting to
100, and 0 is excluded from new target selection. Logical Multicast
includes each positive member exactly once, and doesn't increase submit
count by weight magnitude. An out-of-range startup/runtime setting is a
configuration error. Logical Multicast's remote target is submitted
once to the local transport queue of the MeshNode route fixed on the
source, and the local target is submitted once to the matching local
Spot queue. Per-target success/drop/unreachable results aren't returned
as await()'s result or aggregated into public monitoring. Remote Spot
queue admission and remote/local handler execution or completion aren't
the coroutine bridge's completion condition.
fun ZLinkFrameworkOptions.routeMesh(
meshName: String,
configure: ZLinkMeshNodeBuilder.() -> Unit,
): ZLinkMeshNodeBuilder
fun ZLinkMeshNodeBuilder.channelName(
channelName: String,
configure: ZLinkMeshChannelBuilder.() -> Unit = {},
): ZLinkMeshChannelBuilder
fun ZLinkMeshPeerConnections.connect(
expectedRoutingId: RoutingId,
endpoint: String,
)
inline fun <reified THandler : Any, reified TMessage : Any>
ZLinkMeshNodeBuilder.addRouteSendHandler(): ZLinkMeshNodeBuilder
inline fun <reified THandler : Any, reified TRequest : Any, reified TReply : Any>
ZLinkMeshNodeBuilder.addRouteRequestHandler(): ZLinkMeshNodeBuilder
inline fun <reified THandler : ZLinkSendHandler<TMessage>, reified TMessage : Any>
ZLinkMeshChannelServerBuilder.addSendHandler(): ZLinkMeshChannelServerBuilder
inline fun <reified THandler : ZLinkRouteSendHandler<TMessage>, reified TMessage : Any>
ZLinkMeshChannelServerBuilder.addRouteSendHandler(): ZLinkMeshChannelServerBuilder
inline fun <reified THandler : ZLinkRequestHandler<TRequest, TReply>, reified TRequest : Any, reified TReply : Any>
ZLinkMeshChannelServerBuilder.addRequestHandler(): ZLinkMeshChannelServerBuilder
inline fun <reified THandler : ZLinkSendHandler<TMessage>, reified TMessage : Any>
ZLinkClientServerChannelServerBuilder.addSendHandler(): ZLinkClientServerChannelServerBuilder
inline fun <reified THandler : ZLinkRequestHandler<TRequest, TReply>, reified TRequest : Any, reified TReply : Any>
ZLinkClientServerChannelServerBuilder.addRequestHandler(): ZLinkClientServerChannelServerBuilder
Generated JVM Signature¶
The JVM signature below is the generated form of the Kotlin source contract.
public final class systems.zlink.framework.kotlin.ZLinkMessageExtensionsKt {
public static final <T> systems.zlink.framework.messaging.ZLinkMessage messageOf(T);
public static final systems.zlink.framework.messaging.ZLinkMessage messageOf(java.lang.Object, kotlin.reflect.KClass<?>);
public static final <T> T decode(systems.zlink.framework.messaging.ZLinkMessage);
}
public final class systems.zlink.framework.kotlin.ZLinkRouteMeshExtensionsKt {
public static final systems.zlink.framework.configuration.ZLinkMeshNodeBuilder routeMesh(systems.zlink.framework.configuration.ZLinkFrameworkOptions, java.lang.String, kotlin.jvm.functions.Function1<? super systems.zlink.framework.configuration.ZLinkMeshNodeBuilder, kotlin.Unit>);
public static final systems.zlink.framework.configuration.ZLinkMeshChannelBuilder channelName(systems.zlink.framework.configuration.ZLinkMeshNodeBuilder, java.lang.String, kotlin.jvm.functions.Function1<? super systems.zlink.framework.configuration.ZLinkMeshChannelBuilder, kotlin.Unit>);
public static systems.zlink.framework.configuration.ZLinkMeshChannelBuilder channelName$default(systems.zlink.framework.configuration.ZLinkMeshNodeBuilder, java.lang.String, kotlin.jvm.functions.Function1, int, java.lang.Object);
public static final void connect(systems.zlink.framework.configuration.ZLinkMeshPeerConnections, systems.zlink.contracts.core.RoutingId, java.lang.String);
}
public final class systems.zlink.framework.kotlin.ZLinkFrameworkExtensionsKt {
public static final <THandler, TMessage> systems.zlink.framework.configuration.ZLinkMeshNodeBuilder addRouteSendHandler(systems.zlink.framework.configuration.ZLinkMeshNodeBuilder);
public static final <THandler, TRequest, TReply> systems.zlink.framework.configuration.ZLinkMeshNodeBuilder addRouteRequestHandler(systems.zlink.framework.configuration.ZLinkMeshNodeBuilder);
public static final <THandler extends systems.zlink.framework.channels.ZLinkSendHandler<TMessage>, TMessage> systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder addSendHandler(systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder);
public static final <THandler extends systems.zlink.framework.channels.ZLinkRouteSendHandler<TMessage>, TMessage> systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder addRouteSendHandler(systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder);
public static final <THandler extends systems.zlink.framework.channels.ZLinkRequestHandler<TRequest, TReply>, TRequest, TReply> systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder addRequestHandler(systems.zlink.framework.configuration.ZLinkMeshChannelServerBuilder);
public static final <THandler extends systems.zlink.framework.channels.ZLinkSendHandler<TMessage>, TMessage> systems.zlink.framework.configuration.ZLinkClientServerChannelServerBuilder addSendHandler(systems.zlink.framework.configuration.ZLinkClientServerChannelServerBuilder);
public static final <THandler extends systems.zlink.framework.channels.ZLinkRequestHandler<TRequest, TReply>, TRequest, TReply> systems.zlink.framework.configuration.ZLinkClientServerChannelServerBuilder addRequestHandler(systems.zlink.framework.configuration.ZLinkClientServerChannelServerBuilder);
}
public final class systems.zlink.framework.kotlin.ZLinkSuspendingHandlersKt {
}
public interface systems.zlink.framework.kotlin.ZLinkSuspendingPublishHandler<TMessage> {
public abstract java.lang.Object handle(TMessage, systems.zlink.framework.channels.ZLinkPublishMessageContext, kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkSuspendingRequestHandler<TRequest, TReply> {
public abstract java.lang.Object handle(TRequest, systems.zlink.framework.ZLinkMessageContext, kotlin.coroutines.Continuation<? super TReply>);
}
public interface systems.zlink.framework.kotlin.ZLinkSuspendingRouteRequestHandler<TRequest, TReply> {
public abstract java.lang.Object handle(TRequest, systems.zlink.framework.channels.ZLinkRouteMessageContext, kotlin.coroutines.Continuation<? super TReply>);
}
public interface systems.zlink.framework.kotlin.ZLinkSuspendingRouteSendHandler<TMessage> {
public abstract java.lang.Object handle(TMessage, systems.zlink.framework.channels.ZLinkRouteMessageContext, kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkSuspendingSendHandler<TMessage> {
public abstract java.lang.Object handle(TMessage, systems.zlink.framework.ZLinkMessageContext, kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall {
public abstract systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall metadata(java.lang.String, java.lang.String);
public abstract java.lang.Object await(kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinSubmissionCall {
public abstract java.lang.Object await(kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> {
public abstract systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> metadata(java.lang.String, java.lang.String);
public abstract systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> timeout(java.time.Duration);
public abstract java.lang.Object await(kotlin.coroutines.Continuation<? super TReply>);
public abstract java.lang.Object yield(kotlin.coroutines.Continuation<? super TReply>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinClient {
public abstract systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall sendToChannel(java.lang.String, java.lang.Object);
public abstract <TReply> systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> requestToChannel(java.lang.String, java.lang.Object, kotlin.reflect.KClass<TReply>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinFanoutClient {
public abstract systems.zlink.framework.kotlin.ZLinkKotlinSubmissionCall publish(java.lang.String, java.lang.String, java.lang.Object);
public abstract systems.zlink.framework.kotlin.ZLinkKotlinSubmissionCall publish(java.lang.String, java.lang.Object);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinRouteClient {
public abstract systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall sendToNode(java.lang.String, systems.zlink.contracts.core.RoutingId, java.lang.Object);
public abstract <TReply> systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> requestToNode(java.lang.String, systems.zlink.contracts.core.RoutingId, java.lang.Object, kotlin.reflect.KClass<TReply>);
public abstract systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall sendToChannel(java.lang.String, java.lang.Object);
public abstract <TReply> systems.zlink.framework.kotlin.ZLinkKotlinRequestCall<TReply> requestToChannel(java.lang.String, java.lang.Object, kotlin.reflect.KClass<TReply>);
}