
\begin{quote}
``...  it is  very easy to be blinded to  the essential uselessness of
them by  the sense of achievement you  get from getting it  to work at
all.  In other  words --- and that is a  rock-solid principle on which
the whole of the Corporation's Galaxywide success is founded --- their
fundamental design  flaws are  completely hidden by  their superficial
design flaws.''

             D. Adams: So Long and Thanks for all the Fish
\end{quote}

The Implementation Repository is not, as its name suggests, a database
of  implementations.   Rather,  it  contains information  about  where
requests  to specific  CORBA objects  have  to be  redirected and  how
implementations  can be  transparently  instantiated if,  for a  given
request  to   an  object,  none  is   reachable.   ``Instantiating  an
implementation'' means starting a server program that hosts the target
object.  In  this  chapter  we  give  a brief  overview  and  a  short
introduction  on how to  use the  Implementation Repository.  For more
details please see \cite{Henning1999}.

\section{Overview}

Basically, the  Implementation Repository (ImR) is  an indirection for
requests  using  persistent  object  references. A  persistent  object
reference is one that was created  by a POA with a PERSISTENT lifespan
policy. This means that the lifetime of the object is longer than that
of its creating POA.   Using the Implementation Repository for objects
the lifetime  of which does not exceed  the life time of  its POA does
not make sense  as the main function of  the Implementation Repository
is to take care that such  a process exists when requests are made ---
and to start one if necessary.

To fulfill this function, the ImR  has to be involved in every request
to ``persistent  objects''.  This is achieved  by rewriting persistent
object  references to  contain {\em  not}  the address  of its  server
process but  the address  of the ImR.   Thus, requests  will initially
reach the ImR and not the actual server --- which may not exist at the
time of the request. If such a request arrives at the ImR, it looks up
the  server information  in its  internal tables  to determine  if the
target object is reachable or not.  In the latter case, the ImR has to
have  information  about how  an  appropriate  server  process can  be
started.   After   starting  this   server,  the  client   receives  a
LOCATION\_FORWARD  exception  from  the  ImR.  This  exception,  which
contains a new  object reference to the actual  server process now, is
handled by its runtime system  transparently.  As a result, the client
will automatically  reissue its request  using the new  reference, now
addressing the target directly.

\section{Using the JacORB Implementation Repository}

The  JacORB   Implementation  Repository  consists   of  two  separate
components:  a repository  process which  need  only exist  once in  a
domain, and  process startup daemons,  which must be present  on every
host that is  to start processes. Note that none  of this machinery is
necessary for processes that host  objects with a TRANSIENT life time,
such as used by the RootPOA.

First of all, the central repository process (which we will call ImR
in the following) must be started:

\cmdline{imr [-n] [-p <port>] [-i <ior\_file>][-f <file>][-b <file>] [-a]}

The   ImR   is  located   using   the   configuration  property   {\tt
ORBInitRef.ImplementationRepository}.  This property  must be set such
that  a  http  connection  can  be  made and  the  ImR's  IOR  can  be
read. Next, startup  daemons must be created on  selected hosts. To do
this, the following command must is issued on each host:

\cmdline{imr\_ssd}

When a startup  daemon is created, it contacts  the central ImR.

To register  a program such that  the ImR can start  it, the following
command is used (on any machine that can reach the ImR):

\cmdline{imr\_mg add "AServerName" -c "jaco MyServer"}

The {\tt imr\_mg} command is the  generic way of telling the ImR to do
something. It  needs another command  parameter, such as {\tt  add} in
this case. To add a server to the ImR, an {\em implementation name} is
needed. Here, it is {\tt  "AServerName"}.  If the host were the server
should be  restarted is not the  local one, use the  {\tt -h hostname}
option.  Finally, the  ImR needs to know how to  start the server. The
string {\tt "jaco  MyServer"} tells it how. The  format of this string
is simply such  that the server daemon can execute  it (using the Java
API call  {\tt exec()}), i.e.  it  must be intelligible  to the target
host's operating system.   For a Windows machine, this  could, e.g. be
{\tt "start jaco MyServer"} to have the server run in its own terminal
window, under Unix  the same can be achieved with  {\tt "xterm -e jaco
MyServer"}.

The startup  command is a  string that is  passed as the  {\em single}
argument to javas {\tt Runtime.exec()} method, without interpreting it
or adding  anything. Since {\tt  Runtime.exec()} has system--dependent
behaviour, the startup string has to reflect that. While for most unix
systems  it  is  sufficient  to  avoid shell--expansions  like  *  and
\verb+~+,  windows--based  systems  do   not  pass  the  string  to  a
commandline interpreter so a simple {\tt jaco MyServer} will fail even
if it works if directly typed in at the dos prompt. Therefore you have
to  ``wrap'' the  core  startup command  in  a call  to a  commandline
interpreter. On NT the following startup command will do the job: {\tt
cmd /c "jaco MyServer"}.  Please keep in mind that if you use the {\tt
imr\_mg} command  to set the startup  command, you have  to escape the
quotes so they appear inside of the resulting string.

If you don't  intend to have your server  automatically started by the
ImR     you      can     also     set      the     property     ``{\tt
jacorb.imr.allow\_auto\_register}'' or use the  {\tt -a} switch of the
ImR  process. If  this property  is  set, the  ImR will  automatically
create a new  entry for a server on POA activation,  if the server has
not been registered previously. In this case you don't have to use the
ImR Manager to register your server.

For a client program to be  able to issue requests, it needs an object
reference.  Up to  this  point,  we haven't  said  anything about  how
persistent object  references come into  existence. Reference creation
happens as usual, i.e. in the server application one of the respective
operations  on a  POA is  called.  For a  reference to  be created  as
``persistent'',  the POA  must  have been  created  with a  PERSISTENT
lifespan policy. This is done as in the following code snippet:

\small{
\begin{verbatim}
    /* init ORB and root POA */
    orb = org.omg.CORBA.ORB.init(args, props);
    org.omg.PortableServer.POA rootPOA =
        org.omg.PortableServer.POAHelper.narrow(
                        orb.resolve_initial_references("RootPOA"));

    /* create policies  */

    org.omg.CORBA.Policy [] policies = new org.omg.CORBA.Policy[2];
    policies[0] = rootPOA.create_id_assignment_policy(
                                IdAssignmentPolicyValue.USER_ID);
    policies[1] = rootPOA.create_lifespan_policy(
                                LifespanPolicyValue.PERSISTENT);

    /* create POA */

    POA myPOA = rootPOA.create_POA("XYZPOA",
                                rootPOA.the_POAManager(), policies);

    /* activate POAs */
    poa.the_POAManager().activate();

\end{verbatim}
}

(Note that in general the  id assignment policy will be {\tt USER\_ID}
for a POA with persistent object references because this id will often
be a key into  a database where the object state is  stored). If a POA
is created with this lifespan policy and the ORB property ``use\_imr''
is set, the ORB will try to  notify the ImR about this fact so the ImR
knows it doesn't need to start  a new process for requests that target
objects on this  POA.  To set the ORB policy,  simply set the property
{\tt  jacorb.use\_imr=on}.   The   ORB  uses  another  property,  {\tt
jacorb.implname}, as  a parameter for the  notification, i.e.~it tells
the  ImR  that a  process  using this  property's  value  as its  {\em
implementation name} is present. If  the server is registered with the
ImR, this property value has  to match the implementation name that is
used when registering.

The application  can set  these properties on  the command  line using
{\tt java -Djacorb.implname=MyName}, or in the code like this:

\small{
\begin{verbatim}
    /* create and set properties */
    java.util.Properties props = new java.util.Properties();
    props.setProperty("jacorb.use_imr","on");
    props.setProperty("jacorb.implname","MyName");

    /* init ORB  */
    orb = org.omg.CORBA.ORB.init(args, props);
\end{verbatim}
}

There are a few things  you have to consider especially when restoring
object state  at startup time or  saving the state of  your objects on
shutdown. It is important that, at startup time, object initialization
is complete when the object  is activated because from this instant on
operation calls  may come  in. The repository  knows about  the server
when the  first POA with  a PERSISTENT lifespan policy  registers, but
does not  forward object  references to clients  before the  object is
actually reachable. (Another, unreliable way to handle this problem is
to  increase the {\tt  jacorb.imr.object\_activation\_sleep} property,
so the repository waits longer for the object to become ready again.)

When the server shuts down,  it is equally important that object state
is saved by the time the last POA in the server goes down because from
this moment  the Implementation Repository regards the  server as down
and will start a new one upon requests.  Thus, a server implementor is
responsible for avoiding reader/writer problems between servers trying
to store and  restore the object state.  (One way of  doing this is to
use POA  managers to set  a POA to  holding while saving state  and to
inactive when done.)

Please keep in mind  that even if you don't have to  save the state of
your objects  on server shutdown  you {\em must} deactivate  your POAs
prior   to   exiting   your    process   (or   at   least   use   {\tt
orb.shutdown(\dots)} which  includes POA deactivation).  Otherwise the
ImR keeps the  server as active and will return  invalid IORs. In case
of  a  server crash  you  can either notify the ImR manually by  using
the  command  {\tt imr\_mg  setdown AServerName} or allow the ImR to
detect the crashed server and restart it if necessary.

\section{Server migration}

The  implementation  repository  offers  another  useful  possibility:
server migration.   Imagine the  following scenario: You  have written
your  server with  persistent  POAs,  but after  a  certain time  your
machine  seems   to  be   too  slow  to   serve  all   those  incoming
requests.  Migrating your  server to  a more  powerful machine  is the
obvious  solution.    Using  the  implementation   repository,  client
references do not contain addressing information for the slow machine,
so server migration can be done transparently to client.

Assuming  that you  added your  server to  the repository,  and  it is
running  correctly.

\cmdline{imr\_mg add AServerName -h a\_slow\_machine -c "jaco MyServer"}

The first step is to {\em  hold} the server, that means the repository
delays all requests for that server until it is released again.

\cmdline{imr\_mg hold AServerName}

Now  your server  will not  receive  any requests  for its  registered
POAs. If you can't shut your server down such that it sets itself down
at  the repository,  i.e.~your POAs  are  set to  inactive prior  to
terminating the process, you can use

\cmdline{imr\_mg setdown AServerName}

to  do  that.   Otherwise  your  POAs  can't  be  reactivated  at  the
repository because they are still logged as active.

If you  want your  server to be  restarted automatically, you  have to
tell the repository the new host and maybe a new startup command.

\cmdline{imr\_mg edit AServerName -h the\_fastest\_available\_machine\\
-c "jaco MyServer"}

If your server can be restarted automatically, you now don't even have
to start it manually, but it is instead restarted by the next incoming
request.  Otherwise start it manually on the desired machine now.

The last step is to release  the server, i.e.~let all delayed requests
continue.

\cmdline{imr\_mg release AServerName}

By now your  server should be running on  another machine, without the
clients noticing.

\section{A Note About Security}
Using the imr can pose a major security threat to your system. Imagine
the following standard setup: an imr  is running on a machine, its IOR
file is placed in a directory where  it can be read by the web server,
and several  imr\_ssds are running  on other machines. An  attacker can
now  execute processes  on the  machines the  ssds are  running  on by
taking the following steps:
\begin{enumerate}
         \item  Setting the  {\tt ORBInitRef.ImplementationRepository}
                property to the IOR file on your server.
         \item  Creating a new logical server with the desired command
           to execute as startup command on the desired host (where a
           ssd is running). This is the crucial point. The ssd calls
           {\tt Runtime.exec()} with the supplied string, and there
           is no way to check if the command does what it is supposed
           to do, i.e.~start a server.
         \item Start the server with the imr\_mg. The startup command
           of the server will be exec'd on the specified host.
\end{enumerate}

Now this should  not generally discourage you to use  the imr but show
you  that   there  are  risks,  which  can   be  reduced  significantly
nonetheless. There  are several ways  to encounter this threat  and we
don't consider this list to be complete:
\begin{enumerate}
        \item Try to control the distribution of the IOR file. Hiding
          it should not be considered here, because {\it security by
            obscurity} is generally a bad approach. Try to make use of
          file system mechanisms like groups and ACLs.
          \item Use a firewall which blocks of incoming traffic. Keep
            in mind that if the attacker is inside of your protection
            domain, the firewall won't help. It is also not that hard
            to write a Trojan that can tunnel those firewalls that
            block incoming traffic.
          \item Enforce SSL connections to the imr. This blocks all
            client connections that don't have a certificate signed by
            a CA of your choice. See chapter \ref{ch:SSL} for more
            information.
\end{enumerate}


%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "../ProgrammingGuide"
%%% End: 
