Link Channel Adapter

The link adapter allows two internal flows within the same PipeliteContext to be connected, forwarding the Exchange from one flow to the consumer of another.

Availability

Included in default-channel-adapters, transitively available with pipelite-core.

Usage

// Main flow
Pipelite.defineFlow("main-flow")
    .fromSource("http://ingest")
    .process("enrich", exchange -> { /* enrichment */ })
    .toSink("link://secondary-flow")          (1)
    .build();

// Linked secondary flow
Pipelite.defineFlow("secondary-flow")
    .fromSource("secondary-flow")           (2)
    .process("finalize", exchange -> { /* ... */ })
    .toSink("slf4j://output")
    .build();
1 The link://secondary-flow sink sends the Exchange directly to the secondary flow consumer.
2 The source is the plain name secondary-flow, with no protocol: it receives what the main flow sends to link://secondary-flow.

URL format

link://<source-endpoint-name>
Parameter Description

source-endpoint-name

The name the receiving flow declares in .fromSource(…​), without protocol - not the flow’s own defineFlow(…​) name

The way to address an internal flow

A flow is always addressed by URL, and link://<source endpoint name> is the URL of an internal one. The same rule holds everywhere a destination is written - toSink(…​), the destinations of toRoute(…​) and toRecipientList(…​), wireTap(…​), toChannel(…​) - and for PipeliteContext.supplyExchange(…​). A bare name is not a destination: it is rejected when the flow is defined, or when the exchange is delivered if the value is only known at runtime.

The receiving side is the exception on purpose: fromSource(…​) takes the name of its own source endpoint, with no protocol.

Characteristics

  • Exchange handoff is synchronous in the sender flow thread.

  • No serialization is involved: the Exchange is passed by reference.

  • Useful for splitting complex pipelines into modular, reusable flows.

  • The receiving flow’s source can declare ?concurrency=N to process linked Exchanges concurrently — see Flow Definition.

Startup validation

PipeliteContext.start() checks that every link:// target is the source endpoint name of a flow registered in the same context: the destinations of toSink(…​), of the routes and the recipient list, of wireTap(…​), and the target of toChannel(…​), alone or as the exhaustion action of a retry. If one is not - a typo, a rename on one side only - start() throws a ContextValidationException that lists every problem, naming the flow and the DSL construct, before anything is started.

A destination that contains an expression (#{…​}) is only known when an exchange is routed, so it is not checked at startup; if it names no flow then, the delivery fails with an IllegalArgumentException. Destinations with any other protocol are not checked either.