Sophie

Sophie

distrib > Mandriva > 8.2 > i586 > by-pkgid > b53adf8a0c2b67740bddc191aeb39a8a > files > 18

libomniorb3-doc-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>
 Interface Type Checking
</TITLE>
</HEAD>
<BODY >
<A HREF="omniORB006.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="omniORB008.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H1>Chapter&nbsp;7&nbsp;&nbsp; Interface Type Checking</H1>
<A NAME="ch_intf"></A>This chapter describes the mechanism used by omniORB to ensure type
safety when object references are exchanged across the network. This
mechanism is handled completely within the ORB. There is no
programming interface visible at the application level. However, for
the sake of diagnosing the problem when there is a type violation, it
is useful to understand the underlying mechanism in order to interpret
the error conditions reported by the ORB.<BR>
<BR>
<A NAME="toc39"></A>
<H2>7.1&nbsp;&nbsp; Introduction</H2>In GIOP/IIOP, an object reference is encoded as an Interoperable
Object Reference (IOR) when it is sent across a network connection.
The IOR contains a Repository ID (RepoId) and one or more
communication profiles. The communication profiles describe where and
how the object can be contacted. The RepoId is a string which uniquely
identifies the IDL interface of the object.<BR>
<BR>
Unless the <TT>ID</TT> pragma is specified in the IDL, the ORB generates
the RepoId string in the so-called OMG IDL Format<A NAME="text19" HREF="#note19"><SUP><FONT SIZE=2>1</FONT></SUP></A>. For instance, the RepoId for the <TT>Echo</TT>
interface used in the examples of chapter&nbsp;<A HREF="omniORB002.html#ch_basic">2</A> is
<TT>IDL:Echo:1.0</TT>.<BR>
<BR>
When interface inheritance is used in the IDL, the ORB always sends the
RepoId of the most derived interface. For example:<BR>
<BR>
<PRE>
   // IDL
   interface A {
     ...
   };
   interface B : A {
     ...
   };
   interface C {
      void op(in A arg);
   };
</PRE><PRE>
   // C++
   C_ptr server;
   B_ptr objB;
   A_ptr objA = objB;
   server-&gt;op(objA);  // Send B as A
</PRE>In the example, the operation <TT>C::op()</TT> accepts an object reference
of type <TT>A</TT>. The real type of the reference passed to <TT>C::op()</TT>
is <TT>B</TT>, which inherits from <TT>A</TT>. In this case, the RepoId of
<TT>B</TT>, and not that of <TT>A</TT>, is sent across the network.<BR>
<BR>
The GIOP/IIOP specification allows an ORB to send a null string in the
RepoId field of an IOR. It is up to the receiving end to work out the
real type of the object. omniORB never sends out null strings as
RepoId. However, it may receive null RepoId from other ORBs. In that
case, it will use the mechanism described below to ensure type safety.<BR>
<BR>
<A NAME="toc40"></A>
<H2>7.2&nbsp;&nbsp; Basic Interface Type Checking</H2>
<A NAME="sec_intf"></A>The ORB is provided with the interface information by the stubs via
the <TT>proxyObjectFactory</TT> class. For an interface <TT>A</TT>, the
stub of <TT>A</TT> contains a <TT>_pof_A</TT> class. This class is
derived from the <TT>proxyObjectFactory</TT> class. The
<TT>proxyObjectFactory</TT> is an abstract class which contains 3
functions of interest:<BR>
<BR>
<PRE>
class proxyObjectFactory {
public:

  const char *irRepoId() const;

  virtual CORBA::Boolean is_a(const char *base_repoId) const = 0;
       
  virtual CORBA::Object_ptr newObjRef(const char* mostDerivedTypeId,
                                      IOP::TaggedProfileList* profiles,
                                      omniIdentity* id,
                                      omniLocalIdentity* lid) = 0;
};
</PRE><UL>
<LI>
 <TT>irRepoId()</TT> returns the RepoId of the interface.

<LI> <TT>is_a()</TT> returns true(1) if the argument is the RepoId of the
interface itself or it is that of its base interfaces.<BR>
<BR>

<LI> <TT>newObjRef()</TT> returns an object reference based on the
information supplied in the arguments.
</UL>A single instance of every <TT>_pof_*</TT> is instantiated at runtime.
The instances are entered into a list inside the ORB. The list
constitutes all the interface information known to the ORB.<BR>
<BR>
When the ORB receives an IOR from the network, it unmarshals and
extracts the RepoId from the IOR. At this point, the ORB has two
pieces of information in hand:<BR>
<BR>
<OL type=1>
<LI>
 The RepoId of the object reference received from the network.

<LI> The RepoId the ORB is expecting. This comes from the unmarshal
 function that tells the ORB to receive the object reference.
</OL>Using the RepoId received, the ORB searches its proxyObjectFactory
list for an exact match. If there is an exact match, all is well
because the runtime can use the <TT>is_a()</TT> method of the proxyFactory
to check if the expected RepoId is the same as the received RepoId or
if it is one of its base interfaces. If the answer is positive, the
IOR passes the type checking test and the ORB can proceed to create an
object reference in its own address space to represent the IOR.<BR>
<BR>
However, the ORB may fail to find a match in its proxyObjectFactory
list. This means that the ORB has no local knowledge of the RepoId.
There are three possible causes:<BR>
<BR>
<OL type=1>
<LI>
 The remote end is another ORB and it sends a null string as the RepoId.

<LI> The ORB is expecting an object reference of interface A. The remote
 end sends the RepoId of B which is an interface that inherits from A.
 The stubs of A are linked into the executable but the stubs of B are
 not.

<LI> The remote end has sent a duff IOR.
</OL>To handle this situation, the ORB must find out the type information
dynamically. This is explained in the next section.<BR>
<BR>
<A NAME="toc41"></A>
<H2>7.3&nbsp;&nbsp; Interface Inheritance</H2>When the ORB receives an IOR of interface type B when it expects the
type to be A, it must find out if B inherits from A. When the ORB has
no local knowledge of the type B, it must work out the type of B
dynamically.<BR>
<BR>
The CORBA specification defines an Interface Repository (IR) from
which IDL interfaces can be queried dynamically. In the above
situation, the ORB could contact the IR to find out the type of B.
However, this approach assumes that an IR is always available and
contains the up-to-date information of all the interfaces used in the
domain. This assumption may not be valid in many applications.<BR>
<BR>
An alternative is to use the <TT>_is_a()</TT> operation to work out the
actual type of an object. This approach is simpler and more robust
than the previous one because no 3rd party is involved.<BR>
<BR>
<PRE>
class Object{
    CORBA::Boolean _is_a(const char* type_id);
};
</PRE>The <TT>_is_a()</TT> operation is part of the <TT>CORBA::Object</TT>
interface and must be implemented by every object. The input argument
is a RepoId. The function returns true(1) if the object is really an
instance of that type, including if that type is a base type of the
most derived type of that object.<BR>
<BR>
In the situation above, the ORB would invoke the <TT>_is_a()</TT>
operation on the object and ask if the object is of type A
<EM>before</EM> it processes any application invocation on the object.<BR>
<BR>
Notice that the <TT>_is_a()</TT> call is <EM>not</EM> performed when the IOR
is unmarshalled. It is performed just prior to the first application
invocation on the object. This leads to some interesting failure modes
if B reports that it is not an A. Consider the following example:<BR>
<BR>
<PRE>
// IDL
interface A { ... };
interface B : A { ... };
interface D { ... };
interface C {
  A      op1();
  Object op2();
};
</PRE>
<PRE>
 1  // C++
 2  C_ptr objC;
 3  A_ptr objA;
 4  CORBA::Object_ptr objR;
 5
 6  objA =  objC-&gt;op1();
 7  (void) objA-&gt;_non_existent();
 8
 9  objR =  objC-&gt;op2();
10  objA =  A::_narrow(objR);
</PRE>If the stubs of A,B,C,D are linked into the executable and:<BR>
<BR>
<DL COMPACT=compact>
<DT>
Case 1<DD> <TT>C::op1()</TT> and <TT>C::op2()</TT> return a B. Lines 6--10
complete successfully. The remote object is only contacted at line 7.<BR>
<BR>

<DT>Case 2<DD> <TT>C::op1()</TT> and <TT>C::op2()</TT> return a D. This condition
only occurs if the runtime of the remote end is buggy. The ORB raises
a CORBA::Marshal exception at line 1 because it knows it has received
an interface of the wrong type.
</DL>If only the stubs of A are linked into the executable and:<BR>
<BR>
<DL COMPACT=compact>
<DT>
Case 1<DD> <TT>C::op1()</TT> and <TT>C::op2()</TT> return a B. Lines 6--10
complete successfully. When lines 7 and 10 are executed, the object is
contacted to ask if it is an A.<BR>
<BR>

<DT>Case 2<DD> <TT>C::op1()</TT> and <TT>C::op2()</TT> return a D. This condition
only occurs if the runtime of the remote end is buggy. Line 6
completes and no exception is raised. At line 7, the object is
contacted to ask if it is an A. If the answer is no, a
<TT>CORBA::INV_OBJREF</TT> exception is raised. The application will
also see a <TT>CORBA::INV_OBJREF</TT> at line 10.
</DL><HR WIDTH="50%" SIZE=1><DL>
<DT><A NAME="note19" HREF="#text19"><FONT SIZE=5>1</FONT></A><DD> For further
details of the repository ID formats, see section 10.6 in the CORBA
2.3 specification.
</DL>
<HR>
<A HREF="omniORB006.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="omniORB008.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>