NAME

RPC::Any::Server - The RPC Server

SYNOPSIS

use RPC::Any::Server::XMLRPC;
# Create a server where calling Foo.bar will call My::Module->bar.
my $server = RPC::Any::Server::XMLRPC->new(
   dispatch => { 'Foo' => 'My::Module' }
);
# Read from STDIN and print result to STDOUT.
print $server->handle_input();

DESCRIPTION

This is an RPC "server" that can call methods and return a result to a client. Unlike other RPC modules, RPC::Any::Server doesn't actually start a listening daemon, it just reads the input that you give it and gives you output that you can send to your client any way that you like. This may sound like a bit of additional complexity, but in fact it makes it much simpler to use than other RPC modules.

This module itself doesn't do anything--it just acts as a base class for other Server modules, like RPC::Any::Server::XMLRPC and so on. (They are all listed in the "SEE ALSO" section below.) However, all Server types have certain things in common, and those things are documented here, in this POD.

RPC::Any::Server is designed to be subclassed and easily customized for your environment. Look at the handle_input method in its code to understand how it works and all the methods that you can override.

RPC::Any::Server uses Moose, so subclasses may use all the power of Moose to adjust its behavior.

INSTANCE METHODS

handle_input

This is, normally, the only method you will call on a Server instance. It takes a single scalar as an argument. This can be a string, in which case that string will be treated as the input to the server. Alternately, you can specify a filehandle which will be slurped in for input.

If you do not specify an argument, handle_input reads from STDIN to get its input.

handle_input returns a string that you can print directly as the result to your client. (For example, in the HTTP and CGI servers, the string includes all HTTP headers required.)

CLASS METHODS

The only class method is new, which takes any of the "INSTANCE ATTRIBUTES" below as named parameters, like this:

RPC::Any::Server::XMLRPC->new(dispatch => {}, allow_constants => 1);

It is recommended that you specify at least "dispatch".

INSTANCE ATTRIBUTES

All of these values can be set in new and they can also be set on an existing object by passing an argument to them (like $server->method($value)).

dispatch

This is a hashref that maps "package names" in RPC method requests to actual Perl module names (in a format like My::Module::Name). For example, let's say that you have a dispatch that looks like this:

{
   'Util'     => 'Foo::Service::Util',
   'Calendar' => 'Bar::Baz'
}

So then, calling the method Util.get will call Foo::Service::Util->get. Calling Calendar.create will call Bar::Baz->create. You don't have to pre-load the Perl modules, RPC::Any::Server will load them for you when they are needed.

If you want to dispatch methods in some totally different way, then you should override get_method or get_package in a subclass of RPC::Any::Server.

See "HOW RPC METHODS ARE CALLED" for more information on how this is used.

allow_constants

By default, RPC::Any::Server doesn't allow you to call methods whose names are all in caps. (So, for example, trying to call the method Foo.THIS_METHOD would throw an error.) If you would like to allow calling methods whose names are all in caps, you can set this to 1.

package_base

Right before RPC::Any::Server calls a method, it modifies the @ISA array of the method's package so that it inherits from this class. So, for example, let's say you have a "dispatch" that looks like { 'Foo' => 'Bar::Baz' }, and somebody calls Foo.some_method. So RPC::Any::Server translates that to a call to Bar::Baz->some_method. Right before it calls that method, it pushes the class listed in package_base on to the end of @Bar::Baz::ISA. It remains in the @ISA only for the duration of the call, and then it is removed.

To see what functionality this gives you by default, see "RPC::Any::Package", which describes the methods and functionality added to your class immediately before the method is called.

HOW RPC METHODS ARE CALLED

When RPC::Any::Server gets a request to call a method, it goes through several steps. Let's say that you have a "dispatch" that looks like { 'Foo' => 'Bar::Baz' }, and somebody calls the Foo.something method.

  1. We make sure that the method call has both a package and a method name separated by a period. (If you don't want to call methods in this way, you should subclass one of the RPC::Any::Server implementations, and override get_method.)

    If there is more than one period in the name, we split at the last period, so the package name can contain multiple periods.

  2. We validate the method name. Private methods (methods whose names start with an underscore) cannot be called using this interface. We also make sure that the name isn't all uppercase, if "allow_constants" is off.

  3. We use "dispatch" to locate and load the Perl module that contains the method being called.

  4. We check that the module can execute the requested method, like $module->can($method). (Because we use can, if you use AUTOLOAD in your modules, you will have to explicitly declare any sub that can be used (like sub something;), or override can in your module.)

  5. We modify the Perl module's @ISA to include the class from "package_base". This lets you do $class->type('some_type', $some_value) inside of your methods to explicitly type return values. See "package_base" and "RPC::Any::Package" for more information.

  6. Your method is actually called, as a class method on the module, like this:

    my @retval = $module->$method(@args);

    Where @args is the method arguments that you specified as part of the RPC protocol.

  7. If you return a single item, that item is used as the return value. If you return multiple items, they will be returned as an array. If you return no items, then a single undef will be the only return value.

RPC::Any::Package

Right before RPC::Any::Server calls your methods, it pushes a protocol-specific class on to the @ISA of your method's module. (See "package_base" for more details.) For example, if you are using the XMLRPC server, it pushes RPC::Any::Package::XMLRPC into your module's @ISA.

This adds a single method, "type", to your class, that you can use to return explicit types of values. You don't have to use type on your return values--RPC::Any will do its best to figure out good types for them. But if you want to be explicit about your return values, you should use type.

You don't need to call type for arrays and hashes--RPC::Any always properly converts those.

type

Takes two arguments. The first is a string representing the name of a type. The second is a scalar value. It returns an object (or sometimes a scalar) that will be properly interpreted by RPC::Any as being the type you specified.

You must not modify the value returned from type in any way before returning it.

In case your class already has a method named type, you can also call this method as rpc_type.

Here are the valid types, and how they translate in the various protocols:

int

An integer. Translates to <int> in XML-RPC, and a number without any quotes on it in JSON-RPC.

double

A floating-point number. Translates to <double> in XML-RPC and a number without any quotes on it, in JSON-RPC. (Note, though, that numbers like '2.0' may be convered to a literal 2 when returned.)

string

A simple string. Translates to <string> in XML-RPC and a quoted string in JSON-RPC.

boolean

A true or false value. Translates to <boolean> in XML-RPC, with a 0 or 1 value. In JSON-RPC, translates to true or false.

base64

A base64-encoded string. The input data will be encoded to base64--you should not do the encoding yourself. This is the only way to transfer binary data using RPC::Any. In XML-RPC, this translates to <base64>. In JSON-RPC it becomes a quoted string containing base64.

dateTime

A date and time. In XML-RPC, this translates to a <dateTime.iso8601> field, and will throw an error if you pass in a value that is not formatted properly according to the XML-RPC spec. In JSON-RPC, no translation of the passed-in value is done.

nil

A "null" value. If you pass undef as the second argument to type, you will always get this type back, regardless of what type you requested. In XML-RPC, this translates differently depending on how you've set "send_nil" in RPC::Any::Server::XMLRPC. In JSON-RPC, this translates to null.

ERROR HANDLING

During any call to handle_input, all calls to die are trapped and converted to an error format appropriate for the server being used. (So, for example, if you are using an XML-RPC server, the output will be an XML-RPC error if anything goes wrong with the server.)

By default, all errors are of the type "PerlError" in RPC::Any::Exception, meaning that they have the code -32603. If you want to specify your own error codes (or if you don't want the at some/dir/foo.pl string in your errors), you can die with an RPC::Any::Exception, like this:

use RPC::Any::Exception;
die RPC::Any::Exception(code => 123, message => "I'm dead!");

And that will be translated properly by the RPC::Any::Server into an RPC error.

TAINT BEHAVIOR

If you give RPC::Any::Server tainted input, then it will taint all the arguments it passes to your methods.

UNICODE

For simplicity's sake, RPC::Any assumes that all output from the server will be UTF-8.

RPC::Any does its best to handle Unicode input well. However, if you expect perfect Unicode handling, you should make sure that your input is marked clearly as Unicode. For the basic (non-HTTP) servers, this means that you should pass in character strings with the "utf8 bit" turned on. For HTTP servers, this means you should send a charset of UTF-8 in your Content-Type header.

SEE ALSO

RPC::Any for general information about RPC::Any.

The various server modules:

RPC::Any::Server::XMLRPC
RPC::Any::Server::XMLRPC::HTTP
RPC::Any::Server::XMLRPC::CGI
RPC::Any::Server::JSONRPC
RPC::Any::Server::JSONRPC::HTTP
RPC::Any::Server::JSONRPC::CGI