NAME

POE::Request - a common message class for POE::Stage

SYNOPSIS

# Note, this is not a complete program.
# See the distribution's examples directory.

my $req_subrequest = POE::Request->new(
	method    => "method_name",   # invoke this method
	stage     => $self,           # of this stage
	on_one    => "do_one",        # map a "one" response to method
	args      => {
		one => 123,         # with this parameter
		two => "abc",       # and this one
	}
);

# Handle a "one" response.
sub do_one :Handler {
	my ($arg_one, $arg_two);
	print "$arg_one\n";  # 123
	print "$arg_two\n";  # abc
	...;
	my $req;
	$req->return( type => "one", moo => "retval" );
}

# Handle one's return value.
sub do_one :Handler {
	my $arg_moo;
	print "$arg_moo\n";  # "retval"
}

DESCRIPTION

POE::Request objects encapsulate messages passed between POE::Stage objects. Each request includes a destination (the stage and method to call), optional data to be sent to the destination method (args), and optional hints where to send responses (on_* mappings). There may be other parameters.

POE::Request includes methods that transmit responses when called. These methods internally create instances of POE::Request subclasses. The return() method creates a POE::Stage::Return object, which ends a transaction and returns a final result. There is also an emit() method that creates a POE::Request::Emit object. Emitted messages do not terminate the transactions they're belong to, so they may act as interim responses.

POE::Request::Emit has its own response method, recall(). The recipient of an emitted interim response can recall the session at the other end of the current transaction. emit() and recall() may be used together to extend a two-way dialog within the context of an original request.

Each new POE::Request creates two closures, one for the sender and one for the receiver. Members of the sender's closure can be accessed using POE::Stage's expose() function. For example, to expose a sub-request's "hostname" member as the lexical $subrequest_hostname variable:

use POE::Session qw(expose);
my $req_subrequest = POE::Request->new(...);
expose $req_subrequest, my $subrequest_hostname;
$subrequest_hostname = "remote.host.name";

The request's destination may have its own "hostname" member, but it will be separate from the caller's. The special $req lexical refers to the POE::Request object that called us, while $req_hostname refers to the "hostname" member in the invocant's end of the request.

sub on_request {
	my $req_hostname = Sys::Hostname::hostname();
	...;
	$req->return(
		type => "success",
		args => { retval => $something }
	);
}

When the caller receives a response, either via an invocant's use of emit() or return(), there are special $rsp and $rsp_membername lexicals. $rsp refers to the POE::Request::Emit or ::Return message we're handling. It's usually used to call $rsp->recall(...). Lexicals prefixed by "rsp_", such as $rsp_hostname, refer to values previously stored in the original request via expose(). In our contrived example:

sub on_resolver_success {
	my $arg_retval;  # contains the value of the "retval" argument
	my $rsp_hostname;  # contains "remote.host.name", assigned above
}

This lexical magic only works with methods intended to be used as message handlers. They are identified by the :Handler attribute or by method names beginning with "on_".

PUBLIC METHODS

Request methods are called directly on the objects themselves.

new PARAM => VALUE, PARAM => VALUE, ...

Create a new POE::Request object. The request will automatically be sent to its destination, currently asynchronously, but the exact implementation has not solidified yet. In the future we hope that factors on the local or remote process, or pertaining to the network between them, may prevent requests from being delivered immediately.

POE::Request->new() requires at least two parameters. "stage" contains the POE::Stage object that will receive the request, and "method" is the method to call when the remote stage handles the request. For remote calls, the stage may merely be a local proxy for a remote object, but this feature has yet to be defined.

Parameters for the message's destination can be supplied in the optional "args" parameter. These parameters will be passed untouched to the message's destination via lexical variables with the $arg_ prefix.

POE::Request->new() returns an object which must be saved. Destroying a request object will cancel the request and automatically free all data and resources associated with it, including those allocated by sub-stages and sub-requests on behalf of the original request. This can be ensured by storing sub-stages and sub-requests within the context of higher-level requests.

Instances of POE::Request subclasses, such as those created by $request->return(), do not need to be saved. They are ephemeral responses and/or re-requests, and their lifespans do not control the lifetime duration of the transaction they belong to.

TODO - on_foo TODO - role

new_without_send SAME_AS_NEW

A "friend" method used internally to create POE::Request objects without automatically sending them to their targets.

init HASHREF

init() is a callback that subclasses receive as part of the request's construction. It's used to perform final initialization before requests are transmitted.

The init() method receives the request's constructor 'args' before they are processed and stored in the request. This timing allows init() to modify the arguments, adding, removing or altering them before the request is sent. To do this properly, however, one must manipulate the entire hash directly. Fortunately POE::Stage provides that through @_ and the $args variable:

sub init {
	my ($self, $my_args) = @_;

	# Changing $my_args or $args will alter the same, original
	# argument hash.
}

Custom POE::Request subclasses may use init() to verify that parameters are correct. Currently init() must throw an exeception with die() to signal some form of failure.

return type => RETURN_TYPE, args => \%RETURN_VALUES

return() cancels the current POE::Request object, and returns a message with an optional RETURN_TYPE and some optional RETURN_VALUES. The response is encapsulated in a POE::Request::Return object and automatically sent back to the caller---the POE::Stage that created the POE::Request that triggered this return().

Please see POE::Request::Return for details about return messages.

The type of message defaults to "return" if not specified.

emit type => EMIT_TYPE, args => \%EMIT_VALUES

emit() sends a message to the caller, using an optional EMIT_TYPE and optional EMIT_VALUES. emit() does not cancel the current transaction, unlike return(). The response is encapsulated in a POE::Request::Emit object, and it's automatically sent to the caller.

emit() was created to send back interim or ongoing statuses, possibly as part of a two-way dialog between a caller and callee.

The type of message defaults to "emit" if not specified.

cancel

Explicitly cancel a request. It's intended for use by the invoked stage, since the caller is free to destroy its request at any time. The callee doesn't have that ability, so cancel() grants it explicitly.

A canceled request cannot generate a response. If you are tempted to precede cancel() with emit(), then use return() instead. The return() method is essentially an emit() followed by a cancel().

As mentioned earlier, canceling a request frees up the data associated with that request. Cancellation and destruction cascade through the data associated with a request and any sub-stages and sub-requests. This efficiently and automatically releases all resources associated with the entire request tree rooted with the canceled request.

For example:

App creates a request for an http client.
	HTTP client creates a request for a socket.
		Socket factory creates a request for a DNS resolver.

At any point in the hierarchy, a cancellation clears its context and cancels the lower-level requests. For example, if the App cancels the HTTP request, the cancelation cascades to the socket factory, and then to the DNS resolver.

This happens because of one recursive rule: When a request is canceled, the data members on both sides of the transaction are destroyed. This only works when stages consistently store subrequests within their own requests. Here the socket factory request is stored in the main HTTP fetch request. If the HTTP fetch is canceled before the socket factory can create a connection, then the socket factory's request is also canceled.

sub on_http_fetch {
	...;
	my $req_socket = POE::Request->new(
		stage => $socket_factory,
		method => "open_socket",
	);

This behavior can be nested arbitrarily deep.

DESIGN GOALS

Requests are designed to encapsulate messages passed between stages, so you don't have to roll your own message-passing schemes. It's our hope that providing a standard, effective message passing system will maximize interoperability between POE stages.

Requests may be subclassed, incorporating specific features and defaults to make their use easier.

Future plans:

At some point in the future, request classes may be used as message types rather than <type = $type>> parameters. More formal POE::Stage interfaces may take advantage of explicit message typing in the future.

We'd also like to incorporate a standard form of interprocess communication within POE::Request, possibly with the use of proxy stages that represent remote code. In theory, a stage doesn't need to know its peers are off-world.

BUGS

See http://thirdlobe.com/projects/poe-stage/report/1 for known issues. See http://thirdlobe.com/projects/poe-stage/newticket to report one.

POE::Stage is too young for production use. For example, its syntax is still changing. You probably know what you don't like, or what you need that isn't included, so consider fixing or adding that, or at least discussing it with the people on POE's mailing list or IRC channel. Your feedback and contributions will bring POE::Stage closer to usability. We appreciate it.

SEE ALSO

POE::Request has subclasses that are used internally. While they share the same interface as POE::Request, not all of its methods are appropriate in all its subclasses.

Please see POE::Request::Upward for a discussion of response events (emit and return), and how they are mapped to method calls by the requesting stage. POE::Request::Return and POE::Request::Emit are specific kinds of upward-facing response messages.

POE::Request::Return, POE::Request::Recall, POE::Request::Emit, and POE::Request::Upward.

AUTHORS

Rocco Caputo <rcaputo@cpan.org>.

LICENSE

POE::Request is Copyright 2005-2006 by Rocco Caputo. All rights are reserved. You may use, modify, and/or distribute this module under the same terms as Perl itself.