Quick Start with Python

Python is a rich object oriented (OO) scripting language being a good choice for rapid prototyping up to complete projects. Implementing server and client of this distributed postoffice is straight forward and could be integrated easily into existing applications.

Please have a look for the code here: postoffice python code

TipRequirements
 

You need at least Python-2.2 and newest version of orbit-python-1.99 . In case you are running Redhat-8.0 GNU/Linux or similar distribution you need to update the orbit-python library. Have a look at the website of you distributer and install from there the update of orbit-python packages. If not available it is possible to download original sources from CVS repository and compile it on your machine, here a quick sketch:

Table 2. Updating ORBit-Python

# check out project sources of orbit-python library
cd /tmp
cvs -d:pserver:anonymous@cvs.orbit-python.sourceforge.net:/cvsroot/orbit-python login
#press enter for 'login'

cvs -z3 -d:pserver:anonymous@cvs.orbit-python.sourceforge.net:/cvsroot/orbit-python co
python-orbit

# change to checked out project and compile sources
cd /tmp/python-orbit
./configure --prefix=/usr
make

# switch user to administrator (super user)
su
#enter root-password
make install

Server Application

Writing the server with Python is quite simple, and needs a few lines of code only. Each line of code will be explained afterwards.

Table 3. PostOffice server application


#!/usr/bin/env python

#    PostOffice, demo application for ORBit2. 
#    Copyright (C) 2001  Frank Rehberger <frehberg@cs.tu-berlin.de>
# 
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import CORBA
import sys
import PostOffice, PostOffice__POA

class Counter(PostOffice__POA.Counter):
    def __init__(self):
        self.box=[]
        
    def has_letter_for(self, recipient):
        print 'Counter.hasLetterFor (%s)' % (recipient)
        for letter in self.box:
            if letter.recipient==recipient:
                return 1

        return 0
    
    def fetch_letter_for (self, recipient):
        print 'Counter.fetchLetterFor (%s)' % (recipient)
        for letter in self.box:
            if letter.recipient==recipient:
                self.box.remove(letter)
                return letter

        # reached if no letter for recipient
        raise PostOffice.UnknownRecipient(message='unknown recipient')
        

    def send_letter (self, letter):
        print 'Counter.sendLetter (%s)' % (letter)
        self.box.append(letter)
        for l in self.box:
            print l

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references("RootPOA")
ref = Counter()._this() # implicit activation

poa._get_the_POAManager().activate()

# print IOR to console
#
sys.stdout.write (orb.object_to_string(ref)+"\n")
sys.stdout.flush();
orb.run()

The first lines of code import the CORBA module of Python, which might be located at path /usr/lib/python2.2/site-packages/CORBAmodule.so. Furtheron the PostOffice IDL file "postoffice.idl" is searched and loaded from current working directory. As first step the Python environment uses this interface description to generate data types and structures needed for server and client implementation of PostOffice-Counter. Every file with matching *.idl is opened to search for the interface declaration of PostOffice module.

import CORBA
import sys
import PostOffice, PostOffice__POA

Afterwards, when the IDL interfaces are present in Python environment, it is necessary to implement the logics behind. The following lines define the Counter class of our "PostOffice Counter". The Counter class inherits its interface from "PostOffice_POA.Counter", which is part of the code generated while importing the IDL file postoffice.idl. All letters of customers are stored in a single list called "box", being empty initially. Each method requests or changes state of this list.

class Counter(PostOffice__POA.Counter):
    def __init__(self):
        self.box=[]
        
    def has_letter_for(self, recipient):
        print 'Counter.hasLetterFor (%s)' % (recipient)
        for letter in self.box:
            if letter.recipient==recipient:
                return 1

        return 0
    
    def fetch_letter_for (self, recipient):
        print 'Counter.fetchLetterFor (%s)' % (recipient)
        for letter in self.box:
            if letter.recipient==recipient:
                self.box.remove(letter)
                return letter

        # reached if no letter for recipient
        raise PostOffice.UnknownRecipient(message='unknown recipient')
        

    def send_letter (self, letter):
        print 'Counter.sendLetter (%s)' % (letter)
        self.box.append(letter)
        for l in self.box:
            print l

The last few lines instanciate the ORB setting up the CORBA environment and create a portable object adapter (POA) that serves as container for CORBA objects. Afterwards the server object of the postoffice counter itsself is created and the reference is written to some file that can be read from client to establish connection. At last the POA is activated, being ready for requests, and enters an endless event loop, waiting for client requests.

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references("RootPOA")
ref = Counter()._this() # implicit activation

poa._get_the_POAManager().activate()

# print IOR to console
#
sys.stdout.write (orb.object_to_string(ref)+"\n")
sys.stdout.flush();
orb.run()

Client Application

The client is as simple as the server to implement. Most of the CORBA stuff is done in background from Python environment which generates PostOffice data types from scratch based on postoffice.idl file. This client establishes connection to postoffice server and initially sends three letters various times. Afterwards those three letters are fetched and removed from mailbox of postoffice. Finally the client triggers exceptions by fetching letters from empty mailbox. This demonstrates how to handle CORBA exceptions.

Table 4. PostOffice Client Application

#!/usr/bin/env python

#    PostOffice, demo application for ORBit2. 
#    Copyright (C) 2001  Frank Rehberger <frehberg@cs.tu-berlin.de>
# 
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import CORBA
import sys
import PostOffice

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)

# read IOR from stdin
#
ior = raw_input()

o = orb.string_to_object(ior)

print "established connection"

letter1=PostOffice.Letter (sender='goldfinger&64;gnome.org',
                           recipient='bond&64;gnome.org',
                           content='what is your name?')

letter2=PostOffice.Letter (sender='bond&64;gnome.org',
                          recipient='goldfinger&64;gnome.org',
                          content='My Name is Bond, James Bond!')

letter3=PostOffice.Letter (sender='goldfinger&64;gnome.org',
                           recipient='pussy&64;gnome.org',
                           content='Please, show Mr. Bond his room..')

for i in range(100):
    o.send_letter (letter1)
    assert o.has_letter_for (letter1.recipient)
    print '+',

for i in range(100):
    o.send_letter (letter2)
    assert o.has_letter_for (letter2.recipient)
    print '+',
    
for i in range(100):
    o.send_letter (letter3)
    assert o.has_letter_for (letter3.recipient)
    print '+',
    
try:
    while o.has_letter_for (letter1.recipient):
        letter=o.fetch_letter_for (letter1.recipient)
        print '-',
        
    while o.has_letter_for (letter2.recipient):
        letter=o.fetch_letter_for (letter2.recipient)
        print '-',

    while o.has_letter_for (letter3.recipient):
        letter=o.fetch_letter_for (letter3.recipient)
        print '-',

    print
    print "ok"
except:
    print 'server raised unexpected exception'

for i in range(100):
     try:
         letter=o.fetch_letter_for (letter1.recipient)
         print "CRITICAL, exception expected"
     except PostOffice.UnknownRecipient, e:
         print '!',

print
print "ok"

To run the application you need to start the server at first, which writes the objects IOR to file postoffice.ior:

bash$ ./postoffice-server.py > objref.ior
      

Afterwards the client can be started that reads the postoffice.ior file and will connect to server., eg:

bash$ ./postoffice-client.py < objref.ior
      

The client reads the stringified obejct reference from redirected console input and will connect to the service.

Bonobo Activation

FIXME, write this section