/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/*
* oafd: OAF CORBA dameon.
*
* Copyright (C) 1999, 2000 Red Hat, Inc.
* Copyright (C) 1999, 2000 Eazel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Authors: Elliot Lee <sopwith@redhat.com>,
*
*/
#include "config.h"
#include <stdio.h>
#include <time.h>
#include <glib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <glib/gi18n.h>
#include "server.h"
#include "object-directory.h"
#include "bonobo-activation/bonobo-activation-private.h"
#include "activation-server-corba-extensions.h"
#include <glib/gstdio.h>
/* no longer used. */
#define RESIDUAL_SERVERS 0
static GObjectClass *parent_class = NULL;
static gboolean finished_internal_registration = FALSE;
typedef struct {
char *iid;
int n_servers;
struct {
Bonobo_ActivationEnvironment environment;
CORBA_Object server;
} servers [1]; /* flexible array */
} ActiveServerList;
typedef struct {
/* client's environment */
Bonobo_ActivationEnvironment *env;
/* "runtime" servers registered by this client */
CORBA_sequence_CORBA_string *runtime_iids;
} ClientContext;
static void
client_context_free (ClientContext *self)
{
CORBA_free (self->env);
if (self->runtime_iids)
CORBA_free (self->runtime_iids);
g_free (self);
}
static ObjectDirectory *main_dir = NULL;
#ifdef BONOBO_ACTIVATION_DEBUG
static void
od_dump_list (ObjectDirectory * od)
{
#if 0
int i, j, k;
for (i = 0; i < od->attr_servers->_length; i++) {
g_print ("IID %s, type %s, location %s\n",
od->attr_servers->_buffer[i].iid,
od->attr_servers->_buffer[i].server_type,
od->attr_servers->_buffer[i].location_info);
for (j = 0; j < od->attr_servers->_buffer[i].props._length;
j++) {
Bonobo_ActivationProperty *prop =
&(od->attr_servers->_buffer[i].
props._buffer[j]);
if (strchr (prop->name, '-') != NULL) /* Translated, likely to
be annoying garbage value */
continue;
g_print (" %s = ", prop->name);
switch (prop->v._d) {
case Bonobo_ACTIVATION_P_STRING:
g_print ("\"%s\"\n", prop->v._u.value_string);
break;
case Bonobo_ACTIVATION_P_NUMBER:
g_print ("%f\n", prop->v._u.value_number);
break;
case Bonobo_ACTIVATION_P_BOOLEAN:
g_print ("%s\n",
prop->v.
_u.value_boolean ? "TRUE" : "FALSE");
break;
case Bonobo_ACTIVATION_P_STRINGV:
g_print ("[");
for (k = 0;
k < prop->v._u.value_stringv._length;
k++) {
g_print ("\"%s\"",
prop->v._u.
value_stringv._buffer[k]);
if (k <
(prop->v._u.
value_stringv._length - 1))
g_print (", ");
}
g_print ("]\n");
break;
}
}
}
#endif
}
#endif
static gboolean
registry_directory_needs_update (ObjectDirectory *od,
const char *directory)
{
gboolean needs_update;
struct stat statbuf;
time_t old_mtime;
if (g_stat (directory, &statbuf) != 0) {
return FALSE;
}
old_mtime = (time_t) g_hash_table_lookup (
od->registry_directory_mtimes, directory);
g_hash_table_insert (od->registry_directory_mtimes,
(gpointer) directory,
(gpointer) statbuf.st_mtime);
needs_update = (old_mtime != statbuf.st_mtime);
#ifdef BONOBO_ACTIVATION_DEBUG
if (needs_update)
g_warning ("Compare old_mtime on '%s' with %ld ==? %ld",
directory,
(long) old_mtime, (long) statbuf.st_mtime);
#endif
return needs_update;
}
static void
update_registry (ObjectDirectory *od, gboolean force_reload)
{
int i;
time_t cur_time;
gboolean must_load;
static gboolean doing_reload = FALSE;
if (doing_reload)
return;
doing_reload = TRUE;
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("Update registry %p", od->by_iid);
#endif
/* get first time init right */
must_load = (od->by_iid == NULL);
cur_time = time (NULL);
if (cur_time - 5 > od->time_did_stat) {
od->time_did_stat = cur_time;
for (i = 0; od->registry_source_directories[i] != NULL; i++) {
if (registry_directory_needs_update
(od, od->registry_source_directories[i]))
must_load = TRUE;
}
}
if (must_load || force_reload) {
/*
* FIXME bugzilla.eazel.com 2727: we should only reload those
* directories that have actually changed instead of reloading
* all when any has changed.
*/
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("Re-load %d %d", must_load, force_reload);
#endif
if (od->attr_servers)
CORBA_free (od->attr_servers);
od->attr_servers = CORBA_sequence_Bonobo_ServerInfo__alloc ();
bonobo_server_info_load (od->registry_source_directories,
od->attr_servers,
od->attr_runtime_servers,
&od->by_iid,
bonobo_activation_hostname_get ());
od->time_did_stat = od->time_list_changed = time (NULL);
#ifdef BONOBO_ACTIVATION_DEBUG
od_dump_list (od);
#endif
if (must_load)
activation_clients_cache_notify ();
}
doing_reload = FALSE;
}
static gchar **
split_path_unique (const char *colon_delimited_path)
{
int i, max;
gboolean different;
gchar **ret, **wrk;
GSList *l, *tmp = NULL;
g_return_val_if_fail (colon_delimited_path != NULL, NULL);
wrk = g_strsplit (colon_delimited_path, G_SEARCHPATH_SEPARATOR_S, -1);
g_return_val_if_fail (wrk != NULL, NULL);
for (max = i = 0; wrk [i]; i++) {
different = TRUE;
for (l = tmp; l; l = l->next) {
if (!strcmp (l->data, wrk [i])) {
different = FALSE;
} else if (wrk [i] == '\0') {
different = FALSE;
}
}
if (different) {
tmp = g_slist_prepend (tmp, g_strdup (wrk [i]));
max++;
}
}
tmp = g_slist_reverse (tmp);
ret = g_new (char *, max + 1);
for (l = tmp, i = 0; l; l = l->next)
ret [i++] = l->data;
ret [i] = NULL;
g_slist_free (tmp);
g_strfreev (wrk);
return ret;
}
static Bonobo_ServerInfoListCache *
impl_Bonobo_ObjectDirectory__get_servers (
PortableServer_Servant servant,
Bonobo_CacheTime only_if_newer,
CORBA_Environment *ev)
{
ObjectDirectory *od;
Bonobo_ServerInfoListCache *retval;
server_lock ();
od = OBJECT_DIRECTORY (servant);
update_registry (od, FALSE);
retval = Bonobo_ServerInfoListCache__alloc ();
retval->_d = (only_if_newer < od->time_list_changed);
if (retval->_d) {
retval->_u.server_list = *od->attr_servers;
CORBA_sequence_set_release (&retval->_u.server_list,
CORBA_FALSE);
}
server_unlock ();
return retval;
}
typedef struct {
Bonobo_ImplementationID *seq;
int last_used;
} StateCollectionInfo;
static void
collate_active_server (char *key, gpointer value, StateCollectionInfo *sci)
{
sci->seq [(sci->last_used)++] = CORBA_string_dup (key);
}
static Bonobo_ServerStateCache *
impl_Bonobo_ObjectDirectory_get_active_servers (
PortableServer_Servant servant,
Bonobo_CacheTime only_if_newer,
CORBA_Environment *ev)
{
ObjectDirectory *od;
Bonobo_ServerStateCache *retval;
server_lock ();
od = OBJECT_DIRECTORY (servant);
retval = Bonobo_ServerStateCache__alloc ();
retval->_d = (only_if_newer < od->time_active_changed);
if (retval->_d) {
StateCollectionInfo sci;
retval->_u.active_servers._length =
g_hash_table_size (od->active_server_lists);
retval->_u.active_servers._buffer = sci.seq =
CORBA_sequence_Bonobo_ImplementationID_allocbuf
(retval->_u.active_servers._length);
sci.last_used = 0;
g_hash_table_foreach (od->active_server_lists,
(GHFunc) collate_active_server, &sci);
CORBA_sequence_set_release (&(retval->_u.active_servers),
CORBA_TRUE);
}
server_unlock ();
return retval;
}
static CORBA_Object
od_get_active_server (ObjectDirectory *od,
const char *iid,
const Bonobo_ActivationEnvironment *environment)
{
ActiveServerList *servers;
CORBA_Object retval;
int i;
servers = g_hash_table_lookup (od->active_server_lists, iid);
if (!servers)
return CORBA_OBJECT_NIL;
retval = CORBA_OBJECT_NIL;
for (i = 0; i < servers->n_servers; i++) {
if (Bonobo_ActivationEnvironment_match (
&servers->servers [i].environment,
environment)) {
retval = servers->servers [i].server;
break;
}
}
if (retval != CORBA_OBJECT_NIL &&
!CORBA_Object_non_existent (retval, NULL))
return CORBA_Object_duplicate (retval, NULL);
return CORBA_OBJECT_NIL;
}
/*
* returns (@merged_environment) new environment as result of
* merging activation request environment and client registered
* environment; the activation supplied environment takes precedence
* over the client one
*/
static void
od_merge_client_environment (ObjectDirectory *od,
Bonobo_ServerInfo const *server,
const Bonobo_ActivationEnvironment *environment,
Bonobo_ActivationEnvironment *merged_environment,
Bonobo_ActivationClient client)
{
GArray *array;
int i, serverinfo_env_idx;
const Bonobo_ActivationEnvironment *client_env;
const Bonobo_StringList *serverinfo_env = NULL;
ClientContext *client_context;
array = g_array_new (FALSE, FALSE, sizeof (Bonobo_ActivationEnvValue));
/* copy all values from @environment */
for (i = 0; i < environment->_length; ++i)
g_array_append_val (array, environment->_buffer[i]);
if (G_UNLIKELY (client == CORBA_OBJECT_NIL))
goto exit;
client_context = ((ClientContext *) g_hash_table_lookup
(od->client_contexts, client));
if (G_UNLIKELY (!client_context))
goto exit;
client_env = client_context->env;
if (G_UNLIKELY (!client_env))
goto exit;
/* scan through server properties */
if (!server) goto exit;
for (i = 0; i < server->props._length; ++i) {
if (strcmp (server->props._buffer[i].name, "bonobo:environment") == 0)
{
Bonobo_ActivationPropertyValue const *prop =
&server->props._buffer[i].v;
if (prop->_d == Bonobo_ACTIVATION_P_STRINGV)
serverinfo_env = &prop->_u.value_stringv;
else
g_warning ("bonobo:environment should have type stringv");
break;
}
}
if (!serverinfo_env)
goto exit;
/* do the actual merging */
for (serverinfo_env_idx = 0;
serverinfo_env_idx < serverinfo_env->_length; ++serverinfo_env_idx)
{
CORBA_char *env = serverinfo_env->_buffer[serverinfo_env_idx];
gboolean duplicated_env = FALSE;
/* check if array already has this environment */
for (i = 0; i < environment->_length; ++i) {
if (strcmp (environment->_buffer[i].name, env) == 0) {
duplicated_env = TRUE;
break;
}
}
if (duplicated_env)
continue;
/* look for environment in client_env */
for (i = 0; i < client_env->_length; ++i) {
if (strcmp (client_env->_buffer[i].name, env) == 0) {
g_array_append_val (array, client_env->_buffer[i]);
break;
}
}
}
exit:
/* return the resulting environment */
merged_environment->_buffer = (Bonobo_ActivationEnvValue *) array->data;
merged_environment->_length = merged_environment->_maximum = array->len;
g_array_free (array, FALSE);
}
static CORBA_Object
impl_Bonobo_ObjectDirectory_activate (
PortableServer_Servant servant,
const CORBA_char *iid,
const Bonobo_ActivationContext ac,
const Bonobo_ActivationEnvironment *environment,
const Bonobo_ActivationFlags flags,
Bonobo_ActivationClient client,
CORBA_Context ctx,
CORBA_Environment *ev)
{
ObjectDirectory *od;
CORBA_Object retval = NULL;
Bonobo_ServerInfo *si;
ODActivationInfo ai;
Bonobo_ActivationEnvironment merged_environment = { 0, };
server_lock ();
od = OBJECT_DIRECTORY (servant);
od_merge_client_environment (od, (Bonobo_ServerInfo *)
g_hash_table_lookup (od->by_iid, iid),
environment, &merged_environment, client);
retval = CORBA_OBJECT_NIL;
update_registry (od, FALSE);
if (!(flags & Bonobo_ACTIVATION_FLAG_PRIVATE)) {
retval = od_get_active_server (od, iid, &merged_environment);
if (retval != CORBA_OBJECT_NIL)
goto act_out;
}
if (flags & Bonobo_ACTIVATION_FLAG_EXISTING_ONLY)
goto act_out;
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "thread %p start activate '%s'\n",
g_thread_self(), iid);
#endif
ai.ac = ac;
ai.flags = flags;
ai.ctx = ctx;
si = g_hash_table_lookup (od->by_iid, iid);
if (si) {
retval = od_server_activate (
si, &ai, BONOBO_OBJREF (od), &merged_environment, client, ev);
/* NB. si can now be invalid - due to re-enterancy */
/* If we failed to activate - it may be because our
* request re-entered _during_ the activation
* process resulting in a second process being started
* but failing to register - so we'll look up again here
* to see if we can get it.
* FIXME: we should not be forking redundant processes
* while an activation of that same process is on the
* stack.
* FIXME: we only get away with this hack because we
* try and fork another process & thus allow the reply
* from the initial process to be handled in the event
* loop.
*/
/* FIXME: this path is theoretically redundant now */
if (ev->_major != CORBA_NO_EXCEPTION ||
retval == CORBA_OBJECT_NIL) {
retval = od_get_active_server (od, iid, &merged_environment);
if (retval != CORBA_OBJECT_NIL)
CORBA_exception_free (ev);
}
}
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "thread %p end activate '%s' = %p ['%s']\n",
g_thread_self(), iid, retval,
bonobo_exception_get_text (ev)
);
#endif
act_out:
g_free (merged_environment._buffer);
server_unlock ();
return retval;
}
extern GMainLoop *main_loop;
static gboolean
quit_server_timeout (gpointer user_data)
{
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("Quit server !");
#endif
if (!main_dir ||
main_dir->n_active_servers > RESIDUAL_SERVERS ||
!activation_clients_is_empty_scan ())
g_warning ("Serious error handling server count, not quitting");
else
g_main_loop_quit (main_loop);
main_dir->no_servers_timeout = 0;
return FALSE;
}
void od_finished_internal_registration (void)
{
finished_internal_registration = TRUE;
}
void
check_quit (void)
{
ObjectDirectory *od = main_dir;
/* We had some activity - so push out the shutdown timeout */
if (od->no_servers_timeout != 0)
g_source_remove (od->no_servers_timeout);
od->no_servers_timeout = 0;
if (od->n_active_servers <= RESIDUAL_SERVERS &&
activation_clients_is_empty_scan ())
od->no_servers_timeout = g_timeout_add (
SERVER_IDLE_QUIT_TIMEOUT, quit_server_timeout, NULL);
od->time_active_changed = time (NULL);
}
static void
remove_active_server_entry (ActiveServerList *servers,
int index)
{
CORBA_Object_release (servers->servers [index].server, NULL);
CORBA_free (servers->servers [index].environment._buffer);
if (index != servers->n_servers - 1)
memcpy (&servers->servers [index],
&servers->servers [servers->n_servers - 1],
sizeof (servers->servers [index]));
servers->n_servers--;
}
static ActiveServerList *
add_active_server_entry (ActiveServerList *servers,
const Bonobo_ActivationEnvironment *environment,
CORBA_Object object)
{
int index, i;
index = servers->n_servers - 1;
if (index != 0)
servers = g_realloc (servers,
sizeof (*servers) + sizeof (servers->servers [0]) * index);
servers->servers [index].server = CORBA_Object_duplicate (object, NULL);
servers->servers [index].environment._length = environment->_length;
servers->servers [index].environment._maximum = environment->_maximum;
servers->servers [index].environment._buffer =
Bonobo_ActivationEnvironment_allocbuf (environment->_length);
servers->servers [index].environment._release = TRUE;
for (i = 0; i < environment->_length; i++)
Bonobo_ActivationEnvValue_copy (
&servers->servers [index].environment._buffer [i],
&environment->_buffer [i]);
return servers;
}
static gboolean
prune_dead_servers (gpointer key,
gpointer value,
gpointer user_data)
{
ObjectDirectory *od = user_data;
ActiveServerList *servers = value;
int i;
for (i = 0; i < servers->n_servers; i++) {
ORBitConnectionStatus status;
gboolean dead;
status = ORBit_small_get_connection_status (
servers->servers [i].server);
dead = (status == ORBIT_CONNECTION_DISCONNECTED);
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "IID '%20s' (%p), %s \n",
(char *) key, servers->servers [i].server,
dead ? "dead" : "alive");
#endif
if (dead) {
remove_active_server_entry (servers, i);
od->n_active_servers--;
i--;
}
}
return !servers->n_servers;
}
static gboolean
as_rescan (gpointer data)
{
ObjectDirectory *od;
static gboolean in_rescan = FALSE;
static guint idle_id = 0;
server_lock ();
if (!(od = main_dir)) { /* shutting down */
server_unlock ();
return FALSE;
}
/* We tend to get a lot of 'broken' callbacks at once */
if (in_rescan) {
if (!idle_id)
idle_id = g_idle_add (as_rescan, NULL);
server_unlock ();
return FALSE;
}
in_rescan = TRUE;
g_hash_table_foreach_remove (od->active_server_lists,
prune_dead_servers, od);
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("After prune: %d live servers",
od->n_active_servers - RESIDUAL_SERVERS);
#endif
check_quit ();
in_rescan = FALSE;
server_unlock ();
return FALSE;
}
static void
active_server_cnx_broken (ORBitConnection *cnx,
gpointer dummy)
{
as_rescan (NULL);
}
static void
add_active_server (ObjectDirectory *od,
const char *iid,
const Bonobo_ActivationEnvironment *environment,
CORBA_Object object)
{
ActiveServerList *servers;
ORBitConnection *cnx;
cnx = ORBit_small_get_connection (object);
if (cnx) {
if (!g_object_get_data (G_OBJECT (cnx), "object_count")) {
g_object_set_data (
G_OBJECT (cnx), "object_count", GUINT_TO_POINTER (1));
g_signal_connect (
cnx, "broken",
G_CALLBACK (active_server_cnx_broken),
NULL);
}
} else
g_assert (!strcmp (iid, NAMING_CONTEXT_IID) ||
!strcmp(iid, EVENT_SOURCE_IID));
servers = g_hash_table_lookup (od->active_server_lists, iid);
if (!servers) {
servers = g_new0 (ActiveServerList, 1);
servers->iid = g_strdup (iid);
servers->n_servers = 1;
servers = add_active_server_entry (
servers, environment, object);
g_hash_table_insert (
od->active_server_lists, servers->iid, servers);
} else {
ActiveServerList *new_servers;
g_assert (servers->n_servers > 0);
servers->n_servers++;
new_servers = add_active_server_entry (
servers, environment, object);
if (new_servers != servers) { /* Need to reset the pointer */
g_hash_table_steal (od->active_server_lists, new_servers->iid);
g_hash_table_insert (
od->active_server_lists, new_servers->iid, new_servers);
}
}
if (finished_internal_registration)
od->n_active_servers++;
if (cnx)
check_quit ();
}
static void
active_server_list_free (gpointer data)
{
ActiveServerList *servers = data;
int i;
for (i = 0; i < servers->n_servers; i++) {
CORBA_Object_release (servers->servers [i].server, NULL);
CORBA_free (servers->servers [i].environment._buffer);
}
g_free (servers);
}
static gboolean
remove_active_server (ObjectDirectory *od,
const char *iid,
CORBA_Object object)
{
ActiveServerList *servers;
gboolean removed = FALSE;
int i;
servers = g_hash_table_lookup (od->active_server_lists, iid);
if (!servers)
return FALSE;
for (i = 0; i < servers->n_servers; i++)
if (CORBA_Object_is_equivalent (
servers->servers [i].server, object, NULL)) {
remove_active_server_entry (servers, i);
removed = TRUE;
break;
}
if (removed)
od->n_active_servers--;
if (servers->n_servers == 0)
g_hash_table_remove (od->active_server_lists, iid);
check_quit ();
return removed;
}
/* Parse server description and register it, replacing older
* definition if necessary. Returns the regsitered ServerInfo */
static Bonobo_ServerInfo const *
od_register_runtime_server_info (ObjectDirectory *od,
const char *iid,
const CORBA_char *description,
Bonobo_ActivationClient client)
{
Bonobo_ServerInfo *old_serverinfo, *new_serverinfo;
GSList *parsed_serverinfo = NULL, *l;
int i;
ClientContext *context;
update_registry (od, FALSE);
old_serverinfo = (Bonobo_ServerInfo *) g_hash_table_lookup (od->by_iid, iid);
if (old_serverinfo)
return old_serverinfo;
if (!(*description)) /* empty description? */
return NULL;
/* parse description */
bonobo_parse_server_info_memory (description, &parsed_serverinfo,
bonobo_activation_hostname_get ());
/* check for zero entries */
if (!parsed_serverinfo)
return NULL;
/* check for more than one entry */
if (parsed_serverinfo->next) {
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("More than one <oaf_server> specified, ignoring all");
#endif
for (l = parsed_serverinfo; l; l = l->next) {
Bonobo_ServerInfo__freekids (l->data, NULL);
g_free (l->data);
}
g_slist_free (parsed_serverinfo);
return NULL;
}
new_serverinfo = (Bonobo_ServerInfo *) parsed_serverinfo->data;
g_slist_free (parsed_serverinfo);
g_ptr_array_add (od->attr_runtime_servers, new_serverinfo);
ORBit_sequence_append (od->attr_servers, new_serverinfo);
/* rebuild od->by_iid hash table, because
* ORBit_sequence_append reallocs _buffer, and that
* sometimes changes the addresses of the
* serverinfo items */
g_hash_table_destroy (od->by_iid);
od->by_iid = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; i < od->attr_servers->_length; ++i)
g_hash_table_insert (od->by_iid,
od->attr_servers->_buffer[i].iid,
od->attr_servers->_buffer + i);
/* Take note that this client registered this iid, so that
* when the client disconnects we unregister its
* corresponding serverinfo's */
context = g_hash_table_lookup (od->client_contexts, client);
g_return_val_if_fail (context, new_serverinfo);
if (context->runtime_iids)
ORBit_sequence_append (context->runtime_iids, iid);
else {
context->runtime_iids = ORBit_sequence_alloc
(TC_CORBA_sequence_CORBA_string, 1);
ORBit_sequence_index (context->runtime_iids, 0) =
CORBA_string_dup (iid);
}
od->time_list_changed = time (NULL);
activation_clients_cache_notify ();
return new_serverinfo;
}
static Bonobo_RegistrationResult
impl_Bonobo_ObjectDirectory_register_new_full (
PortableServer_Servant servant,
const CORBA_char *iid,
const Bonobo_ActivationEnvironment *environment,
const CORBA_Object obj,
Bonobo_RegistrationFlags flags,
const CORBA_char *description,
CORBA_Object *existing,
Bonobo_ActivationClient client,
CORBA_Environment *ev)
{
ObjectDirectory *od;
CORBA_Object oldobj;
Bonobo_ActivationEnvironment merged_environment;
Bonobo_ServerInfo const *serverinfo;
Bonobo_RegistrationResult retval = Bonobo_ACTIVATION_REG_SUCCESS;
server_lock ();
od = OBJECT_DIRECTORY (servant);
oldobj = od_get_active_server (od, iid, environment);
*existing = oldobj;
serverinfo = od_register_runtime_server_info (od, iid, description, client);
od_merge_client_environment (od, serverinfo, environment,
&merged_environment, client);
oldobj = od_get_active_server (od, iid, &merged_environment);
if (oldobj != CORBA_OBJECT_NIL) {
if (!CORBA_Object_non_existent (oldobj, ev)) {
if (CORBA_Object_is_equivalent (oldobj, obj, ev))
retval = Bonobo_ACTIVATION_REG_SUCCESS;
else
retval = Bonobo_ACTIVATION_REG_ALREADY_ACTIVE;
goto reg_out;
}
}
if (!serverinfo) {
if (!(flags&Bonobo_REGISTRATION_FLAG_NO_SERVERINFO)) {
retval = Bonobo_ACTIVATION_REG_NOT_LISTED;
goto reg_out;
}
}
#ifdef BONOBO_ACTIVATION_DEBUG
g_warning ("Server register. '%s' : %p", iid, obj);
#endif
add_active_server (od, iid, &merged_environment, obj);
bonobo_event_source_notify_listeners
(od->event_source,
"Bonobo/ObjectDirectory:activation:register",
NULL, NULL);
reg_out:
g_free (merged_environment._buffer);
server_unlock ();
return retval;
}
static Bonobo_RegistrationResult
impl_Bonobo_ObjectDirectory_register_new (
PortableServer_Servant servant,
const CORBA_char *iid,
const Bonobo_ActivationEnvironment *environment,
const CORBA_Object obj,
Bonobo_RegistrationFlags flags,
const CORBA_char *description,
CORBA_Object *existing,
CORBA_Environment *ev)
{
return impl_Bonobo_ObjectDirectory_register_new_full
(servant, iid, environment, obj, flags,
description, existing, CORBA_OBJECT_NIL, ev);
}
static void
impl_Bonobo_ObjectDirectory_unregister (
PortableServer_Servant servant,
const CORBA_char *iid,
const CORBA_Object obj,
CORBA_Environment *ev)
{
ObjectDirectory *od;
server_lock ();
od = OBJECT_DIRECTORY (servant);
if (!remove_active_server (od, iid, obj))
CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
ex_Bonobo_ObjectDirectory_NotRegistered,
NULL);
else
bonobo_event_source_notify_listeners
(od->event_source,
"Bonobo/ObjectDirectory:activation:unregister",
NULL, NULL);
server_unlock ();
}
static Bonobo_DynamicPathLoadResult
impl_Bonobo_ObjectDirectory_add_path(
PortableServer_Servant servant,
const CORBA_char * add_path,
CORBA_Environment *ev)
{
ObjectDirectory *od;
int i, j, dir_num, max;
char **add_directoies, **ret;
GSList *l, *tmp = NULL;
gboolean different;
Bonobo_DynamicPathLoadResult retval = Bonobo_DYNAMIC_LOAD_SUCCESS;
server_lock ();
od = OBJECT_DIRECTORY (servant);
if (!od->registry_source_directories) {
od->registry_source_directories = split_path_unique (add_path);
goto add_path_out;
} else
add_directoies = split_path_unique (add_path);
if (!add_directoies) {
retval = Bonobo_DYNAMIC_LOAD_ERROR;
goto add_path_out;
}
for (max = i = 0; od->registry_source_directories[i]; i++) {
tmp = g_slist_append(tmp,g_strdup(od->registry_source_directories[i]));
max++;
}
dir_num = max;
for (i = 0; add_directoies[i]; i++) {
different = TRUE;
for (j = 0; od->registry_source_directories[j]; j++) {
if (!strcmp(add_directoies[i], od->registry_source_directories[j])) {
different = FALSE;
break;
}
}
if (different) {
tmp = g_slist_append(tmp, g_strdup(add_directoies[i]));
max++;
}
}
if (max == dir_num) {
g_strfreev(add_directoies);
g_slist_free(tmp);
retval = Bonobo_DYNAMIC_LOAD_ALREADY_LISTED;
goto add_path_out;
}
ret = g_new(char *, max + 1);
for (l = tmp, i = 0; l; l = l->next)
ret[i++]=l->data;
ret[i] = NULL;
g_slist_free(tmp);
g_strfreev(add_directoies);
g_strfreev(od->registry_source_directories);
od->registry_source_directories = ret;
update_registry(od, TRUE);
add_path_out:
server_unlock ();
return retval;
}
static Bonobo_DynamicPathLoadResult
impl_Bonobo_ObjectDirectory_remove_path(
PortableServer_Servant servant,
const CORBA_char * remove_path,
CORBA_Environment *ev)
{
ObjectDirectory *od;
char **remove_directoies, **ret;
int i, j, max;
GSList *l, *tmp = NULL;
gboolean different;
Bonobo_DynamicPathLoadResult retval = Bonobo_DYNAMIC_LOAD_SUCCESS;
server_lock();
od = OBJECT_DIRECTORY (servant);
remove_directoies = split_path_unique (remove_path);
if (!remove_directoies) {
retval = Bonobo_DYNAMIC_LOAD_ERROR;
goto rm_path_out;
}
for (max = i = 0; od->registry_source_directories[i]; i++) {
different = TRUE;
for (j = 0; remove_directoies[j]; j++) {
if (!strcmp(od->registry_source_directories[i], remove_directoies[j])) {
different = FALSE;
break;
}
}
if (different) {
tmp = g_slist_append(tmp, g_strdup(od->registry_source_directories[i]));
max++;
}
}
if (max == i) {
g_slist_free(tmp);
g_strfreev(remove_directoies);
retval = Bonobo_DYNAMIC_LOAD_NOT_LISTED;
goto rm_path_out;
}
ret = g_new(char *, max + 1);
for (l = tmp, i = 0; l; l = l->next)
ret[i++]=l->data;
ret[i] = NULL;
g_slist_free(tmp);
g_strfreev(remove_directoies);
g_strfreev(od->registry_source_directories);
od->registry_source_directories = ret;
update_registry(od, TRUE);
rm_path_out:
server_unlock();
return retval;
}
static void
client_cnx_broken (ORBitConnection *cnx,
const Bonobo_ActivationClient client)
{
ObjectDirectory *od;
ClientContext *context;
int i;
server_lock();
if (!(od = main_dir)) { /* shutting down */
server_unlock();
return;
}
/* unregister runtime server definitions */
context = g_hash_table_lookup (od->client_contexts, client);
if (context->runtime_iids) {
for (i = 0; i < context->runtime_iids->_length; ++i)
{
CORBA_char *iid = ORBit_sequence_index
(context->runtime_iids, i);
int j;
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "Removing runtime definition '%s' from hash table\n", iid);
#endif
g_hash_table_remove (od->by_iid, iid);
for (j = 0; j < od->attr_runtime_servers->len; ++j) {
Bonobo_ServerInfo *server = g_ptr_array_index
(od->attr_runtime_servers, j);
if (strcmp (server->iid, iid) == 0) {
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "Removing from od->attr_runtime_servers[%i]\n", j);
#endif
g_ptr_array_remove_index
(od->attr_runtime_servers, j);
Bonobo_ServerInfo__freekids (server, NULL);
g_free (server);
break;
}
}
for (j = 0; j < od->attr_servers->_length; ++j) {
Bonobo_ServerInfo *server =
&ORBit_sequence_index (od->attr_servers, j);
if (strcmp (server->iid, iid) == 0) {
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "Removing from od->attr_servers[%i]\n", j);
#endif
ORBit_sequence_remove (od->attr_servers, j);
break;
}
}
#ifdef BONOBO_ACTIVATION_DEBUG
fprintf (stderr, "Runtime definition '%s' cleaned\n", iid);
#endif
}
}
g_hash_table_remove (od->client_contexts, client);
od->time_list_changed = time (NULL);
activation_clients_cache_notify ();
server_unlock();
}
static void
impl_Bonobo_ObjectDirectory_addClientEnv (
PortableServer_Servant servant,
const Bonobo_ActivationClient client,
const Bonobo_StringList *client_env,
CORBA_Environment *ev)
{
Bonobo_ActivationEnvironment *env;
ObjectDirectory *od;
ClientContext *context;
int i;
server_lock();
od = OBJECT_DIRECTORY (servant);
env = Bonobo_ActivationEnvironment__alloc ();
env->_length = env->_maximum = client_env->_length;
env->_buffer = Bonobo_ActivationEnvironment_allocbuf (env->_length);
env->_release = CORBA_TRUE;
for (i = 0; i < client_env->_length; ++i)
{
const char *keyval = client_env->_buffer[i];
const char *equals = strchr (keyval, '=');
guint keylen;
if (!equals) {
g_warning ("Duff env. var '%s'", keyval);
continue;
}
keylen = (guint) (equals - keyval);
env->_buffer[i].name = CORBA_string_alloc (keylen + 1);
strncpy (env->_buffer[i].name, keyval, keylen);
env->_buffer[i].name[keylen] = 0;
env->_buffer[i].value = CORBA_string_dup (equals + 1);
env->_buffer[i].flags = 0;
}
context = g_new (ClientContext, 1);
context->env = env;
context->runtime_iids = NULL;
g_hash_table_insert (od->client_contexts, client, context);
ORBit_small_listen_for_broken (client, G_CALLBACK (client_cnx_broken),
(gpointer) client);
server_unlock();
}
Bonobo_ObjectDirectory
bonobo_object_directory_get (void)
{
if (!main_dir)
return CORBA_OBJECT_NIL;
else
return BONOBO_OBJREF (main_dir);
}
Bonobo_EventSource
bonobo_object_directory_event_source_get (void)
{
if (!main_dir)
return CORBA_OBJECT_NIL;
else
return BONOBO_OBJREF (main_dir->event_source);
}
void
bonobo_object_directory_init (PortableServer_POA poa,
const char *registry_path,
CORBA_Environment *ev)
{
g_assert (main_dir == NULL);
main_dir = g_object_new (OBJECT_TYPE_DIRECTORY,
"poa", poa, NULL);
main_dir->registry_source_directories = split_path_unique (registry_path);
update_registry (main_dir, FALSE);
}
void
bonobo_object_directory_shutdown (PortableServer_POA poa,
CORBA_Environment *ev)
{
bonobo_object_set_immortal (BONOBO_OBJECT (main_dir), FALSE);
bonobo_object_unref (BONOBO_OBJECT (main_dir));
}
CORBA_Object
bonobo_object_directory_re_check_fn (const Bonobo_ActivationEnvironment *environment,
const char *act_iid,
gpointer user_data)
{
CORBA_Object retval;
server_lock ();
retval = od_get_active_server (
main_dir, (Bonobo_ImplementationID) act_iid, environment);
server_unlock ();
return retval;
}
void
bonobo_object_directory_reload (void)
{
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "reloading our object directory!");
update_registry (main_dir, TRUE);
}
static void
object_directory_finalize (GObject *object)
{
ObjectDirectory *od = (ObjectDirectory *) object;
main_dir = NULL;
g_hash_table_destroy (od->active_server_lists);
g_hash_table_destroy (od->registry_directory_mtimes);
g_strfreev (od->registry_source_directories);
if (od->client_contexts) {
g_hash_table_destroy (od->client_contexts);
od->client_contexts = NULL;
}
parent_class->finalize (object);
}
static void
object_directory_class_init (ObjectDirectoryClass *klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
POA_Bonobo_ObjectDirectory__epv *epv = &klass->epv;
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = object_directory_finalize;
epv->get_servers = impl_Bonobo_ObjectDirectory__get_servers;
epv->get_active_servers = impl_Bonobo_ObjectDirectory_get_active_servers;
epv->activate = impl_Bonobo_ObjectDirectory_activate;
epv->register_new = impl_Bonobo_ObjectDirectory_register_new;
epv->register_new_full = impl_Bonobo_ObjectDirectory_register_new_full;
epv->unregister = impl_Bonobo_ObjectDirectory_unregister;
epv->dynamic_add_path = impl_Bonobo_ObjectDirectory_add_path;
epv->dynamic_remove_path = impl_Bonobo_ObjectDirectory_remove_path;
epv->addClientEnv = impl_Bonobo_ObjectDirectory_addClientEnv;
}
static void
object_directory_init (ObjectDirectory *od)
{
bonobo_object_set_immortal (BONOBO_OBJECT (od), TRUE);
od->by_iid = NULL;
od->registry_directory_mtimes = g_hash_table_new (g_str_hash, g_str_equal);
od->active_server_lists =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, active_server_list_free);
od->no_servers_timeout = 0;
od->attr_runtime_servers = g_ptr_array_new ();
od->event_source = bonobo_event_source_new ();
od->client_contexts = g_hash_table_new_full
(NULL, NULL, NULL,
(GDestroyNotify) client_context_free);
}
BONOBO_TYPE_FUNC_FULL (ObjectDirectory,
Bonobo_ObjectDirectory,
BONOBO_TYPE_OBJECT,
object_directory)
syntax highlighted by Code2HTML, v. 0.9.1