Object Activation

Dies ist sicher eines der komplexesten Kapitel von CORBA. Auf den ersten Blick, scheint es ja eine intuitive Lösung zu geben: wie bei der Programmierung in C++ oder Java Objekte mit new anzulegen.

Doch CORBA bietet hier eine etwas andere Lösung. Zunächst unterscheidet es einmal zwischen Objekt und Servant (die Implementierung des Objekts); dh es kann zu einem Zeitpunkt Objekte geben zu denen es keine Servants gibt. Weiters versucht CORBA nicht, irgendeine Art von verteilter Garbage Collection zu implementieren.

Wie gelangt nun ein Client an eine Objekt-Referenz?

Eine Methode ist, dass der Server seine Objektreferenz in eine Datei schreibt, auf die der Client zugreift und die Objektreferenz ausliest.

Wesentlich eleganter geht's allerdings, indem sich der Server beim CORBA NameService registriert und der Client sich die Objektreferenz des Servers vom NameSerivce holt (wie der Client die Objektreferenz des NameService bekommt, ist bereits weiter oben beschrieben).

Auf den ersten Blick ist hier vielleicht nicht ganz klar, dass bei diesem Vorgang kein neues Objekt angelegt wird, sondern nur eine Objektreferenz auf ein bereits bestehendes Objekt zurückgegeben wird. Dh es kann (natürlich abhängig vom jeweiligen Anwendungsfall) sinnvoll sein, dass dieses Objekt ein Factory-Objekt ist, mit dem die eigentlich benötigten Objekte erstellt werden können.

Abstrakte Objekte

In CORBA gibt es auch sogenannte abstrakte Objekte. Das sind Objekte zu denen es keinen aktiven Servant gibt. Diese Objekte können vom Server bei Bedarf (also bei einem Methodenaufruf) aktiviert werden. Dazu erzeugt der Server einen Portable Object Adapter mit den Policies USE_SERVANT_MANAGER und NON_RETAIN. Bei einem Methodenaufruf wird ein ServantLocator informiert, der nun entweder einen bereits bestehenden Servant auswählen kann oder einen neuen Servant generieren kann.

Aufpassen sollte man bei einer impliziten Aktivierung des Servants, dass CORBA auch interne Methoden wie _is_a oder _non_existent eines Objekts aufrufen kann. Bei so einem Methodenaufruf kann es sinnvoll sein, einen default Servant zu verwenden, der die Methoden für alle Objekte (evtl. unter Zuhilfenahme des Current Interfaces) implementiert.

Beispiel 5. On-Demand Servant Activation

PortableServer::POAManager_var poaManager = rootPoa->the_POAManager();

CORBA::PolicyList policies;
policies.length(4);
policies[0] =
  rootPoa->create_servant_retention_policy(PortableServer::NON_RETAIN);
policies[1] = rootPoa->create_request_processing_policy(
    PortableServer::USE_SERVANT_MANAGER);
policies[2] = rootPoa->create_id_assignment_policy(
    PortableServer::USER_ID);
policies[3] = rootPoa->create_implicit_activation_policy(
    PortableServer::NO_IMPLICIT_ACTIVATION);

poa = rootPoa->create_POA("MyOnDemandPoa", poaManager, policies);

locator = new MyServantLocator(this);
poa->set_servant_manager(locator->_this());

PortableServer::ObjectId_var oid =
  PortableServer::string_to_ObjectId("myOid");

CORBA::Object_var obj =
  poa->create_reference_with_id(oid, "IDL:MyInterface:1.0");

Beispiel 6. Implementierung eines ServantLocators

PortableServer::Servant MyServantLocator::preinvoke(
  const PortableServer::ObjectId &oid,
  PortableServer::POA_ptr adapter,
  const char *operation,
  PortableServer::ServantLocator::Cookie &the_cookie)
{
  CORBA::String_var s = PortableServer::ObjectId_to_string(oid);

  if (strcmp(operation, "work"))
  {
    Object_Impl *servant = registry->createServant(s);
    servant->pre_work();

    activeObjectMap.insert(
      ActiveObjectMap::value_type(static_cast<const char *>(s),
        servant));

    return servant;
  }
  else if (!strcmp(operation, "cancel"))
  {
    ActiveObjectMap::const_iterator activeObjectIter =
      activeObjectMap.find(static_cast<const char *>(s));

    if (activeObjectIter != activeObjectMap.end())
    {
      return activeObjectIter->second;
    }
    else
    {
      return NULL;
    }
  }
  else
  {
    return defaultServant;
  }
}


void MyServantLocator::postinvoke(
  const PortableServer::ObjectId &oid,
  PortableServer::POA_ptr adapter,
  const char *operation,
  PortableServer::ServantLocator::Cookie the_cookie,
  PortableServer::Servant the_servant)
{
  if (!strcmp(operation, "work"))
  {
    Object_Impl *servant = dynamic_cast<Object_Impl *>(the_servant);

    if (servant)
    {
      CORBA::String_var s = PortableServer::ObjectId_to_string(oid);

      ActiveObjectMap::iterator activeObjectIter =
        activeObjectMap.find(static_cast<const char *>(s));
      activeObjectMap.erase(activeObjectIter);

      servant->post_work();
    }

    delete the_servant;
  }
}