The OpenSRF messaging system works on two different primary layers: the transport layer and the application layer. The transport layer manages virtual connections between client and server, while the application layer manages user/application level messages. All messages must declare which protocol version they are requesting. The current protocol level is 1.
There are currently three types of messages in the transport layer: CONNECT, STATUS, and DISCONNECT.
STATUS messages provide general information to the transport layer and are used in different
ways throughout the system. They are sent primarily by the server in response to client requests.
Each message comes with
a status and statusCode. The actual status part of the STATUS message is just a helpful message
(mostly for debugging). The
statusCode is an integer representing the exact status this message represents. The status codes
are modeled after HTTP status codes. Currently used codes consist of the following:
100 STATUS_CONTINUE
200 STATUS_OK
205 STATUS_COMPLETE
307 STATUS_REDIRECTED
400 STATUS_BADREQUEST
404 STATUS_NOTFOUND
408 STATUS_TIMEOUT
417 STATUS_EXPFAILED
This list is likely to change at least a little.
The CONNECT message initiates the virtual connection for a client and expects a STATUS in return. If the connection is successful, the statusCode for the STATUS message shall be STATUS_OK.
If at any point the client sends a non-connect message to the server when the client is not connected or the connection has timed out, the STATUS that is returned shall have statusCode STATUS_EXPFAILED.
The DISCONNECT message is sent by the client to the server to end the virtual session. The server shall not respond to any disconnect messages.
There are currently two types of message layer messages: REQUEST and RESULT. REQUEST messages represent application layer requests made by a client and RESULT messages are the servers response to such REQUEST's.
By design, all CONNECT and REQUEST messages sent by a client will be acknowledged by one or more responses from the server. This is much like the SYN-ACK philosophy of TCP, however different in many ways. The only guarantees made by the server are 1. you will know that we received your request and 2. you will know the final outcome of your request. It is the responsibility of the actual application to send the requested application data (e.g. RESULT messages, intermediate STATUS messages).
The server responses are matched to client requests by a threadTrace. A threadTrace is simply a number and all application layer messages and STATUS messages are required to have one. (Note that the threadTrace contained within a STATUS message sent in response to a CONNECT will be ignored). Currently, there is no restriction on the number other than it shall be unique within a given virtual connection. When the server receives a REQUEST message, it extracts the threadTrace from the message and all responses to that request will contain the same threadTrace.
As mentioned above, every CONNECT message will be acknowledged by a single STATUS message. REQUEST's are a little more complex, however. A REQUEST will receive one or more RESULT's if the REQUEST warrants such a response. A REQUEST may even receive one or more intermediate STATUS's (e.g. STATUS_CONTINUE). (Consult the documentation on the application request the client is requesting for more information on the number and type of responses to that request). All REQUEST's, however, regardless of other response types, shall receieve as the last response a STATUS message with statusCode STATUS_COMPLETE. This allows the client to wait for REQUEST "completeness" as opposed to waiting on or calculating individual responses.
send CONNECT msg = recv() if ( msg.statusCode == STATUS_OK ) OK. continue while ( more requests ) { /* you may send multiple requests before processing any responses. For the sake of this example, we will only walk through a single client request */ send REQUEST with threadTrace X while ( response = recv ) { if ( response.threadTrace != X ) continue/ignore if ( response.type == STATUS ) if ( response.statusCode == STATUS_TIMEOUT or response.statusCode == STATUS_REDIRECTED or response.statusCode == STATUS_EXPFAILED) resend the the request with threadTrace X because it was not honored. if ( response.statusCode == STATUS_COMPLETE ) the request is now complete, nothing more to be done with this request break out of loop if ( response.typ == RESULT ) pass result to the application layer for processing } // receiving } // sending
while( message = recv() ) { if( message.type != CONNECT ) return a STATUS with statusCode STATUS_EXPFAILED start loop over if ( message.type == CONNECT ) return STATUS with statusCode STATUS_OK and continue while ( msg = recv() and virtual session is active ) { if ( msg.type == REQUEST ) Record the threadTrace. Pass the REQUEST to the application layer for processing. When the application layer has completed processing, respond to the client with a STATUS message with statusCode STATUS_COMPLETE and threadTrace matching the threadTrace of the REQUEST. Once the final STATUS_COMPLETE message is sent, the session is over. Return to outer server loop. /* Note: during REQUEST processing by the application layer, the application may opt to send RESULT and/or STATUS messages to the client. The server side transport mechanism is not concerned with these messages. The server only needs to be notified when the REQUEST has been sucessfully completed. */ if( message.type == DISCONNECT ) Virtual session has ended. Return to outer loop. } // Sessin loop } // Main server loop
<oils:domainObjectAttr value="1" name="protocol"/>
<oils:domainObjectAttr value="1" name="threadTrace"/>
<oils:domainObject name="oilsMessage"> <oils:domainObjectAttr value="CONNECT" name="type"/> <oils:domainObjectAttr value="1" name="threadTrace"/> <oils:domainObjectAttr value="1" name="protocol"/> </oils:domainObject>
<oils:domainObject name="oilsMessage"> <oils:domainObjectAttr value="DISCONNECT" name="type"/> <oils:domainObjectAttr value="0" name="threadTrace"/> <oils:domainObjectAttr value="1" name="protocol"/> </oils:domainObject>
<oils:domainObject name="oilsMessage"> <oils:domainObjectAttr value="STATUS" name="type"/> <oils:domainObjectAttr value="0" name="threadTrace"/> <oils:domainObjectAttr value="1" name="protocol"/> <oils:domainObject name="oilsConnectStatus"> <oils:domainObjectAttr value="Connection Successful" name="status"/> <oils:domainObjectAttr value="200" name="statusCode"/> </oils:domainObject> </oils:domainObject>
<oils:domainObject name="oilsMessage"> <oils:domainObjectAttr value="REQUEST" name="type"/> <oils:domainObjectAttr value="4" name="threadTrace"/> <oils:domainObjectAttr value="1" name="protocol"/> <oils:domainObject name="oilsMethod"> <oils:domainObjectAttr value="mult" name="method"/> <oils:params>[1, 2]</oils:params> </oils:domainObject> </oils:domainObject>
<oils:domainObject name="oilsMessage"> <oils:domainObjectAttr value="RESULT" name="type"/> <oils:domainObjectAttr value="4" name="threadTrace"/> <oils:domainObjectAttr value="1" name="protocol"/> <oils:domainObject name="oilsResult"> <oils:domainObjectAttr value="OK" name="status"/> <oils:domainObjectAttr value="200" name="statusCode"/> <oils:domainObject name="oilsScalar">2</oils:domainObject> </oils:domainObject> </oils:domainObject>