Merge pull request #1551 from DOCGroup/plm_jira_333
[ACE_TAO.git] / TAO / orbsvcs / tests / FT_App / FT_ReplicaFactory_i.cpp
blob798c79a9e82dcf86c06eb8fb6f26886b0615808f
1 /* -*- C++ -*- */
2 //=============================================================================
3 /**
4 * @file FT_ReplicaFactory_i.cpp
6 * This file is part of Fault Tolerant CORBA.
8 * @author Dale Wilson <wilson_d@ociweb.com>
9 */
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, \
23 "Enter %s\n", #name \
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
30 // to return xyzzy;
31 // METHOD_RETURN(Plugh::troll); is equivalent to
32 // return;
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, \
39 "Leave %s\n", #name \
40 )); \
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 ()
50 : internals_ ()
51 , orb_ (CORBA::ORB::_nil ())
52 , poa_ (PortableServer::POA::_nil ())
53 , object_id_ ()
54 , ior_ ()
55 , ior_output_file_ (0)
56 , identity_ ()
57 , have_replication_manager_(0)
58 , replication_manager_(0)
59 , factory_registry_ior_(0)
60 , factory_registry_ (0)
61 , registered_(0)
62 , test_output_file_(0)
63 , ns_name_("")
64 , naming_context_ (CosNaming::NamingContext::_nil ())
65 , this_name_ ()
66 , roles_ ()
67 , location_ ("unknown")
68 , quit_on_idle_ (0)
69 , unregister_by_location_ (0)
70 , replicas_ ()
71 , empty_slots_(0)
72 , quit_requested_(0)
73 , name_persistent_file_(ACE_TEXT(""))
75 char const * repo_id =
76 FT_TEST::_tc_TestReplica->id ();
78 ACE_DEBUG ((LM_DEBUG,
79 "TestReplica type_id: %s\n",
80 repo_id));
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
95 shutdown_i ();
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)
112 id = pos;
116 else
118 this->replicas_.push_back(0);
119 this->empty_slots_ += 1;
121 return id;
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];
130 if (replica != 0)
132 replica->request_quit();
137 int FT_ReplicaFactory_i::write_ior(const ACE_TCHAR * outputFile, const char * ior)
139 int result = -1;
140 FILE* out = ACE_OS::fopen (outputFile, "w");
141 if (out)
143 ACE_OS::fprintf (out, "%s", ior);
144 ACE_OS::fclose (out);
145 result = 0;
147 else
149 ACE_ERROR ((LM_ERROR,
150 "Open failed for %s\n", outputFile
153 return result;
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"));
162 int c;
164 while ((c = get_opts ()) != -1)
166 switch (c)
168 case 'o':
170 this->ior_output_file_ = get_opts.opt_arg ();
171 break;
173 case 'n':
175 this->ns_name_ = ACE_TEXT_ALWAYS_CHAR(get_opts.opt_arg ());
176 break;
178 case 'f':
180 this->factory_registry_ior_ = get_opts.opt_arg ();
181 break;
183 case 'i':
185 this->roles_.push_back(ACE_TEXT_ALWAYS_CHAR(get_opts.opt_arg ()));
186 break;
188 case 'l':
190 this->location_ = ACE_TEXT_ALWAYS_CHAR(get_opts.opt_arg ());
191 break;
193 case 'q':
195 this->quit_on_idle_ = 1;
196 break;
198 case 'u':
200 this->unregister_by_location_ = 1;
201 break;
204 case 't':
206 this->test_output_file_ = get_opts.opt_arg ();
207 break;
209 case 'p':
211 this->name_persistent_file_ = get_opts.opt_arg ();
212 break;
215 case '?':
216 // fall thru
217 default:
218 ACE_ERROR_RETURN ((LM_ERROR,
219 "usage: %s\n"
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",
229 argv [0]),
230 -1);
231 break;
234 // Indicates successful parsing of the command line
235 return 0;
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)
250 result = 0;
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];
257 if (replica != 0)
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",
280 identity()
282 quit = 1;
286 return quit;
291 int FT_ReplicaFactory_i::init (CORBA::ORB_ptr orb)
293 int result = 0;
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")),
305 -1);
308 // Get the POA object.
309 this->poa_ =
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")),
316 -1);
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_
345 result = -1;
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;
360 // empty criteria
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" ));
368 else
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" ));
375 else
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",
410 roleName,
411 location_.c_str ()
414 char const * replica_repository_id =
415 FT_TEST::_tc_TestReplica->id ();
417 this->factory_registry_->register_factory(
418 roleName,
419 replica_repository_id,
420 info);
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 ());
435 identified = 1;
438 if (this->ior_output_file_ != 0)
440 if (!identified)
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 ());
448 else
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)
461 if (!identified)
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 ());
498 return result;
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 ();
514 if (registered_)
516 registered_ = 0;
518 if (this->unregister_by_location_)
520 ACE_ERROR (( LM_INFO,
521 "%s: unregistering all factories at %C\n",
522 identity(),
523 location_.c_str ()
526 PortableGroup::Location location(1);
527 location.length(1);
528 location[0].id = CORBA::string_dup(location_.c_str ());
529 this->factory_registry_->unregister_factory_by_location (
530 location);
532 else
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",
540 roleName,
541 location_.c_str ()
544 PortableGroup::Location location(1);
545 location.length(1);
546 location[0].id = CORBA::string_dup(location_.c_str ());
547 this->factory_registry_->unregister_factory (
548 roleName,
549 location);
554 return 0;
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)
565 replica->fini();
566 delete replica;
567 this->replicas_[id] = 0;
568 this->empty_slots_ += 1;
570 else
572 ACE_ERROR (( LM_ERROR,
573 "Remove replica %d mismatch.\n",
574 static_cast<int> (id)
578 else
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) )
617 ACE_ERROR((LM_INFO,
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",
629 missingParameterName
631 throw PortableGroup::InvalidCriteria();
634 FT_TestReplica_i * replica = create_replica(role);
635 if (replica == 0)
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;
649 ACE_ERROR ((LM_INFO,
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(
667 this,
668 name,
669 factoryId
672 this->replicas_[factoryId] = pFTReplica;
673 this->empty_slots_ -= 1;
675 pFTReplica->init (this->orb_, this->name_persistent_file_);
676 return pFTReplica;
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();
694 else
696 throw ::PortableGroup::ObjectNotFound();
699 else
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)
709 true;
712 void FT_ReplicaFactory_i::shutdown (void)
714 METHOD_ENTRY(FT_FaultDetectorFactory_i::shutdown);
715 ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->internals_);
716 shutdown_i ();
717 this->quit_requested_ = 1;
718 METHOD_RETURN(FT_FaultDetectorFactory_i::shutdown);