Abstract

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.

Transport Layer

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.

Message Layer

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.

Client Pseudocode


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


		

Server Pseudocode


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



		

XML Examples


Protocol Element


<oils:domainObjectAttr value="1" name="protocol"/>

		

threadTrace Element


<oils:domainObjectAttr value="1" name="threadTrace"/>

		

CONNECT Message


<oils:domainObject name="oilsMessage">
	<oils:domainObjectAttr value="CONNECT" name="type"/>
	<oils:domainObjectAttr value="1" name="threadTrace"/>
	<oils:domainObjectAttr value="1" name="protocol"/>
</oils:domainObject>

		

DISCONNECT Message


<oils:domainObject name="oilsMessage">
	<oils:domainObjectAttr value="DISCONNECT" name="type"/>
	<oils:domainObjectAttr value="0" name="threadTrace"/>
	<oils:domainObjectAttr value="1" name="protocol"/>
</oils:domainObject>

		

STATUS Message


<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>

		

REQUEST Message


<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>

		

RESULT Message


<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>