Announcement Announcement Module
Collapse
No announcement yet.
Starting a chain with an inbound adapter Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Starting a chain with an inbound adapter

    This works:
    Code:
    <int-http:inbound-adapter channel="channel1" ... />
    <int:channel id="channel1" />
    <int:service-activator input-channel="channel1" ... />
    This doesn't:
    Code:
    <int:chain>
        <int-http:inbound-adapter ... />
        <int:service-activator ... />
    </int:chain>
    There are cases where decoupling the inbound adapter from the rest of the flow is necessary; but when it's the only entry point, it feels cumbersome to have to define an extra, effectively anonymous channel. This is particularly true when the adapter feeds directly into a chain. If I could put the adapter inside the chain, it would really stand out in the markup that those things were grouped together. Does anyone know why this isn't supported?

  • #2
    A chain, needs an input channel - it is a consumer so it expects something to send it data. You don't have to explicitly define the input-channel...

    Code:
    <int-http:inbound-adapter channel="channel1" ... />
    <int-chain input-channel="channel1" ...>
     ...
    </int:chain>
    works; as does

    Code:
    <int-http:inbound-adapter channel="channel1" ... />
    <int-service-activator input-channel="channel1" ... />
    Last edited by Gary Russell; May 16th, 2013, 05:00 PM.

    Comment


    • #3
      I edited the post; note that most consuming endpoints (except outbound adapters and gateways) will auto-declare a direct channel if no channel with the specified name is supplied.

      Comment


      • #4
        Right, but the chain could obtain that input channel implicitly from the output of an inbound adapter at the top of the chain. Semantically, everything involved with the chain has channel connections...the chain just provides a way to eliminate redundant syntax when there's no reason to declare them explicitly. It's counter-intuitive to me that the same simplification can't apply to an inbound adapter whose purpose is to feed the chain.

        I would generalize it to:
        1. Any inbound adapter declared inside a chain should output by default to the input channel of the chain.
        2. If the chain does not declare an explicit input channel, then an anonymous direct channel should be created.

        I appreciate the tip about not having to declare the channel. I haven't gotten a feel yet for when that's required and when it isn't. But there's still a need to come up with a unique channel name and type it correctly in both places. I wish the syntax could take that bit of overhead off my plate. Maybe this is something the DSLs do better...

        Comment


        • #5
          I was simply explaining why the semantics are the way they are; feel free to open a JIRA issue and it will be considered. Even better, submit a pull request to resolve the JIRA issue... https://github.com/SpringSource/spri...ONTRIBUTING.md; but consider that the inbound adapter would have to be the first element in the chain.

          Comment


          • #6
            Sure. I dug into the code a bit. The underlying architecture is a lot to take in, but it's clearer from that view that a chain is a MessageHandlerChain and that adapters don't fit into that definition as comfortably even though the syntax would be awfully convenient. I created INT-3023, signed the CLA and posted a gist. If it's too much of a stretch, I can live with that...but channel naming is something that I'm finding to be a bit of a chore in some cases, and anything to streamline or eliminate it when it's unnecessary is welcome.

            Is the forum the right place to start topics like this, or is the preference that anything that could lead to a code change start in Jira?

            Comment


            • #7
              Thanks.

              I do understand your motivation here; I just haven't considered a chain in this context; it just seems "wrong" to me at first glance.

              As an aside I, personally, am not a big fan of chains, except for the simplest cases (stringing a number of mid-flow elements into a single "black box"). I (again personally) rarely put outbound gateways and adapters within chains. But I can see that, since we allow that (gateways anywhere within a chain and outbound adapters at the end of a chain), I can accept an argument that, perhaps, an inbound adapter should be allowed at the beginning of the chain, at the very least, for symmetry.

              A big benefit of SI is that the channel is a first class citizen, and it is easy to change channel implementations to suit particular environments; of course, using the chain convenience shortcut precludes that (without busting up the chain).

              I'd be very interested in hearing the opinion of @Cleric (aka "Mr. <chain/>") who, as a very active forum contributor and committer - and who is a very strong advocate for chains - he has done a lot of work to enhance the chain "experience" over the last year or so and probably uses chains (in his real world solutions) more than anybody I know of.

              Comment


              • #8
                I've been dealing mostly with direct channels so far. In that case, the endpoints are like associative terms in an algebraic expression. You should be able to group them in whatever way is most natural to improve the clarity of the expression.

                In practical terms, if you have a payload transformation that associates more cleanly with an inbound adapter than with endpoints downstream, then it's perfectly natural to group (chain) it with the inbound adapter. Logically, the chain takes on the characteristics of its components and becomes one big inbound adapter. This compositional flexibility reduces the number of things you have to track when working with a large flow. Instead of having to collect that a message comes in and then flows through a named channel to another top-level endpoint where it is transformed, you can reason about it more simply as a message that arrives in the desired format to begin with.

                With that said, in the issue, I suggested allowing the input-channel attribute of the chain to imply the channel attribute of the inbound-channel-adapter. Your comment about symmetry got me thinking more formally about what a chain is, and I realize now that that would be a bad idea. If a chain starting with an inbound adapter is in-aggregate a kind of inbound adapter, then it doesn't logically have an inbound channel, and the chain's input-channel attribute shouldn't be coerced into some other purpose. As you said, if you need something other than a direct channel between any of the links, then you break the chain.

                In summary, the combination of channel attributes of a chain should imply its composition:
                • <int:chain input-channel="in" output-channel="out"> ... <int:some-endpoint /> ... </int:chain>
                • <int:chain input-channel="in"> ... <int:outbound-channel-adapter /> </int:chain>
                • <int:chain output-channel="out"> <int:inbound-channel-adapter /> ... </int:chain>
                • <int:chain> <int:inbound-channel-adapter /> ... <int:outbound-channel-adapter /> </int:chain>

                Comment


                • #9
                  @Nathan,

                  Thanks for your zeal!

                  I'll come back to you with my opinion soon. Next week...

                  Take care,
                  Artem

                  Comment


                  • #10
                    Hi!

                    Sorry for delay.
                    It was in my mind last time and I was going to find something against, but...

                    Well, a bit from practies.
                    After Spring Integration release 2.0, when SpEL and scripting were introduced, this framework became as central tool in my applications independently from domain: WS, HTTP, DB, JPA, MQ, XML, FTP etc...
                    There are many protocols and concepts supported by SI.
                    Another central goal of SI clear and dirrect implementation of EIP.
                    So, when I start to develop, I just need to get a component from out of the box and configure it within Spring context.
                    But it is XML and there is need more typing, when it would be with direct Java code.
                    It is time when <chain> comes to the rescue. It's first +1. Another one: <chain> wraps several handlers to the one endpoint and there are no registered additional beans within container.
                    However this week we opened the black box a bit (https://jira.springsource.org/browse/INT-2755), and now we register chain child handlers as beans, if they have an 'id'.

                    From other side <chain> has a value only in the meager XML syntax. If you take a look into our DSLs (https://github.com/SpringSource/spri...tion-dsl-scala, https://github.com/SpringSource/spri...ion-dsl-groovy), you'll see that they don't have 'chain' concept, however they introduce some another one MessageFlow, which, in its turn, creates separate applicationContext, however it looks as chain for end-developers.

                    Regarding channel naming. Yes, your're right I also follow with similar convention. But in big applications, where a count of channels crosses over a hundred, the fantasy is exhausting about names... Thanks to IDE, it tells about the duplicate .

                    I appreciate the tip about not having to declare the channel.
                    Maybe do you have an exporiance with Apache Camel?
                    Believe me you'll appreciate "first class citizen" from SI, and, of course, I don't worry about beaking my chains, when I see, that channel gives me some prize, unlike Camel, who doesn't have it at all. Rhetorical question: can we make Camel as a central tool of our applications?..
                    So, I'd say <chain> is approximated to the Camel flow.

                    But let's go on.
                    I so often use chains, and so often I should break them to separate endpoint, that I think Gary's strategy to try do not use chain at all, seems to me more better. But it is so difficult in big applications...
                    IMO <chain> is some compromise in the XML pain.

                    Now on the matter.
                    As Gary said it should be done, at least, for symmetry.
                    And sometimes hands are itching to get rid of excess point, e.g. a sample from my app:
                    HTML Code:
                    <inbound-channel-adapter id="claimCheckProducer" expression="''" channel="claimCheckListGatewayChannel"
                    							 auto-startup="false">
                    	<poller trigger="claimCheckProducerTrigger">
                    		<transactional synchronization-factory="claimCheckProducerTxSync"/>
                    	</poller>
                    </inbound-channel-adapter>
                    
                    <chain input-channel="claimCheckListGatewayChannel" output-channel="postReadClaimCheckListGatewayChannel">
                    	<jdbc:outbound-gateway query="SELECT count(*) FROM in_payment_batches WHERE status = 20"
                    						   data-source="dataSource" row-mapper="longSingleColumnRowMapper"/>
                    
                    	<filter expression="payload > 0" discard-channel="postReadClaimCheckListGatewayChannel"/>
                    
                    	<jdbc:outbound-gateway data-source="dataSource" row-mapper="longSingleColumnRowMapper"
                    						   query="SELECT MIN(batch_id) FROM in_payment_batches WHERE status = 20"/>
                    
                    	<jdbc:outbound-gateway data-source="dataSource" row-mapper="claimCheckMapRowMapper"
                    						   max-rows-per-poll="0"
                    						   update="UPDATE in_payment_batches SET status = 30 WHERE batch_id = :payload">
                    		<jdbc:query>
                    			SELECT *
                    			FROM in_payments WHERE batch_id = :payload
                    			and status in (20, 30)
                    		</jdbc:query>
                    		<jdbc:request-handler-advice-chain>
                    			<beans:ref bean="claimCheckProduceExpEvalRHA"/>
                    		</jdbc:request-handler-advice-chain>
                    	</jdbc:outbound-gateway>
                    	<transformer>
                    		<groovy:script>
                    			<![CDATA[ [] + payload ]]>
                    		</groovy:script>
                    	</transformer>
                    	<header-enricher>
                    		<header name="#{PAYMENT_CLAIM_CHECK_CAUSED_BY_SYSTEM}" value="${adapter.id}"/>
                    	</header-enricher>
                    </chain>
                    However it won't be so easy, as it was for <outbound-channel-adapter>: <chain> produces a consumer endpoint, so in case of <inbound-channel-adapter> its infrastructure has to be reworked, to allow to produce MesageProducer Endpoint.

                    We can live without this feature, however we'll add it, when it will be so strongly need.
                    Maybe after Spring Framework 4.0 release we forget about XML at all, and our <chain> sinks into oblivion...

                    Nathan, your turn!

                    Artem

                    Comment


                    • #11
                      Hi Artem, thank you for your thoughtful reply!

                      Your example with the claimCheckProducer is an interesting one. It would be a little simpler in terms of wiring to be able to move the inbound adapter inside the chain, but it's also a scenario where the adapter is not closely related to the internal processing of the chain; it's basically a trigger. And the chain that follows has sufficient size/gravity that the adapter doesn't appear so awkward in its orbit. You would also have flexibility with that configuration to invoke the chain from a different source if necessary. So, it's important to acknowledge that not every adapter/chain scenario is going to make sense to combine.

                      However, in cases where the adapter is closely-related to the endpoints that follow, producer-side chaining does seem to have real compositional value. My use case for SI right now is mapping invalidation events from a content management system to updates to a Solr search index, and I have a number of HTTP inbound adapters where I immediately want to validate and transform the input to a canonical internal format. In my mind, that initial processing sequence is an atomic unit. The raw HTTP adapter isn't something I want to think about on its own. I want to be able to think about the whole assembly as an inbound adapter that receives HTTP and produces valid messages. In an early revision, I found myself grouping a producer-side message handler in the consumer-side chain. Chains have a sort of magnetism, and I had allowed this one to latch onto something that didn't belong there. It was a difficult decision to relocate the misplaced node because the syntax for the producer side didn't compose as nicely.

                      However it won't be so easy, as it was for <outbound-channel-adapter>: <chain> produces a consumer endpoint, so in case of <inbound-channel-adapter> its infrastructure has to be reworked, to allow to produce MesageProducer Endpoint.
                      I'm not sure I understand this statement. I wouldn't recommend touching the inbound adapters. There isn't a consistent class hierarchy to work with there. And I also wouldn't change MessageHandlerChain. Instead, I would adjust the parsing logic to support nesting an inbound adapter, but wire up the beans the same as if they had been declared conventionally. The main change would be to have the ChainParser create an additional anonymous DirectChannel in between. It amounts to "syntactic sugar", but if syntax didn't matter, there wouldn't be 3 different ways of expressing SI flows. If you haven't already, please take a look at the gist I posted in INT-3023. I know that letting the implementing object graph deviate too much from the declared syntax can create headaches, but this doesn't seem like much of a stretch.

                      I'm a newcomer to SI, so I'm still getting acquainted with its philosophy, direction and culture, but I appreciate the purity of its commitment to implementing the EIPs, and I can understand the reluctance to go too far beyond them. I haven't read the book, but my impression is that there's a lot left unsaid about how to assemble EIPs into larger applications. Whether this is by intent (leaving it as an exercise for different implementations) or because there is still theoretical work left to be done on the subject, the fact is that in programming terms, a pure EIP flow is refreshingly elemental, but also a bit primitive. Channels are like GOTOs, and without higher-order structures for composition, large flows risk becoming tangled and unintelligible. Representation matters for EIP flows, and maybe their graphical heritage is part of why it's a challenge to communicate them using conventional, linear syntax. (Although they are also somewhat functional which is an area the DSLs seem well-positioned to explore. I plan to try them out for comparison after my XML-based flow is done.) So, I'll just say that if Spring/SI is going places that will address some of these compositional gaps in a more comprehensive way, then I can understand not wanting to confuse matters with measures that are intermediate and incomplete by comparison. But in the current XML-based syntax for expressing EIPs, I think there's a fairly evident gap which is all I'm trying to see addressed.

                      At the end, I'm not sure what your conclusion is. Like I said in the issue, if the team is good with it, I'd be glad to do the grunt work of cleaning it up, writing tests and submitting a pull request. Or you could take it over if you prefer. Dropping it is an option too, though I hope I've been able to adequately communicate how it could be of value. It's not an urgent need; this is just an itch that I wanted to scratch, so let me know.

                      Comment


                      • #12
                        Hi, Nathan!

                        Well, I see you really need to read the EIP book and this one too: Spring Integration in Action.
                        At least you'll understand what EIP are and where they are suitable.
                        And my recomendation: decouple your application to separate modules, At least via <import resource="classpath:flow-context.xml"/>.
                        And that's why our DSLs introduced a MessageFlow concept. And it will be one of tasks which Spring XD will provide.
                        I'm about your concern to the <chain>. There are many benefits to have channel for all endoint:
                        - MessageHistory
                        - JMX metrics
                        - DRY, when you reuse an existing endpoint in other message flows.

                        And now regarding your task.
                        As I see by your sample you whant to place an HTTP-inbound-adapter to the <chain>. But there it is a component who must be determined by Spring MVC Servlet infrastructure. Thanks to latest change of <chain> (http://static.springsource.org/sprin...sub-components) it may be possible with
                        explicit 'id' of HTTP adapter within chain. BTW, by default chain sub-components aren't registered as beans in the application context.
                        There are many other non-trigerring endpoint (JMS, AMQP, TCP etc.), which also play a role of entry point from external world to the SI-application.
                        So, looking at the Spring Integration concepts more, I'd say 'NO' to the inbound-channel-adapter as first handler of the chain.
                        I think in the future we introduce some analytic, which show endpoints of SI-application for external world with their types and goals.
                        In addition I am against the proposed solutions in your gist: it the same as it is now but without one more attribute about channel.
                        It fully breaks a concept of the chain and doesn't do nothing useful. And don't forget about nested chains:
                        HTML Code:
                        <chain>
                             <chain>
                                <http:inbound-channel-adapter/>
                             </chain>
                        </chain>
                        What does it mean?
                        And if we go ahead, we'll see that there are inboud-gateways. So, should we allow place them within <chain> too ?

                        Conclusion:
                        Endpoints, which are initiated by Spring Integration Message Bus are OK for <chain> and they are now.
                        But endpoints, which are triggered by external world should be separate ones and do their central goal - be channel adapters.
                        The <chain> is some internal component, which isn't so important in the application generally.

                        Take care,
                        Artem

                        Comment


                        • #13
                          I've been reading Spring Integration in Action. I hope to find the time to read the EIP book at some point.

                          I don't think that making chains more symmetrical damages the existing concept. It just makes them useful in a wider variety of situations. But, if it's an unpopular idea, I won't push for it further.

                          You can nest chains due to the XSD allowing "any" (for extensibility), but I've never seen an example of where it would make sense to do so. If there's a use case for that, I'd be interested in seeing it.

                          I haven't seen gateways differentiated as inbound or outbound before. Aren't they just an intermediate call to another system (and fully supported in chains already)?

                          Comment

                          Working...
                          X