|
What better could have spoiled
the party for CORBA than portability concerns?
The first drive was to standardize the client
interface of CORBA. This was a success. However,
the server side was underspecified and resulted
in incompatible server side implementations. Portability
needs to be addressed in the next specification.
This resulted in the CORBA 2.2 construct Portable
Object Adapter. Well, what is an Object Adapter?
It's the CORBA construct that adapts the CORBA
World with the Native World, more on this in a
short while from now. It implements the adapter
pattern. All CORBA objects are to be registered
with the Object Adapter, failing to do so would
make the object a mere programming language construct.
The Object Adapter creates all the CORBA Objects.
Issues like its life cycle and availability of
a native implementation to incarnate a CORBA Object
are left to the adapter to address. All in all,
the entire adapter is an important part of the
CORBA world.
What if the adapter had no standard support for
all these needs? This was what the Basic Object
Adapter offered, limited capability and space
for expansion was limited. So, in order to address
theses needs POA came by, offering a better server
side framework for CORBA applications. All that
POA added to CORBA was portability and more control
over the object life cycle. This brought in more
power to CORBA and was capable of addressing needs
of a server side framework on which CORBA Components
could be defined. More on this in a later issue.
Lets look at the POA in detail.
Actually, the Portable in the POA is an understatement.
It's more than portable. It's a framework on which
people can built their advanced server side implementations.
All issues like servant management (we shall see
what a servant is in some time from now) and request
handling are taken care of by the POA. I am not
going to give a detailed introduction to the POA.
However, what I shall talk to you will be about
the servant management issues in the POA. The
POA makes the lifecycle of a CORBA Object more
complete. A CORBA Object goes through four stages
in its entire life cycle.
- Creation
- Incarnation
- Etheralization
- Destruction
Creating a CORBA Object introduces
it to the CORBA World and from that point onwards,
its available for any client to make invocation.
This is equivalent to saying new to a Java Object,
except that it has CORBA semantics like being
location independent and platform independent.
The essence of this approach is hiding all platform
details behind an interface that it promises to
implements.
Lets jump to deletion of a CORBA Object. It's
as good as saying delete to a Java Object. What
would happen behind the scene is plain, whenever
a request is received for a deleted CORBA Object,
the Object Adapter will throw a OBJECT_NOT_EXIST
exception. This is the death certificate for a
CORBA Object. Once the Object Adapter decided
to throw this exception, it should continually
maintain to throw it. You cannot reactivate a
dead CORBA Object and doing so would keep you
out of the CORBA Object Model.
Before I take you the details of incarnation and
etheralization, I would like to make a few points
clear. A CORBA Object lives in the CORBA World,
which is independent of all architectural and
implementation issues. As I said before, this
is achieved with the help of IDL. However, we
still need a mechanism to deal with CORBA requests.
This is where native issues starts creeping in.
You need a native entity to handle the request.
A native entity could be a Java Object or could
be a Python Object. We call this native entity
a Servant. Servant management mainly deals with
associating a CORBA Object with a native implementation.
Incarnation is the process by which a CORBA Object
is bound with a native servant. POA offers us
a portable and dynamic way of associating a CORBA
Object with its Servant. Meaning, we can bind
the Servant to the CORBA Object at runtime (some
form of late binding). Hence the term servant
management. We control the servant management
characteristics of a POA with POA Policies. POA
Policies control the characteristics of the POA,
which manages the CORBA Object. Etheralization
is the opposite of Incarnation. Here we delete
the binding between the CORBA Object and its Servant.
Now, the concept of all objects being accessed
by their interface using references was limiting.
There needed to be objects by value semantics
for CORBA. This resulted in the Object by Value
specification for CORBA (This specification has
gone through some changes and is now called Value
Type specification). When dealing with data structures
that would need to be copied from the server side
to the client side, for reasons like efficiency
and prevention of direct access to the data, there
needed to be a mechanism to pass objects by value.
However, what a CORBA Object offered was just
an interface and did not define state. What came
close to object by value were structures. However,
there was no behavior associated with it and inheritance
was not possible. The lack of specifying behavior
resulted in encapsulation being broken - what
is to be done with the data is now left to the
client, essentially resulting in various incompatible
implementations. So, there needed to be a new
type in the CORBA that answered this issue. Thus
came a compromise that resulted in an integration
of structures and interfaces. It was called valuetypes.
In IDL speak "value".
However, valuetypes did not augment objects by
value semantics to CORBA Objects. It's a totally
new type introduced to associate behavior and
inheritance with data and has no remote semantics.
All operations performed on valuetypes are done
on a local copy. When a valuetypes is passed over
the wire, a stream of bytes representing the data
is passed and a copy is reconstructed at the calle's
side. Why was it difficult to address these issues
at the CORBA Object level? To pass a CORBA Object
by value required of migrating it from the server
to a client side. This meant unregistering it
from the POA at the server side and registering
it at the client side. Easy said than done. A
stateful POA, which kept track of all the object
references, would be a bottleneck for CORBA. First
of all it's not scalable and portability would
be difficult to address. A global repository of
CORBA Objects would be a solution, this is complex
and with the existing CORBA infrastructure was
not possible.
So lets see more about valuetypes and how to use
it efficiently. Here I quote the Valuetype specification.
- Valuetypes were designed to support complex
state descriptions like arbitrary graphs with
recursion and cycles.
- Instances of valuetypes are local in the context
in which they are used and always copied when
passed as a parameter to a remote call.
- They support both public and private data
members. Protected members are in consideration.
- They can be used to specify the state of an
object (not a CORBA Object) implementation.
- They support single inheritance and can support
an interface. They can derive from multiple
abstract valuetypes and abstract interfaces.
Valuetypes come in two forms,
those that have state and those that do not have
state. We have seen valuetypes with state. Well,
if the intention of a valuetype was to express
state, what is a stateless valuetype doing? They
are more used to achieve the polymorphic behavior
that has been so much used in OOP. Abstract valuetypes
contain just operations and look more like an
interface. They are a bundle of operation signatures,
just like in an interface; however, all the operations
are performed locally. Also, a concrete valuetypes
with empty state is not an abstract valuetype.
A valuetype is copied only if its part of an interface
operation specification, otherwise, just the reference
of the valuetype is sent if its passed to an operation
in a valuetype. Lets talk about copy semantics
a bit more in detail. When an operation takes
the same valuetype in two in parameters, a single
valuetype is passed instead of multiple ones.
This is contrary to what happens when a structure
is passed over the wire. Also, copy semantics
ensure that a valuetype that is passed from the
server will be replicated as is on the client
side, meaning, all valuetype reference semantics
will be assured to hold at the client side. An
arbitrary graph with cycles and recursions will
hold on, no separate copy is created. This is
much in line with the way we do it in many programming
languages.
Also, null semantics are also allowed. You could
not have passed a null structure in CORBA, however,
with the addition of valueboxes, you can easily
achieve this. So is the case of strings. Infact,
the CORBA module has an additional valuebox called
StringValue and WstringValue that are added.
So much for semantics. Now more about valuetype
creation and destruction. Basically, valutypes
are to look much like a special native language
object, which has state and behavior. Even the
construction and destruction is to look very natural.
As for construction, as soon a valuetype enters
an address space, it's the responsibility of the
ORB to provide a new implementation construct
in the current context. For this, there need to
be factories in the system. So, there need to
be factories that got to be registered with the
ORB, indicating the repository id of the valuetype
that its creating. As for destruction, it's just
plain deletion as in the case of a normal native
object.
Now, the valuetype specifiers did something surprising.
They added a concept called abstract interfaces.
Well, does it make sense to introduce a new concept
called abstract interfaces into the CORBA type
system when there really existed interfaces, that
again was abstract by definition? Let's see this
in more detail. The introduction of abstract interfaces
has much to do with the ability to hide the fact
whether a valuetype or a CORBA Object reference
is passed to the client. More clearly, if it's
not possible to determine it a valuetype or a
CORBA Object is expected at compile time. This
is not a very common situation. I do not see where
abstract valuetypes can be used practically. One
of the reason that was given was the ability to
achieve security in CORBA. The idea was so supply
a reference to a trusted client and a value to
an untrusted client. All that is achieved with
abstract interfaces is implementation independence,
which I strongly content, it would have been achievable
with interfaces. You need not worry about what
kind of an implementation you are accessing. It
could be a remote/collocated CORBA Object or a
local valuetype.
Abstract valuetypes and support for interfaces
also added to CORBA some very special cases. Narrowing
and widening of abstract valuetypes. As is valuetypes
can be widened and narrowed to it's base valuetypes,
abstract, concrete or even interfaces. However,
an interface type cannot be narrowed down to a
valuetype instance. If the designer of the interface
would wish this behavior, an operation on the
interface, which returns a valuetype, has to be
included. Also, if a valuetype that supports an
interface is to be passed as a reference, it has
to be registered with the object adapter. An IOR
will be passed to the calle in this case. If not,
an OBJECT_NOT_EXISTS exception will be thrown.
What if it's a valuetype that is to be narrowed
down to? It requires of an implementation of the
requested valuetype with it. As discussed above,
we can provide a factory type. It's also possible
that a truncateable specified added to a valuetype
inheritance specification. Meaning, truncate the
valuetype to the base type and all those state
members that belong to the derived type are discarded.
This could lead to some problems, if the state
is to be transferred to another implementation.
However, it might look structurally complete to
do so. Well, what if the implementation is not
available, it will raise a NO_IMPLEMENT exception.
I should also mention a very powerful feature
of valuetypes. It's possible to download the required
code in the case of a valuetype. Provision of
this is allowed with the help of a codebase argument.
Its possible that some client on the Internet
can download the required Java class files and
work perfectly. As for C++, its a possibility
as well if code is written in shared libraries.
However, it won't be as flexible as the Java solution.
Lets look at the Java Mapping for Valuetypes and
the like. A concrete value is mapped to a concrete
usable class, similar to that of a struct. Unlike
structs, the valuetype extends from the Java interface
java.io.Serializable (very real). Remember that
all valutypes implicitly inherit from CORBA::ValueBase.
And java.io.Serializable is the equivalent for
it in the mapping. An abstract valuetype is mapped
to an interface in Java. They too inherit from
the java.io.Serializable interface. Also, corresponding
Helper and Holder classes are generated. A valuetype
that supports an interface uses the tie mechanism
to achieve the needed semantics.
Let's take an example:
typedef
sequence WeightedSeq;
module Example {
value WeightedBinaryTree {
// private members
unsigned long weight;
WeightedBinaryTree left;
WeightedBinaryTree right;
// constructor...
init();
// operations
WeightedSeq preOrder();
WeightedSeq postOrder();
};
}; |
| Is mapped to: |
public
class WeightedBinaryTree implements java.io.Serializable
{
// instance variables
private int weight;
private WeightedBinaryTree left;
private WeightedBinaryTree right;
// the constructor public
WeightedBinaryTree( int w ) {...}
// operations
public int[] preOrder();
public int[] postOrder();
}
final public class WeightedBinaryTreeHelper
{
...
public static org.omg.CORBA.ValueDef get_value_def()
{ ... }
...
}
final public class WeightedBinaryTreeHolder
{
public WeightedBinaryTree value;
public WeightedBinaryTreeHolder() { ... }
...
public void _read( ... ) { ... }
public void _wirte( ... ) { ... }
public org.omg.CORBA.TypeCOde _type() { ...
}
} |
| Why did we
talk so much about Valuetypes when this is
an article on Java and CORBA integration?
We shall see more in the next session. |
- Mr.
Jacob Jose Cherakal - Software Architect,
|