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",
290 int FT_ReplicaFactory_i::init (CORBA::ORB_ptr orb
)
294 this->orb_
= CORBA::ORB::_duplicate (orb
);
296 // Use the ROOT POA for now
297 CORBA::Object_var poa_object
=
298 this->orb_
->resolve_initial_references (TAO_OBJID_ROOTPOA
);
300 if (CORBA::is_nil (poa_object
.in ()))
302 ACE_ERROR_RETURN ((LM_ERROR
,
303 ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n")),
307 // Get the POA object.
309 PortableServer::POA::_narrow (poa_object
.in ());
311 if (CORBA::is_nil(this->poa_
.in ()))
313 ACE_ERROR_RETURN ((LM_ERROR
,
314 ACE_TEXT (" (%P|%t) Unable to narrow the POA.\n")),
318 PortableServer::POAManager_var poa_manager
=
319 this->poa_
->the_POAManager ();
321 poa_manager
->activate ();
323 // Register with the POA.
325 this->object_id_
= this->poa_
->activate_object (this);
327 CORBA::Object_var this_obj
=
328 this->poa_
->id_to_reference (object_id_
.in ());
330 this->ior_
= this->orb_
->object_to_string (this_obj
.in ());
332 if (this->factory_registry_ior_
!= 0)
334 if (ACE_OS::strcmp (this->factory_registry_ior_
, ACE_TEXT("none")) != 0)
336 CORBA::Object_var reg_obj
= this->orb_
->string_to_object(factory_registry_ior_
);
337 this->factory_registry_
= ::PortableGroup::FactoryRegistry::_narrow(reg_obj
.in ());
338 if (CORBA::is_nil(this->factory_registry_
.in ()))
340 ACE_ERROR (( LM_ERROR
,
341 "Can't resolve Factory Registry IOR %s\n",
342 this->factory_registry_ior_
348 else // no -f option. Try RIR(RM)
350 ///////////////////////////////
351 // Find the ReplicationManager
354 CORBA::Object_var rm_obj
= orb
->resolve_initial_references("ReplicationManager");
355 this->replication_manager_
= ::FT::ReplicationManager::_narrow(rm_obj
.in());
356 if (!CORBA::is_nil (replication_manager_
.in ()))
358 this->have_replication_manager_
= 1;
360 ::PortableGroup::Criteria criteria
;
361 this->factory_registry_
= this->replication_manager_
->get_factory_registry(criteria
);
362 if (CORBA::is_nil (this->factory_registry_
.in ()))
364 ACE_ERROR ((LM_ERROR
,"ReplicaFactory: ReplicationManager failed to return FactoryRegistry. Factory will not be registered.\n" ));
369 this->factory_registry_
= ::PortableGroup::FactoryRegistry::_narrow(rm_obj
.in());
370 if (!CORBA::is_nil(this->factory_registry_
.in ()))
372 ACE_DEBUG ((LM_DEBUG
,"Found a FactoryRegistry DBA ReplicationManager\n" ));
376 ACE_ERROR ((LM_ERROR
,"ReplicaFactory: Can't resolve ReplicationManager.\n" ));
380 catch (const CORBA::Exception
& ex
)
382 if (this->test_output_file_
== 0) // ignore if this is a test run
384 ex
._tao_print_exception (
385 "ReplicaFactory: Exception resolving ReplicationManager. Factory will not be registered.\n");
391 if ( ! CORBA::is_nil (this->factory_registry_
.in ()))
393 size_t roleCount
= roles_
.size();
394 for (size_t nRole
= 0; nRole
< roleCount
; ++nRole
)
396 const char * roleName
= this->roles_
[nRole
].c_str();
398 PortableGroup::FactoryInfo info
;
399 info
.the_factory
= ::PortableGroup::GenericFactory::_narrow(this_obj
.in ());
400 info
.the_location
.length(1);
401 info
.the_location
[0].id
= CORBA::string_dup(this->location_
.c_str ());
402 info
.the_criteria
.length(1);
403 info
.the_criteria
[0].nam
.length(1);
404 info
.the_criteria
[0].nam
[0].id
= CORBA::string_dup(PortableGroup::role_criterion
);
405 info
.the_criteria
[0].val
<<= CORBA::string_dup(roleName
);
407 ACE_ERROR (( LM_INFO
,
408 "Factory: %s@%C registering with factory registry\n",
413 char const * replica_repository_id
=
414 FT_TEST::_tc_TestReplica
->id ();
416 this->factory_registry_
->register_factory(
418 replica_repository_id
,
421 this->registered_
= 1;
424 int identified
= 0; // bool
426 if (this->roles_
.size() > 0)
428 this->identity_
= ACE_TEXT("Factory");
429 if (this->location_
.length () != 0)
431 this->identity_
+= ACE_TEXT("@");
432 this->identity_
+= ACE_TEXT_CHAR_TO_TCHAR(this->location_
.c_str ());
437 if (this->ior_output_file_
!= 0)
441 this->identity_
= ACE_TEXT("file:");
442 this->identity_
+= this->ior_output_file_
;
443 // note: don't set identified--ns identity overrides file identitiy
445 result
= write_ior (this->ior_output_file_
, this->ior_
. in ());
449 if (this->registered_
)
451 // if we didn't register with a FactoryRegistry
452 // and no IOR file specified,
453 // then always try to register with name service
454 this->ns_name_
= "FT_ReplicaFactory";
458 if (this->ns_name_
.length () != 0)
462 this->identity_
= ACE_TEXT("name:");
463 this->identity_
+= ACE_TEXT_CHAR_TO_TCHAR(this->ns_name_
.c_str ());
466 CORBA::Object_var naming_obj
=
467 this->orb_
->resolve_initial_references ("NameService");
469 if (CORBA::is_nil(naming_obj
.in ())){
470 ACE_ERROR_RETURN ((LM_ERROR
,
471 "%T %n (%P|%t) Unable to find the Naming Service\n"),
475 this->naming_context_
=
476 CosNaming::NamingContext::_narrow (naming_obj
.in ());
478 this->this_name_
.length (1);
479 this->this_name_
[0].id
= CORBA::string_dup (this->ns_name_
.c_str ());
481 this->naming_context_
->rebind (this->this_name_
, this_obj
.in());
484 // if we're testing. Create a replica at startup time
485 if (this->test_output_file_
!= 0)
487 // shouldn't be necessary, but create_replica assumes this
488 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
, guard
, this->internals_
, 1);
489 FT_TestReplica_i
* replica
= create_replica ("test");
491 PortableServer::POA_var poa
= replica
->_default_POA ();
492 ::CORBA::Object_var replica_obj
= poa
->servant_to_reference(replica
);
493 ::CORBA::String_var replicaIOR
= this->orb_
->object_to_string(replica_obj
.in ());
494 write_ior (this->test_output_file_
, replicaIOR
.in ());
500 int FT_ReplicaFactory_i::fini ()
502 if (this->ior_output_file_
!= 0)
504 ACE_OS::unlink (this->ior_output_file_
);
505 this->ior_output_file_
= 0;
507 if (this->ns_name_
.length () != 0)
509 this->naming_context_
->unbind (this_name_
);
510 this->ns_name_
.clear ();
517 if (this->unregister_by_location_
)
519 ACE_ERROR (( LM_INFO
,
520 "%s: unregistering all factories at %C\n",
525 PortableGroup::Location
location(1);
527 location
[0].id
= CORBA::string_dup(location_
.c_str ());
528 this->factory_registry_
->unregister_factory_by_location (
533 size_t roleCount
= roles_
.size();
534 for (size_t nRole
= 0; nRole
< roleCount
; ++nRole
)
536 const char * roleName
= this->roles_
[nRole
].c_str();
537 ACE_ERROR (( LM_INFO
,
538 "Factory for: %s@%C unregistering from factory registry\n",
543 PortableGroup::Location
location(1);
545 location
[0].id
= CORBA::string_dup(location_
.c_str ());
546 this->factory_registry_
->unregister_factory (
557 void FT_ReplicaFactory_i::remove_replica(CORBA::ULong id
, FT_TestReplica_i
* replica
)
559 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
560 if (id
< this->replicas_
.size())
562 if(this->replicas_
[id
] == replica
)
566 this->replicas_
[id
] = 0;
567 this->empty_slots_
+= 1;
571 ACE_ERROR (( LM_ERROR
,
572 "Remove replica %d mismatch.\n",
573 static_cast<int> (id
)
579 ACE_ERROR (( LM_ERROR
,
580 "Attempt to remove invalid replica %d. Limit %d.\n",
581 static_cast<int> (id
),
582 static_cast<int> (this->replicas_
.size())
587 //////////////////////////////////////////
588 // FT_ReplicaFactory_i CORBA methods
590 CORBA::Object_ptr
FT_ReplicaFactory_i::create_object (
591 const char * type_id
,
592 const PortableGroup::Criteria
& the_criteria
,
593 PortableGroup::GenericFactory::FactoryCreationId_out factory_creation_id
)
595 METHOD_ENTRY(FT_ReplicaFactory_i::create_object
);
596 ACE_UNUSED_ARG (type_id
);
597 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
, guard
, this->internals_
, CORBA::Object::_nil ());
599 ::TAO::PG_Property_Set
decoder (the_criteria
);
601 // boolean, becomes true if a required parameter is missing
602 int missingParameter
= 0;
603 const char * missingParameterName
= 0;
605 CORBA::Long initialValue
= 0;
606 if (! ::TAO::find (decoder
, criterion_initial_value
, initialValue
) )
608 // not required. Otherwise:
609 // missingParameter = 1;
610 // missingParameterName = criterion_initial_value;
613 const char * role
= "replica";
614 if (! ::TAO::find (decoder
, PortableGroup::role_criterion
, role
) )
617 "Property \"%s\" not found?\n", PortableGroup::role_criterion
619 // not required. Otherwise:
620 // missingParameter = 1;
621 // missingParameterName = PortableGroup::role_criterion;
624 if (missingParameter
)
626 ACE_ERROR ((LM_ERROR
,
627 "Throwing 'InvalidCriteria' due to missing %s\n",
630 throw PortableGroup::InvalidCriteria();
633 FT_TestReplica_i
* replica
= create_replica(role
);
636 ACE_ERROR ((LM_ERROR
,
637 "New Replica_i returned NULL. Throwing ObjectNotCreated.\n"
639 throw PortableGroup::ObjectNotCreated();
642 ACE_NEW_THROW_EX ( factory_creation_id
,
643 PortableGroup::GenericFactory::FactoryCreationId
,
644 PortableGroup::ObjectNotCreated());
645 CORBA::ULong factory_id
= replica
->factory_id();
646 (*factory_creation_id
) <<= factory_id
;
649 "Created %s@%C#%d.\n", role
, this->location_
.c_str (), static_cast<int> (factory_id
)
653 ::CORBA::Object_ptr replica_obj
=
654 replica
->_default_POA()->servant_to_reference(replica
);
655 METHOD_RETURN(FT_ReplicaFactory_i::create_object
) replica_obj
->_duplicate(replica_obj
);
658 FT_TestReplica_i
* FT_ReplicaFactory_i::create_replica(const char * name
)
660 // assume mutex is locked
661 CORBA::ULong factoryId
= allocate_id();
663 FT_TestReplica_i
* pFTReplica
= 0;
665 ACE_NEW_NORETURN(pFTReplica
, FT_TestReplica_i(
671 this->replicas_
[factoryId
] = pFTReplica
;
672 this->empty_slots_
-= 1;
674 pFTReplica
->init (this->orb_
, this->name_persistent_file_
);
678 void FT_ReplicaFactory_i::delete_object (
679 const PortableGroup::GenericFactory::FactoryCreationId
& factory_creation_id
)
681 METHOD_ENTRY(FT_ReplicaFactory_i::delete_object
);
683 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
685 CORBA::ULong factoryId
;
686 factory_creation_id
>>= factoryId
;
687 if (factoryId
< this->replicas_
.size())
689 if(this->replicas_
[factoryId
] != 0)
691 this->replicas_
[factoryId
]->request_quit();
695 throw ::PortableGroup::ObjectNotFound();
700 throw ::PortableGroup::ObjectNotFound();
702 METHOD_RETURN(FT_ReplicaFactory_i::delete_object
);
705 CORBA::Boolean
FT_ReplicaFactory_i::is_alive ()
707 METHOD_RETURN(FT_ReplicaFactory_i::is_alive
)
711 void FT_ReplicaFactory_i::shutdown ()
713 METHOD_ENTRY(FT_FaultDetectorFactory_i::shutdown
);
714 ACE_GUARD (TAO_SYNCH_MUTEX
, guard
, this->internals_
);
716 this->quit_requested_
= 1;
717 METHOD_RETURN(FT_FaultDetectorFactory_i::shutdown
);