The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

POE::Component::Generic - A POE component that provides non-blocking access to a blocking object.

SYNOPSIS

    use POE::Component::Generic;

    my $telnet = POE::Component::Generic->spawn(

        # required; main object is of this class
        package => 'Net::Telnet',

        # optional; Options passed to Net::Telnet->new()
        object_options => [ ],

        # optional; You can use $poco->session_id() instead
        alias => 'telnet',
        # optional; 1 to turn on debugging
        debug => 1,
        # optional; 1 to see the child's STDERR
        verbose => 1,

        # optional; Options passed to the internal session
        options => { trace => 1 },

        # optional; describe package signatures 
        packages => {
            'Net::Telnet' => {
                # Methods that require coderefs, and keep them after they 
                # return.  
            
                # The first arg is converted to a coderef
                postbacks => { option_callback=>0 } 
            },
            'Other::Package' => {
                # only these methods are exposed
                methods => [ qw( one two ) ],

                # Methods that require coderefs, but don't keep them
                # after they return 
                callbacks => [ qw( two ) ]
            }
        }
    );

    # Start your POE session, then...

    $telnet->open( { event => 'result' }, "rainmaker.wunderground.com");
    # result state
    sub result {
        my ($kernel, $ref, $result) = @_[KERNEL, ARG0, ARG1];

        if( $ref->{error} ) {
            die join(' ', @{ $ref->{error} ) . "\n";
        }
        print "connected: $result\n";
    }


    # Setup a postback
    $telnet->option_callback( {}, "option_back" );

    # option_back state
    sub option_back {
        my( $obj, $option, $is_remote,
                $is_enabled, $was_enabled, $buf_position) = @_[ARG0..$#_];
        # See L<Net::Telnet> for a discussion of the above.

        # NOTE: Callbacks and postbacks can't currently receive objects.
    }

    # Use a callback
    # Pretend that $other was created as a proxy to an Other::Package object
    $other->two( {}, sub { warn "I was called..." } );

    my $code = $session->postback( "my_state" );
    $other->two( {}, $code );

DESCRIPTION

POE::Component::Generic is a POE component that provides a non-blocking wrapper around any object. It works by forking a child process with POE::Wheel::Run and creating the object in the child process. Method calls are then serialised and sent via STDIN to the child to be handled. Return values are posted back to your session via STDOUT. This means that all method arguments and return values must survive serialisation. If you need to pass coderefs, use "callbacks", "postbacks" or "factories".

Method calls are wrapped in eval in the child process so that errors may be propagated back to your session. See "OUTPUT".

Output to STDERR in the child, that is from your object, is shown only if debug or verbose is set.

STDOUT in the child, that is from your object, is redirected to STDERR and will be shown in the same circomstances.

METHODS

spawn

    my $obj = POE::Component::Generic->new( $package );
    my $obj = POE::Component::Generic->new( %arguments );

Create the POE::Component::Generic component.

Takes either a single scalar, which is assumed to be a package name, or a hash of arguments, of which all but package are optional.

alias

Session alias to register with the kernel. Also used as the child processes' name. See "STATUS" below. Default is none.

alt_fork

Set to true if you want to run another perl instance. That is, the child process will exec a new instance of perl using $^X to do the work. @INC is preserved. If present, $ENV{HARNESS_PERL_SWITCHES} is preserved.

Using alt_fork might help save memory; while the child process will only contain POE::Component::Generic and your object, it will not be able to share as many memory pages with other processes.

Care must be taken that the all necessary modules are loaded in the new perl instance. Make sure that your main package loads all modules that it might interact with.

Default is false.

Please note that alt_fork does not currently work on MSWin32. The problem is that exec() is failing in POE::Wheel::Run. If you can fix that I will reactivate alt_fork for MSWin32.

callbacks

List of methods that have callbacks in their parameter list.

A callback is a coderef that the object will only use during that method call. After the method returns, the callback will be invalidated. If you need to pass a coderef that must last longer then one method, use "postbacks".

When one of the methods in callbacks is called, any coderefs in the parameters are converted into a message to the child process to propagate the call back to the parent.

IMPORTANT: The callback is called from inside POE::Component::Generic. This means that the current session is NOT your session. If you need to be inside your session, use POE::Session/postback.

Defaults to empty.

child_package

Set the package that the child process worker object. Sometimes advanced interaction with objects will require more smarts in the child process. You may control child process behaviour by setting this to an subclass of POE::Component::Generic::Child. For more details, consult the source!

debug

Set to true to see component debug information, such as anything output to STDERR by your code. Default to false.

factories

List of methods that are object factories. An object factory is one that returns a different object. For example, DBI's $dbh->prepare returns a statement handle object, so it is an object factory.

The first value of the return argument is assumed to be the object. It is kept in the child process. Your return event will receive a proxy object that will allow you to use the "yield", "call" and "psuedo-method" calls, as documented below.

See POE::Component::Generic::Object for details.

You should configure package signatures for the proxy objects that factories return with "packages".

methods

An array ref containing methods that you want the component to expose. If not specified, all the methods of package and its super-classes are exposed.

Note that methods that begin with _ or don't end with a lower case letter (a-z) are excluded, as well as methods that end in carp, croak and confess.

options

A hashref of POE::Session options that are passed to the component's session creator.

object_options

An optional array ref of options that will be passed to the main object constructor.

package

Package used to create the main object.

Object creation happens in the child process. The package is loaded, if it isn't already, then a constructor is called with object_options as the parameters. The constructor is a package method named new, spawn or create, searching in that order.

packages

Set the package signature for packages that might be used. This allows you to configure the "callbacks", "postbacks" and "methods" for objects that are returned by factory methods.

Must be a hashref, keys are package names, values are either a scalar, which will case the package will be scanned for methods, a arrayref, which is taken as a list of "methods", or a hashref, which gives you full control. The hashref may contain the keys "methods", "callbacks" and "postbacks", which work as described above and below.

It is also possible to specify the package signature for the main object with "packages".

Example:

    POE::Component::Generic->spawn( 
                        package   => 'Honk',
                        methods   => [ qw(off on fast slow) ],
                        postbacks => { slow=>1, fast=>[1,2] }
                   );
    # Could also be written as
    POE::Component::Generic->spawn( 
                    package  =>'Honk',
                    packages => {
                        Honk => {
                            methods=>[ qw(off on fast slow) ],
                            postbacks=>{ slow=>1, fast=>[1,2] }
                        }
                    }
                );
postbacks

List of methods that have a coderef in there parameters. These coderefs will remain valid after the method returns.

postbacks must be a hashref, keys are method names, values are lists of the offsets of argument that will be converted into postbacks. These offsets maybe be a number, or an array of numeric offsets. Remember that argument offsets are numbered from 0.

postbacks may also be an array of method names. In this case, the argument offset for each listed method is assumed to be 0.

Examples:

    [ qw( new_cert new_connect ) ]
    { new_cert=>0, new_connect=>0 }     # equivalent to previous
    { double_set=>[0,3] }

When calling a method that has a postback, you specify an event name in the current session, or a hashref containing event and session keys. If session is missing, the current session is used. Yes, this means you may create postbacks that go to other sessions.

Examples:

    "some_back"
    { event=>"some_back" }
    { event=>"some_back", session=>"my-session" }

You can use "state" in POE::Kernel to create postbacks states out of closures.

Your postback will have the arguments that the object calls it with. Contrary to response events, ARG0 isn't the OUTPUT data hashref. At least, not for now.

verbose

Component tells you more about what is happening in the child process. The child's PID is reported to STDERR. All text sent to STDERR in the child process is report. Any abnormal error conditions or exits are also reported. All this reported via warn.

shutdown

Shut the component down, doing all the magic so that POE may exit. The child process will exit, causing DESTROY to be called on your object. The child process will of course wait if the object is in a blocking method.

Note that this is also a POE event, which means you can not call a method named 'shutdown' on your object.

Shuting down if there are response pending (see "OUTPUT" below) is undefined.

Note that "shutdown" will not cause the kernel to exit if you have other components or sessions keeping POE from doing so.

session_id

Takes no arguments, returns the POE::Session ID of the component. Useful if you don't want to use aliases.

METHOD CALLS

There are 4 ways of calling methods on the object.

All methods need a data hashref that will be handed back to the return event. This data hash is discussed in the "INPUT" section.

post

Post events to the object. First argument is the event to post, second is the data hashref, following arguments are sent as arguments in the resultant post.

  $poe_kernel->post( $alias => 'method',
                        open => { event => 'result' }, "localhost" );

yield

This method provides an alternative object based means of asynchronisly calling methods on the object. First argument is the method to call, second is the data hashref (described in "INPUT"), following arguments are sent as arguments to the resultant post.

  $generic->yield( open => { event => 'result' }, "localhost" );

call

This method provides an alternative object based means of synchronisly calling methods on the object. First argument is the event to call, second is the data hashref (described in "INPUT"), following arguments are following arguments are sent as arguments to the resultant call.

  $generic->call( open => { event => 'result' }, "localhost" );

Call returns a request ID which may be matched with the response. NOT IMPLEMENTED.

psuedo-method

All methods of the object can also be called directly, but the first argument must be the data hashref as noted in the "INPUT" section.

    $generic->open( { event => 'opened' }, "localhost" );

INPUT

Each method call requires a data hashref as it's first argument.

The data hashref may have the following keys.

data

Opaque data element that will be present in the "OUTPUT" hash. While it is possible that other hash members will also work for now, only this one is reserved for your use.

event

Event in your session that you want the results of the method to go to. event is needed for all requests that you want a response to. You may send responses to other sessions with session.

No response is sent if event is missing.

obj

Don't call the method on the main object, but rather on this object. Value is the ID of an object returned by a factory method. Doesn't work for "psuedo-method" calls.

session

Session that you want the response event to be sent to. Defaults to current session. Abuse with caution.

wantarray

Should the method be called in array context (1), scalar context (0) or void context (undef)? Defaults to void context, unless you specify a response "event", in which case it defaults to scalar context.

Note that at some point in the future this data hashref is going to be a full object for better encapsulation.

OUTPUT

You may specify a response event for each method call. ARG0 of this event handler contains the data hashref. ARG1..$#_ are the returned values, if any.

data

Opaque value that was set in "INPUT".

error

In the event of an error occurring this will be defined. It is a scalar which contains the text of the error, which is normally $@.

method

Name of the method this is the output of. That is, if you call the method "foo", method is set to "foo" in the response event.

result

This is an arrayref containing the data returned from the function you called.

Method calls in scalar context have the return value at result->[0]. That is, they look like:

    $response->{result}[0] = $object->method(...);

Method calls in array context populate as much of the array as needed. That is, they look like:

    $response->{result} = [ $object->method(...) ];

HELPER METHODS

These methods will help you writing components based on POE::Component::Generic.

Argument processing

Callbacks and postbacks expect the arguments are in order. This is a pain for your users and isn't really the POE-way. Instead, your method may accept a hash, and then convert it into the argument list.

For a given event FOO, there are 2 possible arguments:

FOOEvent

The argument is a POE event, either a simple string (event in the current session) or a hashref ({event=>$event, session=>$session}).

FOOSub

The argument is a subref.

You may use the following 2 methods to help convert the arguments into the appropriate type for a given situaion. They return undef() if the argument isn't present. This so you may use the following idiom and it will Just Work:

    sub method {
        my( $self, %args ) = @_;
        my @args;
        foreach my $ev ( qw(Stdin Stdout Close) ) {
            push @args, $self->__postback_argument( $ev, \%args );
        }
        $self->true_method( @args );
    }

__callback_argument

    my $coderef = $self->__callback_argument( $event, \%args );

Converts argument into a coderef appropriate for "callbacks".

Returns $args{ "${event}Sub" } if present.

If present, converts $args{ "${event}Event" } to a coderef and returns that.

Returns undef() otherwise.

__postback_argument

Converts argument into a POE event call appropriate for "postbacks".

Returns $args{ "${event}Event" } if present.

If present, converts $args{ "${event}Sub" } to a state of the current session and returns a call to that. NOT YET IMPLEMENTED.

Returns undef() otherwise.

STATUS

For your comfort and conveinence, the child process update $O to tell you what it is doing. On many systems, $O is available via /proc/$PID/cmdline.

AUTHOR

Philip Gwyn <gwyn-at-cpan.org>

Based on work by David Davis <xantus@cpan.org>

SEE ALSO

POE

RATING

Please rate this module. http://cpanratings.perl.org/rate/?distribution=POE-Component-Generic

BUGS

Probably. Report them here: http://rt.cpan.org/NoAuth/ReportBug.html?Queue=POE%3A%3AComponent%3A%3AGeneric

CREDITS

BinGOs for POE::Component::Win32::Service that helped xantus get started.

David Davis for POE::Component::Net::Telnet on which this is originally based.

COPYRIGHT AND LICENSE

Copyright 2006 by Philip Gwyn;

Copyright 2005 by David Davis and Teknikill Software.

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