STOMP stands for the Simple (or Streaming) Text Oriented Messaging Protocol. STOMP provides an interoperable wire format so that STOMP clients can communicate with any STOMP message broker to provide easy and widespread messaging interoperability among many languages, platforms and brokers.
STOMP is loosely modeled after the HTTP protocol, where "messages" will typically start with an uppercase command (like GET in HTTP), followed by a number of headers (format is similar) and possibly followed by a body. Messages are ended by ^@, i.e. the zero character, aka ASCII 0, '\0'. STOMP advocates utf-8 on the wire and provides mechanisms that keep the connection alive, if necessary, thus making sure routers do not close connections. The complete specification is rather short and specifically targets scripting languages.
As I (EF) needed to understand STOMP in a better way, and despite there was already an implementation available at [L1 ], I decided to start coding it from scratch again. An earlier implementation of the resulting library is in the half-bakery [L2 ]. The library offers both a client and server implementation. The client implementation is almost complete, it is only missing support for transactions. The whole implementation has now moved to github . Please report issues and proposal for improvements through the facilities offered by github .
My client implementation differentiates itself from the other in the following ways:
The server supports the following features:
The current implementation has had little testing, initial tests against the Apache Apollo broker have shown proper behaviour. Please send any positive or negative feedback to me on the usual channels.
As part of the new project on github, three small utilities exist to exhibit the capabilities of the library:
The following script highlights some of the capabilities of the client library, there is example code to instantiate the server at the bottom of this page.
package require stomp::client proc received { cid rid } { puts "Server has received message, id: $rid" } proc incoming { msg } { puts "Incoming message: [::stomp::message::getCommand $msg]" } # Connect to broker (following is default admin user for Apollo) set s [::stomp::client::connect -user admin -password password] # Subscribe to a queue at the server and arrange to receive # messages for that queue in the procedure called "incoming" # We wait before the subscription because connecting to a server # implies a handshake mechanism. Instead, we could use the # introspection mechanisms provided by the -liveness option to # ::stomp::client::connect after 1000 ::stomp::client::subscribe $s /queue/a \ -handler incoming # Send a message to the same queue, meaning we'll receive it # in the "incoming" procedure. Also make sure we'll receive # a receipt for the message in the procedure "received" after 2000 ::stomp::client::send $s /queue/a -body "Hello world" -receipt received # Disconnect after a while, you might want to force disconnection from # the web UI at the server to see what happens in the mean time. after 60000 ::stomp::client::disconnect $s # Live for ever.. vwait forever
APN Very much interested in this, the server side as well. So happens I was looking for a simple message broker implementation in script and your post showed up. Serendipity!
EF You are welcome, and please try it as it's really in its early days... :) As long as you're not too impatient, I hope to be able to finish up some initial version of the server within the next few weeks. It needs some refactoring, moving out most of the actual code to a ::stomp::client namespace so I can start having common procedures in ::stomp and start with a ::stomp::server.
APN Any thought of putting it in a public repository ? The half-bakery is not the most convenient for keeping track of changes.
APN Tried it (took an hour to set up Apollo thanks to spaces in the path to the JRE). Looks pretty good. Stopped and restarted Apollo and life went on without a hitch. Didn't see how to get the data of received message so directly accessed the ::stomp::message::msg_* array. Also binary data did not seem to get through, probably I have to explicitly set the content-length header. Looks like a great start.
For anyone else interested in trying this out, here is a summary of steps to set up Apache Apollo on Windows:
set JAVA_HOME=c:\src\jdk1.7.0_21 (Note no quotes around the path even if it has spaces else batch files will fail) cd c:\src\stomp-test C:\bin\x86\apache-apollo-1.6\bin\apollo create mybroker mybroker\bin\apollo-broker.cmd run
EF It'll probably end up in my efr-tools , or if suitable in the tcllib (dreaming?). There are a number of procedures to access the messages ::stomp::message::get*. This is loosely based on the API of the HTTP package where you have a set of procedures to access the most usual bits and pieces, but where you can access the array directly. There is some code to set the content-length automatically if you haven't set it, to be frank... there might be bugs there!
EF New version in the half-bakery. I have started to refactor the code, so most procedures now live in the ::stomp::client namespace instead, the main namespace being mostly empty. The new version behaves properly on binary messages, a bug that you APN had discovered. There is now a complete set of ::stomp::message::get* procedure to access the content of the messages, for example from a callback. I've updated the code example above to reflect the API change.
Can somebody help me so that some of the internal procedures from the main ::stomp namespace are directly available from, say the ::stomp::client namespace without having to prefix namespace parent:: to calls? You'll see an attempt at the beginning of the client.tcl implementation, but that does not work for GetOpt since that one relies on uplevel... I am looking for aliasing or similar...
APN How about using namespace path ? Something like
namespace eval ::stomp::client { namespace path [linsert [namespace path] 0 [namespace parent]] }
EF Indeed, I was. Thank you very much! but that is construct which appeared in 8.5, meaning that it cannot be used when run under JTcl, which is one of my goals. Any other solution would be appreciated since the latest version performs some introspection in the linked procedures to access the variables from the callers. (ugly) APN Does JTcl support namespace import ? You could use that. Or perhaps even interp alias instead of proc wrappers. The problem with proc wrappers is that they introduce an additional frame level so it is difficult to write procs that use uplevel/upvar (the number of levels up depends on whether the proc is called from the same namespace or another namespace).
EF New version available in the half-bakery, now with some server-side code, able to handle both binary and textual messages. Creating the server is as simple as the following code. Updating the top of this page to describe the feature-set of the server.
package require stomp::server set s [::stomp::server::new] vwait forever
APN Played with latest version. Seems to work as advertised in basic usage.
EF New version, changed how packages depend between one another (see package require calls in the (updated) examples above) and adding a few features that were missing from the implementations: