NAME

POE::Session::Multiplex - POE session with object multiplexing

SYNOPSIS

use POE;
use POE::Session::Multiplex;

My::Component->spawn( @args );
$poe_kernel->run;

package My::Component;

sub spawn {
    my( $package, @args ) = @_;
    POE::Session::Multiplex->create(
                    package_states => [
                            $package => [ qw( _start ) ]
                            'My::Component::Object' => 
                                    [qw( fetch decode back )] 
                        ]
                    args => [ @args ]
                );
}

##### To add an object to the session:
my $obj = My::Component::Object->new();
$_[SESSION]->object( $name, $obj );
    # or
$_[SESSION]->object_register( name => $name, object => $obj );

##### To remove an object
$_[SESSION]->object_unregister( $name );


##### Address an event to the current object:
my $state = ev"state";

##### To build a session/event tuple addressed to the current object
my $rsvp = rsvp "state";

# this tuple would be useful for getting a response from another session
$poe_kernel->post( $session=>'fetch', $params, rsvp"fetch_back" );

# and in the 'fetch' handler, you could reply with:
my $rsvp = $_[ARG1];
$poe_kernel->post( @$rsvp, $reply );

##### Posting to a specific object from inside the session
$poe_kernel->yield( evo( $name, $state ), @args );

##### Posting to a specific object from outside the session
$poe_kernel->post( evos( $session, $name, $state ), @args );
$poe_kernel->post( $session, evo( $name, $state ), @args );

DESCRIPTION

POE::Session::Multiplex allows you to have multiple object handling event from a single POE::Session.

A standard POE design is to have one POE::Session per object and to address each object using session IDs or aliases. POE::Session::Multiplex takes the oposite approach; there is only one session and each object is addressed by manipulating the event name.

The advantage is that you save the overhead of multiple sessions. While session creation is very fast, the POE kernel garbage collection must continually verify that each session should still be alive. For a system with many sessions this could represent a non-trivial task.

POE::Session::Multiplex provides handy routines to do the event name manipulation. See "HELPER FUNCTIONS".

To make an object available via multiplexing, that object must be registered with the session with "object_register".

Objects pass to the session via object_states are currently not multiplexed, though their events are available to objects of the same class. This could change in the future.

Event methods

POE::Session::Multiplex makes sure that a given event handler method has been set up for a given object. That is, if you define an event for a certain class, that event is not available for objects of other classes, unless they are descendents of the first class.

For example, a session is created with the following.

POE::Session::Multiplex->create(
                # ...
                package_states => [
                        Class1 => [ qw( load save ) ],
                        Class2 => [ qw( marshall demarshall ) ],
                    ],
                # ...
            );

Objects of Class1 are only accessible via the load and save events and objects of Class2 are only accessible via marshall and demarshall, unless Class2 is a sub-class of Class1.

POE::Session::Multiplex does the same thing with object_states. UNIVERSAL::isa is used to verify that 2 objects are of the same class.

Examples

When creating a socket factory, we use "ev" to create an event name addressed to the current object:

use POE::Wheel::SocketFactory;

sub open_connection {
    my( $self, $params ) = @_[OBJECT, ARG0];
    $self->{wheel} = POE::Wheel::SocketFactory->new(
                        %$params,
                        SuccessEvent => ev "connected",
                        FailureEvent => ev "error"
                    );
}

When sending a request to another session, we use "rsvp" to create an event that is addressed tot he current object and session:

$poe_kernel->post( $session, 'sum', 
                    [ 1, 2, 3, 4 ], rsvp "reply" 
                 );

$session's sum event handler would then be: sub sum_handler { my( $array, $reply ) = @_[ ARG0, ARG1 ]; my $tot = 0; foreach ( @$array ) { $tot += $_ } $_[KERNEL]->post( @$reply, $tot ); }

This could also have been implemented as:

$poe_kernel->post( $session, 'sum', 
                    [ 1, 2, 3, 4 ], ev "reply" 
                 );

sub sum_handler {
    my( $array, $reply ) = @_[ ARG0, ARG1 ];
    # ...
    $_[KERNEL]->post( $_[SENDER], $reply, $tot );
}

Limits

It is impossible to multiplex events that are sent from the POE kernel. Specifically, _start, _stop and _child can not be multiplexed.

Object Names

POE::Session::Multiplex requires each object to have a name. If you do not supply one when registering an object, the method __name is called to fetch the name. This is a crude form of meta-object protocol. If your object does not implement the __name method, a name is generated from the stringised object reference.

Note

This documentation tries to consistently use the proper term 'event' to refer to POE's confusingly named 'state'.

Event Names

Currently POE::Session::Multiplex uses event names of the form NAME->EVENT to address EVENT to the object named NAME. BUT YOU MUST NOT DEPEND ON THIS BEHAVIOUR. It could very well change to EVENT@NAME or anything else in the future. Please use the event helper functions provided.

METHODS

create

POE::Session::Multiplex->create( @lots_of_stuff );

Creates a new multiplexed POE::Session. No new parameters are defined by POE::Session::Multiplex. Parameters of interest to this module are package_states and object_states; they define event -> object method mappings that are also used by POE::Session::Multiplex. Objects referenced in ojbect_states are currently not multiplexed.

object_register

$_[SESSION]->object_register( $object );
$_[SESSION]->object_register( name => $name,
                              object => $object,
                              events => $events
                            );

Register a new $object named $name with the session. Optionally creating POE states in $events.

object

The object to be registered with the session. Required.

name

The name of the object being registered. If omitted, object_register will attempt to get an object name via a __name method call. If this method isn't available, a stringised object reference is used.

events

Optional hashref or arrayref of POE events to create. If it is a hashref, keys are POE event names, values are the names of event handler methods.

events => { load => 'load_handler', save => 'save_handler }

If you create POE events with an object, they are available to other objects of the same class. However, they will be removed when this object is unregistered. If you do not want this, use "package_register".

object_get

my $obj = $_[SESSION]->object_get( $name );

Returns the object named $name.

object_list

my @list = $_[SESSION]->object_list;

Returns a list of names of all the currently registered objects.

object_unregister

$_[SESSION]->object_unregister( $name );
$_[SESSION]->object_unregister( $self );

Unregisters an object. This makes the object unavailable for events. Any POE events created when the object was registered are removed.

object

# Register an object
$_[SESSION]->object( $name => $self, $events );
$_[SESSION]->object( $self, $events );

# Unregister an object
$_[SESSION]->object( $name );
$_[SESSION]->object( $self );

Syntactic sugar for "object_register" or "object_unregister".

package_register

$_[SESSION]->package_register( $package, $events );

Creates the POE events defined in $events as package methods of $package. This also makes the events available to all objects of class $package.

It is not currently possible to unregister a package.

HELPER FUNCTIONS

POE::Session::Multiplex exports a few helper functions for manipulating.

ev

$event = ev "handler";
$poe_kernel->yield( ev"handler" );

Returns an event name that is addressed to a handler of the current object. Obviously may only be called from within a multiplexed event.

evo

$state = evo( $name, "handler" );
$poe_kernel->yield( ev"handler" );

Returns an event name addressed to a handler of the $nameed object. Used when you want to address a specific object.

evs

$poe_kernel->post( evs "handler", @args );

Returns session/event tuple addressed to handler of the current object. Obviously may only be called from within a multiplexed event.

evos

$poe_kernel->post( evos( $session, $name, "handler" ), @args );

Returns session/event tuple addressed to a handler of the $nameed object in $session. Currently syntatic sugar for:

$poe_kernel->post( $session, evo( $name, "handler" ), @args );

rsvp

my $rsvp = rsvp "handler";

Returns an opaque object that may be used to post an event addressed to a handler of the current object. Obviously may only be called from within a multiplexed event.

rsvp is used by object to create postbacks. You may pass the returned object to other objects or sessions. They reply with:

$poe_kernel->post( @$rsvp, @answer );

FYI, rsvp is from the French Repondez, s'il vous plais. Answer, please in English.

POE::Session::PlainCall

It is unfortunately impossible to have clean multiple inheritance of POE::Session. However, POE::Session::Multiplex is compatible with POE::Session::PlainCall. It does this by checking its inheritance and implementing a few of POE::Session::PlainCall's methods.

If you wish to use both, create a session class as follows:

package My::Session;
use base qw( POE::Session::Multiplex POE::Session::PlainCall );

Then use that class to create your sessions:

My::Session->create( 
            package_states => [],
            args           => \@args
        );

SEE ALSO

POE and POE::Session for details of POE.

POE::Stage for the final solution

AUTHOR

Philip Gwyn, <gwyn-at-cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2009 by Philip Gwyn

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.