mirror of
https://github.com/AdaCore/PolyORB.git
synced 2026-02-12 13:01:15 -08:00
980 lines
32 KiB
Plaintext
980 lines
32 KiB
Plaintext
@c Copyright (C) 2004-2015, Free Software Foundation, Inc.
|
|
|
|
\input texinfo @c load conversion file for TeX format
|
|
|
|
@c start of the header
|
|
@setfilename polyorb_dg.info
|
|
@settitle PolyORB Developer's Guide
|
|
@documentlanguage en
|
|
@documentencoding US-ASCII
|
|
@syncodeindex fn cp
|
|
@c end of the header
|
|
|
|
@copying
|
|
Here shall lie the licence of this document
|
|
@end copying
|
|
|
|
@titlepage
|
|
@title PolyORB Developer's Guide
|
|
@author Thomas Vergnaud
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
@insertcopying
|
|
@end titlepage
|
|
|
|
@contents
|
|
@ifnottex
|
|
@node Top
|
|
@top PolyORB Developer's Guide
|
|
@insertcopying
|
|
@end ifnottex
|
|
|
|
@menu
|
|
* About this guide::
|
|
* Introduction::
|
|
* Main packages::
|
|
* Application personalities::
|
|
* Protocol layer::
|
|
* Neutral layer::
|
|
* Services::
|
|
* Coding rules::
|
|
* GNU Free Documentation License::
|
|
@end menu
|
|
|
|
@c -------------------------------------------------------------------
|
|
@node About this guide
|
|
@unnumbered About this guide
|
|
@c -------------------------------------------------------------------
|
|
|
|
@noindent
|
|
This guide aims at giving you some information about the PolyORB
|
|
global structure, in order to help find your way though the packages.
|
|
It also gives you hints on how to build protocol or application
|
|
personalities.
|
|
|
|
@node Introduction
|
|
@chapter Introduction
|
|
|
|
@cindex Introduction
|
|
|
|
PolyORB aims at providing a uniform solution to build distributed
|
|
applications. To do so, the architecture of PolyORB allows for
|
|
providing multiple middleware behaviors, both on the application side
|
|
(e.g. CORBA, Distributed Systems Annex of Ada 95) and protocol side
|
|
(e.g. GIOP, SOAP). Those behaviors are implemented by
|
|
``personalities'', which can be viewed as interfaces between networks
|
|
or applications and the PolyORB core. Through them, PolyORB behaves as
|
|
if it were a particular middleware implementation.
|
|
|
|
Personalities mainly use or extend mechanisms that are provided by the
|
|
PolyORB core, and thus adapt them to implement specific
|
|
implementations. As the PolyORB core provides the basis of all what
|
|
personalities provide, it is called ``neutral core''.
|
|
|
|
What is very special in the PolyORB architecture, is that there can be
|
|
multiple application and protocol personalities in the same configuration.
|
|
Thus, PolyORB is said to have a ``schizophrenic architecture''.
|
|
@cindex schizophrenic architecture
|
|
|
|
The architecture of a PolyORB personalisation is made of three layers:
|
|
@itemize @bullet
|
|
@item the application personalities;
|
|
@item the neutral layer;
|
|
@item the protocol personalities.
|
|
@end itemize
|
|
|
|
Above the application personalities lie the user applications; the
|
|
protocol personalities directly rely on the network.
|
|
|
|
Actually, one can view three sublayers within the neutral layer. At
|
|
the very heart of the layer, there is the neutral core, which is
|
|
nearly a middleware implementation in itself. Above and below the
|
|
neutral inner core lie the mechanisms to operate with the
|
|
personalities.
|
|
|
|
@node Main packages
|
|
@chapter Main packages
|
|
|
|
As PolyORB is a rather big program, here is a short description of the
|
|
main packages, in order to help you find what functionality you
|
|
search. All these packages are located in @code{src/}.
|
|
|
|
@c -------------------
|
|
@section Tool packages
|
|
|
|
Those packages provide various tools and facilities, which can be used
|
|
by all other PolyORB packages.
|
|
|
|
@subsection @code{PolyORB.Calendar}
|
|
|
|
A calendar implementation that works with all tasking policies. See
|
|
@ref{calendar} for details.
|
|
|
|
@subsection @code{PolyORB.Log}
|
|
|
|
Logging facility. Provides a unified means for other units
|
|
to output debugging, diagnostics and error messages.
|
|
|
|
@subsection @code{PolyORB.Utils.Chained_Lists}
|
|
|
|
Generic chain list facility with generic iterator.
|
|
|
|
@subsection @code{PolyORB.Utils.Dynamic_Tables}, @code{PolyORB.Utils.Htables.*}
|
|
|
|
Functions to handle arrays of variable size, and hash tables.
|
|
|
|
@subsection @code{PolyORB.Utils.Simple_Flags}
|
|
|
|
Utility functions to provide binary flag sets.
|
|
|
|
@subsection @code{PolyORB.Utils.Strings.Lists}, @code{PolyORB.Utils.Strings}
|
|
|
|
Handling of dynamic string allocation and chained lists of strings.
|
|
|
|
@subsection @code{PolyORB.Sequences.*}
|
|
|
|
@{Bounded,unbounded@} variable length arrays (cf. CORBA.Sequences.)
|
|
Notionally based on Ada.Strings.Unbounded.
|
|
|
|
@subsection @code{PolyORB.Dynamic_Dict}
|
|
|
|
Efficient dictionnary of key-value pairs.
|
|
|
|
@subsection @code{PolyORB.Utils.Random}
|
|
|
|
A random number generator, which is meant to replace
|
|
Ada.Numerics.Discrete_Random.
|
|
|
|
@subsection @code{PolyORB.Fixed_Point}
|
|
|
|
A package to represent fixed point numbers.
|
|
|
|
@c --------------------------------
|
|
@section Configuration packages
|
|
|
|
Those packages support the main configuration functionalities of
|
|
PolyORB.
|
|
|
|
@subsection @code{PolyORB.Configuration}
|
|
|
|
User control of various middleware aspects is implemented
|
|
through a generic configuration framework.
|
|
|
|
At start-up, PolyORB will search for various configuration files,
|
|
containing application profiles. See 'polyorb.conf' for a detail
|
|
of PolyORB generic configuration, 'moma/*.conf' for MOMA specific
|
|
configuration files.
|
|
|
|
@subsection @code{PolyORB.Initialization}
|
|
|
|
Software modules manager for initialization of the middleware. Each
|
|
module is registered with this package, indicating its
|
|
dependencies. Initialization is performed as a topological sort of the
|
|
dependency lattice. A check is performed to control consistency of the
|
|
tree.
|
|
|
|
@subsection @code{PolyORB.Tasking.*}
|
|
|
|
Tasking runtime, support full tasking, ravenscar tasking subset and no
|
|
tasking modes. Provides advanced mutexes, mutexes, watchers, r/w locks
|
|
abstractions.
|
|
|
|
@subsection @code{PolyORB.Setup.*}
|
|
|
|
Handle the initialization of a PolyORB node.
|
|
|
|
@subsection @code{PolyORB.Parameters.*}
|
|
|
|
Facilities to read and handle configuration parameters. Among other
|
|
things, those packages are used to manage the configuration file
|
|
@code{polyorb.conf}.
|
|
|
|
@c ------------------------
|
|
@section Data manipulation packages
|
|
|
|
Those package gather all functions and definitions concerning the data
|
|
handled within the neutral layer.
|
|
|
|
@subsection @code{PolyORB.Types}
|
|
|
|
Base data types used throughout PolyORB.
|
|
|
|
@subsection @code{PolyORB.Any.*}
|
|
|
|
Neutral, self-descriptive data representation. See @ref{any types} for
|
|
details.
|
|
|
|
|
|
|
|
@c -------------------------
|
|
@section Architectural packages
|
|
|
|
Those packages do not correspond to functional parts of PolyORB: they
|
|
provide architectural components.
|
|
|
|
@subsection @code{PolyORB.Annotations}
|
|
|
|
The Annotation pattern, which allows clients of a data structure
|
|
to independently enrich it, thus decoupling data extension from
|
|
type extension.
|
|
|
|
@subsection @code{PolyORB.Components}
|
|
|
|
The Component pattern, which allows objects to exchange
|
|
synchronous messages through connections, thus decoupling
|
|
behaviour profiles from Ada typing.
|
|
|
|
@subsection @code{PolyORB.Smart_Pointers}
|
|
|
|
The smart pointers are used to reproduce a garbage collecting process.
|
|
|
|
@c -----------
|
|
@section Application layer framework and support functionalities
|
|
|
|
@subsection @code{PolyORB.Call_Back}
|
|
|
|
Interceptor for request processing completion signalling.
|
|
|
|
@subsection @code{PolyORB.Obj_Adapters}
|
|
|
|
The abstract interface of object adapters in PolyORB.
|
|
|
|
@subsection @code{PolyORB.Poa}
|
|
|
|
The base class for all Portable Object Adapter implementations (generic
|
|
hierarchical object adapters modeled after the CORBA POA.)
|
|
|
|
@subsection @code{PolyORB.Poa_Types}
|
|
|
|
Base data structures handled by PolyORB.POA.
|
|
|
|
@subsection @code{PolyORB.Poa_Policies}
|
|
|
|
Children of this unit define various policy objects that can be used
|
|
to customise the behaviour of portable object adapters.
|
|
|
|
@subsection @code{PolyORB.Servants}, @code{PolyORB.Minimal_Servants}
|
|
|
|
Base class for all application objects.
|
|
|
|
|
|
@c -----------------------------
|
|
@section Neutral Core
|
|
|
|
@subsection @code{PolyORB.Orb}
|
|
|
|
The core component: provides the global ORB activities scheduler,
|
|
as well as registries for personality components (binding object
|
|
factories, transport access points, object adapters).
|
|
|
|
@subsection @code{PolyORB.Requests}
|
|
|
|
The central data structure in PolyORB: an object representing a method
|
|
invocation request to be executed by an object in a way that is independent
|
|
of the application and protocol personalities.
|
|
|
|
@subsection @code{PolyORB.References}
|
|
|
|
Object reference management.
|
|
|
|
@subsection @code{PolyORB.References.Binding}
|
|
|
|
Client-side binding factory. Either binds directly
|
|
or creates a binding to a remote object.
|
|
|
|
@subsection @code{PolyORB.Scheduler}
|
|
|
|
Coordinates the scheduling policies for the tasks that have been
|
|
created by the ORB.
|
|
|
|
@subsection @code{PolyORB.Jobs}
|
|
|
|
A Job is anything that can keep a task busy (like a Runnable
|
|
in Java). This unit declares an abstract Job type, and a means
|
|
to maintain job queues.
|
|
|
|
|
|
@c -------------
|
|
@section Protocol layer framework and support functionalities
|
|
|
|
@subsection @code{PolyORB.Opaque.Chunk_Pools}, @code{PolyORB.Opaque}, @code{PolyORB.Buffers}
|
|
|
|
Manage memory buffers for various purposes
|
|
|
|
@subsection @code{PolyORB.Utils.Buffers}, @code{PolyORB.Utils.Text.Buffers}
|
|
|
|
Utilities for buffer access.
|
|
|
|
@subsection @code{PolyORB.Filters}
|
|
|
|
Framework for layered components that form a protocol stack. Each
|
|
filter transmits SDUs (service data units) from its lower layer to its
|
|
upper layer, and can perform some processing on the SDU and its
|
|
associated data.
|
|
|
|
The lowest layer is a polyorb.filters.sockets.socket_filter, which
|
|
does not receive SDUs from a lower layer but directly from the ORB
|
|
engine.
|
|
|
|
The uppermost layer is a Session, which does not actually transmits
|
|
SDUs to an upper layer but takes action based on received SDUs.
|
|
|
|
@subsection @code{PolyORB.Transport}
|
|
|
|
The abstraction of access points and end points in the transport
|
|
service. An access point is an entity that has an address, to which
|
|
other nodes can connect. An end point is an entity that represents an
|
|
established connection with an access point, and can be used to
|
|
exchange information.
|
|
|
|
@subsection @code{PolyORB.Transport.Sockets}
|
|
|
|
A concrete implementation of the classes defined in PolyORB.Transport,
|
|
based on TCP sockets.
|
|
|
|
@subsection @code{PolyORB.Representations}
|
|
|
|
The abstraction of a method to represent data in a form suitable for
|
|
transmission. Children of this unit are expected to derive the
|
|
PolyORB.Representations.Representation abstract type into a concrete
|
|
type implementing one representation mechanism.
|
|
|
|
@subsection @code{PolyORB.Protocols}
|
|
|
|
The abstraction of a remote invocation protocol. To be derived by
|
|
concrete personalities. A Protocol is a factory of Session. A Session
|
|
is the actual object that implements one particular
|
|
protocols. Protocols are factories of Sessions, and are used as parts
|
|
of binding object factories.
|
|
|
|
@subsection @code{PolyORB.Binding_Data}
|
|
|
|
Client-side remote binding object factories.
|
|
|
|
|
|
@c ---------
|
|
@section Socket manipulation
|
|
|
|
Those package handle low-level operations.
|
|
|
|
@subsection @code{PolyORB.Sockets.*}
|
|
|
|
Socket management. Protocol personalities are placed between those
|
|
packages and the lower part of the neutral layer.
|
|
|
|
@subsection @code{PolyORB.Asynch_Ev.*}
|
|
|
|
Asynchronous event sources objects, which can trigger asynchronous
|
|
ORB activities to react to external stimuli.
|
|
|
|
|
|
@node Application personalities
|
|
@chapter Application personalities
|
|
|
|
@noindent
|
|
Application personalities constitute the application layer, which is
|
|
the upper part of PolyORB. Application personalities act as an
|
|
interface between user applications and inner middleware (i.e. the
|
|
neutral layer, @ref{Neutral layer}).
|
|
|
|
The client part consists of forwarding the requests made by the
|
|
application to the proper neutral primitives. The server part of a
|
|
personality mainly consists of a set of servants that handle requests.
|
|
Two kinds of servants are integrated into PolyORB: ``normal servants''
|
|
and minimal servants.
|
|
|
|
@section Setting a ``normal'' servant
|
|
|
|
Servants are components (@pxref{components}) that receive requests, do
|
|
some work on them, and then may return an answer.
|
|
|
|
@subsection Creating a servant
|
|
|
|
The type @dfn{Servant} is defined in @code{PolyORB.Servants}, and is
|
|
an abstract type, which must be derived to create a concrete servant
|
|
type that will handle the requests sent to the application managed by
|
|
your personality.
|
|
|
|
Along with this type, you must write a @code{Execute_Servant} function
|
|
that will receive messages, do some work, and then return another
|
|
message. Basically, two kinds of messages are associated to servants:
|
|
@code{Execute_Request} and @code{Executed_Request}, which are defined
|
|
in @code{PolyORB.Servants.Interface}. Thus, the body of
|
|
@code{Execute_Servant} should test if the incoming message is of type
|
|
@code{Execute_Request}, and return a message of type
|
|
@code{Executed_Request}.
|
|
|
|
An @code{Execute_Request} message contains the request to handle, and
|
|
a profile, from which comes the request, in order to know who sent the
|
|
request. An @code{Executed_Request} message just contains the answer
|
|
(the type of which is also @code{Request}).
|
|
|
|
@subsection Registering a servant
|
|
|
|
Once you have created a servant, you have to register it to the
|
|
Neutral layer so that it can be receive requests from clients.
|
|
|
|
The registering of a servant involves the @acronym{POA} (Portable
|
|
Object Adapter, @pxref{object adapter}), which is concept coming from
|
|
@acronym{CORBA}.
|
|
|
|
Assuming you have created a POA called @code{The_POA} and you want to
|
|
register a servant called @code{The_Servant}, you have to type
|
|
something like this:
|
|
|
|
@example
|
|
PolyORB.POA.Basic_POA.Set_Servant
|
|
(PolyORB.POA.Basic_POA.Basic_Obj_Adapter (The_POA.all)'Access,
|
|
The_Servant'Unchecked_Access,
|
|
Error);
|
|
@end example
|
|
|
|
By doing this, you associated @code{The_Servant} to
|
|
@code{The_POA}. Now you just have to know which reference must be used
|
|
to reach @code{The_Servant}, in order to communicate it to the
|
|
clients. This is done by getting the ID @code{The_POA} assigned to
|
|
@code{The_Servant}, and then creating a corresponding reference:
|
|
|
|
@example
|
|
declare
|
|
Servant_Id : Object_Id_Access;
|
|
The_Reference : PolyORB.References.Ref;
|
|
begin
|
|
Servant_To_Id
|
|
(PolyORB.POA.Basic_POA.Basic_Obj_Adapter
|
|
(The_POA.all)'Access,
|
|
The_Servant'Unchecked_Access,
|
|
Servant_Id,
|
|
Error);
|
|
|
|
if not PolyORB.Exceptions.Found (Error) then
|
|
Create_Reference (The_ORB,
|
|
Servant_Id,
|
|
"",
|
|
The_Reference);
|
|
end if;
|
|
end;
|
|
@end example
|
|
|
|
And then you just have to convert the reference into an IOR, URI, or
|
|
whatever you wish (@pxref{references}).
|
|
|
|
@section Setting a minimal servant
|
|
@anchor{minimal servants}
|
|
|
|
Minimal servants are alternative to classical servants. As their name
|
|
suggests, they offer less flexibility than normal servants; however
|
|
they are easier to set up, as they are some sort of pre-defined
|
|
servants. Minimal servants are provided by the packages
|
|
@code{PolyORB.Minimal_Servant} and
|
|
@code{PolyORB.Minimal_Servant.Tools}.
|
|
|
|
As for normal servants, you first have to create a concrete type by
|
|
deriving type @code{Servant}. You also have to write the specification
|
|
of a procedure named @code{Invoke}, that more or less corresponds to
|
|
@code{Execute_Servant}. @code{Invoke} receives an access to the
|
|
request, reads it and then puts the response in it while
|
|
@code{Execute_Request} receives a message containing a request and
|
|
returns another message containing a request (which should be the one
|
|
which has been received, carrying the results).
|
|
|
|
Then you just have to call @code{Initiate_Servant}, which associates
|
|
your minimal servant to the object adapter (@pxref{object adapter})
|
|
set in the ORB.
|
|
|
|
Minimal servants actually provide a simple way to easily set up
|
|
servants without bothering about object adapter configuration. The
|
|
main consequence is that a minimal servant is always referenced to the
|
|
root object adapter, while using normal servants let you reference
|
|
your servant to an object adapter you created yourself and then set in
|
|
the object adapter arborescence.
|
|
|
|
@subsection Managing the arguments
|
|
|
|
When your servant receives a request, it must get all information in
|
|
order to correctly handle the request.
|
|
|
|
Method name is simply retrieved by reading the corresponding field
|
|
inside the request.
|
|
|
|
In order to retrieve the arguments, you have to call the procedure
|
|
@code{Arguments} of the package @code{PolyORB.Requests}. Indeed, the
|
|
argument list carried by the request contains both @code{in} and
|
|
@code{out} arguments; you only want to get the @code{in} ones.
|
|
@code{Arguments} is called with the request, a freshly created NV-List
|
|
containing the signature of the arguments you are expecting, and two
|
|
parameters indicating how to handle the argument list:
|
|
@code{Identification} and @code{Can_Extend}.
|
|
|
|
@code{Identification} allows for dealing with the different ways of
|
|
handling argument lists, corresponding to different middleware
|
|
paradigms. For example, in CORBA middleware, arguments are identified
|
|
by their position, while in Web middleware they are identified by
|
|
their name. So, for a Web personality, the order in which the
|
|
personality handles the parameters does not matter. Depending on how
|
|
the applications handle arguments, you can specify how the neutral
|
|
layer should consider the argument lists.
|
|
|
|
@code{Can_Extend} is meant to indicate wether @code{Arguments} can add
|
|
arguments to your list or not. This is useful for personalities that
|
|
do not know which arguments they are supposed to receive. This is the
|
|
case for a web personality: indeed, in this middleware paradigm, the
|
|
server reads all the arguments the client sends to it, and then looks
|
|
if there is anything interesting; in @acronym{CORBA}, client and
|
|
server follow an IDL contract, so all received arguments should be
|
|
expected, and there should be no extra ones.
|
|
|
|
@section Invoking a request
|
|
|
|
Invoking a request implies three mechanisms:
|
|
|
|
@enumerate
|
|
@item
|
|
create a request;
|
|
|
|
@item
|
|
send it through the ORB;
|
|
|
|
@item
|
|
receive and analyse the answer (if the personality is based on a
|
|
request/answer mechanism).
|
|
@end enumerate
|
|
|
|
All those operations are handled by the package
|
|
@code{PolyORB.Requests}.
|
|
|
|
@subsection Creating a new request
|
|
|
|
Before sending a request to anybody, the application personality has
|
|
to create a new one. This is done by calling @code{Create_Request}
|
|
located in the package @code{PolyORB.Requests}. The main parameters
|
|
are:
|
|
|
|
@itemize
|
|
|
|
@item
|
|
the neutral reference of the targeted object;
|
|
|
|
@item
|
|
the name of the operation you want to invoke
|
|
|
|
@item
|
|
a list containing all the arguments sent to the object;
|
|
|
|
@item
|
|
a list describing the signature of the data expected as return, and an
|
|
optional other for the possible exceptions;
|
|
|
|
@end itemize
|
|
|
|
See @ref{references} for information about how to get a neutral
|
|
reference to an object. The list of arguments is built using
|
|
functions associated to @code{NV-List}s @pxref{nvlists}. Note that
|
|
the argument list has to actually contain the arguments the
|
|
application wants to send, while the return and exception lists only
|
|
contain the signature of the expected data.
|
|
|
|
|
|
@subsection Sending a request through the ORB
|
|
|
|
Sending a request is very easy: you just have to call the
|
|
@code{Invoke} procedure located in package @code{PolyORB.Requests}.
|
|
|
|
Calling @code{Invoke} will pause your application, waiting for
|
|
getting the request back with an answer.
|
|
|
|
@subsection Handling the answer
|
|
|
|
When the request comes back from the server, the field @code{Result}
|
|
contains the answer to the request.
|
|
|
|
@section Object adapter
|
|
@anchor{object adapter}
|
|
|
|
The concept of Object Adapter comes from the @acronym{CORBA}
|
|
specifications. An object adapter manages the servants in order to
|
|
send incoming requests to the proper one.
|
|
|
|
Several packages gather the functions associated with the object
|
|
adapters: they are named @code{PolyORB.Obj_Adapter.*} and
|
|
@code{PolyORB.POA.*}.
|
|
|
|
Two kinds of object adapters are presently defined within PolyORB: the
|
|
Simple Object Adapter, defined in @code{PolyORB.Obj_Adapter.Simple},
|
|
and the Portable Object Adapter (POA), defined in packages
|
|
@code{PolyORB.POA.*}.xs
|
|
|
|
@subsection Simple Object Adapter
|
|
|
|
The @acronym{SOA} only allows for basic registering and unregistering
|
|
servants: servants are registered using @code{Export} and unregistered
|
|
using @code{Unexport}. Thus it fits well for basic needs; minimal
|
|
servants rely on the SOA (see @pxref{minimal servants}). An SOA can be
|
|
created and destroyed using procedures @code{Create} and
|
|
@code{Destroy}.
|
|
|
|
@subsection Portable Object Adapter
|
|
|
|
The @acronym{POA} behaves like what is specified in @acronym{CORBA}.
|
|
POA are organized as a tree, with a root POA. You can create POAs and
|
|
attach them to another one. Each POA has a name, which is used to
|
|
retrieve it in the tree. Each POA is associated with certain policies,
|
|
that drive its behaviour.
|
|
|
|
@subsubsection Basic POA
|
|
|
|
A @acronym{POA} implementation is located in
|
|
@code{PolyORB.POA.Basic_POA}. This means that you may create other
|
|
kinds of POA for special purposes.
|
|
|
|
In order to be used in place of an SOA, the basic POA offers the same
|
|
interface as SOA. It also offers the interface specified in
|
|
@acronym{CORBA}.
|
|
|
|
@subsubsection POA policies
|
|
|
|
A POA is managed following policies, that define how to manage
|
|
servants, etc. The available policies are those that are defined
|
|
in @acronym{CORBA}. They are located in @code{PolyORB.POA_Policies.*}
|
|
|
|
@node Protocol layer
|
|
@chapter Protocol personalities
|
|
|
|
Protocol personalities handle the communications with other nodes.
|
|
All files concerning a protocol personality are usually put in a
|
|
subdirectory of @code{src/}: @code{src/soap/} for the SOAP
|
|
personality, etc.
|
|
|
|
Creating a protocol personality is basically creating subpackages that
|
|
implement concrete functions from abstract ones declared in the
|
|
neutral layer.
|
|
|
|
On an architectural point of view, a protocol personality is a stack
|
|
of filters, like a stack of layers in OSI norms.
|
|
|
|
When a protocol personality receives a request, it has to create a
|
|
neutral request, as an application personality would do
|
|
(@pxref{Application personalities}), but without including the request
|
|
parameters. Indeed, as some protocols do not indicate the structure of
|
|
the arguments, the protocol personality has to wait for a description
|
|
of the arguments coming from the application personality (which is the
|
|
only one supposed to know what is expected, according to the request
|
|
name). When the argument description comes back through the neutral
|
|
layer, then the personality can extract (unmarshal) the arguments, and
|
|
send them.
|
|
|
|
@section Reference management
|
|
|
|
As PolyORB can handle several protocols, references are actually sets
|
|
of several @dfn{profiles}, one for each protocol. Moreover, a profile
|
|
must be printable according all available reference syntaxes (URI,
|
|
IOR, etc.). A profile is identified by a @dfn{tag}, which is
|
|
associated to a string prefix that characterizes the stringified
|
|
version of the profile (i.e. ``IOR:'' for IORs) and functions to get a
|
|
the profile from a string, and vice-versa.
|
|
|
|
|
|
In order to be usable, a protocol personality has to provide functions
|
|
to manage its profiles, and register them to the neutral layer. To do
|
|
so, you have to create a subpackage of @code{PolyORB.Binding_Data},
|
|
which will contain concrete implementations of the abstract procedure
|
|
and functions declared in @code{PolyORB.Binding_Data}. The functions
|
|
provided by this package will be called by the neutral layer in order
|
|
to make conversion between profiles and printable strings.
|
|
|
|
To specify the functions that deal with references, the package must
|
|
call the @code{Register} procedures located in packages
|
|
@code{PolyORB.References.*}, giving them the profile tag, the
|
|
stringifying and destringifying functions, etc. The call to those
|
|
procedures must be handled by the PolyORB Initialization facility. To
|
|
do so, you simple have to create a procedure that will contain all the
|
|
calls to the registering procedures, and specify that this procedure
|
|
should be called when the module is initialized by PolyORB. So you
|
|
should write something like:
|
|
|
|
@example
|
|
procedure body Initialize is
|
|
begin
|
|
-- calling the registering procedures
|
|
end Initialize;
|
|
|
|
begin
|
|
Register_Module
|
|
(Module_Info'
|
|
(Name => +"binding_data.my_proto_perso",
|
|
Conflicts => Empty,
|
|
Depends => +"sockets",
|
|
Provides => +"binding_factories",
|
|
Implicit => False,
|
|
Init => Initialize'Access));
|
|
end PolyORB.Binding_Data.My_Proto_Perso;
|
|
@end example
|
|
|
|
@section Architecture of a protocol personality
|
|
|
|
As said before, a protocol personality is mainly a stack of filters
|
|
exchanging information. The filter stack relies on an access point.
|
|
An access point is associated to a socket (@code{PolyORB.Socket},
|
|
@code{PolyORB.Transport.*}). PolyORB allows to create TCP-related
|
|
access points (@code{PolyORB.Utils.TCP_Access_Points}) or UDP-related
|
|
access points (@code{PolyORB.Utils.UDP_Access_Points}).
|
|
|
|
The filter stack is built using @code{Chain_Factories} located in
|
|
@code{PolyORB.Filters}.
|
|
|
|
The access points is then registered to the ORB, using
|
|
@code{Register_Access_Point}.
|
|
|
|
@section Protocol functionalities
|
|
|
|
A protocol personality provides functionalities to perform various
|
|
operations concerning the requests. To do so, you have to create a
|
|
subpackage @code{PolyORB.Protocols.My_Proto_Perso}, which contains
|
|
concrete implementations of the abstract procedures declared in
|
|
@code{PolyORB.Protocols}.
|
|
|
|
@node Neutral layer
|
|
@chapter Neutral layer
|
|
|
|
@noindent
|
|
The Neutral Layer is actually the inner middleware in itself. It
|
|
offers several services and mechanisms to personalities.
|
|
|
|
@section References
|
|
@anchor{references}
|
|
@cindex references
|
|
|
|
@noindent
|
|
@dfn{References} are used to identify an object, a resource, or
|
|
whatever you may call it in the middleware paradigm you plan to
|
|
implement.
|
|
|
|
References generation and conversions are handled by the package
|
|
@code{PolyORB.References} and its subpackages.
|
|
|
|
Given a string representing an IOR, URI, Corbaloc, etc.@:,
|
|
@code{PolyORB.References} provides the procedure
|
|
@code{String_To_Object} that converts the string into a reference.
|
|
|
|
The symmetric operation is implemented in subpackages
|
|
@code{PolyORB.References.IOR}, @code{PolyORB.References.URI},
|
|
etc@. Each subpackage provides a function called
|
|
@code{Object_To_String} that returns a representation of the reference
|
|
using IOR, URI, etc@.
|
|
|
|
@section Components
|
|
@anchor{components}
|
|
|
|
@section Any types and associates
|
|
@anchor{any types}
|
|
|
|
Data that are exchanged between client and server are transported in
|
|
what are called @dfn{Any types}. Any types can carry various data
|
|
types: integer, string, etc.@: An Any type associates raw data to a
|
|
@dfn{TypeCode}, which indicates the nature of the
|
|
data.
|
|
|
|
@subsection Any types
|
|
|
|
All usefull functions dealing with Any types are located in package
|
|
@code{PolyORB.Any}. @code{PolyORB.Any} provides functions to compare
|
|
Any types, get their TypeCode (in order to know what kind of data
|
|
extract from them), build them and extract data from them, etc.@:
|
|
|
|
TypeCode are predefined for simple data types: Long, String, etc.@: So
|
|
@code{PolyORB.Any} provides @code{To_Any} functions to build Any types
|
|
from simple data types (integer, string, etc.), and symmetrically
|
|
provides @code{From_Any} functions to extract data from an Any type.
|
|
|
|
Complex types are a little more tricky: indeed, you have to create an
|
|
appropriate @dfn{TypeCode}, then create an Any type with this
|
|
TypeCode, and then store your data into it. The specification of the
|
|
package describes the right way for creating such complex Any types.
|
|
|
|
Here is a small example (adapted from @code{SOAP.Types} in the Web
|
|
personality). Let's suppose we want to create an array of long
|
|
integers. We first have to declare a new TypeCode, using the
|
|
stereotype @code{TC_Array}.
|
|
|
|
@example
|
|
Ar_Type : PolyORB.Any.TypeCode.Object
|
|
:= PolyORB.Any.TypeCode.TC_Array;
|
|
@end example
|
|
|
|
Then, as indicated in the specification, we have to store the size of
|
|
the array and then the type of the data we want to store.
|
|
|
|
@example
|
|
PolyORB.Any.TypeCode.Add_Parameter
|
|
(Ar_Type,
|
|
PolyORB.Any.To_Any (PolyORB.Types.Unsigned_Long
|
|
(Size_Of_The_Array_To_Store)));
|
|
PolyORB.Any.TypeCode.Add_Parameter
|
|
(Ar_Type,
|
|
To_Any (PolyORB.Any.TypeCode.TC_Long));
|
|
@end example
|
|
|
|
We then have a proper TypeCode; we have to create an Any with this TypeCode:
|
|
|
|
@example
|
|
Ar : PolyORB.Any.Any :=
|
|
PolyORB.Any.Get_Empty_Any_Aggregate (Ar_Type);
|
|
@end example
|
|
|
|
Finally we store the array into the Any:
|
|
|
|
@example
|
|
for K in The_Array'Range loop
|
|
PolyORB.Any.Add_Aggregate_Element
|
|
(Ar, To_Any (The_Array (K)));
|
|
end loop;
|
|
@end example
|
|
|
|
In order to retrieve data from an Any, we first get the TypeCode of
|
|
the Any:
|
|
|
|
@example
|
|
Kind_Of_Any : constant PolyORB.Any.TCKind
|
|
:= PolyORB.Any.TypeCode.Kind
|
|
(PolyORB.Any.Get_Unwound_Type (The_Any));
|
|
@end example
|
|
|
|
Considering this is an array, we then have to extract its size and the
|
|
type of data:
|
|
|
|
@example
|
|
if Kind_Of_Any = Tk_Array then
|
|
declare
|
|
use PolyORB.Types;
|
|
|
|
Number_Of_Elements : constant Unsigned_Long
|
|
:= Unsigned_Long (PolyORB.Any.TypeCode.Length
|
|
(PolyORB.Any.Get_Type (The_Any)));
|
|
|
|
Element_Type : constant PolyORB.Any.TypeCode.Object
|
|
:= PolyORB.Any.TypeCode.Content_Type
|
|
(PolyORB.Any.Get_Type (Item));
|
|
|
|
The_Array : array (1 .. Integer (Number_Of_Elements))
|
|
of Element_Type;
|
|
@end example
|
|
|
|
Finally, we retrieve all element one by one:
|
|
|
|
@example
|
|
begin
|
|
for Index in 1 .. Number_Of_Elements loop
|
|
The_Array (Index) := From_Any
|
|
(PolyORB.Any.Get_Aggregate_Element
|
|
(The_Any, Element_Type,
|
|
PolyORB.Types.Unsigned_Long (Index - 1)));
|
|
end loop;
|
|
end;
|
|
end if;
|
|
@end example
|
|
|
|
@subsection Named Values
|
|
@anchor{named values}
|
|
|
|
@dfn{Named Values} are data structure associating an Any type and a
|
|
string representing the data name. Named Values transport data along
|
|
with a type (provided by the Any type) and a name (stored in the
|
|
string), thus allowing to fully identify data.
|
|
|
|
Functions to handle Named Values are provided by @code{PolyORB.Any}.
|
|
|
|
@subsection NV-Lists
|
|
@anchor{nvlists}
|
|
@cindex nv-lists
|
|
|
|
@dfn{NV-List} stands for ``Named Value List''. This directly comes
|
|
from the @acronym{CORBA} specifications. All data transferred across
|
|
layers are put in NV-Lists.
|
|
|
|
The package @code{PolyORB.Any.NVLists} provides primitives to handle
|
|
NV-Lists. Before using a NV-List, you must create it using
|
|
@code{Create}; then you can add NamedValues or Any types using
|
|
@code{Add_Item} (in fact, adding an Any type will result in building a
|
|
Named Value an adding it to the NV-List). When you have finished using
|
|
the NV-List, you destroy it using @code{Free}.
|
|
|
|
@node Services
|
|
@chapter Services
|
|
|
|
PolyORB contains several packages offering services to developer.
|
|
|
|
@section Exceptions
|
|
@anchor{exceptions}
|
|
|
|
PolyORB introduces its own system of exceptions, which should be used
|
|
instead of Ada exceptions. PolyORB exceptions are defined in
|
|
@code{PolyORB.Exceptions}. they basically consist of an out parameter
|
|
passed to procedures. This may appear obsolete compared to Ada
|
|
mechanism; the main advantage of this approach is that it increases
|
|
performances compared to Ada exceptions.
|
|
|
|
@section Logging facility
|
|
|
|
The package @code{PolyORB.Log} provides a facility to display messages
|
|
on screen, typically for debugging purposes. You can use this package
|
|
this way:
|
|
|
|
@example
|
|
with PolyORB.Log;
|
|
|
|
package body MyPackage is
|
|
|
|
use PolyORB.Log;
|
|
package L is new PolyORB.Log.Facility_Log ("my.facility");
|
|
procedure O (Message : in Standard.String; Level : Log_Level := Debug)
|
|
renames L.Output;
|
|
|
|
...
|
|
|
|
pragma Debug (O ("hello there!"));
|
|
@end example
|
|
|
|
The parameter @code{Level} indicates the default logging level,
|
|
allowing for a hierarchy in messages. Usually this is set to
|
|
@code{Debug}. See @code{polyorb-log.ads} for the list of possible log
|
|
levels.
|
|
|
|
When the application is launched, the logging facility looks for a
|
|
file named @code{polyorb.conf} in the current directory. This file
|
|
should contain lines indicating from which log level messages should
|
|
be logged. The reference @code{polyorb.conf} file is located in the
|
|
src/ subdirectory. So you just have to copy it into your execution
|
|
directory and add the required lines. In our example, you should add
|
|
@example
|
|
my.facility=debug
|
|
@end example
|
|
indicating that all messages of higher importance than ``debug''
|
|
should be displayed. If you did not add a line for your logging
|
|
facility, then ``notice'' is used as a default value.
|
|
|
|
@section Calendar
|
|
@anchor{calendar}
|
|
Due to PolyORB configurability towards tasking policies, there are
|
|
restrictions regarding which package to use to get the time. Thus,
|
|
Ravenscar compliant applications cannot use @code{Ada.Calendar}. In
|
|
the other hand, systematically relying on @code{Ada.Real_Time} to get
|
|
the time may uselessly use the memory. You should use the package
|
|
@code{PolyORB.Calendar}, which provides the primitives of
|
|
@code{Ada.Calendar}, and the implementation of which depends on the
|
|
tasking policy.
|
|
|
|
@node Coding rules
|
|
@chapter Coding rules
|
|
|
|
You should follow a few coding rules, in order to preserve harmony in
|
|
the code. Basically, you must follow the GNAT coding style, and a few
|
|
others that are mentioned in a file named @code{CODING_GUIDELINES},
|
|
located in the @code{doc/} subdirectory.
|
|
|
|
@include gfdl.texi
|
|
|
|
|
|
@bye
|
|
|
|
|