Stomp protocol provides an interoperable wire format so that any of the available Stomp Clients can communicate with any Stomp Message Broker to provide easy and widespread messaging interop among languages, platforms and brokers.

The Delphi Stomp Client is an open source implementation of the STOMP protocol for Delphi 2010 (should work with Delphi 2007 and 2009 too) and FreePascal 2.4.x.

This Delphi Stomp Client isn’t an attempt to copy JMS client architecture to Delphi. So aren’t included some JMS specific features like message transformations.

This stomp client is actually tested on ActiveMQ 5.2 and ActiveMQ 5.3, but should work with every STOMP compliant server.

In Delphi you can use the built-in INDY component suite or the OpenSource Synapse acording with a compiler directive. In StompClient.pas there is following definitions:

  1. unit StompClient;
  2.  
  3. // For FreePascal users:
  4. // Automatically selected synapse tcp library
  5. {$IFDEF FPC}
  6. {$MODE DELPHI}
  7. {$DEFINE USESYNAPSE} //FREEPASCAL ALWAYS USE SYNAPSE
  8. {$ENDIF}
  9. // For Delphi users:
  10. // Decomment following line to use synapse also in Delphi
  11. { .$DEFINE USESYNAPSE } //DELPHI USERS CAN USE INDY OR SYNAPSE

Some examples of basic functionalities (not real world example, use included examples instead):

  1. program SimpleMessaging;
  2. {$APPTYPE CONSOLE}
  3.  
  4. uses
  5.   SysUtils, StompClient, StompTypes;
  6.  
  7. procedure Example_Pub_Subscriber;
  8. var
  9.   StompPub, StompSubscriber: IStompClient;
  10.   StompFrame: IStompFrame;
  11. begin
  12.   WriteLn('==> Example_Pub_Subscriber');
  13.   StompSubscriber := StompUtils.NewStomp('127.0.0.1'); // default port
  14.   StompSubscriber.Subscribe('/topic/dummy');
  15.   StompPub := StompUtils.NewStomp('127.0.0.1'); // default port
  16.   StompPub.Send('/topic/dummy', 'Some test message');
  17.   repeat
  18.     StompFrame := StompSubscriber.Receive;
  19.   until Assigned(StompFrame);
  20.   WriteLn(StompFrame.GetBody); // Print "Some test message"
  21.   WriteLn;
  22. end;
  23.  
  24. procedure Example_OnePub_TwoSubscriber;
  25. var
  26.   StompPub, StompSub1, StompSub2: IStompClient;
  27.   StompFrame: IStompFrame;
  28. begin
  29.   WriteLn('==> Example_OnePub_TwoSubscriber');
  30.   StompSub1 := StompUtils.NewStomp('127.0.0.1'); // default port
  31.   StompSub2 := StompUtils.NewStomp('127.0.0.1'); // default port
  32.   StompSub1.Subscribe('/topic/dummy');
  33.   StompSub2.Subscribe('/topic/dummy');
  34.  
  35.  
  36.   StompPub := StompUtils.NewStomp('127.0.0.1'); // default port
  37.   StompPub.Send('/topic/dummy', 'First test message on a topic');
  38.   StompPub.Send('/topic/dummy', 'Second test message on a topic');
  39.  
  40.   StompFrame := StompSub1.Receive(2000);
  41.   if Assigned(StompFrame) then
  42.     WriteLn(StompFrame.GetBody);
  43.   StompFrame := StompSub1.Receive(2000);
  44.   if Assigned(StompFrame) then
  45.     WriteLn(StompFrame.GetBody);
  46.  
  47.   StompFrame := StompSub2.Receive(2000);
  48.   if Assigned(StompFrame) then
  49.     WriteLn(StompFrame.GetBody);
  50.   StompFrame := StompSub2.Receive(2000);
  51.   if Assigned(StompFrame) then
  52.     WriteLn(StompFrame.GetBody);
  53.   WriteLn;
  54. end;
  55.  
  56. procedure Example_PointToPoint;
  57. var
  58.   StompPub, StompSub1, StompSub2: IStompClient;
  59.   StompFrame: IStompFrame;
  60. begin
  61.   WriteLn('==> Example_PointToPoint');
  62.   StompSub1 := StompUtils.NewStomp('127.0.0.1'); // default port
  63.   StompSub2 := StompUtils.NewStomp('127.0.0.1'); // default port
  64.   StompSub1.Subscribe('/queue/dummy');
  65.   StompSub2.Subscribe('/queue/dummy');
  66.  
  67.   StompPub := StompUtils.NewStomp('127.0.0.1'); // default port
  68.   StompPub.Send('/queue/dummy', 'First test message on a queue');
  69.   StompPub.Send('/queue/dummy', 'Second test message on a queue');
  70.  
  71.   StompFrame := StompSub1.Receive(2000);
  72.   if Assigned(StompFrame) then
  73.     WriteLn(StompFrame.Output);
  74.   StompFrame := StompSub1.Receive(2000);
  75.   if Assigned(StompFrame) then
  76.     WriteLn(StompFrame.Output);
  77.  
  78.   StompFrame := StompSub2.Receive(2000);
  79.   if Assigned(StompFrame) then
  80.     WriteLn(StompFrame.Output);
  81.   StompFrame := StompSub2.Receive(2000);
  82.   if Assigned(StompFrame) then
  83.     WriteLn(StompFrame.Output);
  84.  
  85.   WriteLn;
  86. end;
  87.  
  88.  
  89. begin
  90.   try
  91.     Example_Pub_Subscriber;
  92.     Example_OnePub_TwoSubscriber;
  93.     Example_PointToPoint;
  94.   except
  95.     on E: Exception do
  96.       WriteLn(E.ClassName, ': ', E.message);
  97.   end;
  98. end.

DelphiStompClient have also a simple listener for asynchronous use. To use the listener you should implement follwing interface:

  1.   IStompClientListener = interface
  2.     ['{C4C0D932-8994-43FB-9D32-A03FE86AEFE4}']
  3.     procedure OnMessage(StompFrame: IStompFrame);
  4.   end;

Also a normal form can be used

  1.   TForm1 = class(TForm, IStompClientListener)
  2.  
  3.   public
  4.     procedure OnMessage(StompFrame: IStompFrame);  //Called by the stomp receiver
  5.   end;

And then you can manager your message in a simple form’s method.

There are many features in this STOMP client. I’ve tried to respect all the STOMP specs also in the transactions side (http://stomp.codehaus.org/Protocol).

You can find all the source code and the examples at following Google Code Project:
http://code.google.com/p/delphistompclient/

The FreePascal version is actually mantained by Daniel Gaspary, thank Daniel.