2 //=============================================================================
4 * @file FT_ReplicaFactory_i.cpp
6 * This file is part of Fault Tolerant CORBA.
8 * @author Dale Wilson <wilson_d@ociweb.com>
10 //=============================================================================
11 #include "FT_ReplicaFactory_i.h"
12 #include "FT_TestReplica_i.h"
13 #include "ace/Get_Opt.h"
14 #include "ace/OS_NS_unistd.h"
15 #include "orbsvcs/CosNamingC.h"
16 #include "orbsvcs/PortableGroupC.h"
17 #include "orbsvcs/PortableGroup/PG_Property_Set.h"
19 // Use this macro at the beginning of CORBA methods
20 // to aid in debugging.
21 #define METHOD_ENTRY(name) \
22 ACE_DEBUG (( LM_DEBUG, \
26 // Use this macro to return from CORBA methods
27 // to aid in debugging. Note that you can specify
28 // the return value after the macro, for example:
29 // METHOD_RETURN(Plugh::plover) xyzzy; is equivalent
31 // METHOD_RETURN(Plugh::troll); is equivalent to
33 // WARNING: THIS GENERATES TWO STATEMENTS!!! THE FOLLOWING
34 // will not do what you want it to:
35 // if (cave_is_closing) METHOD_RETURN(Plugh::pirate) aarrggh;
36 // Moral: Always use braces.
37 #define METHOD_RETURN(name) \
38 ACE_DEBUG (( LM_DEBUG, \
41 return /* value goes here */
44 static const char * criterion_initial_value
= "INITIAL_VALUE";
46 //////////////////////////////////////////////////////
47 // FT_ReplicaFactory_i Construction/destruction
49 FT_ReplicaFactory_i::FT_ReplicaFactory_i ()
51 , orb_ (CORBA::ORB::_nil ())
52 , poa_ (PortableServer::POA::_nil ())
55 , ior_output_file_ (0)
57 , have_replication_manager_(0)
58 , replication_manager_(0)
59 , factory_registry_ior_(0)
60 , factory_registry_ (0)
62 , test_output_file_(0)
64 , naming_context_ (CosNaming::NamingContext::_nil ())
67 , location_ ("unknown")
69 , unregister_by_location_ (0)
73 , name_persistent_file_(ACE_TEXT(""))
75 char const * repo_id
=
76 FT_TEST::_tc_TestReplica
->id ();
79 "TestReplica type_id: %s\n",
82 // ACE_DEBUG((LM_DEBUG, "Hobbit type_id: %s\n", FT_TEST::_tc_Hobbit->id() ));
83 // ACE_DEBUG((LM_DEBUG, "Elf type_id: %s\n", FT_TEST::_tc_Elf->id() ));
84 // ACE_DEBUG((LM_DEBUG, "Human type_id: %s\n", FT_TEST::_tc_Human->id() ));
88 FT_ReplicaFactory_i::~FT_ReplicaFactory_i ()
91 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
93 // be sure all replicas are gone
94 // before this object disappears
99 ////////////////////////////////////////////
100 // FT_ReplicaFactory_i private methods
102 CORBA::ULong
FT_ReplicaFactory_i::allocate_id()
104 // assume mutex is locked
105 CORBA::ULong id
= this->replicas_
.size();
106 if (this->empty_slots_
!= 0)
108 for(CORBA::ULong pos
= 0; pos
< id
; ++pos
)
110 if (this->replicas_
[pos
] == 0)
118 this->replicas_
.push_back(0);
119 this->empty_slots_
+= 1;
124 void FT_ReplicaFactory_i::shutdown_i()
126 // assume mutex is locked
127 for (size_t nReplica
= 0; nReplica
< this->replicas_
.size(); ++nReplica
)
129 FT_TestReplica_i
* replica
= this->replicas_
[nReplica
];
132 replica
->request_quit();
137 int FT_ReplicaFactory_i::write_ior(const ACE_TCHAR
* outputFile
, const char * ior
)
140 FILE* out
= ACE_OS::fopen (outputFile
, "w");
143 ACE_OS::fprintf (out
, "%s", ior
);
144 ACE_OS::fclose (out
);
149 ACE_ERROR ((LM_ERROR
,
150 "Open failed for %s\n", outputFile
156 //////////////////////////////////////////////////////
157 // FT_ReplicaFactory_i public, non-CORBA methods
159 int FT_ReplicaFactory_i::parse_args (int argc
, ACE_TCHAR
* argv
[])
161 ACE_Get_Opt
get_opts (argc
, argv
, ACE_TEXT("o:n:f:i:l:t:p:qu"));
164 while ((c
= get_opts ()) != -1)
170 this->ior_output_file_
= get_opts
.opt_arg ();
175 this->ns_name_
= ACE_TEXT_ALWAYS_CHAR(get_opts
.opt_arg ());
180 this->factory_registry_ior_
= get_opts
.opt_arg ();
185 this->roles_
.push_back(ACE_TEXT_ALWAYS_CHAR(get_opts
.opt_arg ()));
190 this->location_
= ACE_TEXT_ALWAYS_CHAR(get_opts
.opt_arg ());
195 this->quit_on_idle_
= 1;
200 this->unregister_by_location_
= 1;
206 this->test_output_file_
= get_opts
.opt_arg ();
211 this->name_persistent_file_
= get_opts
.opt_arg ();
218 ACE_ERROR_RETURN ((LM_ERROR
,
220 " -o <factory ior file>\n"
221 " -n <naming service registration name>\n"
222 " -f <factory registry ior file>\n"
223 " -i <registration: role>\n"
224 " -l <registration: location>\n"
225 " -t <test replica ior file>\n"
226 " -p <name presistent file>\n"
227 " -u{nregister by location}\n"
228 " -q{uit on idle}\n",
234 // Indicates successful parsing of the command line
238 const char * FT_ReplicaFactory_i::location () const
240 return this->location_
.c_str ();
243 const ACE_TCHAR
* FT_ReplicaFactory_i::identity () const
245 return this->identity_
.c_str();
248 int FT_ReplicaFactory_i::idle (int & result
)
251 size_t replicaCount
= this->replicas_
.size();
252 if (replicaCount
!= this->empty_slots_
)
254 for (size_t nReplica
= 0; result
== 0 && nReplica
< replicaCount
; ++nReplica
)
256 FT_TestReplica_i
* replica
= this->replicas_
[nReplica
];
259 // give the replica's idle processing a change
260 // ignore the return status (the replica should shut itself down
261 // unless result is non-zero.
262 // non-zero result means panic.
263 replica
->idle(result
);
268 int quit
= (this->quit_requested_
|| result
!= 0);
269 if (!quit
&& this->replicas_
.size() == this->empty_slots_
)
271 /* if you re-enable this, add some kind of throttle to avoid noise.
272 ACE_ERROR (( LM_ERROR,
273 "ReplicaFactory is idle.\n"
276 if (this->quit_on_idle_
&& this->empty_slots_
!= 0)
278 ACE_ERROR (( LM_ERROR
,
279 "%s exits due to quit on idle option.\n",
291 int FT_ReplicaFactory_i::init (CORBA::ORB_ptr orb
)
295 this->orb_
= CORBA::ORB::_duplicate (orb
);
297 // Use the ROOT POA for now
298 CORBA::Object_var poa_object
=
299 this->orb_
->resolve_initial_references (TAO_OBJID_ROOTPOA
);
301 if (CORBA::is_nil (poa_object
.in ()))
303 ACE_ERROR_RETURN ((LM_ERROR
,
304 ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n")),
308 // Get the POA object.
310 PortableServer::POA::_narrow (poa_object
.in ());
312 if (CORBA::is_nil(this->poa_
.in ()))
314 ACE_ERROR_RETURN ((LM_ERROR
,
315 ACE_TEXT (" (%P|%t) Unable to narrow the POA.\n")),
319 PortableServer::POAManager_var poa_manager
=
320 this->poa_
->the_POAManager ();
322 poa_manager
->activate ();
324 // Register with the POA.
326 this->object_id_
= this->poa_
->activate_object (this);
328 CORBA::Object_var this_obj
=
329 this->poa_
->id_to_reference (object_id_
.in ());
331 this->ior_
= this->orb_
->object_to_string (this_obj
.in ());
333 if (this->factory_registry_ior_
!= 0)
335 if (ACE_OS::strcmp (this->factory_registry_ior_
, ACE_TEXT("none")) != 0)
337 CORBA::Object_var reg_obj
= this->orb_
->string_to_object(factory_registry_ior_
);
338 this->factory_registry_
= ::PortableGroup::FactoryRegistry::_narrow(reg_obj
.in ());
339 if (CORBA::is_nil(this->factory_registry_
.in ()))
341 ACE_ERROR (( LM_ERROR
,
342 "Can't resolve Factory Registry IOR %s\n",
343 this->factory_registry_ior_
349 else // no -f option. Try RIR(RM)
351 ///////////////////////////////
352 // Find the ReplicationManager
355 CORBA::Object_var rm_obj
= orb
->resolve_initial_references("ReplicationManager");
356 this->replication_manager_
= ::FT::ReplicationManager::_narrow(rm_obj
.in());
357 if (!CORBA::is_nil (replication_manager_
.in ()))
359 this->have_replication_manager_
= 1;
361 ::PortableGroup::Criteria criteria
;
362 this->factory_registry_
= this->replication_manager_
->get_factory_registry(criteria
);
363 if (CORBA::is_nil (this->factory_registry_
.in ()))
365 ACE_ERROR ((LM_ERROR
,"ReplicaFactory: ReplicationManager failed to return FactoryRegistry. Factory will not be registered.\n" ));
370 this->factory_registry_
= ::PortableGroup::FactoryRegistry::_narrow(rm_obj
.in());
371 if (!CORBA::is_nil(this->factory_registry_
.in ()))
373 ACE_DEBUG ((LM_DEBUG
,"Found a FactoryRegistry DBA ReplicationManager\n" ));
377 ACE_ERROR ((LM_ERROR
,"ReplicaFactory: Can't resolve ReplicationManager.\n" ));
381 catch (const CORBA::Exception
& ex
)
383 if (this->test_output_file_
== 0) // ignore if this is a test run
385 ex
._tao_print_exception (
386 "ReplicaFactory: Exception resolving ReplicationManager. Factory will not be registered.\n");
392 if ( ! CORBA::is_nil (this->factory_registry_
.in ()))
394 size_t roleCount
= roles_
.size();
395 for (size_t nRole
= 0; nRole
< roleCount
; ++nRole
)
397 const char * roleName
= this->roles_
[nRole
].c_str();
399 PortableGroup::FactoryInfo info
;
400 info
.the_factory
= ::PortableGroup::GenericFactory::_narrow(this_obj
.in ());
401 info
.the_location
.length(1);
402 info
.the_location
[0].id
= CORBA::string_dup(this->location_
.c_str ());
403 info
.the_criteria
.length(1);
404 info
.the_criteria
[0].nam
.length(1);
405 info
.the_criteria
[0].nam
[0].id
= CORBA::string_dup(PortableGroup::role_criterion
);
406 info
.the_criteria
[0].val
<<= CORBA::string_dup(roleName
);
408 ACE_ERROR (( LM_INFO
,
409 "Factory: %s@%C registering with factory registry\n",
414 char const * replica_repository_id
=
415 FT_TEST::_tc_TestReplica
->id ();
417 this->factory_registry_
->register_factory(
419 replica_repository_id
,
422 this->registered_
= 1;
425 int identified
= 0; // bool
427 if (this->roles_
.size() > 0)
429 this->identity_
= ACE_TEXT("Factory");
430 if (this->location_
.length () != 0)
432 this->identity_
+= ACE_TEXT("@");
433 this->identity_
+= ACE_TEXT_CHAR_TO_TCHAR(this->location_
.c_str ());
438 if (this->ior_output_file_
!= 0)
442 this->identity_
= ACE_TEXT("file:");
443 this->identity_
+= this->ior_output_file_
;
444 // note: don't set identified--ns identity overrides file identitiy
446 result
= write_ior (this->ior_output_file_
, this->ior_
. in ());
450 if (this->registered_
)
452 // if we didn't register with a FactoryRegistry
453 // and no IOR file specified,
454 // then always try to register with name service
455 this->ns_name_
= "FT_ReplicaFactory";
459 if (this->ns_name_
.length () != 0)
463 this->identity_
= ACE_TEXT("name:");
464 this->identity_
+= ACE_TEXT_CHAR_TO_TCHAR(this->ns_name_
.c_str ());
467 CORBA::Object_var naming_obj
=
468 this->orb_
->resolve_initial_references ("NameService");
470 if (CORBA::is_nil(naming_obj
.in ())){
471 ACE_ERROR_RETURN ((LM_ERROR
,
472 "%T %n (%P|%t) Unable to find the Naming Service\n"),
476 this->naming_context_
=
477 CosNaming::NamingContext::_narrow (naming_obj
.in ());
479 this->this_name_
.length (1);
480 this->this_name_
[0].id
= CORBA::string_dup (this->ns_name_
.c_str ());
482 this->naming_context_
->rebind (this->this_name_
, this_obj
.in());
485 // if we're testing. Create a replica at startup time
486 if (this->test_output_file_
!= 0)
488 // shouldn't be necessary, but create_replica assumes this
489 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
, guard
, this->internals_
, 1);
490 FT_TestReplica_i
* replica
= create_replica ("test");
492 PortableServer::POA_var poa
= replica
->_default_POA ();
493 ::CORBA::Object_var replica_obj
= poa
->servant_to_reference(replica
);
494 ::CORBA::String_var replicaIOR
= this->orb_
->object_to_string(replica_obj
.in ());
495 write_ior (this->test_output_file_
, replicaIOR
.in ());
501 int FT_ReplicaFactory_i::fini (void)
503 if (this->ior_output_file_
!= 0)
505 ACE_OS::unlink (this->ior_output_file_
);
506 this->ior_output_file_
= 0;
508 if (this->ns_name_
.length () != 0)
510 this->naming_context_
->unbind (this_name_
);
511 this->ns_name_
.clear ();
518 if (this->unregister_by_location_
)
520 ACE_ERROR (( LM_INFO
,
521 "%s: unregistering all factories at %C\n",
526 PortableGroup::Location
location(1);
528 location
[0].id
= CORBA::string_dup(location_
.c_str ());
529 this->factory_registry_
->unregister_factory_by_location (
534 size_t roleCount
= roles_
.size();
535 for (size_t nRole
= 0; nRole
< roleCount
; ++nRole
)
537 const char * roleName
= this->roles_
[nRole
].c_str();
538 ACE_ERROR (( LM_INFO
,
539 "Factory for: %s@%C unregistering from factory registry\n",
544 PortableGroup::Location
location(1);
546 location
[0].id
= CORBA::string_dup(location_
.c_str ());
547 this->factory_registry_
->unregister_factory (
558 void FT_ReplicaFactory_i::remove_replica(CORBA::ULong id
, FT_TestReplica_i
* replica
)
560 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
561 if (id
< this->replicas_
.size())
563 if(this->replicas_
[id
] == replica
)
567 this->replicas_
[id
] = 0;
568 this->empty_slots_
+= 1;
572 ACE_ERROR (( LM_ERROR
,
573 "Remove replica %d mismatch.\n",
574 static_cast<int> (id
)
580 ACE_ERROR (( LM_ERROR
,
581 "Attempt to remove invalid replica %d. Limit %d.\n",
582 static_cast<int> (id
),
583 static_cast<int> (this->replicas_
.size())
588 //////////////////////////////////////////
589 // FT_ReplicaFactory_i CORBA methods
591 CORBA::Object_ptr
FT_ReplicaFactory_i::create_object (
592 const char * type_id
,
593 const PortableGroup::Criteria
& the_criteria
,
594 PortableGroup::GenericFactory::FactoryCreationId_out factory_creation_id
)
596 METHOD_ENTRY(FT_ReplicaFactory_i::create_object
);
597 ACE_UNUSED_ARG (type_id
);
598 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
, guard
, this->internals_
, CORBA::Object::_nil ());
600 ::TAO::PG_Property_Set
decoder (the_criteria
);
602 // boolean, becomes true if a required parameter is missing
603 int missingParameter
= 0;
604 const char * missingParameterName
= 0;
606 CORBA::Long initialValue
= 0;
607 if (! ::TAO::find (decoder
, criterion_initial_value
, initialValue
) )
609 // not required. Otherwise:
610 // missingParameter = 1;
611 // missingParameterName = criterion_initial_value;
614 const char * role
= "replica";
615 if (! ::TAO::find (decoder
, PortableGroup::role_criterion
, role
) )
618 "Property \"%s\" not found?\n", PortableGroup::role_criterion
620 // not required. Otherwise:
621 // missingParameter = 1;
622 // missingParameterName = PortableGroup::role_criterion;
625 if (missingParameter
)
627 ACE_ERROR ((LM_ERROR
,
628 "Throwing 'InvalidCriteria' due to missing %s\n",
631 throw PortableGroup::InvalidCriteria();
634 FT_TestReplica_i
* replica
= create_replica(role
);
637 ACE_ERROR ((LM_ERROR
,
638 "New Replica_i returned NULL. Throwing ObjectNotCreated.\n"
640 throw PortableGroup::ObjectNotCreated();
643 ACE_NEW_THROW_EX ( factory_creation_id
,
644 PortableGroup::GenericFactory::FactoryCreationId
,
645 PortableGroup::ObjectNotCreated());
646 CORBA::ULong factory_id
= replica
->factory_id();
647 (*factory_creation_id
) <<= factory_id
;
650 "Created %s@%C#%d.\n", role
, this->location_
.c_str (), static_cast<int> (factory_id
)
654 ::CORBA::Object_ptr replica_obj
=
655 replica
->_default_POA()->servant_to_reference(replica
);
656 METHOD_RETURN(FT_ReplicaFactory_i::create_object
) replica_obj
->_duplicate(replica_obj
);
659 FT_TestReplica_i
* FT_ReplicaFactory_i::create_replica(const char * name
)
661 // assume mutex is locked
662 CORBA::ULong factoryId
= allocate_id();
664 FT_TestReplica_i
* pFTReplica
= 0;
666 ACE_NEW_NORETURN(pFTReplica
, FT_TestReplica_i(
672 this->replicas_
[factoryId
] = pFTReplica
;
673 this->empty_slots_
-= 1;
675 pFTReplica
->init (this->orb_
, this->name_persistent_file_
);
679 void FT_ReplicaFactory_i::delete_object (
680 const PortableGroup::GenericFactory::FactoryCreationId
& factory_creation_id
)
682 METHOD_ENTRY(FT_ReplicaFactory_i::delete_object
);
684 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
686 CORBA::ULong factoryId
;
687 factory_creation_id
>>= factoryId
;
688 if (factoryId
< this->replicas_
.size())
690 if(this->replicas_
[factoryId
] != 0)
692 this->replicas_
[factoryId
]->request_quit();
696 throw ::PortableGroup::ObjectNotFound();
701 throw ::PortableGroup::ObjectNotFound();
703 METHOD_RETURN(FT_ReplicaFactory_i::delete_object
);
706 CORBA::Boolean
FT_ReplicaFactory_i::is_alive (void)
708 METHOD_RETURN(FT_ReplicaFactory_i::is_alive
)
712 void FT_ReplicaFactory_i::shutdown (void)
714 METHOD_ENTRY(FT_FaultDetectorFactory_i::shutdown
);
715 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
717 this->quit_requested_
= 1;
718 METHOD_RETURN(FT_FaultDetectorFactory_i::shutdown
);