Objective
=========
Provide an abstract model for providing services to the world and
for requesting services from a compatable provider.




Motivation
==========

Several GNUe tools require a platform- and implementation-independent means
of communicating with other GNUe tools:

   * GNUe Forms (client)
   * GNUe Reports (server/client)
   * GEAS (server/client) (?)
   * GNUe Integrator (server/client)
   * GNUe Transaction Server (server/client)???
   * GNUe Security Server (server/client)???

Each of these tools will need to communicate with the world via several
protocols:

   * Sockets
   * Corba
   * XML-RPC
   * SOAP
   * Local Instance (?)

The goal of GComm is to abstract inter-tool communications so that all tools
can share a common code base.  This also allows new mechanisms to be added
via plug-ins that will work with all tools.  For example, as soon as an
XML-RPC driver is implemented, all the tools using GComm can utilite XML-RPC.
Likewise, as soon as new encryption techniques are implemented, all the
GComm tools will support the new encryption model.


 Provider/Server                                              Requester/Client
                  .-------------.                  .-------------.
                  |             | --> XML-RPC  <-- |             |
MyFunction1() --> |    GComm    | -->  SOAP    <-- |    GComm    |
                  |             | --> Sockets  <-- |             | <-- Client
MyFunction2() --> | Abstraction | -->  CORBA   <-- | Abstraction |    Requests
                  |             | -->  Other   <-- |             |
                  `-------------'                  `-------------'



Remote Objects vs Remote Services
=================================

This design is meant to exposes services. It does not try to emulate
Object management for transports that do not support Object management
natively. Such a design is far too complicated of a task for GNUe to
embark upon (and would be a futile exercise as there are plenty of
existing Object management tools.) If objects are used in a non-object
transport, a simple reference passing mechanism will be used and all
objects will be maintained/accessed by the server.

However, if your design requires the use of remote objects, you might
need to re-evaluate your design as, all-to-often, objects are overkill
for remote services. (I'm sure we will get flamed for that statement,
but it's true.)


How to call methods of dynamic objects with non-object RPC?
===========================================================

If you want to call a method of a dynamic object, you need a
handle for this dynamic object. Now there are two ways to
transfer the handle from the client to the server:

a) the first parameters to any "Object" methods is a 
   "passed reference" (i.e. the object handle)
   f.e.:  Bakery.BakingUnit.setFlavor("34345634635","glaced")
   this is similar to the method definitions in
   python

b) put the object handler in front of the method name.
   f.e.: [23523sdfser3234345].setFlavor("glaced")

Because the implementation of one of these two methods is
protocol specific. Both ways can happyly coexit in different
protokol plugins.



Design Considerations
=====================

The main considerations are (in no particular order as all are critical):

   * Reusability
       GComm must meet the communication needs of all the GNUe
       GNUe clients and servers.  Where practical, this is not
       limited to the communication between the clients and
       servers, but also between the clients/servers and other
       non-GNUe sources (i.e., if a server exports a CORBA
       interface, this interface should be usable by GNUe and
       non-GNUe clients. Likewise, if a GNUe client needs to
       connect to a non-GNUe service, GComm should provide the
       basis for this connectivity.

   * Security
       GComm must securely pass through whatever security
       mechanisms are in place.  If simple username/password
       mechanisms are used, then this must be passed along.
       Likewise, if a session-ticketing mechanism is used,
       this "ticket" should be passed.

       GComm drivers should support some sort of encryption
       if the communications medium doesn't directly support
       such.

   * Modularity
       GComm should support a plug-in based driver mechanism
       so that new communication channels can easily be added
       to the system.  This will help ensure the long-term
       viability of our system as new communication methods
       can be added as they become popular.

   * Portability
       The GComm interface should be abstracted to be platform
       and communication medium independent.

       Individual drivers for OS-specific communications media
       can, of course, be OS-specific. (e.g, if someone really
       wanted an AppleTalk client, the plug-in driver could be
       Mac specific if necessary.)



Features
========

 * Exceptions
   Python server handlers can use standard Python exceptions to
   signal errors.  The GComm adapters will translate these to
   whatever error mechanism that adapter provides.  Should the
   adapter provide named exceptions, then

 * Loopback/Local Proxy Mode
   GComm provides a "short circuit" mode so that two modules designed to
   run as separate servers can be run under the same server instance and
   access each others services without using an external protocol. In
   other words, the two "servers" co-exist in the same python instance
   and can use each others' services without the use of CORBA, XML-RPC,
   or any other network-based protocol.

   To use this feature, use the "proxy" interface.



How a client works
==================

Client program needs to use services on Server X. As specified by the
end-user in its configuration file, it will use the XML-RPC adapter.

The client program gets a GComm interface instance by calling
GComm.attach(). A ClientAdapter is returned.



How a server works
==================

First, some terminology:

  * Interface: In Serverland, an Interface one of the methods of exporting
    our services.  CORBA, XML-RPC, SOAP, and SOCKETS are four separate
    Interfaces. A commdriver is written for each Interface.

  * ServerAdapter: Part of the commdriver, the ServerAdapter implements
    the required server-side code to run an Interface.


An application makes a call to GComm.bind() with a list of requested
interfaces and the location of its .grpc file

A ServerAdapter is loaded from commdrivers for each requested interface.
Currently, each ServerAdapter is forked into a separate process and
loops indefinitely. This is to ease the implementation of concurrently
running interfaces, so that the loops for CORBA will not interfere with
the loops for XML-RPC or SOCKETS (and so on...)  This may change in the
future (i.e., to a separate thread for each interface or to a select()
based polling mechanism)





Simple Example
==============

Example IDL:

  Module DonutProvider {

    Module Management {

      void   Restart()
      void   Shutdown()
      string Status()

    }

    Module Factory {

      module BakingUnit {

        string flavor
        string unitLocation

        integer requestDelivery(string address)

      }

      BakingUnit getDonutBakery (string flavor)

    }

  }



Example Client
==============


  params = { 'host': 'myserver.mydomain',
             'port': 8765,
             'transport': 'https' }

  server = GComm.attach('xmlrpc', params)


  print "Donut Plant Operational Status: ",
  print server.DonutProvider.Management.Status()


  address = 'Jason Cater\n123 Main St\nMemphis, TN 38001"
  glazedBakery = server.DonutProvider.Factory.getDonutBakery('glazed yeast')

  print "Sending %s donuts to Jason Cater" % glazedBakery.get_flavor()
  print "Kitchen in use:", glazedBakery.get_unitLocation()
  print "Success: ", glazedBakery.requestDelivery(address)


  server.close()



Possible Interfaces
===================
                                                                 OpenOffice
                      Corba     Pyro   Java RMI  XML-RPC   SOAP     UNO
                     -------- -------- -------- -------- -------- --------
Distributed Objects      X        X        X        -        ??       X

Exceptions               X        X        X        X        ??       X

Pass simple types        X        X        X        X        X        X
Pass aggegrate types     X        X        X        X        ??       X
Pass userdef types       X        X        X        ??       ??       X

Return simple types      X        X        X        ??       ??       X
Return aggregate types   X        X        X        ??       ??       X
Return userdef types     X        X        X        ??       ??       X

Python Native            -        X       ??        X        X        -
Python Bindings          X        X       ??        X        X        -

