Transports and Channels
Channels and Transports provide the basic unit of communication in XFire. A Channel simply sends messages (via send()) and listens for messages (via receive()). If you want to send a message to a particular URL you do:
Each transport is responsible for creating its own protocol specific listener, for example a servlet in the case of HTTP. This listener then passes whatever messages it receives to the channel via Channel.receive(MessageContext,InMessage). Channels simply delegate their receive() to a ChannelEndpoint which application specific handling of what to do with the message. The default endpoint is aptly named DefaultEndpoint and will be covered in the next section.
Each OutMessage has a MessageSerializer. A message serializer takes the message body (message.getBody()) and writes it to an XMLStreamWriter that the Channel provides. The semantics of MessageSerializers should be such that they can be invoked multiple times.
Channels/Transports without Services
Its important to note that Channels and transports are completely independent of XFire's Services. So I can use a channel to send a receive messages and never even create a service. So for testing, lets not even create a service. We'll want to just use the Channel to send and receive messages.
DefaultEndpoint and the processing flow
DefaultEndpoint takes a message, creates a default message exchange called InMessageExchange and creates a message pipeline. The message pipeline at first consists of the global in handlers from XFire.getInHandlers() and the transport handlers from Transport.getInHandlers. Later on when the service is resolved, the service's handlers get added into the pipeline. Once the operation is resolved, if there is an out message to be set an Out pipeline is created and added to the MessageContext.
Phases and Handlers
See Processing Pipeline for now.
SOAPTransport.createTransport() adds SOAP support to a particular transport. It does so by adding three additional handlers:
- ReadHeaderHandler - this handler reads in the soap headers. It stops reading the XML stream the moment the whitespace stops after the <Body> tag. If it encounters a <Fault> in the Body, an XFireFault is thrown.
- ValidateHeadersHandler - Ensure that all the necessary headers are understood by the receiving handlers.
- SoapSerializerHandler - Services provide a MessageSerializer of their own which is responsible for serializing the soap body. But what about the message headers? This is written out by the SoapSerializer. What the SoapSerializerHandler does is replace the outMessage.MessageSerializer with new SoapSerializer(outMsg.getMessageSerializer()).
WS-RM Architecture Plan
There will be two transports involved in this. First, the low-level transport like HTTP, UDP or TCP. We'll use UdpTransport for the examples below. Second, there is the WS-RM Transport - WSRMTransport.
The high-level ws-rm document outlines the basic sequence which I'll refer to:
- App gets ready to send its message
- WS-RM sends CreateSequence
- Receive CreateSequence Response
- Send app message (initial transmission in spec) which has WS-RM sequence headers
- Receive acknowledgements
- If acknowledgement is missing after X amount of time, resend message
- TerminateSequence when done
The server side correlate:
- WS-RM receives CreateSequence
- WS-RM sends CreateSequence Response
- Receive InMessage which has WS-RM sequence headers
- Send acknowledgements
- Pass off application message to Service, unless out of order
- Receive TerminateSequence when done
Ideally I'd like to be able to do:
When an application does WSRMChannel.send() it will handle the sequence processing and ultimately use UdpChannel to send its messages. When UdpTransport receives its messages, we'll need them to delegate on up to the WSRMTransport. To do this we'll need to create a new ChannelEndpoint which does this.
- Make sure WS-A MessageID/RelatesTo functions as needed
- Make sure fault handling in XFire is appropriate for WS-RM