ArmarXManager.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarXCore::core
19 * @author Kai Welke (kai dot welke at kit dot edu)
20 * @date 2012
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25#include "ArmarXManager.h" // for ArmarXManager, etc
26
27#include <limits.h> // for hostname max length
28
29#include <chrono> // for seconds
30#include <cstddef> // for size_t, NULL
31#include <iostream> // for operator<<, basic_ostream, etc
32#include <map> // for _Rb_tree_iterator, etc
33#include <ratio> // for ratio
34#include <sstream> // for basic_stringbuf<>::int_type, etc
35#include <string> // for string, allocator, etc
36#include <thread> // for thread, sleep_for
37#include <utility> // for pair, make_pair, move
38#include <vector> // for vector, vector<>::iterator
39
40#include <unistd.h> // for hostname
41
42#include <Ice/BuiltinSequences.h> // for StringSeq
43#include <Ice/Communicator.h> // for CommunicatorPtr, etc
44#include <Ice/Identity.h> // for Identity
45#include <Ice/Initialize.h> // for initialize
46#include <Ice/LocalException.h> // for AlreadyRegisteredException, etc
47#include <Ice/Metrics.h> // for Metrics
48#include <Ice/NativePropertiesAdmin.h>
49#include <Ice/ObjectAdapter.h> // for ObjectAdapterPtr
50#include <Ice/ObjectF.h> // for upCast
51#include <Ice/Properties.h> // for Properties
52#include <Ice/PropertiesF.h> // for upCast
53#include <Ice/Proxy.h> // for Object
54#include <Ice/ProxyF.h> // for ObjectPrx
55#include <IceGrid/Admin.h> // for Admin, ObjectObserverPrx, upCast
56#include <IceGrid/Registry.h> // for RegistryPrx, upCast
57#include <IceStorm/IceStorm.h> // for TopicPrx, TopicManagerPrx, etc
58#include <IceUtil/Handle.h> // for HandleBase, Handle
59
63#include "ArmarXCore/core/exceptions/Exception.h" // for LocalException, etc
64#include "ArmarXCore/core/logging/LogSender.h" // for LogSender
65#include "ArmarXCore/core/logging/Logging.h" // for ARMARX_VERBOSE, etc
66#include "ArmarXCore/core/services/tasks/ThreadList.h" // for ThreadList
67#include "ArmarXCore/interface/core/BasicTypes.h"
68#include "ArmarXCore/interface/core/Log.h" // for LogPrx, MessageType, etc
69#include "ArmarXCore/interface/core/ManagedIceObjectDefinitions.h"
70#include "ArmarXCore/interface/core/ThreadingIceBase.h" // for upCast
72#include <ArmarXCore/core/Component.h> // for ComponentPtr, Component
73#include <ArmarXCore/core/IceManager.h> // for IceManager
74#include <ArmarXCore/core/ManagedIceObject.h> // for ManagedIceObject
79#include <ArmarXCore/core/system/ArmarXDataPath.h> // for ArmarXDataPath
82#include <ArmarXCore/core/time/LocalTimeServer.h> // for LocalTimeServer
83#include <ArmarXCore/core/time/TimeUtil.h> // for TimeUtil
85
87#include "IceGridAdmin.h" // for IceGridAdmin
88
89namespace Ice
90{
91 struct Current;
92} // namespace Ice
93
94namespace armarx
95{
96#define MANAGEROBJNAME applicationName + "Manager"
97#define OBJOBSNAME std::string("ArmarXObjectObserver_") + applicationName
98
99 // *******************************************************
100 // construction
101 // *******************************************************
102 ArmarXManager::ArmarXManager(std::string applicationName,
103 int port,
104 std::string host,
105 std::string locatorName,
106 Ice::StringSeq args) :
107 applicationName(applicationName), managerState(eCreated)
108 {
109 // initialize communicator
110 std::stringstream defaultLocator;
111 defaultLocator << "--Ice.Default.Locator=" << locatorName << ":tcp -p " << port << " -h "
112 << host;
113 args.push_back(defaultLocator.str());
114 Ice::CommunicatorPtr communicator = Ice::initialize(args);
115
116 // init members
117 init(applicationName, communicator);
118 }
119
120 ArmarXManager::ArmarXManager(std::string applicationName,
121 const Ice::CommunicatorPtr& communicator) :
122 applicationName(applicationName), managerState(eCreated)
123 {
124 // init members
125 init(applicationName, communicator);
126 }
127
133
134 bool
136 {
137 return CheckIceConnection(iceManager->getCommunicator(), printHint);
138 }
139
140 bool
141 ArmarXManager::CheckIceConnection(const Ice::CommunicatorPtr& communicator, bool printHint)
142 {
143 const std::string armarxHint = "'\nDid you start armarx?\n\nTo start armarx: armarx start\n"
144 "To kill a hanging armarx: armarx killIce";
145 try
146 {
147 if (communicator->getProperties()->getProperty("Ice.Default.Locator").empty())
148 {
149 if (printHint)
150 {
151 std::cerr << "Required Ice property 'Ice.Default.Locator' not set! "
152 << "It has to has a value similar to 'IceGrid/Locator:tcp -p 4061 -h "
153 "localhost'";
154 }
155 return false;
156 }
157 auto locatorProp = communicator->getProperties()->getProperty("Ice.Default.Locator");
158 auto pos = locatorProp.find_first_of(':');
159 std::string locatorId = locatorProp.substr(0, pos);
160 auto proxy = communicator->stringToProxy(locatorId);
161 IceGrid::LocatorPrx::checkedCast(proxy);
162 }
163 catch (...)
164 {
165 if (printHint)
166 {
167 std::cerr << "Could not contact default locator at '"
168 << communicator->getProperties()->getProperty("Ice.Default.Locator")
169 << armarxHint;
170 }
171 return false;
172 }
173
174 try
175 {
176 std::string registryId = "IceGrid/Registry";
177 auto proxy = communicator->stringToProxy(registryId);
178 IceGrid::RegistryPrx::checkedCast(proxy);
179 }
180 catch (...)
181 {
182 if (printHint)
183 {
184 std::cerr << "Could not contact IceGrid registry at '"
185 << communicator->getProperties()->getProperty(
186 "IceGrid.Registry.Client.Endpoints")
187 << armarxHint;
188 }
189 return false;
190 }
191
192 try
193 {
194 IceManager::GetTopicManager(communicator);
195 }
196 catch (const Ice::NoEndpointException& e)
197 {
198 std::cout << "Caught exception: \n" << e.what() << std::endl;
199
200 if (printHint)
201 {
202 std::cerr
203 << "Could not contact TopicManager at '"
204 // This string is actually used in IceManager::GetTopicManager()
205 << "IceStorm/TopicManager"
206 // << communicator->getProperties()->getProperty("IceStormAdmin.TopicManager.Default")
207 << armarxHint;
208 }
209 return false;
210 }
211
212 return true;
213 }
214
215 // *******************************************************
216 // ArmarXManager property setters
217 // *******************************************************
218 void
223
224 void
226 {
227 ThreadList::getApplicationThreadList()->enableProfiler(enable);
228 }
229
230 void
235
236 void
237 ArmarXManager::setDataPaths(std::string dataPaths)
238 {
240 }
241
242 // *******************************************************
243 // adding / removing ManagedIceObjects
244 // *******************************************************
245
246
247 void
249 bool addWithOwnAdapter,
250 const std::string& objectName,
251 bool useOwnScheduleThread)
252 {
253 addObject(object,
254 addWithOwnAdapter ? Ice::ObjectAdapterPtr() : getAdapter(),
255 objectName,
256 useOwnScheduleThread);
257 }
258
259 void
261 const std::string& objectName,
262 bool addWithOwnAdapter,
263 bool useOwnScheduleThread)
264 {
265 addObject(object, addWithOwnAdapter, objectName, useOwnScheduleThread);
266 }
267
268 void
270 Ice::ObjectAdapterPtr objectAdapterToAddTo,
271 const std::string& objectName,
272 bool useOwnScheduleThread)
273 {
274 if (!object)
275 {
276 throw LocalException("Cannot add NULL object");
277 }
278 {
279 auto cptr = ComponentPtr::dynamicCast(object);
280 if (cptr && !cptr->createdByComponentCreate)
281 {
282 throw LocalException("Components need to be created by Component::create");
283 }
284 }
285
286 if (!objectName.empty())
287 {
288 if (!object->getName().empty())
289 {
290 ARMARX_INFO << "Adding object with custom name: " << objectName;
291 }
292 object->setName(objectName);
293 }
294 if (object->getName().empty())
295 {
296 object->setName(object->getDefaultName());
297 }
298 if (object->getName().empty())
299 {
300 throw LocalException("Object name must not be empty");
301 }
302 auto lock = acquireManagedObjectsMutex();
303 if (!lock)
304 {
305 return;
306 }
307
308 bool reachable = false;
309
310 try
311 {
312 reachable = getIceManager()->isObjectReachable(object->getName());
313 }
314 catch (...)
315 {
316 throw;
317 }
318
319 if (reachable)
320 {
321 throw Ice::AlreadyRegisteredException(
322 __FILE__, __LINE__, object->ice_id(), object->getName());
323 }
324
325 try
326 {
328 this, iceManager, object, objectAdapterToAddTo, useOwnScheduleThread);
329 auto pair = managedObjects.insert(
330 std::make_pair(object->getName(), std::move(objectScheduler)));
331 if (!pair.second)
332 {
333 throw Ice::AlreadyRegisteredException(
334 __FILE__, __LINE__, object->ice_id(), object->getName());
335 }
336 if (!useOwnScheduleThread)
337 {
338 std::scoped_lock lock(schedulerListMutex);
339 singleThreadedSchedulers.at(rand() % singleThreadedSchedulers.size())
340 ->addObjectScheduler(pair.first->second);
341 }
342 }
343 catch (...)
344 {
345 throw;
346 }
347 }
348
349 void
351 const std::string& objectName,
352 bool addWithOwnAdapter,
353 bool useOwnScheduleThread)
354 {
355 ArmarXManagerPtr manager(this);
356 std::thread{
357 [=]
358 {
359 try
360 {
361 manager->addObject(object, objectName, addWithOwnAdapter, useOwnScheduleThread);
362 }
363 catch (...)
364 {
366 }
367 }
368
369 }.detach();
370 }
371
372 void
373 ArmarXManager::removeObjectBlocking(const std::string& objectName)
374 {
375 ArmarXObjectSchedulerPtr scheduler;
376 {
377 auto lock = acquireManagedObjectsMutex();
378 if (!lock)
379 {
380 return;
381 }
382 auto it = managedObjects.find(objectName);
383 if (it == managedObjects.end())
384 {
385 ARMARX_WARNING << "Cannot remove unknown object '" << objectName << "'";
386 return;
387 }
388 scheduler = it->second;
389 }
390 try
391 {
392 if (scheduler)
393 {
394 removeObject(scheduler, true);
395 }
396 }
397 catch (...)
398 {
399 throw;
400 }
401 }
402
403 void
404 ArmarXManager::removeObjectNonBlocking(const std::string& objectName)
405 {
406 auto removal = [objectName, this]()
407 {
408 ArmarXObjectSchedulerPtr scheduler;
409 {
410 auto lock = acquireManagedObjectsMutex();
411 if (!lock)
412 {
413 return;
414 }
415 auto it = managedObjects.find(objectName);
416 if (it == managedObjects.end())
417 {
418 ARMARX_WARNING << "Cannot remove unknown object '" << objectName << "'";
419 return;
420 }
421 scheduler = it->second;
422 }
423 try
424 {
425 this->removeObject(scheduler, false);
426 }
427 catch (...)
428 {
429 throw;
430 }
431 };
432 std::thread{removal}.detach();
433 }
434
435 void
437 {
438 removeObjectBlocking(object->getName());
439 }
440
441 void
446
447 // *******************************************************
448 // shutdown handling
449 // *******************************************************
450 void
452 {
453 // assure no state changed
454 managerStateMutex.lock();
455
456 if (managerState == eShutdown)
457 {
458 managerStateMutex.unlock();
459 return;
460 }
461
462 // wait for shutdown
463 std::unique_lock lock(shutdownMutex);
464 managerStateMutex.unlock();
465 shutdownCondition.wait(lock);
466 ARMARX_VERBOSE << "Waiting for shutdown finished";
467 }
468
469 void
471 {
472 try
473 {
474 // check state
475 {
476 std::scoped_lock lock(managerStateMutex);
477
478 // do not shutdown if shutdown is in progress
479 if (managerState >= eShutdownInProgress)
480 {
481 return;
482 }
483
484 managerState = eShutdownInProgress;
485
486 // locking managedObjects ne done before state mutex is released
487 managedObjectsMutex.lock();
488 }
489
490 ARMARX_VERBOSE << "Shutting down ArmarXManager" << std::endl;
491
492 // stop cleanup task. All objects will be removed manually in shutdown
493 cleanupSchedulersTask->stop();
494
495 if (checkDependencyStatusTask)
496 {
497 checkDependencyStatusTask->stop();
498 }
499
500 sharedRemoteHandleState.reset();
501 remoteReferenceCountControlBlockManager.reset();
502
503 disconnectAllObjects();
504
505 // shutdown log sender
507
508 // remove all managed objects
509 removeAllObjects(true);
510 try
511 {
512 iceManager->getIceGridSession()->getAdmin()->removeObject(
513 Ice::Identity{MANAGEROBJNAME, ""});
514 }
515 catch (...)
516 {
517 }
518
519 singleThreadedSchedulers.clear();
520
521 try
522 {
523 // deactivate all object adapters (and do internal iceManager shutdown)
524 iceManager->shutdown();
525
526 // wait until all adapters have been deactivated
527 iceManager->waitForShutdown();
528 }
529 catch (...)
530 {
531 }
532 // destroy manager and communicator
533 iceManager->destroy();
534
535 // set to NULL to avoid cycle in pointers ArmarXManager <-> ArmarXObjectObserver
536 objObserver = nullptr;
537
538 // set state to shutdown and notify waitForShutdown
539 {
540 std::scoped_lock lock(managerStateMutex);
541
542 // inform waiting threads of shutdown
543 {
544 std::unique_lock lock(shutdownMutex);
545 ARMARX_VERBOSE << "notifying shutdown waiters" << std::endl;
546 shutdownCondition.notify_all();
547 }
548
549 managerState = eShutdown;
550 }
551
552 managedObjectsMutex.unlock();
553 }
554 catch (std::exception& e)
555 {
556 ARMARX_INFO << "shutdown failed with exception!\n" << e.what() << std::endl;
557 }
558
559 ARMARX_INFO << "Shutdown of ArmarXManager finished!" << std::endl;
560 }
561
562 void
563 ArmarXManager::asyncShutdown(std::size_t timeoutMs)
564 {
565 std::thread{[this, timeoutMs]
566 {
567 std::this_thread::sleep_for(std::chrono::milliseconds{timeoutMs});
568 shutdown();
569 }}
570 .detach();
571 }
572
573 bool
575 {
576 std::scoped_lock lock(managerStateMutex);
577 return (managerState == eShutdown);
578 }
579
580 // *******************************************************
581 // getters
582 // *******************************************************
583
584 const IceManagerPtr&
586 {
587 return iceManager;
588 }
589
592 {
593 return iceManager->getCommunicator();
594 }
595
596 std::vector<ManagedIceObjectPtr>
598 {
599 std::vector<ManagedIceObjectPtr> objects;
600
601 auto lock = acquireManagedObjectsMutex();
602 if (!lock)
603 {
604 return objects;
605 }
606
607 ObjectSchedulerMap::iterator iter = managedObjects.begin();
608
609 while (iter != managedObjects.end())
610 {
611 objects.push_back(iter->second->getObject());
612 iter++;
613 }
614
615
616 return objects;
617 }
618
619 // *******************************************************
620 // Slice MiceManagerInsightProvider implementation
621 // *******************************************************
622
623 std::string
624 ArmarXManager::getHostname(const Ice::Current&)
625 {
626 char hostname[HOST_NAME_MAX];
627 gethostname(hostname, HOST_NAME_MAX);
628 return std::string(hostname);
629 }
630
631 Ice::StringSeq
632 ArmarXManager::getObjectNames(const Ice::Current& c)
633 {
634 return getManagedObjectNames();
635 }
636
637 mice::MiceObjectConnectivity
638 ArmarXManager::getMiceObjectConnectivity(const std::string& objectName, const Ice::Current& c)
639 {
640 mice::MiceObjectConnectivity miceCon = mice::MiceObjectConnectivity();
641 ManagedIceObjectConnectivity con = getObjectConnectivity(objectName);
642 miceCon.subscribedTopics = con.usedTopics;
643 miceCon.publishedTopics = con.offeredTopics;
644 miceCon.usedObjects = Ice::StringSeq();
645
646 for (const auto& entry : con.dependencies)
647 {
648 miceCon.usedObjects.push_back(entry.first);
649 }
650
651 return miceCon;
652 }
653
654 IceMX::MetricsAdminPrx
656 {
657 Ice::ObjectPrx adminObj = getIceManager()->getCommunicator()->getAdmin();
658 IceMX::MetricsAdminPrx metrAdmin = IceMX::MetricsAdminPrx::checkedCast(adminObj, "Metrics");
659 return metrAdmin;
660 }
661
662 // *******************************************************
663 // Slice ArmarXManagerInterface implementation
664 // *******************************************************
665 ManagedIceObjectState
666 ArmarXManager::getObjectState(const std::string& objectName, const Ice::Current& c)
667 {
668 auto lock = acquireManagedObjectsMutex();
669 if (!lock)
670 {
671 return eManagedIceObjectExiting;
672 }
673
674 ObjectSchedulerMap::iterator iter = managedObjects.find(objectName);
675
676 if (iter == managedObjects.end())
677 {
678 return eManagedIceObjectExited;
679 }
680
681 ManagedIceObjectState state = (ManagedIceObjectState)iter->second->getObject()->getState();
682
683 return state;
684 }
685
686 ManagedIceObjectConnectivity
687 ArmarXManager::getObjectConnectivity(const std::string& objectName, const Ice::Current& c)
688 {
689 auto lock = acquireManagedObjectsMutex();
690 if (!lock)
691 {
692 return ManagedIceObjectConnectivity();
693 }
694
695 ObjectSchedulerMap::iterator iter = managedObjects.find(objectName);
696
697 if (iter == managedObjects.end())
698 {
699 return ManagedIceObjectConnectivity();
700 }
701
702 ManagedIceObjectConnectivity con = iter->second->getObject()->getConnectivity();
703
704
705 return con;
706 }
707
708 StringStringDictionary
709 ArmarXManager::getObjectProperties(const ::std::string& objectName, const ::Ice::Current&)
710 {
711 StringStringDictionary propertyMap;
712 ObjectSchedulerMap::iterator iter = managedObjects.find(objectName);
713
714 if (iter == managedObjects.end())
715 {
716 return propertyMap;
717 }
718
719 ComponentPtr component = ComponentPtr::dynamicCast(iter->second->getObject());
720
721 if (!component)
722 {
723 return propertyMap;
724 }
725 ARMARX_CHECK_EXPRESSION(component->getPropertyDefinitions());
726 auto result = component->getPropertyDefinitions()->getPropertyValues(
727 component->getPropertyDefinitions()->getPrefix());
728 return result;
729 }
730
731 ObjectPropertyInfos
732 ArmarXManager::getObjectPropertyInfos(const ::std::string& objectName, const ::Ice::Current&)
733 {
734 ObjectPropertyInfos propertyMap;
735 ObjectSchedulerMap::iterator iter = managedObjects.find(objectName);
736
737 if (iter == managedObjects.end())
738 {
739 return propertyMap;
740 }
741
742 ComponentPtr component = ComponentPtr::dynamicCast(iter->second->getObject());
743
744 if (!component)
745 {
746 return propertyMap;
747 }
748
749 ARMARX_CHECK_EXPRESSION(component->getPropertyDefinitions());
750 for (auto prop : component->getPropertyDefinitions()->getPropertyValues())
751 {
752 propertyMap[component->getPropertyDefinitions()->getPrefix() + prop.first] = {
753 component->getPropertyDefinitions()->getDefinitionBase(prop.first)->isConstant(),
754 prop.second};
755 }
756 return propertyMap;
757 }
758
759 ObjectPropertyInfos
761 {
762 ObjectPropertyInfos propertyMap;
763 if (!Application::getInstance() || !Application::getInstance()->getPropertyDefinitions())
764 {
765 return propertyMap;
766 }
767 for (auto prop : Application::getInstance()->getPropertyDefinitions()->getPropertyValues())
768 {
769 propertyMap[Application::getInstance()->getPropertyDefinitions()->getPrefix() +
770 prop.first] = {Application::getInstance()
771 ->getPropertyDefinitions()
772 ->getDefinitionBase(prop.first)
773 ->isConstant(),
774 prop.second};
775 }
776 return propertyMap;
777 }
778
779 Ice::PropertiesAdminPrx
781 {
782 Ice::ObjectPrx adminObj = getIceManager()->getCommunicator()->getAdmin();
783 Ice::PropertiesAdminPrx propAdmin =
784 Ice::PropertiesAdminPrx::checkedCast(adminObj, "Properties");
785 return propAdmin;
786 }
787
788 void
790 {
791 for (ManagedIceObjectPtr& managedObject : getManagedObjects())
792 {
793 ComponentPtr component = ComponentPtr::dynamicCast(managedObject);
794 if (component)
795 {
796 component->setIceProperties(properties);
797 }
798 }
799 }
800
801 void
802 ArmarXManager::updateComponentIceProperties(const Ice::PropertyDict& properties)
803 {
804 for (ManagedIceObjectPtr& managedObject : getManagedObjects())
805 {
806 ComponentPtr component = ComponentPtr::dynamicCast(managedObject);
807 if (component)
808 {
809 component->updateIceProperties(properties);
810 }
811 }
812 }
813
814 Ice::StringSeq
816 {
817 Ice::StringSeq objectNames;
818
819 auto lock = acquireManagedObjectsMutex();
820 if (!lock)
821 {
822 return objectNames;
823 }
824
825 ObjectSchedulerMap::iterator iter = managedObjects.begin();
826
827 while (iter != managedObjects.end())
828 {
829 objectNames.push_back(iter->first);
830 iter++;
831 }
832
833
834 return objectNames;
835 }
836
837 class IcePropertyChangeCallback : public Ice::PropertiesAdminUpdateCallback
838 {
839 public:
840 IcePropertyChangeCallback(armarx::ApplicationPtr application) : application(application)
841 {
842 }
843
844 void
845 updated(const Ice::PropertyDict& changes) override
846 {
847 // ARMARX_INFO << "Properties were updated: " << changes;
848 if (application)
849 {
850 application->updateIceProperties(changes);
851 }
852 }
853
854 private:
855 armarx::ApplicationPtr application;
856 };
857
859
860 // *******************************************************
861 // private methods
862 // *******************************************************
863 void
864 ArmarXManager::init(std::string applicationName, const Ice::CommunicatorPtr& communicator)
865 {
867
869
870
871 // create ice manager
872 iceManager = new IceManager(
873 communicator,
874 applicationName,
875 appInstance ? appInstance->getProperty<std::string>("TopicSuffix").getValue() : "");
876
877
878 if (!checkIceConnection())
879 {
880 throw Ice::ConnectFailedException(__FILE__, __LINE__);
881 }
882
883 this->installProcessFacet();
884
885 // init logging
886 LogSender::setProxy(applicationName, iceManager->getTopic<LogPrx>("Log"));
887
888 setTag("ArmarXManager");
889
891
892
893 // make sure icegrid session exists before continuing
894 auto icegrid = iceManager->getIceGridSession();
895 // register obj observer for onDisconnect
896 objObserver = new ArmarXObjectObserver(this);
897 Ice::ObjectAdapterPtr observerAdapter;
898 Ice::ObjectPrx oPrx =
899 icegrid->registerObjectWithNewAdapter(objObserver, OBJOBSNAME, observerAdapter);
900 IceGrid::ObjectObserverPrx objObsPrx = IceGrid::ObjectObserverPrx::checkedCast(oPrx);
901 icegrid->setObjectObserver(objObsPrx);
902
903 // register manager to ice
904 icegrid->registerObjectWithNewAdapter(this, MANAGEROBJNAME, armarxManagerAdapter);
905
906
907 // create periodic task for starter cleanup
908 cleanupSchedulersTask = new PeriodicTask<ArmarXManager>(this,
909 &ArmarXManager::cleanupSchedulers,
910 500,
911 false,
912 "ArmarXManager::cleanupSchedulers");
913 cleanupSchedulersTask->start();
914
915 checkDependencyStatusTask =
917 &ArmarXManager::checkDependencies,
918 1000,
919 false,
920 "ArmarXManager::DependenciesChecker");
921 checkDependencyStatusTask->start();
922
923
924 // set manager state to running
925 {
926 std::scoped_lock lock(managerStateMutex);
927 managerState = eRunning;
928 }
929
930 // create ThreadList for this process
931 ThreadList::getApplicationThreadList()->setApplicationThreadListName(applicationName +
932 "ThreadList");
933
934 try
935 {
937 }
938 catch (...)
939 {
940 }
941
942 // create a local TimeServer for this process
943 if (appInstance && appInstance->getProperty<bool>("UseTimeServer").getValue())
944 {
945 ARMARX_VERBOSE << "Using time from global time server.";
946 LocalTimeServer::getApplicationTimeServer()->setApplicationTimeServerName(
947 applicationName + "LocalTimeServer");
950 }
951 else
952 {
953 ARMARX_VERBOSE << "Using time from local system clock.";
954 }
955
956 sharedRemoteHandleState.reset(new SharedRemoteHandleState{
957 appInstance
958 ? appInstance->getProperty<unsigned int>("RemoteHandlesDeletionTimeout").getValue()
960 remoteReferenceCountControlBlockManager.reset(
961 new RemoteReferenceCountControlBlockManager{IceUtil::Time::milliSeconds(100)});
962 }
963
964 void
965 ArmarXManager::cleanupSchedulers()
966 {
967 std::scoped_lock lock(terminatingObjectsMutex);
968
969 ObjectSchedulerList::iterator iter = terminatingObjects.begin();
970
971 while (iter != terminatingObjects.end())
972 {
973 const ArmarXObjectSchedulerPtr& sched = *iter;
974 ARMARX_VERBOSE << deactivateSpam(1, sched->getObject()->getName())
975 << "Checking termination state of " << sched->getObject()->getName()
976 << ": "
977 << ManagedIceObject::GetObjectStateAsString(sched->getObjectState());
978 // remove terminated starters
979 if ((*iter)->isTerminated())
980 {
981 ARMARX_VERBOSE << "Delayed Removal of ManagedIceObject "
982 << (*iter)->getObject()->getName() << " finished";
983 iter = terminatingObjects.erase(iter);
984 }
985 else
986 {
987 iter++;
988 }
989 }
990 }
991
992 void
993 ArmarXManager::disconnectDependees(const std::string& object)
994 {
995 try
996 {
997 std::vector<std::string> dependees = getDependendees(object);
998
999 auto lock = acquireManagedObjectsMutex();
1000 if (!lock)
1001 {
1002 return;
1003 }
1004
1005 for (const auto& dependee : dependees)
1006 {
1007 ArmarXManager::ObjectSchedulerMap::iterator it = managedObjects.find(dependee);
1008 ARMARX_INFO << deactivateSpam(10, dependee + object) << "'" << dependee
1009 << "' disconnected because of '" << object << "'";
1010
1011 if (it != managedObjects.end())
1012 {
1013 it->second->disconnected(true);
1014 }
1015 }
1016 }
1017 catch (...)
1018 {
1019 throw;
1020 }
1021 }
1022
1023 void
1024 ArmarXManager::disconnectAllObjects()
1025 {
1026 auto lock = acquireManagedObjectsMutex();
1027 if (!lock)
1028 {
1029 return;
1030 }
1031 ObjectSchedulerMap::iterator iter = managedObjects.begin();
1032
1033 for (; iter != managedObjects.end(); iter++)
1034 {
1035 iter->second->disconnected(false);
1036 }
1037 }
1038
1039 std::vector<std::string>
1040 ArmarXManager::getDependendees(const std::string& removedObject)
1041 {
1042 std::vector<std::string> result;
1043
1044 auto lock = acquireManagedObjectsMutex();
1045 if (!lock)
1046 {
1047 return result;
1048 }
1049
1050 try
1051 {
1052
1053 ObjectSchedulerMap::const_iterator it = managedObjects.begin();
1054
1055 for (; it != managedObjects.end(); it++)
1056 {
1057 ArmarXObjectSchedulerPtr scheduler = it->second;
1058
1059 if (scheduler->dependsOn(removedObject))
1060 {
1061 result.push_back(it->first);
1062 }
1063 }
1064 }
1065 catch (...)
1066 {
1067 throw;
1068 }
1069
1070 return result;
1071 }
1072
1073 void
1074 ArmarXManager::wakeupWaitingSchedulers()
1075 {
1076 auto lock = acquireManagedObjectsMutex();
1077 if (!lock)
1078 {
1079 return;
1080 }
1081
1082 try
1083 {
1084
1085 ObjectSchedulerMap::const_iterator it = managedObjects.begin();
1086
1087 for (; it != managedObjects.end(); it++)
1088 {
1089 ArmarXObjectSchedulerPtr scheduler = it->second;
1090 scheduler->wakeupDependencyCheck();
1091 }
1092 }
1093 catch (...)
1094 {
1095 throw;
1096 }
1097 }
1098
1099 void
1100 ArmarXManager::removeAllObjects(bool blocking)
1101 {
1102 ObjectSchedulerMap tempMap;
1103 {
1104 std::scoped_lock lock(managedObjectsMutex);
1105 tempMap = managedObjects;
1106 }
1107
1108 for (auto& it : tempMap)
1109 {
1110 removeObject(it.second, false);
1111 }
1112
1113 if (blocking)
1114 {
1115 for (auto objectScheduler : terminatingObjects)
1116 {
1117 objectScheduler->waitForTermination();
1118 }
1119
1120 terminatingObjects.clear();
1121 }
1122 }
1123
1124 bool
1125 ArmarXManager::removeObject(const ArmarXObjectSchedulerPtr& objectScheduler, bool blocking)
1126 {
1127 if (!objectScheduler)
1128 {
1129 return true;
1130 }
1131
1132 const std::string objName = objectScheduler->getObject()->getName();
1133
1134 try
1135 {
1136 iceManager->removeObject(objName);
1137 {
1138 std::scoped_lock lock2(managedObjectsMutex);
1139 managedObjects.erase(objectScheduler->getObject()->getName());
1140 }
1141 // terminate
1142 objectScheduler->terminate();
1143
1144 if (blocking)
1145 {
1146 objectScheduler->waitForTermination();
1147 ARMARX_VERBOSE << "Blocking removal of ManagedIceObject " << objName << " finished";
1148 }
1149 else // only move to terminating list if delayed removal
1150 {
1151 ARMARX_VERBOSE << "Inserting ManagedIceObject into delayed removal list: "
1152 << objName;
1153 std::scoped_lock lockTerm(terminatingObjectsMutex);
1154 terminatingObjects.push_back(objectScheduler);
1155 }
1156
1157 return true;
1158 }
1159 catch (...)
1160 {
1161 ARMARX_ERROR << "Removing of object '" << objName << "' failed with an exception!\n"
1163 }
1164
1165 return false;
1166 }
1167
1168 //bool ArmarXManager::removeObject(const ObjectSchedulerMap::iterator& iter, bool blocking)
1169 //{
1170 // if (iter != managedObjects.end())
1171 // {
1172 // const std::string objName = iter->second->getObject()->getName();
1173
1174 // try
1175 // {
1176
1177 // ARMARX_VERBOSE << "Removing ManagedIceObject " << objName << " - blocking = " << blocking;
1178
1179
1180 // ArmarXObjectSchedulerPtr objectScheduler = iter->second;
1181
1182
1183 // // managedObjects.erase(iter);
1184 // return removeObject(objectScheduler, blocking);
1185 // }
1186 // catch (...)
1187 // {
1188 // ARMARX_ERROR << "Removing of object '" << objName << "' failed with an exception!";
1189 // handleExceptions();
1190 // }
1191 // }
1192
1193 // return false;
1194 //}
1195
1197 ArmarXManager::findObjectScheduler(const std::string& objectName) const
1198 {
1199 std::scoped_lock lock(managedObjectsMutex);
1200 auto it = managedObjects.find(objectName);
1201 if (it != managedObjects.end())
1202 {
1203 return it->second;
1204 }
1205 else
1206 {
1207 return ArmarXObjectSchedulerPtr();
1208 }
1209 }
1210
1211 void
1212 ArmarXManager::checkDependencies()
1213 {
1214
1215
1216 auto lock = acquireManagedObjectsMutex();
1217 if (!lock)
1218 {
1219 return;
1220 }
1221
1222 try
1223 {
1224 ObjectSchedulerMap::const_iterator it = managedObjects.begin();
1225
1226 for (; it != managedObjects.end(); it++)
1227 {
1228 const ArmarXObjectSchedulerPtr& scheduler = it->second;
1229
1230 if (scheduler->getObjectState() == eManagedIceObjectStarted &&
1231 !scheduler->checkDependenciesStatus())
1232 {
1233 scheduler->disconnected(true);
1234 }
1235 }
1236 }
1237 catch (...)
1238 {
1239 throw;
1240 }
1241 }
1242
1243 auto
1244 ArmarXManager::acquireManagedObjectsMutex() -> ScopedRecursiveLockPtr
1245 {
1246 // assure no state change until lock of managedObjectsMutex
1247 std::scoped_lock lock(managerStateMutex);
1248
1249 if (managerState >= eShutdownInProgress)
1250 {
1251 return ScopedRecursiveLockPtr();
1252 }
1253
1254 // lock access to managed objects
1256 new std::scoped_lock<std::recursive_mutex>(managedObjectsMutex));
1257
1258 return lock2;
1259 }
1260
1261 void
1262 ArmarXManager::installProcessFacet()
1263 {
1265 Ice::CommunicatorPtr applicationCommunicator = getCommunicator();
1266 ARMARX_CHECK_EXPRESSION(applicationCommunicator);
1267 // remove default Ice::Process facet
1268 if (applicationCommunicator->findAdminFacet("Process"))
1269 {
1270 applicationCommunicator->removeAdminFacet("Process");
1271 }
1272 // create and register new Ice::Process facet
1273 Ice::ProcessPtr applicationProcessFacet = new ApplicationProcessFacet(*this);
1274 applicationCommunicator->addAdminFacet(applicationProcessFacet, "Process");
1275
1276 IcePropertyChangeCallbackPtr propertyChangeCallback =
1277 new IcePropertyChangeCallback(appInstance);
1278
1279 Ice::ObjectPtr obj = applicationCommunicator->findAdminFacet("Properties");
1280 Ice::NativePropertiesAdminPtr admin = Ice::NativePropertiesAdminPtr::dynamicCast(obj);
1281 if (admin)
1282 {
1283 admin->addUpdateCallback(propertyChangeCallback);
1284 }
1285 else
1286 {
1288 << "Could not get properties admin - online property changing will not work";
1289 }
1290
1291 // activate new Ice::Process facet and PropertyChangeCallback
1292 applicationCommunicator->getAdmin();
1293 }
1294
1296
1297 void
1299 {
1300 std::unique_lock lock(FactoryCollectionBase_RegistrationListMutex());
1301
1302 for (const FactoryCollectionBasePtr& preregistration :
1304 {
1305 //ARMARX_INFO_S << "looking for " << preregistration->getFactories();
1306 for (const auto& id2factory : preregistration->getFactories())
1307 {
1308 if (!ic->getValueFactoryManager()->find(id2factory.first))
1309 {
1310 //ARMARX_IMPORTANT_S << "adding object factory for " << id2factory.first;
1311 ic->getValueFactoryManager()->add(id2factory.second, id2factory.first);
1312 }
1313 }
1314 }
1315 }
1316
1317 void
1322
1325 {
1326 return armarxManagerAdapter;
1327 }
1328
1329 const std::shared_ptr<SharedRemoteHandleState>&
1331 {
1332 return sharedRemoteHandleState;
1333 }
1334
1335 void
1337 {
1338 std::scoped_lock lock(schedulerListMutex);
1339 for (int i = 0; i < increaseBy; ++i)
1340 {
1341 singleThreadedSchedulers.push_back(new ArmarXMultipleObjectsScheduler());
1342 }
1343 }
1344
1345 bool
1346 LoadLibFromAbsolutePath(const std::string& path)
1347 {
1348 //these variables should be shared between ArmarXManager -> use static variables
1349 static std::map<std::string, DynamicLibraryPtr> loadedLibs;
1350 static std::mutex libsMutex;
1351 std::lock_guard<std::mutex> guard{libsMutex};
1352 if (loadedLibs.count(path))
1353 {
1354 return true;
1355 }
1357 try
1358 {
1359 lib->load(path);
1360 }
1361 catch (...)
1362 {
1364 return false;
1365 }
1366
1367 if (lib->isLibraryLoaded())
1368 {
1369 ARMARX_INFO << "Loaded library " << path;
1370 loadedLibs[path] = lib;
1371 }
1372 else
1373 {
1374 ARMARX_ERROR << "Could not load lib " + path + ": " + lib->getErrorMessage();
1375 return false;
1376 }
1377 return true;
1378 }
1379
1380 // bool ArmarXManager::loadLibFromPath(const std::string& path)
1381 // {
1382 // std::string absPath;
1383 // if (ArmarXDataPath::getAbsolutePath(path, absPath))
1384 // {
1385 // return LoadLibFromAbsolutePath(absPath);
1386 // }
1387 // ARMARX_ERROR << "Could not find library " + path;
1388 // return false;
1389 // }
1390 // bool ArmarXManager::loadLibFromPackage(const std::string& package, const std::string& libname)
1391 // {
1392 // CMakePackageFinder finder(package);
1393 // if (!finder.packageFound())
1394 // {
1395 // ARMARX_ERROR << "Could not find package '" << package << "'";
1396 // return false;
1397 // }
1398 //
1399 // for (auto libDirPath : Split(finder.getLibraryPaths(), ";"))
1400 // {
1401 // std::filesystem::path fullPath = libDirPath;
1402 // fullPath /= "lib" + libname + "." + DynamicLibrary::GetSharedLibraryFileExtension();
1403 // if (!std::filesystem::exists(fullPath))
1404 // {
1405 // fullPath = libDirPath;
1406 // fullPath /= libname;
1407 // if (!std::filesystem::exists(fullPath))
1408 // {
1409 // continue;
1410 // }
1411 // }
1412 // if (LoadLibFromAbsolutePath(fullPath.string()))
1413 // {
1414 // return true;
1415 // }
1416 // }
1417 // ARMARX_ERROR << "Could not find library " << libname << " in package " << package;
1418 // return false;
1419 // }
1420
1421
1423 armarx::ArmarXManager::getMetaInfo(const std::string& objectName, const Ice::Current&)
1424 {
1425 std::scoped_lock lock(managedObjectsMutex);
1426 StringStringDictionary propertyMap;
1427 ObjectSchedulerMap::iterator iter = managedObjects.find(objectName);
1428
1429 if (iter == managedObjects.end())
1430 {
1431 return StringVariantBaseMap();
1432 }
1433
1434 return iter->second->getObject()->getMetaInfoMap();
1435 }
1436} // namespace armarx
#define OBJOBSNAME
#define MANAGEROBJNAME
constexpr T c
static ApplicationPtr getInstance()
Retrieve shared pointer to the application object.
static void initDataPaths(const std::string &dataPathList)
const Ice::ObjectAdapterPtr & getAdapter() const
Ice::StringSeq getObjectNames(const Ice::Current &c=Ice::emptyCurrent) override
Retrieve the names of all ManagedIceObject.
void setGlobalMinimumLoggingLevel(MessageTypeT minimumLoggingLevel)
Set minimum logging level to output in log stream.
void enableProfiling(bool enable)
Enable or disable profiling of CPU Usage.
mice::MiceObjectConnectivity getMiceObjectConnectivity(const std::string &objectName, const Ice::Current &c=Ice::emptyCurrent) override
Retrieve connectivity of a ManagedIceObject.
const std::shared_ptr< SharedRemoteHandleState > & getSharedRemoteHandleState() const
ArmarXManager(std::string applicationName, int port=4061, std::string host="localhost", std::string locatorName="IceGrid/Locator", Ice::StringSeq args=Ice::StringSeq())
ArmarXManager constructor.
Ice::PropertiesAdminPrx getPropertiesAdmin(const Ice::Current &=Ice::emptyCurrent) override
void updateComponentIceProperties(const Ice::PropertyDict &properties)
const IceManagerPtr & getIceManager() const
Retrieve the instance of the icemanager.
friend class PeriodicTask< ArmarXManager >
ManagedIceObjectConnectivity getObjectConnectivity(const std::string &objectName, const Ice::Current &c=Ice::emptyCurrent) override
Retrieve connectivity of a ManagedIceObject.
IceMX::MetricsAdminPrx getMetricsAdmin(const Ice::Current &=Ice::emptyCurrent) override
void waitForShutdown()
Wait for shutdown.
virtual void addObjectAsync(const ManagedIceObjectPtr &object, const std::string &objectName, bool addWithOwnAdapter=true, bool useOwnScheduleThread=true)
void addObject(const ManagedIceObjectPtr &object, bool addWithOwnAdapter=true, const std::string &objectName="", bool useOwnScheduleThread=true) override
Add a ManagedIceObject to the manager.
::armarx::StringStringDictionary getObjectProperties(const ::std::string &objectName, const ::Ice::Current &=Ice::emptyCurrent) override
getObjectProperties is used to retrieve the properties of an object
const Ice::CommunicatorPtr & getCommunicator() const
static bool CheckIceConnection(const Ice::CommunicatorPtr &communicator, bool printHint)
void shutdown()
Shuts down the ArmarXManager.
void increaseSchedulers(int increaseBy)
increased the number of single threaded schedulers.
std::string getHostname(const Ice::Current &c=Ice::emptyCurrent) override
Gets the hostname of the host running the manager.
static void RegisterKnownObjectFactoriesWithIce(const Ice::CommunicatorPtr &ic)
Registers all object factories that are known with Ice.
void removeObjectBlocking(const ManagedIceObjectPtr &object) override
Removes an object from the manager.
void setDataPaths(std::string dataPaths)
Set data paths used to search for datafiles.
void asyncShutdown(std::size_t timeoutMs=0)
Calls shutdown() after a timeout.
StringVariantBaseMap getMetaInfo(const std::string &, const Ice::Current &) override
std::vector< ManagedIceObjectPtr > getManagedObjects() override
Retrieve pointers to all ManagedIceObject.
bool checkIceConnection(bool printHint=true) const
bool isShutdown()
Whether ArmarXManager shutdown has been finished.
void enableLogging(bool enable)
Enable or disable logging.
Ice::StringSeq getManagedObjectNames(const Ice::Current &c=Ice::emptyCurrent) override
Retrieve the names of all ManagedIceObject.
ManagedIceObjectState getObjectState(const std::string &objectName, const Ice::Current &c=Ice::emptyCurrent) override
Retrieve state of a ManagedIceObject.
ObjectPropertyInfos getObjectPropertyInfos(const ::std::string &objectName, const ::Ice::Current &) override
void removeObjectNonBlocking(const ManagedIceObjectPtr &object) override
Removes an object from the manager.
ObjectPropertyInfos getApplicationPropertyInfos(const ::Ice::Current &) override
void registerKnownObjectFactoriesWithIce()
non static convenience version of ArmarXManager::RegisterKnownObjectFactoriesWithIce()
void setComponentIceProperties(const Ice::PropertiesPtr &properties)
Calls Component::setIceProperties() on all components assigend to this ArmarXManager Instance.
friend class ArmarXObjectObserver
Takes care of the lifecycle management of ManagedIceObjects.
The DynamicLibrary class provides a mechanism to load libraries at runtime.
static std::vector< FactoryCollectionBasePtr > & PreregistrationList()
The IceManager class provides simplified access to commonly used Ice features.
Definition IceManager.h:106
static IceStorm::TopicManagerPrx GetTopicManager(Ice::CommunicatorPtr communicator)
IcePropertyChangeCallback(armarx::ApplicationPtr application)
void updated(const Ice::PropertyDict &changes) override
static LocalTimeServerPtr getApplicationTimeServer()
Get the applications LocalTimeServer instance.
static void SetGlobalMinimumLoggingLevel(MessageTypeT level)
With setGlobalMinimumLoggingLevel the minimum verbosity-level of log-messages can be set for the whol...
static void SetSendLoggingActivated(bool activated=true)
static void setProxy(const std::string &componentName, LogPrx logProxy)
static void SetLoggingActivated(bool activated=true, bool showMessage=true)
setLoggingActivated() is used to activate or disable the logging facilities in the whole application
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
MessageTypeT minimumLoggingLevel
Definition Logging.h:277
void setTag(const LogTag &tag)
Definition Logging.cpp:54
static std::string GetObjectStateAsString(int state)
static ThreadListPtr getApplicationThreadList()
getApplicationThreadList retrieves the ThreadList, that contains all TimerTasks and PeriodicTasks in ...
static void SetTimeServer(LocalTimeServerPtr ts)
Definition TimeUtil.cpp:106
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:194
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
std::shared_ptr< ScopedRecursiveLock > ScopedRecursiveLockPtr
::IceInternal::Handle<::Ice::Properties > PropertiesPtr
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
::IceInternal::Handle<::Ice::ObjectAdapter > ObjectAdapterPtr
Definition IceManager.h:52
This file offers overloads of toIce() and fromIce() functions for STL container types.
::IceInternal::ProxyHandle<::IceProxy::armarx::Log > LogPrx
Definition LogSender.h:58
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
std::mutex & FactoryCollectionBase_RegistrationListMutex()
std::map< std::string, VariantBasePtr > StringVariantBaseMap
IceUtil::Handle< ArmarXObjectScheduler > ArmarXObjectSchedulerPtr
Definition ArmarXFwd.h:33
std::string GetHandledExceptionString()
void handleExceptions()
bool LoadLibFromAbsolutePath(const std::string &path)
IceUtil::Handle< Application > ApplicationPtr
Definition Application.h:93
IceUtil::Handle< FactoryCollectionBase > FactoryCollectionBasePtr
IceUtil::Handle< IcePropertyChangeCallback > IcePropertyChangeCallbackPtr
IceUtil::Handle< IceManager > IceManagerPtr
IceManager smart pointer.
Definition ArmarXFwd.h:39
MessageTypeT
Definition LogSender.h:46
IceInternal::Handle< Component > ComponentPtr
Component smart pointer type.
Definition ArmarXFwd.h:45
IceInternal::Handle< ManagedIceObject > ManagedIceObjectPtr
Definition ArmarXFwd.h:42
std::shared_ptr< DynamicLibrary > DynamicLibraryPtr
This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
static const unsigned int DEFAULT_DELETION_DELAY
The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht ze...