answers in-lined at the bottom ...
On 16 Nov 2005, at 05:00, Peter Smith wrote:
Geez...this is probably going to cause
somebody a headache. I'm sorry about that - I am just trying to
understand how the architecture works
This email is specifically about the JMSFlow NMR flow type. I am
looking at the ServiceMix 2.0.1 JMSFlow code revision 749 which is
latest AFAIK. Unfortunately I am not in a position to be running this
yet, which means all this email is based just on me staring at the code
for a couple of hrs...
If somebody who knows the implementation details could go through this
and confirm my understanding of JMSFlow it would be a big help.
Here goes....
My understanding of JMSFlow
======================
- There is a main broadcast Topic and a number of Queues
(container specific Queues & Queues for each component)
- Topic is for broadcasting changes to remote containers
- Also for getting advisories if remote container
activated/deactivated
- Queue (per component) is for routing messages to...
- Queue (container) is also for routing messages...
- The JMSFlow instance seems to be the sole JMS MessageListener
for all these Queues/Topics
- The JMSFlow is also an ActiveMQ ConsumerAdvisoryEventListener
meaning it is notified of the start/stop of Consumers for the broadcast
Topic - ie when some other container runs the JMSFlow init/shutdown
- onMessage - JMS MessageListener for Queues/Topic
- ObjectMessage might be a MessageExchangeImpl (for message
routing) OR a ComponentPacketEvent (notifying some change in a remote
component)
- If ComponentPacketEvent
- add/update/remove local knowledge of the remote component
depending on the ComponentPacketEvent status
- If MessageExchangeImpl
- AbstractFlow.doRouting does message routing for the
incoming message to some local component
- onEvent(ConsumerAdvisoryEvent event). I think this is called
when some remote Consumer (ie container/JMSFlow instance) of the Topic
starts/stops
- If remote consumer is stopping
- trash all knowledge of the container components for the
remote container that is leaving
- If remote consumer is starting
- call onEvent(ComponentPacketEvent) for ALL of the LOCAL
container components. I think the main purpose of this is to make use
of the side effect to tell the remote container all the components that
are available to it from this local container. Presumably it there were
a dozen container then remote container 'X' is started then all the
other dozen would be advised that 'X' had started and they would madly
broadcast their respective components to the Topic so container 'X'
would learn about them.
- onEvent(ComponentPacketEvent event)
- I think this is called when a LOCAL component is
activated/deactivated
- Each component has a Queue associated with it and the
JMSFlow instance is the message listener for this Queue [see onMessage]
- Activation makes queue & consumer
- Deactivation closes the consumer for that component Queue
- doSend/doRouting - routing for outgoing messages...
- ObjectMessage send to either Queue for container or Queue
for specific component
QUESTIONS
==========
- In the init() method, how come the connection.start is called
prior to setting up the message listeners. Maybe it makes no difference
- just curious.
This doesn't make any difference - it's just habit on my part.
- I am a bit confused by the terminology "remote" used
throughout JMSFlow? Does it make any difference at all to JMSFlow if
the container (ie JMSFlow instance) is on another machine versus just
another container instance on the same machine. I think there is no
distinction - is that true?
That's correct - it doesn't make any difference to JMS where the other
instances of the JMSFlow are. However, the remote - methods are dealing
with ComponentPackets that are received from the broadcast topic - so
it's to make the distinction between locally activated packets and ones
created by other instances.
- If I understand the onEvent(ConsumerAdvisoryEvent event)
method correctly then that will mean that if a lot of containers get
started, then the same ComponentPacketEvents will be sent to the
broadcast Topic a number of times. That would mean most of the (already
started) containers will be told again and again about remote
components that they already know about. Is that true? How is the
addRemotePacket method is accounting for this scenario (???)
Yes this is true - but the ComponentRegistry only gets updated if it
doesn't already know about the activation of the Component
Quite a few JMS vendors allow for dynamic creation of destinations
(topics/queues) - ActiveMQ does this - and as the JMSFlow is dependant
on ActiveMQ (the advisories are outside the JMS spec) - I decided to
use this feature.
- If onEvent(ConsumerAdvisoryEvent event) is called whenever
some remote container starts, but because it in turn calls
onEvent(ComponentPacketEvent event) pretending to ACTIVATE local
components won't it just end up creating the same queues for the local
components over and over and over again (???)
Yep! Bug! Well spotted. The affect of this doesn't affect functionality
(as The Queue's don't created until a message is sent to them) but it
is a memory leak.
- I don't really understand the distinction of routing the
message to Queue (destination = INBOUND_PREFIX + componentName;) or
Queue (destination = INBOUND_PREFIX + id.getContainerName();). Can you
explain why the difference? It seems to be something like the "request"
going to the remote container Queue, and the "response" is going to the
component specific Queue - but why and what difference does it make
since either way the remote MessageListener is the same isn't it?
The routing is done this way because queue's will load balance delivery
of MessageExchanges. So you can have multiple component
instances listening to the same Queue. However, the response needs to
be sent back to the component that sent the exchange - as the sender
could have sent the exchange synchronously - and is waiting for a
response.