Sophie

Sophie

distrib > Mandriva > 8.2 > i586 > media > contrib > by-pkgid > 51adff6dc4cce5d695a2dcdb26f1a3d7 > files > 319

libomniorb3-devel-3.04-4mdk.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
            "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="hevea 1.05">
<TITLE>
 Python language mapping issues
</TITLE>
</HEAD>
<BODY >
<A HREF="omniORBpy002.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="omniORBpy004.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H1>Chapter&nbsp;3&nbsp;&nbsp; Python language mapping issues</H1>
omniORBpy adheres to the standard Python mapping&nbsp;[<A HREF="omniORBpy009.html#pythonmapping"><CITE>OMG00b</CITE></A>],
so there is no need to describe the mapping here. This chapter
outlines a number of issues which are not addressed by the standard
(or are optional), and how they are resolved in omniORBpy.<BR>
<BR>
<A NAME="toc10"></A>
<H2>3.1&nbsp;&nbsp; Narrowing object references</H2>
<A NAME="sec:narrowing"></A>As explained in chapter&nbsp;<A HREF="omniORBpy002.html#chap:basics">2</A>, whenever you receive an
object reference declared to be base <TT>CORBA::Object</TT>, such as
from <TT>NamingContext::resolve()</TT> or
<TT>ORB::string_to_object()</TT>, you should narrow the reference to
the type you require. You might think that since Python is a
dynamically typed language, narrowing should never be necessary.
Unfortunately, although omniORBpy often generates object references
with the right types, it cannot do so in all circumstances.<BR>
<BR>
The rules which govern when narrowing is required are quite complex.
To be totally safe, you can <EM>always</EM> narrow object references to
the type you are expecting. The advantages of this approach are that
it is simple and that it is guaranteed to work with all Python ORBs.<BR>
<BR>
The disadvantage with calling narrow for all received object
references is that much of the time it is guaranteed not to be
necessary. If you understand the situations in which narrowing
<EM>is</EM> necessary, you can avoid spurious narrowing.<BR>
<BR>

<H3>3.1.1&nbsp;&nbsp; The gory details</H3>When object references are transmitted (or stored in stringified
IORs), they contain a single type identifier string, termed the
<I>repository id</I>. Normally, the repository id represents the most
derived interface of the object. However, it is also permitted to be
the empty string, or to refer to an interface higher up the
inheritance hierarchy. To give a concrete example, suppose there are
two IDL files:<BR>
<BR>
<PRE>
// a.idl
module M1 {
  interface A {
    void opA();
  };
};
</PRE><PRE>
// b.idl
#include "a.idl"
module M2 {
  interface B : M1::A {
    void opB();
  };
};
</PRE>A reference to an object with interface <TT>B</TT> will
normally contain the repository id `<TT>IDL:M2/B:1.0</TT>'<A NAME="text9" HREF="#note9"><SUP><FONT SIZE=2>1</FONT></SUP></A>. It is also permitted to have an empty
repository id, or the id `<TT>IDL:M1/A:1.0</TT>'.
`<TT>IDL:M1/A:1.0</TT>' is unlikely unless the server is being
deliberately obtuse.<BR>
<BR>
Whenever omniORBpy receives an object reference from
somewhere---either as a return value or as an operation argument---it
has a particular <I>target</I> interface in mind, which it compares
with the repository id it has received. A target of base
<TT>CORBA::Object</TT> is just one (common) case. For example, in the
following IDL:<BR>
<BR>
<PRE>
// c.idl
#include "a.idl"
module M3 {
  interface C {
    Object getObj();
    M1::A  getA();
  };
};
</PRE>the target interface for <TT>getObj</TT>'s return value is
<TT>CORBA::Object</TT>; the target interface for <TT>getA</TT>'s return
value is <TT>M1::A</TT>.<BR>
<BR>
omniORBpy uses the result of comparing the received and target
repository ids to determine the type of the object reference it
creates. The object reference has either the type of the received
reference, or the target type, according to this table:<BR>
<BR>
<DIV ALIGN=center>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1>
<TR><BR>
<TD ALIGN=left NOWRAP COLSPAN=2><B>Case</B></TD>
<TD VALIGN=top ALIGN=left NOWRAP><B>Objref Type</B></TD>
</TR>
<TR><TD VALIGN=top ALIGN=left NOWRAP>1.</TD>
<TD VALIGN=top ALIGN=left>The received id is the same as the target id</TD>
<TD VALIGN=top ALIGN=left NOWRAP>received</TD>
</TR>
<TR><TD VALIGN=top ALIGN=left NOWRAP>2.</TD>
<TD VALIGN=top ALIGN=left>The received id is not the same as the target id, but the
 ORB knows that the received interface is derived from
 the target interface</TD>
<TD VALIGN=top ALIGN=left NOWRAP>received</TD>
</TR>
<TR><TD VALIGN=top ALIGN=left NOWRAP>3.</TD>
<TD VALIGN=top ALIGN=left>The received id is unknown to the ORB</TD>
<TD VALIGN=top ALIGN=left NOWRAP>target</TD>
</TR>
<TR><TD VALIGN=top ALIGN=left NOWRAP>4.</TD>
<TD VALIGN=top ALIGN=left>The received id is not the same as the target id, and the
 ORB knows that the received interface is <EM>not</EM>
 derived from the target interface</TD>
<TD VALIGN=top ALIGN=left NOWRAP>target</TD>
</TR></TABLE>
</DIV><BR>
Cases 1 and 2 are the most common. Case 2 explains why it is not
necessary to narrow the result of calling
<TT>resolve_initial_references("RootPOA")</TT>: the return is always
of the known type <TT>PortableServer.POA</TT>, which is derived from the
target type of <TT>CORBA.Object</TT>.<BR>
<BR>
Case 3 is also quite common. Suppose a client knows about IDL modules
<TT>M1</TT> and <TT>M3</TT> from above, but not module <TT>M2</TT>.
When it calls <TT>getA()</TT> on an instance of <TT>M3::C</TT>, the return
value may validly be of type <TT>M2::B</TT>, which it does not know. By
creating an object reference of type <TT>M1::A</TT> in this case, the
client is still able to call the object's <TT>opA()</TT> operation. On the
other hand, if <TT>getObj()</TT> returns an object of type <TT>M2::B</TT>, the
ORB will create a reference to base <TT>CORBA::Object</TT>, since that
is the target type.<BR>
<BR>
Note that the ORB <EM>never</EM> rejects an object reference due to it
having the wrong type. Even if it knows that the received id is not
derived from the target interface (case 4), it might be the case that
the object actually has a more derived interface, which is derived
from both the type it is claiming to be <EM>and</EM> the target type.
That is, of course, extremely unlikely.<BR>
<BR>
In cases 3 and 4, the ORB confirms the type of the object by calling
<TT>_is_a()</TT> just before the first invocation on the object. If it
turns out that the object is not of the right type after all, the
<TT>CORBA.INV_OBJREF</TT> exception is raised. The alternative to this
approach would be to check the types of object references when they
were received, rather than waiting until the first invocation. That
would be inefficient, however, since it is quite possible that a
received object reference will never be used. It may also cause
objects to be activated earlier than expected.<BR>
<BR>
In summary, whenever your code receives an object reference, you
should bear in mind what omniORBpy's idea of the target type is. You
must not assume that the ORB will always correctly figure out a more
derived type than the target. One consequence of this is that you must
always narrow a plain <TT>CORBA::Object</TT> to a more specific type
before invoking on it<A NAME="text10" HREF="#note10"><SUP><FONT SIZE=2>2</FONT></SUP></A>. You
<EM>can</EM> assume that the object reference you receive is of the
target type, or something derived from it, although the object it
refers to may turn out to be invalid. The fact that omniORBpy often
<EM>is</EM> able figure out a more derived type than the target is only
useful when using the Python interactive command line.<BR>
<BR>
<A NAME="toc11"></A>
<H2>3.2&nbsp;&nbsp; Support for Any values</H2>In statically typed languages, such as C++, Anys can only be used with
built-in types and IDL-declared types for which stubs have been
generated. If, for example, a C++ program receives an Any containing a
struct for which it does not have static knowledge, it cannot easily
extract the struct contents. The only solution is to use the
inconvenient DynAny interface.<BR>
<BR>
Since Python is a dynamically typed language, it does not have this
difficulty. When omniORBpy receives an Any containing types it does
not know, it is able to create new Python types which behave exactly
as if there were statically generated stubs available. Note that this
behaviour is not required by the Python mapping specification, so
other Python ORBs may not be so accommodating.<BR>
<BR>
The equivalent of DynAny creation can be achieved by dynamically
writing and importing new IDL, as described in
section&nbsp;<A HREF="omniORBpy006.html#sec:importIDL">6.12</A>.<BR>
<BR>
There is, however, a minor fly in the ointment when it comes to
receiving Anys. When an Any is transmitted, it is sent as a TypeCode
followed by the actual value. Normally, the TypeCodes for entities
with names---members of structs, for example---contain those names as
strings. That permits omniORBpy to create types with the corresponding
names. Unfortunately, the GIOP specification permits TypeCodes to be
sent with empty strings where the names would normally
be<A NAME="text11" HREF="#note11"><SUP><FONT SIZE=2>3</FONT></SUP></A>. In this
situation, the types which omniORBpy creates cannot be given the
correct names. The contents of all types except structs and exceptions
can be accessed without having to know their names, through the
standard interfaces. Unknown structs and exceptions received by
omniORBpy have an attribute named `<TT>_values</TT>' which contains a
sequence of the member values. This attribute is omniORBpy specific.<BR>
<BR>
Similarly, TypeCodes for constructed types such as structs and unions
normally contain the repository ids of those types. This means that
omniORBpy can use types statically declared in the stubs when they are
available. Once again, the specification permits the repository id
strings to be empty<A NAME="text12" HREF="#note12"><SUP><FONT SIZE=2>4</FONT></SUP></A>. This means that even if stubs for a type received in an
Any are available, it may not be able to create a Python value with
the right type. For example, with a struct definition such as:<BR>
<BR>
<PRE>
module M {
  struct S {
    string str;
    long   l;
  };
};
</PRE>The transmitted TypeCode for <TT>M::S</TT> may contain only
the information that it is a structure containing a string followed by
a long, not that it is type <TT>M::S</TT>, or what the member names are.<BR>
<BR>
To cope with this situation, omniORBpy has an extension to the
standard interface which allows you to <I>coerce</I> an Any value to a
known type. Calling an Any's <TT>value()</TT> method with a TypeCode
argument returns either a value of the requested type, or <TT>None</TT>
if the requested TypeCode is not <I>equivalent</I> to the Any's
TypeCode. The following code is guaranteed to be safe, but is not
standard:<BR>
<BR>
<PRE>
a = # Acquire an Any from somewhere
v = a.value(CORBA.TypeCode(CORBA.id(M.S)))
if v is not None:
    print v.str
else:
    print "The Any does not contain a value compatible with M::S."
</PRE><A NAME="toc12"></A>
<H2>3.3&nbsp;&nbsp; Interface Repository stubs</H2>
<A NAME="sec:ifrstubs"></A>The Interface Repository interfaces are declared in IDL module
<TT>CORBA</TT> so, according to the Python mapping, the stubs for them
should appear in the Python <TT>CORBA</TT> module, along with all the
other CORBA definitions. However, since the stubs are extremely large,
omniORBpy does not include them by default. To do so would
unnecessarily increase the memory footprint and start-up time.<BR>
<BR>
The Interface Repository stubs are automatically included if you
define the <TT>OMNIORBPY_IMPORT_IR_STUBS</TT> environment variable.
Alternatively, you can import the stubs at run-time by calling the
<TT>omniORB.importIRStubs()</TT> function. In both cases, the stubs become
available in the Python <TT>CORBA</TT> module.<BR>
<BR>
<A NAME="toc13"></A>
<H2>3.4&nbsp;&nbsp; Using omniORBpy with omniORB 2.8</H2>omniORBpy is designed to work with omniORB 3. When it is used with
omniORB 2.8, many facilities are not available. This section describes
the limitations.<BR>
<BR>
If you require facilities which are not available with omniORB 2.8,
you can cause your program to bail-out gracefully by detecting the
omniORB version at start-up. The <TT>omniORB.coreVersion()</TT> function
returns a string of the form <I>major.minor.micro</I> which
indicates what version of omniORB is in use. The two possible values
are currently `<TT>2.8.0</TT>' and `<TT>3.0.0</TT>'. Versions which
differ only in micro version number are guaranteed to be compatible
with each other.<BR>
<BR>

<H3>3.4.1&nbsp;&nbsp; POA functions</H3>Under 2.8, only the root POA is available. It supports only the
following functions:<BR>
<BR>
<UL>
<LI>
 <TT>destroy()</TT>

<LI> <TT>_get_the_name()</TT>

<LI> <TT>_get_the_POAManager()</TT>

<LI> <TT>activate_object()</TT>

<LI> <TT>deactivate_object()</TT>

<LI> <TT>servant_to_id()</TT>

<LI> <TT>servant_to_reference()</TT>

<LI> <TT>reference_to_servant()</TT>

<LI> <TT>reference_to_id()</TT>

<LI> <TT>id_to_servant()</TT>

<LI> <TT>id_to_reference()</TT>
</UL>The <TT>POAManager</TT> interface only supports:<BR>
<BR>
<UL>
<LI>
 <TT>activate()</TT>

<LI> <TT>get_state()</TT>
</UL>For both interfaces, all other operations fail, raising the
<TT>CORBA.NO_IMPLEMENT</TT> exception.<BR>
<BR>

<H3>3.4.2&nbsp;&nbsp; Local / remote transparency</H3>omniORB 3 goes to great lengths to make sure that the semantics of
local objects are identical to those for remote objects. omniORB 2.8
does not. omniORBpy also tries very hard to keep local and remote
semantics identical, but on the foundation of omniORB 2.8 it is not
always possible.<BR>
<BR>
In most cases, you will not notice a difference between local and
remote operations. The cases where local/remote transparency is broken
under omniORB 2.8 are:<BR>
<BR>
<UL>
<LI> An object is not deactivated until all local references to it
have been released.<BR>
<BR>

<LI> When invoking on an object reference to a local object of the
wrong type, as described in section&nbsp;<A HREF="#sec:narrowing">3.1</A>,
<TT>CORBA.INV_OBJREF</TT> is not raised. Instead, if the operation name
does not exist on the object, <TT>CORBA.NO_IMPLEMENT</TT> is raised; if
the operation name <EM>does</EM> exist but the argument types are wrong,
<TT>CORBA.BAD_PARAM</TT> is raised; if the operation exists and the
argument types are correct, the operation is executed.<BR>
<BR>

<LI> Exception handlers (described later in
section&nbsp;<A HREF="omniORBpy006.html#sec:exHandlers">6.10</A>) are not executed when local objects
raise system exceptions. Exceptions are always propagated to the
caller.</UL>In all of these cases, omniORB 3 properly preserves local/remote
transparency.<BR>
<BR>
<HR WIDTH="50%" SIZE=1><DL>
<DT><A NAME="note9" HREF="#text9"><FONT SIZE=5>1</FONT></A><DD> It
is possible to change the repository id strings associated with
particular interfaces using the <TT>ID</TT>, <TT>version</TT> and
<TT>prefix</TT> pragmas.

<DT><A NAME="note10" HREF="#text10"><FONT SIZE=5>2</FONT></A><DD> Unless you are invoking pseudo
operations like <TT>_is_a()</TT> and <TT>_non_existent()</TT>.

<DT><A NAME="note11" HREF="#text11"><FONT SIZE=5>3</FONT></A><DD> This is now deprecated, but some ORBs may still send empty
strings. No version of omniORB has ever sent empty strings.

<DT><A NAME="note12" HREF="#text12"><FONT SIZE=5>4</FONT></A><DD> And once again, this practice is
deprecated.
</DL>
<HR>
<A HREF="omniORBpy002.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="omniORBpy004.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>