[ICS] Ivory City Systems


mod_perlservice
CHECK OUT OUR ARTICLE ON PERL.COM!
PERL.COM MOD_PERLSERVICE
mod_perlservice developed by:
Michael Collins
Documentation by: Michael Collins
Questions/Comments/Bugs:
michaelcollins@ivorycity.com


DOWNLOAD
mod_perlservice-1.0.4.tar.gz

Perl Client | C Client | Flash Client

DOCUMENTATION

mod_perlservice? What is that?

The cool new way to do remoting with Perl and Apache!
But, lets start by breaking that crazy name apart. mod - perl - service

mod - It's a module for the popular and ubiquitous Apache HTTP Server.
perl - Of course, it's the popular and ubiquitous programming language.
service - Ah, this is the unique part. It's the new ingredient that unifies Apache, Perl and XML into an easy to use web-services system.

With the mod_perlservice system, you can write perl subs and packages on your server and call them over the internet from client code. Clients can pass scalars, arrays and hashes to the server-side subroutines and obtain the return value ( scalar, array or hash ) back from the remote code. Some folks refer to this functionality as "remoting" or "RPC", so if you like, you can say mod_perlservice is remoting with Perl and Apache. Client programs may be written in a variety of languages; libraries for C, Perl, and Flash Action Script are all ready to go!

Now that you know what mod_perlservice is, lets look at why it is.  The author (That's me!) believes that mod_perlservice has a very clean, easy-to-use  interface when compared  with other  RPC systems. Also, since it builds on the Apache platform, it  benefits from  Apache's ubiquity, security, and status as a standard.  Since mod_perlservice sports an embedded perl interpreter, it offers high performance for demanding applications.

So what can I use this mod_perlservice for?

You can use it to create networked applications that require client-server communication, information processing and sharing.  mod_perlservice is for applications and you will not use it to create dynamic content for your HTML pages. However, you surely can use it for Flash remoting with Perl.

Here are some usage examples:

A desktop application (written using your favorite C++ GUI library) that records the current local air temperatue and sends it to an online database every 10 minutes.  The server can be queried to obtain the current and historical local air temperature of any other participating client.

A Flash-based stock portfolio management system. You can create model stock portfolios and retrieve realtime stock quote information and news.

A command-line utility in Perl that accepts English sentences on standard input and outputs the sentences in French. Translation occurs in server-side Perl code. If the sentence is idomatic and the translation is incorrect, the user has the option of sending the server a correct translation that will be stored in an online idiom database.

How Do I Get Started?

Okay, let's move onto the fun stuff and set up a working installation.

Before we begin, make sure you have everything you need!
 You need an apache webserver available at www.apache.org
 You need perl at www.perl.org
 You need expat at expat.sourceforge.net
 You need mod_perlservice
 You need a mod_perlservice client library: Perl Client | C Client | Flash Client

 * You must download a client library separately! They are not included in the mod_perlservice distro!
 
 In your build directory:

myhost$ tar -xvzf mod_perlservice.tar.gz
myhost$ cd mod_perlservice
myhost$ ./configure
myhost$ make
myhost$ make install

 
 If everything goes to plan, you'll have mod_perlservice.so in your apache modules dir, (usually /etc/apache/modules)

 Now we need to configure Apache to use mod_perlservice.
 cd into your apache conf directory (usually /etc/apache/conf)
 
 Add the following lines to the file apache.conf:

LoadModule perlservice_module modules/mod_perlservice.so
AddModule  mod_perlservice.c


 Add the following lines to commonapache.conf:

 <IfModule mod_perlservice.c>
   <Location /perlservice>
     SetHandler mod_perlservice
     Allow From All

     PerlApp myappname /my/app/dir

     #Examples
     PerlApp stockmarket /home/services/stockmarket
     PerlApp temperature /home/services/temperature

   </Location>
 </IfModule>


Pay close attention the PerlApp directive!
For every mod_perlservice application you want to run, you'll need a PerlApp directive.
So, if I were creating stock market application, I might create a directory:  /home/services/stockmarket
and add the following PerlApp directive:

PerlApp stockmarket /home/services/stockmarket

This tells mod_perlservice that you would like to host an application called stockmarket and that the perl code files will be located in the /home/services/stockmarket directory. You may run as many service applications as you wish and you may organize them however you wish.

Okay, now the config files should be set! The next step is to restart apache. This is usually done by:

myhost$ /etc/init.d/apache restart
or
myhost$ apachectl restart


Now if everything went to plan, mod_perlservice should be installed! Congratulations!

How 'Bout An Example?

 
Okay, lets create that stock portfolio example we talked about earlier. We won't implement realtime quotes, but instead we'll create a static database of some common stock names and historical prices. Our application will support stock information for General Electric (GE), Red Hat (RHAT), Coca Cola (KO), and Caterpillar (CAT).

The application will be called stockmarket and we should place all our perl files in the stockmarket application directory (/home/services/stockmarket). The first file will be "quotes.pm" and it reads as follows:

our $lookups = {  
  "General Electric" => "GE",
  "Red Hat" => "RHAT",
  "Coca Cola" => "KO",
  "Caterpillar Inc" => "CAT"
};

our $stocksymbols = {
  "GE"  =>{ "Price"=>33.91, "EarningsPerShare"=>1.544 },
  "RHAT"=>{ "Price"=>14.96, "EarningsPerShare"=>0.129 },
  "KO"  =>{ "Price"=>42.84, "EarningsPerShare"=>1.984 },
  "CAT" =>{ "Price"=>75.74, "EarningsPerShare"=>4.306 }
};

package quotes;

sub
lookupSymbol
{
  my $companyname = shift;
  return $lookups->{$companyname};
}

sub
getLookupTable
{
  return $lookups;
}

sub
getStockPrice
{
  my $stocksymbol = shift;
  return $stocksymbols->{$stocksymbol}->{"Price"};
}

sub
getAllStockInfo
{
  my $stocksymbol = shift;
  return $stocksymbols->{$stocksymbol};
}

1;

 
Okay, that's our example server-side program. Basically, we have two static "databases" ($lookups and $stocksymbols) that serve to provide information about a limited universe of stocks. The static databases are queried through the various above methods; the functionality should be fairly self-explanatory.

You may have as many ".pm" files in your application as you wish and you may also define as many packages within a ".pm" file as you wish. So an extension to this application might be a file called "news.pm" that enables you to fetch current and historical news about your favorite stocks.

Now let's talk some security. As it stands, this code won't work - mod_perlservice will restrict access to any file and method you don't explicitly export for public use. To export stuff we use the .serviceaccess file. Create this file in each application directory you declare with mod_perlservice or you'll have zero access.

Example .serviceaccess file
<ServiceAccess>
  <AllowFile name="quotes.pm">
    Allow quotes::*
  </AllowFile>
</ServiceAccess>

So this file would be /home/services/stockmarket/.serviceaccess because this is where our application resides. IMPORTANT: the apache user should NOT own this file, it could be bad for security.
The above file allows access to the file quotes.pm and allows public access to all (*) the methods in package quotes.

If you just wanted to allow access to getStockPrice, you would have put Allow quotes::getStockPrice. Then after, you could add access to lookupSymbol by adding Allow quotes::lookupSymbol.

To make this file public carte-blanche, you could put Allow *. You won't need to restart apache when you make changes to this file, it reloads automatically.

Client Code

Well, so far I've only shown you half the story. Now let's create some client side code. Our client example uses the Flash "PerlService" library, just one of the client-side interfaces to mod_perlservice ( there are clients for Perl and C as well). The Flash client was developed for browser interfaces while the perl and C clients would be used to create command line, or GUI ( ie GTK or Qt ) applications. This article is on the web, so we'll give the Flash interface a spin and then go through an example in Perl.

Flash Client
The first code smidgen should be located in the first root frame of your Flash application. Below, we basically instantiate the global PerlService object and create event handlers that get called when remote method calls return from the server. The event handlers output the requested stock information to the display box.

#include "PerlService-0.0.2.as"

// Create a global PerlService object
// Tell the PerlService object about the remote code we want to use:
// arg1) host: www.ivorycity.com
// arg2) application: stockmarket
// arg3) file: quotes.pm
// arg4) package: quotes

_global.ps = new PerlService("www.ivorycity.com","stockmarket","quotes.pm","quotes");

// First declare three callback  functions to handle return values
 
function
onStockPrice(val)
{
  output.text = "StockPrice: " + symbolInput.text + " " + val + "\n" + output.text;
}

function
onAllStockInfo(val)
{
  output.text = "Stock Info: " + allInfoInput.text + "\n" +
        "\tPrice: " + val.Price + "\n" +
        "\tEarnings Per Share: " + val.EarningsPerShare + "\n" +
        + output.text;
}

function
onLookupSymbol(val)
{
  output.text = "Lookup Result: " + symbolInput.text + " " + val + "\n" + output.text;
}

// Register callback handlers for managing the return values from the remote methods
// ie. onStockPrice receives the return value from remote method getStockPrice

ps.registerReplyHandler( "getStockPrice",  onStockPrice );
ps.registerReplyHandler( "getAllStockInfo", onAllStockInfo );
ps.registerReplyHandler( "lookupSymbol",  onLookupSymbol );



Now for the code that makes things happen! The following code is attached to three separate buttons. When clicked, the buttons call the remote perl methods using the global PerlService object. Flash Action Script is an event driven system, so click event handlers will call the remote code and return event handlers will do something with those values.



Button 1 Code

When Button 1 is clicked, call the remote method "getStockPrice" and pass the text in the first input box as an argument.

on (release)
{
  ps.getStockPrice(box1.text);
}

Button 2 Code

When Button 2 is clicked, call the remote method "getAllStockInfo" and pass the text in the second input box as an argument.

on (release)
{
  ps.getAllStockInfo(box2.text);
}

Button 3 Code

When Button 3 is clicked, call the remote method "lookupSymbol" and pass the text in the third input box as an argument.

on (release)
{
  ps.lookupSymbol(box3.text);
}

Okay, that's our Flash example! Here is the finished product below.




Perl Client
Not all of you out there use Flash, especially in the Free Software community. The great thing about mod_perlservice is that everyone can join the party. So lets, create a Perl Client that uses the same server side stockmarket API.

use PService;

my $hostname = "www.ivorycity.com";
my $appname  = "stockmarket";
my $filename = "quotes.pm";
my $package  = "quotes";

#Create the client object with following arguments:
#1) The host you want to use
#2) The application on the host
#3) The perl module file name
#4) The package you want to use

my $ps = new PSClient($hostname,$appname,$filename,$package);

# Just call those remote methods and get the return value
my $price  = $ps->getStockPrice("GE");
my $info   = $ps->getAllStockInfo("RHAT");
my $lookup = $ps->lookupSymbol("Coca Cola");

#Share your exciting new information with standard output
print "GE Price: ".$price."\n";
print "Red Hat Price: ".$info->{Price}."\n";
print "Red Hat EPS: ".$info->{EarningsPerShare}."\n";
print "Coca Cola's ticker symbol is ".$lookup."\n";

Using the PSClient object to call remote methods might feel a little awkward since you'd expect to call them like quotes::getStockPrice() ,but think of the $ps instance as a proxy class to your remote methods, if you like.

If things don't work, you can get errors by calling:

print $ps->get_errmsg();

Now, that's a local reserved function, it doesn't call the server. It's one of a few reserved functions detailed in the perl client reference.

As you can see, it requires much less work to create an example with the Perl client.  You simply instantiate the PSClient object, call the remote methods, and do something with the return values. That's it. There is no protocol decoding, dealing with HTTP, CGI arguments, or any of the old annoyances. Your remote code may as well be local code.

Thanks For Taking Our Tour!

Well that's mod_perlservice! I'm sure many of you developing client-server applications can see the advantages of this system.  Personally, I've always found the existing technologies to be inflexible and/or too cumbersome. The mod_perlservice system offers a clean, simple, and scalable interface that unites client and server side code in the most sensible way yet.

What's Next?
mod_parrotservice

Questions-Comments-Support
  michaelcollins@ivorycity.com
 
  Copyright © Ivory City Systems 2004.
  You have permission to copy and redistribute this document
so long as it retains this original copyright and trademark information.

 
  The Seahorse Emblem is a Trademark of Ivory City Systems.