NAME

MOP::Remote - Perl meta-module for transparent distribution of object oriented modules.

SYNOPSIS

# A random package declaration
package MyModule;

# Activate the meta-object protocol for a few methods
use MOP::MOP qw(new method1 method3);
# Our meta-module is 'MOP::Remote'
MOP::MOP::register_meta('MOP::Remote','MyModule');

# Some functions
sub new { return bless { ... }; } # Constructor
sub method1 { ... }
sub method2 { ... }
sub method3 { ... }

##### NOW USING MyModule ####
use MyModule;

# Creates a remote server
my $REMOTE = 'host.name.fr'; my $PORT = 1234;
my $server = MOP::Remote::create_server('MyModule', $REMOTE, $PORT);

# Creates an object - additional argument is grabbed by meta-module
my $o = MyModule->new(..., $server);
# Now, simply use it: all methods are done remotely on $REMOTE_HOST
$o->method1();
my $var = $o->method3('a_value');
...

DESCRIPTION

This module provides two things:

  • An example of basic meta-module that demonstrates how it is possible to design a meta-module, and use it to provide useful functionality to third-party module writers.

  • A transparent way of adding remote processing capabilities to any module with minimal modifications. This will probably work only on Unix systems.

Using this module should be straightforward. In the definition of an object-oriented Perl module that you want to enhance by remote processing capabilities, you simply need to state that several methods should be reflective, with: use MOP::MOP qw(method_name1 method_name2 ...). This simply makes the MOP (Meta-Object Protocol) aware of the given methods. Then, you should probably define a static link between your module and the MOP::Remote meta-module with: MOP::MOP::register_meta('MOP::Remote','MyModule'), at the beginning of MyModule.pm. This magic formula indicates to the MOP that MOP::Remote is the meta-module to be used for MyModule. It is this meta-module that provides the magical remote processing capability.

Then, the user of MyModule creates a new server via the create_server() function of MOP::Remote, in order to create new objects on that server. All method calls on such an object will be performed on the remote server. If the user wants to create a local object (in-process), he simply passes the constant LOCAL instead of a server reference, as in: MyModule->new(..., 'LOCAL'). This creates an object normally. But then, there is nothing funny anymore.

Detailed operation

At creation via MyModule->new(...,$server), the call will be trapped and redirected to the host associated with the given server. The $server argument will be removed before calling the new() method on the server, of course. The remote server will create a new object, and the local machine will simply return you an empty hashref that plays the role of a proxy. In fact, two additional meta-objects will be created: one locally that will hold some useful information (such as the remote object ID) and will control the future method calls made on the proxy, and one meta-object on the remote server that will perform the real base-level method call on the real (remote) object.

Afterwards, all method calls made on objects from MyModule will be trapped by the MOP and redirected to MOP::Remote. The (local) meta-object created after the call to new() will be used to find the remote processing server, and the call with all its arguments will be redirected to that server. On the remote host, the server will catch this request, perform the operation on the real object (via its own meta-object) and communicate the results back to your process. The returned value will be sent back to you. Data::Dumper is used (in deep mode) to pass the arguments back and forth. So, it is possible that some references be lost during the network exchange, depending on the base module operation.

The remote invocation is a blocking one. If you want to perform multiple concurrent remote invocations, you should handle that yourself.

Currently, you should consider MOP::Remote as a form of RPC. It is also preferred to create different remote servers for different modules (ie: one for each class). You can create several objects on one server, and you may also create them from different client machines. However, note that one remote server serializes the method calls (it does not do any fork()) and that you will need to find a way to exchange the server reference. This is not exactly the normal way of operation.

Functions

$server = MOP::Remote::create_server($module_name[,$host,$port,$remote_perl])

This function creates a new server on a remote machine. $module_name should contain the name of the module that is operated by the server. rsh is used to create a Perl process on the remote machine, so you need to have rsh and an account on the remote machine (that does not require a password). The remaining arguments are optional. $host is the name of a remote host on which you want to create the server. It defaults to 'localhost', ie: the local host (in another Perl process in fact - this is a behavior of rsh). However, you will probably want to specify this one. $port is the TCP port number used for the communication between the client and the server. It default to 2345 (an arbitrary value). You should adapt that to your application. Finally, $remote_perl may indicate the name of the Perl executable to use on the remote machine. MOP::Remote tries to be smart and to guess that name, so usually you need not specify it. But in cross-platform configurations, it may be useful to be able to specify it. (Hint: if you configured your shell initializations correcty so that the simple command perl works on the remote host, MOP::Remote will surely find the name of a good Perl executable.)

This function will return you a hash reference that contains server-related information. You may use that hashref to create objects on the server via new().

MOP::Remote::exit_server($server)

This function will send an exit message to the remote server that will handshake and exit.

Notes

MOP::Remote closes STDOUT and STDERR on the remote server by default. It may be difficult to debug your module (that executes remotely). You can set the debug flag $MOP::Remote::DEBUG. In that case, MOP::Remote will not close ouputs and will arrange to maintain a link between the standard outputs of remote processes and the local terminal. You can also set $MOP::Remote::DEBUG2 if you want to see the messages exchanged between the client and the server.

I have successfully tested remote invocations between Solaris and Linux hosts. However, cross-platform invocation, even though possible, still involves careful setup of both platforms Perl5 modules library. (The same modules should be available on both hosts. Versions should be similar. Previous note is really applicable.)

MOP::Remote depends on Data::Dumper.

LIMITATIONS AND FUTURE EVOLUTIONS

The client-server functionality implemented inside MOP::Remote is self-contained but rather basic. It would be desirable to use a more sophisticated set of functionalities for client-server operation (like in EventServer). Only the true meta-level part of MOP::Remote should remain in that case.

As any magical device, MOP::Remote surely has a lot of shortcomings. In fact, it is not sure at all that a MOP::Remote-enhanced module will behave exactly like a normal module. For example, the inheritance semantics of a reflective module is not (yet) clear. If something inherits from MyModule, but overloads some methods, the remote processing capability may be broken for these methods.

Furthermore, if some public methods are not reflective, the MOP does not know them, so they will not be trapped to be sent to the remote server. Instead they will be executed locally by Perl itself: at once on a proxy object. So the result will surely be some bad thing. Private method calls need not be reflective, because the user should never call them (or they would not be private), but well... nothing really prevents them from doing so especially when inheritance is involved.

Finally, there may be meta-meta-objects on any side of the client-server communication, and at this point, my brain usually stops understanding the real path of the method call. Maybe Perl will figure out what to do... (Remember this is just an example.)

BUGS

Due to a limitation of the meta-object protocol of MOP::MOP, the destruction of objects is not handled. If you create a lot of objects on the remote server and do not use them, it may be a (remote) problem.

new() is the only class method name considered. If your module has other constructors that should execute remotely, you should modify the meta-module. Currently MOP::Remote will complain, but it will perform the class method call locally anyway.

The default TCP port number used for communication is arbitrary: it is 2345.

AUTHOR

Rodolphe Ortalo, ortalo@laas.fr

Acknowledgements

This work has been performed with the support of LAAS-CNRS.

SEE ALSO

perl(1), MOP::MOP(3), MOP::MetaModule(3).

1 POD Error

The following errors were encountered while parsing the POD:

Around line 637:

You forgot a '=back' before '=head2'