[Up: Implementation Overview]
[Previous: Interface Repository] [Next: POA]
The Basic Object Adapter (BOA) is the only object adapter specified by CORBA 2. One of its main features is the ability to activate object implementations4.4 when their service is requested by a client. Using the implementation repository the BOA decides how an object implementation has to be activated4.5.
To fulfill these requirements of the CORBA 2 specification the BOA is
implemented partially by a library (libmico2.3.6.a) and
partially by a separate program (micod
) called the BOA daemon.
Similar to the ORB initialization described in section 4.1.1 the BOA has to be initialized like this:
int main (int argc, char *argv[]) { CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, "mico-local-orb"); CORBA::BOA_var boa = orb->BOA_init (argc, argv, "mico-local-boa"); ... }
That way it has access to the applications command line arguments. After
evaluating them the BOA will remove the command line options it knows about
from argv
. As for the ORB you can put BOA specific command line
options into a file called .micorc
in your home directory. Arguments
given on the command line override settings from .micorc
. Here is
a list of command line options the BOA understands:
mico-local-boa
is the only currently
supported BOA identifier.
The BOA daemon (micod
) is the part of the basic object adapter
that activates object implementations when their service is requested.
Moreover micod
contains the implementation repository. To make all
MICO applications use a single implementation repository you have to
take similar actions as for the interface repository as described in
section 4.2. That is you have to tell micod
an address
to bind to using the -ORBIIOPAddr
option and tell all MICO
applications this address by using the -ORBImplRepoAddr
option.
For example:
micod -ORBIIOPAddr inet:<micod-host-name>:9999
Now you can run all MICO applications like this:
some_mico_application -ORBImplRepoAddr inet:<micod-host-name>:9999
or you can put the option into .micorc
and run
some_mico_application
without arguments.
micod
understands the following command line arguments:
micod
to make use of GIOP location
forwarding, which results in much better performance (there is
nearly no overhead compared to not using micod at
all). Unfortunately this requires some client side GIOP features
that some ORBs do not support properly although prescribed in the
CORBA specification. Therefore you may encounter problems when using
clients implemented using such broken ORBs. That is why this feature
is off by default.micod
should save the contents of the
implementation repository when exiting4.6.
When micod
is restarted afterwards it will read the file given
by the --db
option to restore the contents of the implementation
repository.
The implementation repository is the place where information about an object implementation (also known as server) is stored. The CORBA 2 specification gives you only an idea what the implementation repository is for, but does not specify the interface to it. So the design of the implementation repository is MICO specific. Here is the IDL for MICO's implementation repository:
1: module CORBA { 2: /* 3: * Implementation Repository Entry 4: */ 5: interface ImplementationDef { 6: 7: enum ActivationMode { 8: ActivateShared, ActivateUnshared, 9: ActivatePerMethod, 10: ActivatePersistent, 11: ActivateLibrary 12: }; 13: 14: typedef sequence<string> RepoIdList; 15: 16: attribute ActivationMode mode; 17: attribute RepoIdList repoids; 18: readonly attribute string name; 19: attribute string command; 20: }; 21: 22: /* 23: * Implementation Repository 24: */ 25: interface ImplRepository { 26: typedef sequence<ImplementationDef> ImplDefSeq; 27: 28: ImplementationDef create (...); 29: void destroy (in ImplementationDef impl_def); 30: ImplDefSeq find_by_name (in string name); 31: ImplDefSeq find_by_repoid (in string repoid); 32: ImplDefSeq find_all (); 33: }; 34: };
Interface ImplRepository
defined in lines 25-33 is the
implementation repository itself. It contains methods for creating,
destroying and finding entries. An implementation repository entry is defined
by interface ImplementationDef
in lines 5-20. There is exactly one
entry for each server which contains
for the sever. The name uniquely identifies the server. The activation mode tells the BOA whether the server should be activated once (shared server), once for each object instance (unshared server), once for each method invocation (per method server), or not at all (persistent server). See section 4.3.4 for details on activation modes. The shell command is executed by the BOA whenever the server has to be (re)started. Activation mode library is used for loading servers into the same process as the client during runtime. Instead of a shell command you have to specify the path of the loadable server module for library activation mode. Finally there is a repository id for each IDL interface implemented by the server. See section 3.3.3 for details on repository ids.
If you have written a server that should be activated by the BOA daemon
when its service is requested you have to create an entry for that server.
This can be accomplished by using the program imr
. imr
can be
used to list all entries in the implementation repository, to show detailed
information for one entry, to create a new entry, and to delete an entry.
The implementation repository is selected by the -ORBImplRepoAddr
or -ORBImplRepoIOR
options, which you usually put into your
.micorc
file.
Just issue the following command:
imr list
and you will get a listing of the names of all entries in the implementation repository.
imr info <name>
will show you detailed information for the entry named <name>
.
imr create <name> <mode> <command> <repoid1> <repoid2> ...
will create a new entry with name <name>
. <mode>
is one of
<command>
is the shell command that should be used to start the server.
Note that all paths have to be absolute since micod
's current
directory is probably different from your current directory. Furthermore
you have to make sure that the server is located on the same machine as
micod
, otherwise you have to use rsh
; see below for examples.
<repoid1>
, <repoid2>
and so on are the repository ids for
the IDL interfaces implemented by the server.
imr delete <name>
will delete the entry named <name>
.
Registering an implementation in the implementation repository does not automatically activate the implementation. Usually a non-persistent implementation is only activated by the BOA daemon when its service is requested by a client. But sometimes you have to force activation of an implementation, for instance to make the implementation register itself with a naming service.
imr activate <name> [<micod-address>]
will activate the implementation named <name>
. To do this
imr
needs to know the address of the BOA daemon. Usually this
is the same address as for the implementation repository and you do
not need to specify <micod-address>
. Only if the BOA daemon is
bound to an address different from the implementation repository
address and different from the addresses specified using the
-ORBBindAddr
option you have to specify <micod-address>
as a command line option to imr
.
Assume we want to register the account server account_server2
from section 3.3.3 as a shared server. Furthermore assume
that neither micod
nor ird
have been started yet, so we have
to get them running first. Assuming the hostname is zirkon
, you have
to do the following:
# create .micorc (only do that once) echo -ORBIfaceRepoAddr inet:zirkon:9000 > ~/.micorc echo -ORBImplRepoAddr inet:zirkon:9001 >> ~/.micorc # run ird ird -ORBIIOPAddr inet:zirkon:9000 # run micod in a different shell micod -ORBIIOPAddr inet:zirkon:9001
Now we are prepared to create the implementation repository entry for
account_server2
. Recall that this server implemented the interface
Account
whose repository id is IDL:Account:1.0
. Assuming
account_server2
has been copied to /usr/bin
you
can create the implementation repository entry using the following
command:
imr create Account shared /usr/bin/account_server2 IDL:Account:1.0
If account_server2
is located on host diamant
(i.e.,
not on zirkon
) you have to use the rsh
command.
This requires of course that you have entries in your .rhosts
file that allow micod
to execute programs on diamant
.
Here is the command to create the implementation repository entry:
imr create Account shared "rsh diamant /usr/bin/account_server2" \ IDL:Account:1.0
Now you should change account_client2.cc
to bind to the address
of micod
. Note that you no longer need to know the address of
the account server account_server2
, you only need to know the
address of micod
. Here is the part of account_client2.cc
that has to be changed:
// account_client2.cc ... CORBA::Object_var obj = orb->bind ("IDL:Account:1.0", "inet:zirkon:9001"); ...
Running the recompiled client will automatically activate
account_server2
.
Creating an entry for a loadable module (library activation mode) looks
like this if /usr/local/lib/module.so
is the path to the module:
imr create Account library /usr/local/lib/module.so IDL:Account:1.0
Note that you have to make sure that a loadable module and a client that wants to make use of the module reside on the same machine.
As mentioned in the previous section the BOA supports several activation modes. Using them is not simply a matter of creating an implementation repository entry, instead an object implementation has to use special BOA functionality according to the selected activation mode. This section gives you some details on this topic.
Shared servers can serve any number of object instances, which is probably the most widely used approach. The account server from section 3.3.3 is an example for a shared server. Lets look at the code again:
1: // file account_server2.cc 2: 3: #include "account.h" 4: 5: class Account_impl : virtual public Account_skel 6: { 7: // unchanged, see section "MICO Application" 8: // ... 9: }; 10: 11: 12: int main( int argc, char *argv[] ) 13: { 14: // ORB initialization 15: CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" ); 16: CORBA::BOA_var boa = orb->BOA_init( argc, argv, "mico-local-boa" ); 17: 18: Account_impl* server = new Account_impl; 19: 20: boa->impl_is_ready( CORBA::ImplementationDef::_nil() ); 21: orb->run (); 22: CORBA::release( server ); 23: return 0; 24: }
After creating the implementation repository entry for the account server
using the imr
utility the account server stays inactive until the
account client wants to bind to an object with repository id
IDL:Account:1.0
. The BOA daemon recognizes that there are no active
account objects and consults the implementation repository for servers that
implement objects with repository id IDL:Account:1.0
. It will find
the account server and run it. The account server in turn creates an
account object in line 18, which will be announced to the BOA daemon.
The server uses impl_is_ready()
to tell the BOA daemon that
it has completed initialization and is prepared to receive method
invocations. The BOA daemon in turn finds the newly created account object
and answers the bind request from the client with it. Finally run()
is called on the ORB to start processing events.
run()
will wait for requests and serve them as they arrive
until the deactivate_impl()
method is called, which deactivates
the server. Calling the ORB method shutdown()
will make
run()
return and the account server will exit. If method
invocations arrive after the server has exited the BOA daemon will
restart the server. See section 4.3.5 for details on
restaring servers.
There are many reasons for calling deactivate_impl()
. For example we
could augment the account objects interface by a management interface that
offers a method exit()
that will shut down the account
server4.7:
// account.idl interface Account { ... void exit (); };
The implementation of the exit()
method would look like this:
// account.idl class Account_impl : virtual public Account_skel { ... public: ... virtual void exit () { CORBA::BOA_var boa = _boa(); CORBA::ORB_var orb = _orb(); boa->deactivate_impl (CORBA::ImplementationDef::_nil()); orb->shutdown (TRUE); } };
Note that we passed a NIL ImplementationDef
to
deactivate_impl()
as well as to impl_is_ready()
. Usually
the implementation repository has to be searched to find the entry for
the server and pass this one. When passing NIL the entry will be
searched by the BOA. shutdown()
has a boolean wait
parameter which controls whether the ORB should immediately stop
processing events (wait=FALSE
) or wait until all pending
requests have completed (wait=TRUE
).
Persistent servers are just like shared servers, except that
the BOA daemon does not activate them. Instead they have to be started
by means outside of the BOA, e.g. by a system administrator or a shell
script. The code of a persistent server looks exactly like that of a a
shared server. But note that once deactivate_impl()
and
shutdown()
are called the server will not be restarted
by the BOA daemon.
That means persistent servers do not need a running BOA daemon. Instead
clients can connect directly to the object implementation, giving you better
performance. See section 3.3.3 for an example. However,
there is a reason to have even persistent servers register with the
BOA daemon: you can do a bind()
using the address of the BOA daemon,
that is you do not need to know the address of the persistent server. Making
a persistent server register with the BOA daemon is done like this:
some_server -OARemoteAddr <micod-address> -ORBImplRepoAddr <micod-address> \ -OAImplName <impl-name>
where <micod-address>
is the address micod
is bound
to4.8. This
is usually the same address you used as an argument to -ORBIIOPAddr
when starting micod
. See section 3.3.3 for details
on addresses, sections 4.1.1 and 4.3.1 for details
on command line arguments. <impl-name>
is the name of the entry in
the implementation repository the corresponds to the server.
Unshared servers are similar to shared servers. The difference is that
each instance of an unshared server can only serve one object
instance. That is for objects you need
running instances of an
unshared server.
Furthermore you cannot use impl_is_ready()
and
deactivate_impl()
but have to use obj_is_ready()
and
deactivate_obj()
instead. Here is the main()
function of an
unshared account server:
1: // file account_server2.cc 2: 3: #include "account.h" 4: 5: class Account_impl : virtual public Account_skel 6: { 7: // unchanged, see section "MICO Application" 8: // ... 9: }; 10: 11: 12: int main( int argc, char *argv[] ) 13: { 14: // ORB initialization 15: CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" ); 16: CORBA::BOA_var boa = orb->BOA_init( argc, argv, "mico-local-boa" ); 17: 18: Account_impl* server = new Account_impl; 19: 20: boa->obj_is_ready (server, CORBA::ImplementationDef::_nil()); 21: orb->run (); 22: CORBA::release( server ); 23: return 0; 24: }
The exit()
method would look like this in an unshared server:
// account.idl class Account_impl : virtual public Account_skel { ... public: ... virtual void exit () { CORBA::BOA_var boa = _boa(); CORBA::ORB_var orb = _orb(); boa->deactivate_obj (this); orb->shutdown (TRUE); } };
Although an unshared server instance can only serve one object instance it can create more than one object instance. Imagine for instance a bank object
// bank.idl interface Bank { Account create (); void destroy (in Account account); };
that can create new account objects and destroy account objects that are
no longer needed4.9.
The implementation of the create()
method in an unshared server
would look like this:
1: // bank_server.cc 2: class Bank_impl : virtual public Bank_skel { 3: ... 4: public: 5: ... 6: virtual Account_ptr create () 7: { 8: Account_ptr account = new Account_impl; 9: 10: CORBA::BOA_var boa = _boa(); 11: boa->deactivate_obj (account); 12: 13: return Account::_duplicate (account); 14: } 15: };
Note that line 11 calls deactivate_obj()
on the newly created
object4.10. This will tell the
BOA daemon that you are not going to serve this object, instead a new
server instance has to be activated for serving the newly created
account object. For this to work you must of course implement saving
and restoring for your objects as described in section
4.3.5.
If you need access to the newly created account object from within the
server where it was first created you need to take special actions. The
reason for this is that the created account object is initially an account
object implementation (Account_impl
), but in order to access the moved
account object in the other server you need an account stub
(Account_stub
). Here is how to create this stub:
1: // bank_server.cc 2: class Bank_impl : virtual public Bank_skel { 3: ... 4: public: 5: ... 6: virtual Account_ptr create () 7: { 8: CORBA::BOA_var boa = _boa(); 9: CORBA::ORB_var orb = _orb(); 10: 11: Account_ptr account = new Account_impl; 12: boa->deactivate_obj (account); 13: 14: // turn 'account' into a stub 15: CORBA::String_var ref = orb->object_to_string (account); 16: CORBA::release (account); 17: CORBA::Object_var obj = orb->string_to_object (ref); 18: account = Account::_narrow (obj); 19: 20: // now you can invoke methods on (the remote) 'account' 21: account->deposit (100); 22: 23: return Account::_duplicate (account); 24: } 25: };
The demo/boa/account3
directory contains a complete example for
an unshared server that creates more than one object.
Per Method servers are similar to unshared servers, except that
a new server instance is launched for each method invocation. The code
for a per method server looks the same as for an unshared server. But
note that run()
will return after the first method
invocation, whereas in an unshared server run()
will
not return until you call shutdown()
.
All activation modes discussed up until now assume client and server are different programs that run in separate processes. This approach has the advantage that client and server can be bound to each other dynamically during runtime. The drawback is the overhead for doing method invocations across process boundaries using some kind of IPC. The activation mode library eliminates this drawback while still allowing runtime binding. This is achieved by loading an object implementation (called a module from now on) into the running client. Invoking methods on an object loaded this way is as fast as a C++ method invocation.
A client that wants to use this feature does not differ from other clients,
only the loadable module requires special code and you have to create a
special entry in the implementation repository. To give you an example we
want to change the bank account example from section 3.3.3
to make use of dynamic loading. The only change in the client is the
address specified in the call to bind()
: we have to use
"local:"
instead of "inet:localhost:8888"
, because we want
to bind to the dynamically loaded object running in the same process:
1: // file account_client2.cc 2: 3: #include "account.h" 4: 5: 6: int main( int argc, char *argv[] ) 7: { 8: // ORB initialization 9: CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" ); 10: CORBA::BOA_var boa = orb->BOA_init( argc, argv, "mico-local-boa" ); 11: 12: CORBA::Object_var obj 13: = orb->bind ("IDL:Account:1.0", "local:"); 14: if (CORBA::is_nil (obj)) { 15: // no such object found ... 16: } 17: Account_var client = Account::_narrow( obj ); 18: 19: client->deposit( 700 ); 20: client->withdraw( 250 ); 21: cout << "Balance is " << client->balance() << endl; 22: 23: return 0; 24: }
Here is the code for the loadable module:
0: // file module.cc 1: 2: #include "account.h" 3: #include <mico/template_impl.h> 4: 5: class Account_impl : virtual public Account_skel 6: { 7: // unchanged, see section "MICO Application" 8: // ... 9: }; 10: 11: static Account_ptr server = Account::_nil(); 12: 13: extern "C" CORBA::Boolean 14: mico_module_init (const char *version) 15: { 16: if (strcmp (version, MICO_VERSION)) 17: return FALSE; 18: server = new Account_impl; 19: return TRUE; 20: } 21: 22: extern "C" void 23: mico_module_exit () 24: { 25: CORBA::release (server); 26: }
Lines 13-20 define a function mico_module_init()
that is called when
the module is loaded into the running client. Note that this function must
be declared as extern "C"
to avoid C++ name mangling.
The version
argument to mico_module_init()
is a string
specifying the MICO-version of the client the module is loaded into.
Lines 16 and 17 check if this version is the same as the MICO-version
the module was compiled with and make module initialization fail by returning
FALSE
if they differ. Otherwise a new account object is created and
TRUE
is returned indicating successful module initialization. Note
that mico_module_init()
must not perform ORB and BOA initialization
since the client the module is loaded into did this already. The function
mico_module_exit()
is called just before the module is unloaded from
the client and should release all allocated resources: in our example the
account object created in mico_module_init()
.
mico_module_exit()
is only called if mico_module_init()
returned
TRUE
. Modules have to be compiled as a shared library, see section
4.6 for details and an example.
Although communication does not go through the BOA daemon when using
loadable modules you need a running micod
because
you have to create an implementation repository entry for the module.
See section 4.3.3 for details. The directory demo/shlib
contains a complete example.
There is currently one problem with loadable modules: throwing exceptions from a loadable module into non-loadable module code results in a segmentation fault. This is not a bug in MICO but in the GNU-C++ compiler and/or dynamic loader.
In the last section we saw two cases where an object had to be ``moved'' between two different instances of a server4.11:
In all these cases the state of the moved object has to be saved before and restored after moving. Because the BOA has no information about the internal state of an object the user has to provide code for saving and restoring. However, the BOA offers you some support methods.
Saving is done in the _save_object()
method of the object
implementation. If you do not provide this method for an object,
_save_object()
from the base class will be used, which will cause
the object to be treated as transient (i.e., it will not be restored
later). Let us again consider the account example. The internal
state of an account object consists of the current balance. Here is how to
save the state:
1: // account_server3.cc 2: 3: #include "account.h" 4: #include <iostream.h> 5: #include <fstream.h> 6: 7: class Account_impl : virtual public Account_skel { 8: CORBA::Long _current_balance; 9: public: 10: ... 11: virtual CORBA::Boolean _save_object () 12: { 13: ofstream out (_ident()); 14: out << _current_balance; 15: return TRUE; 16: } 17: };
Pretty simple, eh? We just open a file and write the balance into it. The
only noteworthy thing is the file name, which is obtained by using the
_ident()
method. The returned string is guaranteed to be unique
among all objects managed by a single BOA daemon. If you use multiple
BOA daemons or use persistent servers that do not register with the BOA
you have to make sure no name clashes occur. One way to do this is to
create a new directory where all the files are created, in our example
/tmp/account/
would be appropriate. Another way to distinguish
different instances (objects) of on interface (class) is to use
BOA::ReferenceData
. See demo/boa/account2
for an example.
Restoring the state takes a bit more code. You need to subclass the
abstract baseclass CORBA::BOAObjectRestorer
providing an
implementation for the restore()
method:
1: // account_server3.cc 2: 3: class AccountLoader : public CORBA::BOAObjectRestorer { 4: public: 5: CORBA::Boolean restore (CORBA::Object_ptr obj) 6: { 7: if (!strcmp (obj->_repoid(), "IDL:Account:1.0")) { 8: new Account_impl (obj); 9: return TRUE; 10: } 11: // dont know about such objects 12: return FALSE; 14: } 15: };
restore()
receives an object reference for the object that has to
be restored. We use the _repoid()
method to find out the
repository id4.12 of the object to be restored. If it is equal to the
repository id of account objects ("IDL:Account:1.0"
) we can go on
with restoring, otherwise we just return FALSE
indicating that
we cannot restore the object.
Restoring the object is now just a matter of calling a special
Account_impl
constructor which we still have to define:
1: // account_server3.cc 2: 3: class Account_impl : virtual public Account_skel { 4: CORBA::Long _current_balance; 5: public: 6: ... 7: Account_impl (CORBA::Object_ptr obj) 8: : Account_skel (obj) 9: { 10: ifstream in (obj->_ident()); 11: in >> _current_balance; 12: } 13: };
The constructor is basically the counterpart to _save_object()
.
It uses _ident()
to obtain the identification string of the
object to be restored, opens the associated file and reads in the
current balance. Note the invocation of the base class constructor in
line 8, which is very important. If you forget this line the code will
still compile but will give you strange results, because the default
Account_skel
constructor will be used, which is an error.
Note that we have omitted error handling for the ease of exposition.
Usually one would check if the file exists and its contents are valid.
If an error is detected you should make
AccountLoader::restore()
return
FALSE
4.13.
Now what is left to do is to create an instance of the
AccountLoader
class. Note that you have to create at least
one such instance before you do ORB and BOA initialization,
because restoring can already occur during BOA initialization. Of
course you can create serveral different BOAObjectRestorer
subclasses each of which handles special kinds of objects. When an
object has to be restored the restore()
methods of the existing
restorer objects are called until eventually one returns TRUE
.
Note that you should not create new objects if any objects are being
restored, because otherwise you would get an infinitely growing number
of objects over time. The BOA method restoring()
returns
TRUE
if objects are being restored, FALSE
otherwise.
Here is the main()
function:
1: // account_server3.cc 2: 3: int main (int argc, char *argv[]) 4: { 5: // create loader *before* BOA initialization 6: AccountLoader loader; 7: 8: CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, "mico-local-orb"); 9: CORBA::BOA_var boa = orb->BOA_init (argc, argv, "mico-local-boa"); 10: 11: if (!boa->restoring()) { 12: // create new objects only if not restoring 13: new Account_impl; 14: } 15: boa->impl_is_ready (CORBA::ImplementationDef::_nil()); 16: orb->run (); 17: return 0; 18: }
In an unshared or per method server you would call
boa->obj_is_ready (CORBA::Object::_nil(), CORBA::ImplementationDef::_nil());
instead of impl_is_ready()
. The sources for a complete example
can be found in demo/boa/account2
.
Sometimes it is handy to know when saving of objects can occur. But you cannot rely on this being the only occurences of object saving:
_save_object()
method return FALSE
or do not provide a
_save_object()
method at all. The object will then be treated as
transient (i.e., it will not outlive the process it was created in).deactivate_obj()
on an object in an unshared or
per method server saving is done during the call to deactivate_obj()
.
Objects saved this way will not be saved again at server exit
according to 1.deactivate_impl()
in a shared or persistent server
saving of all currently activate objects is done during the call to
deactivate_impl()
.
Objects saved this way will not be saved again at server exit
according to 1.change_implementation()
, see section 4.3.6 for details.
Objects saved this way will not be saved again at server exit
according to 1.
Note that it is quite likely that invocations on objects will occure
after a call to deactivate_obj()
, deactivate_impl()
, or
change_implementation()
because the server has to execute all
(buffered) invocations that arrived up until your call to one of the
above mentioned methods. So your code must be prepared to handle this.
Although the actual code for saving and restoring the state of an account object are two-liners each real world applications often require complex code for making objects persistent. Therefore the OMG has specified the Persistent Object Service (POS), an implementation of which is not yet provided by MICO.
Up until now we described how objects are moved between different instances of the same server. Here we explain how to move objects between two completely different servers. This is for example useful if a server has to be replaced by a new version without interrupting usual business.
Recall that we augmented the account object by a management interface
in section 4.3.4. The management interface offered a method
exit()
that terminates the server when invoked. Now let us add a
method migrate()
that migrates an account object to a new server.
The new server is specified through an implementation repository entry.
// account.idl interface Account { ... void migrate (in CORBA::ImplementationDef destination); };
Here is the implementation of the migrate()
method:
1: #include "account.h" 2: 3: class Account_impl : virtual public Account_skel { 4: ... 5: public: 6: ... 7: virtual void migrate (CORBA::ImplementationDef_ptr dest) 8: { 9: CORBA::BOA_var boa = _boa(); 10: boa->change_implementation (this, dest); 11: } 12: };
The change_implementation()
in line 10 does the whole job. It will
save the object's state as described in section 4.3.4
and tell the BOA daemon to use the new implementation from now on. See
demo/boa/account4
for an example.
The current version of MICO can only perform the migration when the destination implementation is not currently active, which means that:
This limitation will be removed in a future version of MICO.
[Previous: Interface Repository] [Next: POA]
[Up: Implementation Overview]