(re-sent, since apparently the mailing list didn't like my previous
attempt)

Hello.

I am using expand_modules at work. It may not be the best solution to
my problem, but it seemed appropriate. Let's see if I can describe
what I'm doing.

I have a thing that just happens to be a Catalyst application, using
Catalyst::Engine::Stomp to respond to ActiveMQ messages instead of
HTTP requests. Since the actual logic of the application does not
depend on the fact that we're using Catalyst as a module loader and
dispatcher, I have written a sort of "insulation layer" between
Catalyst and the actual business logic.

The "insulated" consumer modules look like this:

  package MyApp::Consume::Something;
  use Moose;
  extends 'MyFramework::Base::Consume';

  sub routes {
    return {
      a_queue_name => {
        a_message_type => \&a_method_to_handle_it,
        another_message_type => \&you_get_the_idea,
      },
      a_different_queue => {
        and_so => \&on_and_on,
      },
    }
  }

  # here go the actual subs / methods

The MyFramework::Base::Consume class is a Catalyst::Component (well,
better said, ->can('COMPONENT')), and implements a expand_modules
method that does more or less this:

- collect the queues this module wants to listen on
- create (via Moose::Meta::Class->create, and only if it's not already
  there) a Catalyst Controller per queue, under the appropriate
  namespace (the controller inherits from
  Catalyst::Controller::MessageDriven, part of the
  Catalyst::Engine::Stomp distribution)
- add a "after 'register_actions'" modifier on the controller to
  create the actions that will dispatch the message to the appropriate
  method as required

Pseudo-code:

  sub expand_modules {
    my ($class) = @_;
    my @ret = ();
    for my $queue (keys %{$class->routes}) {
      my $controller_name = the_name_for($queue);
      if (not is_controller_there($controller_name)) {
         create_controller($controller_name,$queue);
      }
      for my $message_type (keys %{$class->routes->{$queue}}) {
         add_after_register_actions(
            $controller_name,
            $message_type,
            $class->routes->{$queue}{$message_type}
         );
      }
      push @ret, $controller_name;
    }
    return @ret;
  }

Answers to some probable questions:

- Can't your Consume modules be Controllers, and then you do
  $something to the Dispatcher?

  Maybe, but Catalyst::Engine::Stomp /
  Catalyst::Controller::MessageDriven do enough strange things to the
  dispatch, and I prefer not to rewrite them

- Do you really need to insulate your modules so much from Catalyst?

  There is talk to use some other system to handle ActiveMQ in the
  future, and I don't want to have to touch my code more than strictly
  necessary

- How the &%$%$^# did you think this was a good idea?

  Well, it *is* documented :) And it seems to be the obvious hook:
  when loaded, my component creates more components…

Questions:

- am I insane? :)

- is there a better / cleaner / more future-proof way of getting the
  same result?

- will the "much better solution" that t0m hinted at still allow me
  this kind of contortions?

Thanks :)

-- 
        Dakkar - <Mobilis in mobile>
        GPG public key fingerprint = A071 E618 DD2C 5901 9574
                                     6FE2 40EA 9883 7519 3F88
                            key id = 0x75193F88

"Why's it called Ming?" said the Archchancellor, on cue.
The Bursar tapped the pot. It went *ming*.
        -- Discworld archeology revealed
           (Terry Pratchett, Moving Pictures)

_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/

Reply via email to