]> git.mxchange.org Git - simgear.git/blob - simgear/hla/HLAFederate.cxx
1b99ff28c3e4b29e591d74485915297212345ee4
[simgear.git] / simgear / hla / HLAFederate.cxx
1 // Copyright (C) 2009 - 2012  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #include "HLAFederate.hxx"
19
20 #include <algorithm>
21
22 #include "simgear/debug/logstream.hxx"
23
24 #include "RTIFederate.hxx"
25 #include "RTIFederateFactoryRegistry.hxx"
26 #include "RTI13FederateFactory.hxx"
27 #include "RTIInteractionClass.hxx"
28 #include "RTIObjectClass.hxx"
29 #include "HLADataElement.hxx"
30 #include "HLADataType.hxx"
31 #include "HLAOMTXmlVisitor.hxx"
32
33 namespace simgear {
34
35 HLAFederate::HLAFederate() :
36     _version(RTI13),
37     _createFederationExecution(true),
38     _timeConstrained(false),
39     _timeRegulating(false),
40     _timeConstrainedByLocalClock(false),
41     _done(false)
42 {
43     // For now instantiate the current only available factory here explicitly
44     RTI13FederateFactory::instance();
45 }
46
47 HLAFederate::~HLAFederate()
48 {
49     _clearRTI();
50
51     // Remove the data type references from the data types.
52     // This is to remove the cycles from the data types that might happen if a data type references itself
53     for (DataTypeMap::iterator i = _dataTypeMap.begin(); i != _dataTypeMap.end(); ++i) {
54         i->second->releaseDataTypeReferences();
55     }
56 }
57
58 HLAFederate::Version
59 HLAFederate::getVersion() const
60 {
61     return _version;
62 }
63
64 bool
65 HLAFederate::setVersion(HLAFederate::Version version)
66 {
67     if (_rtiFederate.valid()) {
68         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
69         return false;
70     }
71     _version = version;
72     return true;
73 }
74
75 const std::list<std::string>&
76 HLAFederate::getConnectArguments() const
77 {
78     return _connectArguments;
79 }
80
81 bool
82 HLAFederate::setConnectArguments(const std::list<std::string>& connectArguments)
83 {
84     if (_rtiFederate.valid()) {
85         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
86         return false;
87     }
88     _connectArguments = connectArguments;
89     return true;
90 }
91
92 bool
93 HLAFederate::getCreateFederationExecution() const
94 {
95     return _createFederationExecution;
96 }
97
98 bool
99 HLAFederate::setCreateFederationExecution(bool createFederationExecution)
100 {
101     _createFederationExecution = createFederationExecution;
102     return true;
103 }
104
105 const std::string&
106 HLAFederate::getFederationExecutionName() const
107 {
108     return _federationExecutionName;
109 }
110
111 bool
112 HLAFederate::setFederationExecutionName(const std::string& federationExecutionName)
113 {
114     if (_rtiFederate.valid()) {
115         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
116         return false;
117     }
118     _federationExecutionName = federationExecutionName;
119     return true;
120 }
121
122 const std::string&
123 HLAFederate::getFederationObjectModel() const
124 {
125     return _federationObjectModel;
126 }
127
128 bool
129 HLAFederate::setFederationObjectModel(const std::string& federationObjectModel)
130 {
131     if (_rtiFederate.valid()) {
132         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
133         return false;
134     }
135     _federationObjectModel = federationObjectModel;
136     return true;
137 }
138
139 const std::string&
140 HLAFederate::getFederateType() const
141 {
142     return _federateType;
143 }
144
145 bool
146 HLAFederate::setFederateType(const std::string& federateType)
147 {
148     if (_rtiFederate.valid()) {
149         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
150         return false;
151     }
152     _federateType = federateType;
153     return true;
154 }
155
156 const std::string&
157 HLAFederate::getFederateName() const
158 {
159     return _federateName;
160 }
161
162 bool
163 HLAFederate::setFederateName(const std::string& federateName)
164 {
165     if (_rtiFederate.valid()) {
166         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
167         return false;
168     }
169     _federateName = federateName;
170     return true;
171 }
172
173 bool
174 HLAFederate::connect(Version version, const std::list<std::string>& stringList)
175 {
176     _version = version;
177     _connectArguments = stringList;
178     return connect();
179 }
180
181 bool
182 HLAFederate::connect()
183 {
184     if (_rtiFederate.valid()) {
185         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
186         return false;
187     }
188
189     SGSharedPtr<RTIFederateFactoryRegistry> registry = RTIFederateFactoryRegistry::instance();
190     if (!registry) {
191         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: RTIFederateFactoryRegistry is no longer available!");
192         return false;
193     }
194
195     switch (_version) {
196     case RTI13:
197         _rtiFederate = registry->create("RTI13", _connectArguments);
198         break;
199     case RTI1516:
200         _rtiFederate = registry->create("RTI1516", _connectArguments);
201         break;
202     case RTI1516E:
203         _rtiFederate = registry->create("RTI1516E", _connectArguments);
204         break;
205     default:
206         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
207     }
208     return _rtiFederate.valid();
209 }
210
211 bool
212 HLAFederate::disconnect()
213 {
214     if (!_rtiFederate.valid()) {
215         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
216         return false;
217     }
218
219     _clearRTI();
220     return true;
221 }
222
223 bool
224 HLAFederate::createFederationExecution(const std::string& federation, const std::string& objectModel)
225 {
226     if (!_rtiFederate.valid()) {
227         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
228         return false;
229     }
230
231     RTIFederate::FederationManagementResult createResult;
232     createResult = _rtiFederate->createFederationExecution(federation, objectModel);
233     if (createResult == RTIFederate::FederationManagementFatal)
234         return false;
235
236     _federationExecutionName = federation;
237     _federationObjectModel = objectModel;
238     return true;
239 }
240
241 bool
242 HLAFederate::destroyFederationExecution(const std::string& federation)
243 {
244     if (!_rtiFederate.valid()) {
245         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
246         return false;
247     }
248
249     RTIFederate::FederationManagementResult destroyResult;
250     destroyResult = _rtiFederate->destroyFederationExecution(federation);
251     if (destroyResult == RTIFederate::FederationManagementFatal)
252         return false;
253
254     return true;
255 }
256
257 bool
258 HLAFederate::createFederationExecution()
259 {
260     if (!_rtiFederate.valid()) {
261         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
262         return false;
263     }
264
265     RTIFederate::FederationManagementResult createResult;
266     createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
267     if (createResult != RTIFederate::FederationManagementSuccess)
268         return false;
269
270     return true;
271 }
272
273 bool
274 HLAFederate::destroyFederationExecution()
275 {
276     if (!_rtiFederate.valid()) {
277         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
278         return false;
279     }
280
281     RTIFederate::FederationManagementResult destroyResult;
282     destroyResult = _rtiFederate->destroyFederationExecution(_federationExecutionName);
283     if (destroyResult != RTIFederate::FederationManagementSuccess)
284         return false;
285
286     return true;
287 }
288
289 bool
290 HLAFederate::join(const std::string& federateType, const std::string& federation)
291 {
292     if (!_rtiFederate.valid()) {
293         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
294         return false;
295     }
296
297     RTIFederate::FederationManagementResult joinResult;
298     joinResult = _rtiFederate->join(federateType, federation);
299     if (joinResult == RTIFederate::FederationManagementFatal)
300         return false;
301
302     return true;
303 }
304
305 bool
306 HLAFederate::join()
307 {
308     if (!_rtiFederate.valid()) {
309         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
310         return false;
311     }
312
313     RTIFederate::FederationManagementResult joinResult;
314     joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
315     if (joinResult != RTIFederate::FederationManagementSuccess)
316         return false;
317
318     return true;
319 }
320
321 bool
322 HLAFederate::resign()
323 {
324     if (!_rtiFederate.valid()) {
325         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
326         return false;
327     }
328     return _rtiFederate->resign();
329 }
330
331 bool
332 HLAFederate::createJoinFederationExecution()
333 {
334     if (!_rtiFederate.valid()) {
335         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
336         return false;
337     }
338
339     for (;;) {
340         // Try to join.
341         RTIFederate::FederationManagementResult joinResult;
342         joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
343         switch (joinResult) {
344         case RTIFederate::FederationManagementSuccess:
345             // Fast return on success
346             return true;
347         case RTIFederate::FederationManagementFatal:
348             // Abort on fatal errors
349             return false;
350         default:
351             break;
352         };
353
354         // If not already joinable, try to create the requested federation
355         RTIFederate::FederationManagementResult createResult;
356         createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
357         switch (createResult) {
358         case RTIFederate::FederationManagementFatal:
359             // Abort on fatal errors
360             return false;
361         default:
362             // Try again to join
363             break;
364         }
365     }
366 }
367
368 bool
369 HLAFederate::resignDestroyFederationExecution()
370 {
371     if (!_rtiFederate.valid()) {
372         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
373         return false;
374     }
375     
376     // Resign ourselves
377     bool success = _rtiFederate->resign();
378
379     // and try to destroy, non fatal if still some federates joined
380     if (_rtiFederate->destroyFederationExecution(_federationExecutionName) == RTIFederate::FederationManagementFatal)
381         success = false;
382
383     return success;
384 }
385
386 bool
387 HLAFederate::getTimeConstrained() const
388 {
389     return _timeConstrained;
390 }
391
392 bool
393 HLAFederate::setTimeConstrained(bool timeConstrained)
394 {
395     _timeConstrained = timeConstrained;
396
397     if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
398         if (_timeConstrained && !_rtiFederate->getTimeConstrainedEnabled()) {
399             if (!enableTimeConstrained())
400                 return false;
401         } else if (!_timeConstrained && _rtiFederate->getTimeConstrainedEnabled()) {
402             if (!disableTimeConstrained())
403                 return false;
404         }
405
406     }
407
408     return true;
409 }
410
411 bool
412 HLAFederate::getTimeConstrainedByLocalClock() const
413 {
414     return _timeConstrainedByLocalClock;
415 }
416
417 bool
418 HLAFederate::setTimeConstrainedByLocalClock(bool timeConstrainedByLocalClock)
419 {
420     _timeConstrainedByLocalClock = timeConstrainedByLocalClock;
421
422     if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
423         if (_timeConstrainedByLocalClock) {
424             if (!enableTimeConstrainedByLocalClock())
425                 return false;
426         }
427     }
428
429     return true;
430 }
431
432 bool
433 HLAFederate::getTimeRegulating() const
434 {
435     return _timeRegulating;
436 }
437
438 bool
439 HLAFederate::setTimeRegulating(bool timeRegulating)
440 {
441     _timeRegulating = timeRegulating;
442
443     if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
444         if (_timeRegulating && !_rtiFederate->getTimeRegulationEnabled()) {
445             if (!enableTimeRegulation())
446                 return false;
447         } else if (!_timeRegulating && _rtiFederate->getTimeRegulationEnabled()) {
448             if (!disableTimeRegulation())
449                 return false;
450         }
451
452     }
453     return true;
454 }
455
456 bool
457 HLAFederate::setLeadTime(const SGTimeStamp& leadTime)
458 {
459     if (leadTime < SGTimeStamp::fromSec(0)) {
460         SG_LOG(SG_NETWORK, SG_WARN, "Ignoring negative lead time!");
461         return false;
462     }
463
464     _leadTime = leadTime;
465
466     if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
467         if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
468             SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
469             return false;
470         }
471     }
472
473     return true;
474 }
475
476 const SGTimeStamp&
477 HLAFederate::getLeadTime() const
478 {
479     return _leadTime;
480 }
481
482 bool
483 HLAFederate::setTimeIncrement(const SGTimeStamp& timeIncrement)
484 {
485     if (timeIncrement < SGTimeStamp::fromSec(0)) {
486         SG_LOG(SG_NETWORK, SG_WARN, "Ignoring negative time increment!");
487         return false;
488     }
489
490     _timeIncrement = timeIncrement;
491
492     if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
493         if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
494             SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
495             return false;
496         }
497     }
498
499     return true;
500 }
501
502 const SGTimeStamp&
503 HLAFederate::getTimeIncrement() const
504 {
505     return _timeIncrement;
506 }
507
508 bool
509 HLAFederate::enableTimeConstrained()
510 {
511     if (!_rtiFederate.valid()) {
512         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
513         return false;
514     }
515
516     if (!_rtiFederate->enableTimeConstrained()) {
517         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time constrained!");
518         return false;
519     }
520
521     while (!_rtiFederate->getTimeConstrainedEnabled()) {
522         _rtiFederate->processMessage();
523     }
524
525     return true;
526 }
527
528 bool
529 HLAFederate::disableTimeConstrained()
530 {
531     if (!_rtiFederate.valid()) {
532         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
533         return false;
534     }
535     return _rtiFederate->disableTimeConstrained();
536 }
537
538 bool
539 HLAFederate::enableTimeConstrainedByLocalClock()
540 {
541     // Compute the time offset from the system time to the simulation time
542     SGTimeStamp federateTime;
543     if (!queryFederateTime(federateTime)) {
544         SG_LOG(SG_NETWORK, SG_WARN, "Cannot get federate time!");
545         return false;
546     }
547     _localClockOffset = SGTimeStamp::now() - federateTime;
548     return true;
549 }
550
551 bool
552 HLAFederate::enableTimeRegulation(const SGTimeStamp& lookahead)
553 {
554     if (!_rtiFederate.valid()) {
555         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
556         return false;
557     }
558
559     if (!_rtiFederate->enableTimeRegulation(lookahead)) {
560         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time regulation!");
561         return false;
562     }
563
564     while (!_rtiFederate->getTimeRegulationEnabled()) {
565         _rtiFederate->processMessage();
566     }
567
568     return true;
569 }
570
571 bool
572 HLAFederate::enableTimeRegulation()
573 {
574     if (!enableTimeRegulation(SGTimeStamp::fromSec(0))) {
575         SG_LOG(SG_NETWORK, SG_WARN, "Cannot enable time regulation!");
576         return false;
577     }
578     if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
579         SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
580         return false;
581     }
582     return true;
583 }
584
585 bool
586 HLAFederate::disableTimeRegulation()
587 {
588     if (!_rtiFederate.valid()) {
589         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
590         return false;
591     }
592     return _rtiFederate->disableTimeRegulation();
593 }
594
595 bool
596 HLAFederate::modifyLookahead(const SGTimeStamp& timeStamp)
597 {
598     if (!_rtiFederate.valid()) {
599         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
600         return false;
601     }
602     return _rtiFederate->modifyLookahead(timeStamp);
603 }
604
605 bool
606 HLAFederate::timeAdvanceBy(const SGTimeStamp& timeIncrement)
607 {
608     if (!_rtiFederate.valid()) {
609         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
610         return false;
611     }
612
613     SGTimeStamp timeStamp;
614     if (!_rtiFederate->queryFederateTime(timeStamp)) {
615         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query federate time!");
616         return false;
617     }
618
619     if (!_rtiFederate->timeAdvanceRequest(timeStamp + timeIncrement)) {
620         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
621         return false;
622     }
623
624     return processMessages();
625 }
626
627 bool
628 HLAFederate::timeAdvance(const SGTimeStamp& timeStamp)
629 {
630     if (!_rtiFederate.valid()) {
631         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
632         return false;
633     }
634
635     if (!_rtiFederate->timeAdvanceRequest(timeStamp)) {
636         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
637         return false;
638     }
639
640     return processMessages();
641 }
642
643 bool
644 HLAFederate::timeAdvanceAvailable()
645 {
646     if (!_rtiFederate.valid()) {
647         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
648         return false;
649     }
650
651     SGTimeStamp timeStamp;
652     if (_rtiFederate->queryGALT(timeStamp)) {
653         if (!_rtiFederate->timeAdvanceRequestAvailable(timeStamp)) {
654             SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
655             return false;
656         }
657     }
658
659     return processMessages();
660 }
661
662 bool
663 HLAFederate::queryFederateTime(SGTimeStamp& timeStamp)
664 {
665     if (!_rtiFederate.valid()) {
666         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
667         return false;
668     }
669     return _rtiFederate->queryFederateTime(timeStamp);
670 }
671
672 bool
673 HLAFederate::queryLookahead(SGTimeStamp& timeStamp)
674 {
675     if (!_rtiFederate.valid()) {
676         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
677         return false;
678     }
679     return _rtiFederate->queryLookahead(timeStamp);
680 }
681
682 bool
683 HLAFederate::processMessage()
684 {
685     if (!_rtiFederate.valid()) {
686         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
687         return false;
688     }
689     return _rtiFederate->processMessage();
690 }
691
692 bool
693 HLAFederate::processMessage(const SGTimeStamp& timeout)
694 {
695     if (!_rtiFederate.valid()) {
696         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
697         return false;
698     }
699     return _rtiFederate->processMessages(timeout.toSecs(), 0);
700 }
701
702 bool
703 HLAFederate::processMessages()
704 {
705     if (!_rtiFederate.valid()) {
706         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
707         return false;
708     }
709
710     while (_rtiFederate->getTimeAdvancePending()) {
711         _rtiFederate->processMessage();
712     }
713
714     if (_timeConstrainedByLocalClock) {
715         SGTimeStamp federateTime;
716         if (!_rtiFederate->queryFederateTime(federateTime)) {
717             SG_LOG(SG_NETWORK, SG_WARN, "HLA: Error querying federate time!");
718             return false;
719         }
720         SGTimeStamp systemTime = federateTime + _localClockOffset;
721         for (;;) {
722             double rest = (systemTime - SGTimeStamp::now()).toSecs();
723             if (rest < 0)
724                 break;
725             _rtiFederate->processMessages(rest, rest);
726         }
727     }
728     
729     // Now flush just what is left
730     while (_rtiFederate->processMessages(0, 0));
731
732     return true;
733 }
734
735 bool
736 HLAFederate::tick(const double& minimum, const double& maximum)
737 {
738     if (!_rtiFederate.valid()) {
739         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
740         return false;
741     }
742     return _rtiFederate->processMessages(minimum, maximum);
743 }
744
745 bool
746 HLAFederate::readObjectModelTemplate(const std::string& objectModel,
747                                      HLAFederate::ObjectModelFactory& objectModelFactory)
748 {
749     // The XML version of the federate object model.
750     // This one covers the generic attributes, parameters and data types.
751     HLAOMTXmlVisitor omtXmlVisitor;
752     try {
753         readXML(objectModel, omtXmlVisitor);
754     } catch (const sg_throwable& e) {
755         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
756                << e.getMessage());
757         return false;
758     } catch (...) {
759         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
760         return false;
761     }
762
763     omtXmlVisitor.setDataTypesToFederate(*this);
764
765     unsigned numObjectClasses = omtXmlVisitor.getNumObjectClasses();
766     for (unsigned i = 0; i < numObjectClasses; ++i) {
767         const HLAOMTXmlVisitor::ObjectClass* objectClass = omtXmlVisitor.getObjectClass(i);
768         std::string objectClassName = objectClass->getName();
769
770         SGSharedPtr<HLAObjectClass> hlaObjectClass = objectModelFactory.createObjectClass(objectClassName, *this);
771         if (!hlaObjectClass.valid()) {
772             SG_LOG(SG_IO, SG_INFO, "Ignoring object class \"" << objectClassName << "\".");
773             continue;
774         }
775
776         bool publish = objectModelFactory.publishObjectClass(objectClassName, objectClass->getSharing());
777         bool subscribe = objectModelFactory.subscribeObjectClass(objectClassName, objectClass->getSharing());
778
779         // process the attributes
780         for (unsigned j = 0; j < objectClass->getNumAttributes(); ++j) {
781             const simgear::HLAOMTXmlVisitor::Attribute* attribute;
782             attribute = objectClass->getAttribute(j);
783
784             std::string attributeName = attribute->getName();
785             unsigned index = hlaObjectClass->addAttribute(attributeName);
786
787             if (index == ~0u) {
788                 SG_LOG(SG_IO, SG_WARN, "RTI does not know the \"" << attributeName << "\" attribute!");
789                 continue;
790             }
791
792             // the attributes datatype
793             SGSharedPtr<const HLADataType> dataType = getDataType(attribute->getDataType());
794             if (!dataType.valid()) {
795                 SG_LOG(SG_IO, SG_WARN, "Could not find data type for attribute \""
796                        << attributeName << "\" in object class \"" << objectClassName << "\"!");
797             }
798             hlaObjectClass->setAttributeDataType(index, dataType);
799             hlaObjectClass->setAttributeUpdateType(index, attribute->getUpdateType());
800             if (subscribe && objectModelFactory.subscribeAttribute(objectClassName, attributeName, attribute->_sharing))
801                 hlaObjectClass->setAttributeSubscriptionType(index, attribute->getSubscriptionType());
802             if (publish && objectModelFactory.publishAttribute(objectClassName, attributeName, attribute->_sharing))
803                 hlaObjectClass->setAttributePublicationType(index, attribute->getPublicationType());
804         }
805
806         if (publish)
807             hlaObjectClass->publish();
808         if (subscribe)
809             hlaObjectClass->subscribe();
810
811     }
812
813     return resolveObjectModel();
814 }
815
816 bool
817 HLAFederate::readRTI13ObjectModelTemplate(const std::string& objectModel)
818 {
819     SG_LOG(SG_IO, SG_ALERT, "HLA version RTI13 not yet(!?) supported.");
820     return false;
821 }
822
823 bool
824 HLAFederate::readRTI1516ObjectModelTemplate(const std::string& objectModel)
825 {
826     // The XML version of the federate object model.
827     // This one covers the generic attributes, parameters and data types.
828     HLAOMTXmlVisitor omtXmlVisitor;
829     try {
830         readXML(objectModel, omtXmlVisitor);
831     } catch (const sg_throwable& e) {
832         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
833                << e.getMessage());
834         return false;
835     } catch (...) {
836         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
837         return false;
838     }
839
840     omtXmlVisitor.setToFederate(*this);
841
842     return resolveObjectModel();
843 }
844
845 bool
846 HLAFederate::readRTI1516EObjectModelTemplate(const std::string& objectModel)
847 {
848     SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
849     return false;
850 }
851
852 bool
853 HLAFederate::resolveObjectModel()
854 {
855     if (!_rtiFederate.valid()) {
856         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
857         return false;
858     }
859
860     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
861         RTIInteractionClass* rtiInteractionClass = _rtiFederate->createInteractionClass(i->second->getName(), i->second.get());
862         if (!rtiInteractionClass) {
863             SG_LOG(SG_NETWORK, SG_ALERT, "HLAFederate::_insertInteractionClass(): "
864                    "No RTIInteractionClass found for \"" << i->second->getName() << "\"!");
865             return false;
866         }
867         i->second->_setRTIInteractionClass(rtiInteractionClass);
868     }
869
870     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
871         RTIObjectClass* rtiObjectClass = _rtiFederate->createObjectClass(i->second->getName(), i->second.get());
872         if (!rtiObjectClass) {
873             SG_LOG(SG_NETWORK, SG_ALERT, "HLAFederate::_insertObjectClass(): "
874                    "No RTIObjectClass found for \"" << i->second->getName() << "\"!");
875             return false;
876         }
877         i->second->_setRTIObjectClass(rtiObjectClass);
878     }
879
880     return true;
881 }
882
883 const HLADataType*
884 HLAFederate::getDataType(const std::string& name) const
885 {
886     DataTypeMap::const_iterator i = _dataTypeMap.find(name);
887     if (i == _dataTypeMap.end())
888         return 0;
889     return i->second.get();
890 }
891
892 bool
893 HLAFederate::insertDataType(const std::string& name, const SGSharedPtr<HLADataType>& dataType)
894 {
895     if (!dataType.valid())
896         return false;
897     if (_dataTypeMap.find(name) != _dataTypeMap.end()) {
898         SG_LOG(SG_IO, SG_ALERT, "HLAFederate::insertDataType: data type with name \""
899                << name << "\" already known to federate!");
900         return false;
901     }
902     _dataTypeMap.insert(DataTypeMap::value_type(name, dataType));
903     return true;
904 }
905
906 void
907 HLAFederate::recomputeDataTypeAlignment()
908 {
909     // Finish alignment computations
910     bool changed;
911     do {
912         changed = false;
913         for (DataTypeMap::iterator i = _dataTypeMap.begin(); i != _dataTypeMap.end(); ++i) {
914             if (i->second->recomputeAlignment())
915                 changed = true;
916         }
917     } while (changed);
918 }
919
920 HLAInteractionClass*
921 HLAFederate::getInteractionClass(const std::string& name)
922 {
923     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
924     if (i == _interactionClassMap.end())
925         return 0;
926     return i->second.get();
927 }
928
929 const HLAInteractionClass*
930 HLAFederate::getInteractionClass(const std::string& name) const
931 {
932     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
933     if (i == _interactionClassMap.end())
934         return 0;
935     return i->second.get();
936 }
937
938 HLAInteractionClass*
939 HLAFederate::createInteractionClass(const std::string& name)
940 {
941     return new HLAInteractionClass(name, this);
942 }
943
944 HLAObjectClass*
945 HLAFederate::getObjectClass(const std::string& name)
946 {
947     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
948     if (i == _objectClassMap.end())
949         return 0;
950     return i->second.get();
951 }
952
953 const HLAObjectClass*
954 HLAFederate::getObjectClass(const std::string& name) const
955 {
956     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
957     if (i == _objectClassMap.end())
958         return 0;
959     return i->second.get();
960 }
961
962 HLAObjectClass*
963 HLAFederate::createObjectClass(const std::string& name)
964 {
965     return new HLAObjectClass(name, this);
966 }
967
968 HLAObjectInstance*
969 HLAFederate::getObjectInstance(const std::string& name)
970 {
971     ObjectInstanceMap::const_iterator i = _objectInstanceMap.find(name);
972     if (i == _objectInstanceMap.end())
973         return 0;
974     return i->second.get();
975 }
976
977 const HLAObjectInstance*
978 HLAFederate::getObjectInstance(const std::string& name) const
979 {
980     ObjectInstanceMap::const_iterator i = _objectInstanceMap.find(name);
981     if (i == _objectInstanceMap.end())
982         return 0;
983     return i->second.get();
984 }
985
986 HLAObjectInstance*
987 HLAFederate::createObjectInstance(HLAObjectClass* objectClass, const std::string& name)
988 {
989     return new HLAObjectInstance(objectClass);
990 }
991
992 void
993 HLAFederate::setDone(bool done)
994 {
995     _done = done;
996 }
997
998 bool
999 HLAFederate::getDone() const
1000 {
1001     return _done;
1002 }
1003
1004 bool
1005 HLAFederate::readObjectModel()
1006 {
1007     // Depending on the actual version, try to find an apropriate
1008     // file format for the given file. The first one is always the
1009     // version native object model file format.
1010     switch (getVersion()) {
1011     case RTI13:
1012         if (readRTI13ObjectModelTemplate(getFederationObjectModel()))
1013             return true;
1014         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1015             return true;
1016         return readRTI1516EObjectModelTemplate(getFederationObjectModel());
1017     case RTI1516:
1018         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1019             return true;
1020         if (readRTI1516EObjectModelTemplate(getFederationObjectModel()))
1021             return true;
1022         return readRTI13ObjectModelTemplate(getFederationObjectModel());
1023     case RTI1516E:
1024         if (readRTI1516EObjectModelTemplate(getFederationObjectModel()))
1025             return true;
1026         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1027             return true;
1028         return readRTI13ObjectModelTemplate(getFederationObjectModel());
1029     default:
1030         return false;
1031     }
1032 }
1033
1034 bool
1035 HLAFederate::subscribe()
1036 {
1037     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
1038         if (!i->second->subscribe())
1039             return false;
1040     }
1041
1042     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
1043         if (!i->second->subscribe())
1044             return false;
1045     }
1046
1047     return true;
1048 }
1049
1050 bool
1051 HLAFederate::publish()
1052 {
1053     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
1054         if (!i->second->publish())
1055             return false;
1056     }
1057
1058     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
1059         if (!i->second->publish())
1060             return false;
1061     }
1062
1063     return true;
1064 }
1065
1066 bool
1067 HLAFederate::init()
1068 {
1069     // We need to talk to the rti
1070     if (!connect())
1071         return false;
1072     // Join ...
1073     if (_createFederationExecution) {
1074         if (!createJoinFederationExecution())
1075             return false;
1076     } else {
1077         if (!join())
1078             return false;
1079     }
1080     // Read the xml file containing the object model
1081     if (!readObjectModel()) {
1082         shutdown();
1083         return false;
1084     }
1085     // start being time constrained if required
1086     if (_timeConstrained) {
1087         if (!enableTimeConstrained()) {
1088             shutdown();
1089             return false;
1090         }
1091     }
1092     // Now that we are potentially time constrained, we can subscribe.
1093     // This is to make sure we do not get any time stamped message
1094     // converted to a non time stamped message by the rti.
1095     if (!subscribe()) {
1096         shutdown();
1097         return false;
1098     }
1099     // Before we publish anything start getting regulating if required
1100     if (_timeRegulating) {
1101         if (!enableTimeRegulation()) {
1102             shutdown();
1103             return false;
1104         }
1105     }
1106     // Note that starting from here, we need to be careful with things
1107     // requireing unbounded time. The rest of the federation might wait
1108     // for us to finish!
1109     
1110     // Compute the time offset from the system time to the simulation time
1111     if (_timeConstrainedByLocalClock) {
1112         if (!enableTimeConstrainedByLocalClock()) {
1113             SG_LOG(SG_NETWORK, SG_WARN, "Cannot enable time constrained by local clock!");
1114             shutdown();
1115             return false;
1116         }
1117     }
1118     
1119     // Publish what we want to write
1120     if (!publish()) {
1121         shutdown();
1122         return false;
1123     }
1124     
1125     return true;
1126 }
1127
1128 bool
1129 HLAFederate::update()
1130 {
1131     return timeAdvanceBy(_timeIncrement);
1132 }
1133
1134 bool
1135 HLAFederate::shutdown()
1136 {
1137     // On shutdown, just try all in order.
1138     // If something goes wrong, continue and try to get out here as good as possible.
1139     bool ret = true;
1140     
1141     if (_createFederationExecution) {
1142         if (!resignDestroyFederationExecution())
1143             ret = false;
1144     } else {
1145         if (!resign())
1146             ret = false;
1147     }
1148     
1149     if (!disconnect())
1150         ret = false;
1151     
1152     return ret;
1153 }
1154
1155 bool
1156 HLAFederate::exec()
1157 {
1158     if (!init())
1159         return false;
1160     
1161     while (!getDone()) {
1162         if (!update()) {
1163             shutdown();
1164             return false;
1165         }
1166     }
1167     
1168     if (!shutdown())
1169         return false;
1170     
1171     return true;
1172 }
1173
1174 void
1175 HLAFederate::_clearRTI()
1176 {
1177     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i)
1178         i->second->_clearRTIInteractionClass();
1179     for (ObjectInstanceMap::iterator i = _objectInstanceMap.begin(); i != _objectInstanceMap.end(); ++i)
1180         i->second->_clearRTIObjectInstance();
1181     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i)
1182         i->second->_clearRTIObjectClass();
1183
1184     _rtiFederate = 0;
1185 }
1186
1187 bool
1188 HLAFederate::_insertInteractionClass(const SGSharedPtr<HLAInteractionClass>& interactionClass)
1189 {
1190     if (!interactionClass.valid())
1191         return false;
1192     if (_interactionClassMap.find(interactionClass->getName()) != _interactionClassMap.end()) {
1193         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertInteractionClass: object instance with name \""
1194                << interactionClass->getName() << "\" already known to federate!");
1195         return false;
1196     }
1197     _interactionClassMap.insert(InteractionClassMap::value_type(interactionClass->getName(), interactionClass));
1198     return true;
1199 }
1200
1201 bool
1202 HLAFederate::_insertObjectClass(const SGSharedPtr<HLAObjectClass>& objectClass)
1203 {
1204     if (!objectClass.valid())
1205         return false;
1206     if (_objectClassMap.find(objectClass->getName()) != _objectClassMap.end()) {
1207         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertObjectClass: object instance with name \""
1208                << objectClass->getName() << "\" already known to federate!");
1209         return false;
1210     }
1211     _objectClassMap.insert(ObjectClassMap::value_type(objectClass->getName(), objectClass));
1212     return true;
1213 }
1214
1215 bool
1216 HLAFederate::_insertObjectInstance(const SGSharedPtr<HLAObjectInstance>& objectInstance)
1217 {
1218     if (!objectInstance.valid())
1219         return false;
1220     if (objectInstance->getName().empty()) {
1221         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertObjectInstance: trying to insert object instance with empty name!");
1222         return false;
1223     }
1224     if (_objectInstanceMap.find(objectInstance->getName()) != _objectInstanceMap.end()) {
1225         SG_LOG(SG_IO, SG_WARN, "HLA: _insertObjectInstance: object instance with name \""
1226                << objectInstance->getName() << "\" already known to federate!");
1227         return false;
1228     }
1229     _objectInstanceMap.insert(ObjectInstanceMap::value_type(objectInstance->getName(), objectInstance));
1230     return true;
1231 }
1232
1233 void
1234 HLAFederate::_eraseObjectInstance(const std::string& name)
1235 {
1236     ObjectInstanceMap::iterator i = _objectInstanceMap.find(name);
1237     if (i == _objectInstanceMap.end()) {
1238         SG_LOG(SG_IO, SG_WARN, "HLA: _eraseObjectInstance: object instance with name \""
1239                << name << "\" not known to federate!");
1240         return;
1241     }
1242     _objectInstanceMap.erase(i);
1243 }
1244
1245 } // namespace simgear