Announcement Announcement Module
Collapse
No announcement yet.
Remoting version of CafeDemo Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Remoting version of CafeDemo

    Hi,

    I have been trying to make a remoting version of DafeDemo, using RMI for the transport.

    I put the Barista in one module called the "server" and the rest in another module called the "client", except for Drink and DrinkType that goes in a "common" module.

    Here is the configuration for the server:

    Code:
      <integration:message-bus/>
    
      <integration:channel id="coldDrinks"/>
      <integration:channel id="hotDrinks"/>
    
      <integration:rmi-gateway id="rmiSourceColdDrinks" request-channel="coldDrinks"/>
      <integration:rmi-gateway id="rmiSourceHotDrinks" request-channel="hotDrinks"/>
    
      <integration:service-activator input-channel="coldDrinks" ref="barista" method="prepareColdDrink"/>
      <integration:service-activator input-channel="hotDrinks" ref="barista" method="prepareHotDrink"/>
    
      <bean name="barista" class="integration.samples.cafe.server.Barista"/>
    and her is the configuration for the client:

    Code:
      <message-bus/>
      
      <channel id="orders"/>
      <channel id="drinks"/>
      <channel id="coldDrinks"/>
      <channel id="hotDrinks"/>
        
      <rmi-handler id="rmiTargetColdDrinks" remote-channel="coldDrinks" host="localhost" />   
      <rmi-handler id="rmiTargetHotDrinks" remote-channel="hotDrinks" host="localhost"/>
                 
      <beans:bean id="drinkRouter" class="integration.samples.cafe.client.DrinkRouter"/>
      <router input-channel="drinks" ref="drinkRouter" method="resolveDrinkChannel" />
    
      <beans:bean id="orderSplitter" class="integration.samples.cafe.client.OrderSplitter"/>
      <splitter input-channel="orders" output-channel="drinks" ref="orderSplitter" method="split"/>
    
      <service-activator input-channel="coldDrinks" ref="rmiTargetColdDrinks"/>
      <service-activator input-channel="hotDrinks" ref="rmiTargetHotDrinks"/>
    
      <beans:bean id="cafe" class="integration.samples.cafe.client.Cafe">
        <beans:property name="orderChannel" ref="orders"/>
      </beans:bean>
    and here is the display from the server:

    Code:
    INFO: message bus started
    message-bus-2 prepared cold drink #1: iced 3 shot MOCHA
    message-bus-1 prepared hot drink #1: hot 2 shot LATTE
    Then, the server seems to be sleeping, while the client has splitted and routed all messages. Only if I stop the server, the client will try sending the other messages and get an error since the server is down.

    Does anyone knows why the server is blocking on each channel and how to avoid this?

    Thanks!

  • #2
    Can you try setting the 'expect-reply' value to false on those RmiGateways?:
    Code:
    <integration:rmi-gateway id="rmiSourceColdDrinks"
                             request-channel="coldDrinks"
                             expect-reply="false"/>
    
    <integration:rmi-gateway id="rmiSourceHotDrinks"
                             request-channel="hotDrinks"
                             expect-reply="false"/>
    The initial requester thread is waiting for the reply, but the Barista has a void return (only prints out a message).

    Comment


    • #3
      Hi Mark,

      Thanks for your answer (and sorry for cross-posting). It works fine with this configuration.

      I missed the info because I dit not realize that <xsd:extension base="gatewayType"> means that the listed attributes are to be added to the base type.

      Comment


      • #4
        Perhaps we should consider defining 'expect-reply' as a required attribute in the XSD. Even though it is a simple boolean, this might help to clear up the confusion, and arguably, there is no strong default value. What do you think?

        Comment


        • #5
          This is an interesting question. A "true" default value makes sense when the call is returning something. But with a void type, a "false" default value seems to make sense. However, I can imagine examples where we would want a void reply (to make the call synchronous) or where we would want to ignore a returned value (although I would probaly not advocate this kind of use case).

          In fact, I do not know Spring-Integration enough at that time to say if a default value is a good thing for this property. It seems that having no default value would probably help in learning the way it works by making the value explicit to the programmer.

          Beside this, what would probably be the more usefull is a reference of all elements and properties with an explanation of the way they should be used, but I understand it is a big job with a low priority. Reading the XSDs does the job, as long as the reader understands it, which was not my case for this problem. But because of this problem, and with your help, I have learnt not only how rmi-gateway works but also how xsd:extension (and BTW xsd:restiction) works. So, for me, it's perfect like this.

          Pierre-Yves

          Comment


          • #6
            Originally posted by alca View Post
            This is an interesting question. A "true" default value makes sense when the call is returning something. But with a void type, a "false" default value seems to make sense. However, I can imagine examples where we would want a void reply (to make the call synchronous) or where we would want to ignore a returned value (although I would probaly not advocate this kind of use case).

            In fact, I do not know Spring-Integration enough at that time to say if a default value is a good thing for this property. It seems that having no default value would probably help in learning the way it works by making the value explicit to the programmer.

            Beside this, what would probably be the more usefull is a reference of all elements and properties with an explanation of the way they should be used, but I understand it is a big job with a low priority. Reading the XSDs does the job, as long as the reader understands it, which was not my case for this problem. But because of this problem, and with your help, I have learnt not only how rmi-gateway works but also how xsd:extension (and BTW xsd:restiction) works. So, for me, it's perfect like this.

            Pierre-Yves
            I think you could better learn the xsd fine with Ctrl-Space in eclipse (that would show you the attribute without you having to parse the xsd in your head), the SpringSource Tool Suite does this out of the box, but with a vanilla Eclipse you have to add wtp I think. Reading xsd might be a useful exercise, but it is definitely time consuming.

            As for the defaults, I am in love with sensible defaults. What's wrong here with SI's behavior is that:
            1. it assumes you want a reply while it doesn't create a reply out of void
            2. it doesn't time out (with a descriptive error)

            Especially the first point bugs me because SI could have known that it wasn't going to work, right? (Figuratively speaking of course)

            Your response makes me think there is a more elegant set of defaults that would resolve the problem than just making the attribute required, although that would work better than what we have now.

            Comment


            • #7
              Originally posted by iwein View Post
              As for the defaults, I am in love with sensible defaults. What's wrong here with SI's behavior is that:
              1. it assumes you want a reply while it doesn't create a reply out of void
              2. it doesn't time out (with a descriptive error)

              Especially the first point bugs me because SI could have known that it wasn't going to work, right? (Figuratively speaking of course)
              I don't see how it could know actually. All that the gateway knows in this example is the 'requestChannel'. If the ultimate receiver is a void-returning method, then no reply would be sent. The problem is that the gateway has no idea what that ultimate receiver is. Adding 'expect-reply=true' is telling the gateway to provide a returnAddress prior to sending the Message and then to wait (up to the timeout) for a reply.

              Maybe a clearer approach would be to provide an RMI "source" in addition to the gateway. Using gateway would always assume request/reply, but source would always imply "one-way".

              Another consideration would be to always return a reply even if just a "status" Message, but obviously that type of change would extend well beyond just the gateways.

              Comment


              • #8
                Originally posted by Mark Fisher View Post
                I don't see how it could know actually. All that the gateway knows in this example is the 'requestChannel'. If the ultimate receiver is a void-returning method, then no reply would be sent. The problem is that the gateway has no idea what that ultimate receiver is.
                Well, it is quite unreasonable, but to the user it would seem that if you view Spring Integration as a big black box you might expect it to understand about the relationships between components at configuration time, even if they are separated by a channel. You're probably right if you don't want to complicate things that far.

                Comment


                • #9
                  Originally posted by iwein View Post
                  I think you could better learn the xsd fine with Ctrl-Space in eclipse (that would show you the attribute without you having to parse the xsd in your head), the SpringSource Tool Suite does this out of the box, but with a vanilla Eclipse you have to add wtp I think. Reading xsd might be a useful exercise, but it is definitely time consuming.
                  I feel reading the XSD is definitely worth the time spent on it. I allows to learn the relationship between the various elements wether using Ctrl-Space in Eclipse only lists the properties without showing where they come form. But this is a matter of taste.

                  Especially the first point bugs me because SI could have known that it wasn't going to work, right? (Figuratively speaking of course)
                  This would be smart, but wouldn't it be too smart? As it is, it fails, but I eventually know why an can deal with it. If SI was to decide on itself if a reply is expected, it would work and I would not know why. The problem is it might not work the way I intended.

                  I modified the example to make the method return a value, although I still do not want the value to be returned by the gateway. If SI was to decide, it would see that the method is returning a value and it would configure the gateway accordingly, which is not what I want in my new use case. So, I would need a way to overide this behavior.

                  This could be done by letting SI decide from the method in case the expect-reply attribute is not present, and conform to the attribute value if present.

                  This is a bit complicated and would probably lead to a situation of "positive error" where the application works as expected, but for a different reason than what was intended. This might break when the application is later modified.

                  So, my preference would go to no default value, which makes things more explicit.

                  Pierre-Yves

                  Comment

                  Working...
                  X