NAME

Plack::Handler::Stomp - adapt STOMP to (almost) HTTP, via Plack

VERSION

version 1.07

SYNOPSIS

my $runner = Plack::Handler::Stomp->new({
  servers => [ { hostname => 'localhost', port => 61613 } ],
  subscriptions => [
    { destination => '/queue/plack-handler-stomp-test' },
    { destination => '/topic/plack-handler-stomp-test',
      headers => {
          selector => q{custom_header = '1' or JMSType = 'test_foo'},
      },
      path_info => '/topic/ch1', },
    { destination => '/topic/plack-handler-stomp-test',
      headers => {
          selector => q{custom_header = '2' or JMSType = 'test_bar'},
      },
      path_info => '/topic/ch2', },
  ],
});
$runner->run(MyApp->get_app());

DESCRIPTION

Sometimes you want to use your very nice web-application-framework dispatcher, module loading mechanisms, etc, but you're not really writing a web application, you're writing a ActiveMQ consumer. In those cases, this module is for you.

This module is inspired by Catalyst::Engine::Stomp, but aims to be usable by any PSGI application.

Roles Consumed

We consume Net::Stomp::MooseHelpers::CanConnect and Net::Stomp::MooseHelpers::CanSubscribe. Read those modules' documentation to see how to configure servers and subscriptions.

ATTRIBUTES

logger

A logger object used by thes handler. Not to be confused by the logger used by the application (either internally, or via a Middleware). Can be any object that can debug, info, warn, error. Defaults to an instance of Plack::Handler::Stomp::StupidLogger.

destination_path_map

A hashref mapping destinations (queues, topics, subscription ids) to URI paths to send to the application. You should not modify this.

one_shot

If true, exit after the first message is consumed. Useful for testing, defaults to false.

METHODS

run

Given a PSGI application, loops forever:

If the application throws an exception, the loop exits re-throwing the exception. If the STOMP connection has problems, the loop is repeated with a different server (see next_server in Net::Stomp::MooseHelpers::CanConnect).

If "one_shot" is set, this function exits after having consumed exactly 1 frame.

frame_loop

Loop forever receiving frames from the STOMP connection. Call "handle_stomp_frame" for each frame.

If "one_shot" is set, this function exits after having consumed exactly 1 frame.

handle_stomp_frame

Delegates the handling to "handle_stomp_message", "handle_stomp_error", "handle_stomp_receipt", or throws Plack::Handler::Stomp::Exceptions::UnknownFrame if the frame is of some other kind. If you want to handle different kind of frames (maybe because you have some non-standard STOMP server), you can just subclass and add methods; for example, to handle STRANGE frames, add a handle_stomp_strange method.

handle_stomp_error

Logs the error via the "logger", level warn.

handle_stomp_message

Calls "build_psgi_env" to convert the STOMP message into a PSGI environment.

The environment is then passed to "process_the_message", and the frame is acknowledged.

process_the_message

Runs a PSGI environment through the application, then flattens the response body into a simple string.

The response so flattened is sent back via "maybe_send_reply".

handle_stomp_receipt

Logs (level debug) the receipt id. Nothing else is done with receipts.

maybe_send_reply

Calls "where_should_send_reply" to determine if to send a reply, and where. If it returns a true value, "send_reply" is called to actually send the reply.

where_should_send_reply

Returns the header X-Reply-Address or X-STOMP-Reply-Address from the response.

send_reply

Converts the PSGI response into a STOMP frame, by removing the prefix x-stomp- from the key of header fields that have it, removing entirely header fields that don't, and stringifying the body.

Then sends the frame.

subscribe_single

after modifier on the method provided by Net::Stomp::MooseHelpers::CanSubscribe.

It sets the "destination_path_map" to map the destination and the subscription id to the path_info slot of the "subscriptions" element, or to the destination itself if path_info is not defined.

build_psgi_env

Builds a PSGI environment from the message, like:

# server
SERVER_NAME => 'localhost',
SERVER_PORT => 0,
SERVER_PROTOCOL => 'STOMP',

# client
REQUEST_METHOD => 'POST',
REQUEST_URI => $path_info,
SCRIPT_NAME => '',
PATH_INFO => $path_info,
QUERY_STRING => '',

# broker
REMOTE_ADDR => $server_hostname,

# http
HTTP_USER_AGENT => 'Net::Stomp',
HTTP_CONTENT_LENGTH => length($body),
HTTP_CONTENT_TYPE => $content-type,

# psgi
'psgi.version' => [1,0],
'psgi.url_scheme' => 'http',
'psgi.multithread' => 0,
'psgi.multiprocess' => 0,
'psgi.run_once' => 0,
'psgi.nonblocking' => 0,
'psgi.streaming' => 1,

In addition, reading from psgi.input will return the message body, and writing to psgi.errors will log via the "logger" at level error.

Finally, every header in the STOMP message will be available in the "namespace" jms., so for example the message type is in jms.type.

The $path_info is obtained from the "destination_path_map" (i.e. from the path_info subscription options) passed through munge_path_info.

EXAMPLES

You can find examples of use in the tests, or at https://github.com/dakkar/CatalystX-StompSampleApps

AUTHOR

Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Net-a-porter.com.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.