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 adispatch
that looks like this:{ 'Util' => 'Foo::Service::Util', 'Calendar' => 'Bar::Baz' }
So then, calling the method
Util.get
will callFoo::Service::Util->get
. CallingCalendar.create
will callBar::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
orget_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 to1
. 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 callsFoo.some_method
. So RPC::Any::Server translates that to a call toBar::Baz->some_method
. Right before it calls that method, it pushes the class listed inpackage_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.
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.
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.
We use "dispatch" to locate and load the Perl module that contains the method being called.
We check that the module can execute the requested method, like
$module->can($method)
. (Because we usecan
, if you useAUTOLOAD
in your modules, you will have to explicitly declare any sub that can be used (likesub something;
), or overridecan
in your module.)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.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.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 asrpc_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 literal2
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 a0
or1
value. In JSON-RPC, translates totrue
orfalse
. - 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 totype
, 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 tonull
.
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: