Question

I'd like to configure a process that looks something like:

Method Call -> Dynamic Proxy Gateway -> Channel -> Service Activator -> Method Call
             ^---------- Transformer <- Channel <-             [return value]

Effectively, I'd like to somehow access the hidden channel Spring Integration creates and transform the return message payload into a different message type.

A simple solution may at first appear to be configuring a default-reply-channel on the gateway, the issue is that I'm sharing the channel between bundles using OSGi. The Service Activator is provided by Bundle "B", and offers a shared channel for incoming requests (it acts as a data provider service). Bundle "A" requires some data, so it requests it, but needs the result in an alternate format. Note that if Bundle "B" were to be able to use the default-reply-channel specified by Bundle "A" then Bundle "A" must share it. That's all fair and well, but then I have a circular dependency in OSGi, and nothing would start.

It seems like another solution here would be to define an output-channel on the Service Activator, but this suffers from a slightly different problem. Assuming I share the output-channel from Bundle "B" I've mitigated the circular dependency issue, but now anytime someone requests something from Bundle "A" the reply goes to everyone attached to the output channel -- this, too, is undesirable.

[Edit: What I mean here is that if "B" shares both an input and an output channel for its service activator then anyone bound to "B"'s output channel will receive the result of anyone's request to "B"'s input channel -- and the desired behavior is that the replies are directed at the requestors.

I should note that the transformer here makes sense only in the context of Bundle A. Bundle B provides a service (for all intents and purposes one that I have no control over). The transformation, specific to the needs of Bundle A should reside in Bundle A.]

So, what I think I really need is to be able to configure a transformer on replies to a dynamic proxy gateway, but try as I might I can't find such a device in the Spring Integration manual. As always, help would be greatly appreciated.

--

Edit 2: I attempted two other tactics here:

  1. Use a service-activator that refers to the OSGi shared channel from Bundle B

    The result was that the returned element was a GenericMessageType -- which it could be possible to transform. The GenericMessageType is really the boolean result of the "send" method which the service-activator must point to, not the reply message. So this method does not work.

  2. Use a header-enricher to set REPLY_CHANNEL and pass the reply channel as a reference rather than a value.

    This technique did not work, the REPLY_CHANNEL header element appears to be ignored when the default-reply-channel of the gateway is set (and the default-reply-channel must be set).

Was it helpful?

Solution

In theory the real answer here is to use a chain.

The configuration for Bundle A will look something like

<si:gateway id="gw" default-request-channel="xyz" />
<si:channel id="xyz" />
<si:chain input-channel="xyz" />
    <si:service-activator />
    <si:transformer />
</si:chain>

Note for Bundle B the configuration is unchanged and only a single channel is shared through OSGi for access by Bundle A or any tertiary bundles.

Two options for the service-activator are available:

  1. Shared service through OSGi
  2. Custom service that simply invokes a proxy-gateway for the pre-transformation returned data type.

The proxy-gateway in Bundle A will inject into some input-channel "xyz" and ultimately the implied return channel will contained the transformed content as desired.

This solution is nearly the same as the one proposed by SingleShot, however here we prevent the sharing of a real service through OSGi, maintaining bundle boundaries.

OTHER TIPS

I'm a bit confused by your problem description. I understand the circular dependency aspect, and the transformer aspect, but I'm not so sure about "the reply goes to everyone attached to A".

It kind of sounds like you might want to have two service activators for B. Your existing one in B would stay, and most clients would use it. The other one would go in A, and would only use channels defined in A. This would prevent requests from A to B from resulting in responses being received by components outside A.

This should make the problem of transformation easier. Transformers take a message from one channel, transform it, and place it on another. Just add one in A and you should be good.

So in A you would have these components, only useable by A:

  • a gateway
  • an input channel
  • a service activator for B
  • an output channel
  • a transformer
  • a transformed output channel

In B you would have, useable by anyone:

  • an input channel
  • a service activator for B
  • an output channel

A depends on B, but B does not depend on A.

Will that work?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top