]> git.mxchange.org Git - simgear.git/blob - simgear/hla/HLAFederate.cxx
141cbc8e91dbce28c87b7a7574383875fe1fe420
[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         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query GALT!");
654         return false;
655     }
656
657     if (!_rtiFederate->timeAdvanceRequestAvailable(timeStamp)) {
658         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
659         return false;
660     }
661
662     return processMessages();
663 }
664
665 bool
666 HLAFederate::queryFederateTime(SGTimeStamp& timeStamp)
667 {
668     if (!_rtiFederate.valid()) {
669         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
670         return false;
671     }
672     return _rtiFederate->queryFederateTime(timeStamp);
673 }
674
675 bool
676 HLAFederate::queryLookahead(SGTimeStamp& timeStamp)
677 {
678     if (!_rtiFederate.valid()) {
679         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
680         return false;
681     }
682     return _rtiFederate->queryLookahead(timeStamp);
683 }
684
685 bool
686 HLAFederate::processMessage()
687 {
688     if (!_rtiFederate.valid()) {
689         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
690         return false;
691     }
692     return _rtiFederate->processMessage();
693 }
694
695 bool
696 HLAFederate::processMessage(const SGTimeStamp& timeout)
697 {
698     if (!_rtiFederate.valid()) {
699         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
700         return false;
701     }
702     return _rtiFederate->processMessages(timeout.toSecs(), 0);
703 }
704
705 bool
706 HLAFederate::processMessages()
707 {
708     if (!_rtiFederate.valid()) {
709         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
710         return false;
711     }
712
713     while (_rtiFederate->getTimeAdvancePending()) {
714         _rtiFederate->processMessage();
715     }
716
717     if (_timeConstrainedByLocalClock) {
718         SGTimeStamp federateTime;
719         if (!_rtiFederate->queryFederateTime(federateTime)) {
720             SG_LOG(SG_NETWORK, SG_WARN, "HLA: Error querying federate time!");
721             return false;
722         }
723         SGTimeStamp systemTime = federateTime + _localClockOffset;
724         for (;;) {
725             double rest = (systemTime - SGTimeStamp::now()).toSecs();
726             if (rest < 0)
727                 break;
728             _rtiFederate->processMessages(rest, rest);
729         }
730     }
731     
732     // Now flush just what is left
733     while (_rtiFederate->processMessages(0, 0));
734
735     return true;
736 }
737
738 bool
739 HLAFederate::tick(const double& minimum, const double& maximum)
740 {
741     if (!_rtiFederate.valid()) {
742         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
743         return false;
744     }
745     return _rtiFederate->processMessages(minimum, maximum);
746 }
747
748 bool
749 HLAFederate::readObjectModelTemplate(const std::string& objectModel,
750                                      HLAFederate::ObjectModelFactory& objectModelFactory)
751 {
752     // The XML version of the federate object model.
753     // This one covers the generic attributes, parameters and data types.
754     HLAOMTXmlVisitor omtXmlVisitor;
755     try {
756         readXML(objectModel, omtXmlVisitor);
757     } catch (const sg_throwable& e) {
758         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
759                << e.getMessage());
760         return false;
761     } catch (...) {
762         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
763         return false;
764     }
765
766     omtXmlVisitor.setDataTypesToFederate(*this);
767
768     unsigned numObjectClasses = omtXmlVisitor.getNumObjectClasses();
769     for (unsigned i = 0; i < numObjectClasses; ++i) {
770         const HLAOMTXmlVisitor::ObjectClass* objectClass = omtXmlVisitor.getObjectClass(i);
771         std::string objectClassName = objectClass->getName();
772
773         SGSharedPtr<HLAObjectClass> hlaObjectClass = objectModelFactory.createObjectClass(objectClassName, *this);
774         if (!hlaObjectClass.valid()) {
775             SG_LOG(SG_IO, SG_INFO, "Ignoring object class \"" << objectClassName << "\".");
776             continue;
777         }
778
779         bool publish = objectModelFactory.publishObjectClass(objectClassName, objectClass->getSharing());
780         bool subscribe = objectModelFactory.subscribeObjectClass(objectClassName, objectClass->getSharing());
781
782         // process the attributes
783         for (unsigned j = 0; j < objectClass->getNumAttributes(); ++j) {
784             const simgear::HLAOMTXmlVisitor::Attribute* attribute;
785             attribute = objectClass->getAttribute(j);
786
787             std::string attributeName = attribute->getName();
788             unsigned index = hlaObjectClass->addAttribute(attributeName);
789
790             if (index == ~0u) {
791                 SG_LOG(SG_IO, SG_WARN, "RTI does not know the \"" << attributeName << "\" attribute!");
792                 continue;
793             }
794
795             // the attributes datatype
796             SGSharedPtr<const HLADataType> dataType = getDataType(attribute->getDataType());
797             if (!dataType.valid()) {
798                 SG_LOG(SG_IO, SG_WARN, "Could not find data type for attribute \""
799                        << attributeName << "\" in object class \"" << objectClassName << "\"!");
800             }
801             hlaObjectClass->setAttributeDataType(index, dataType);
802             hlaObjectClass->setAttributeUpdateType(index, attribute->getUpdateType());
803             if (subscribe && objectModelFactory.subscribeAttribute(objectClassName, attributeName, attribute->_sharing))
804                 hlaObjectClass->setAttributeSubscriptionType(index, attribute->getSubscriptionType());
805             if (publish && objectModelFactory.publishAttribute(objectClassName, attributeName, attribute->_sharing))
806                 hlaObjectClass->setAttributePublicationType(index, attribute->getPublicationType());
807         }
808
809         if (publish)
810             hlaObjectClass->publish();
811         if (subscribe)
812             hlaObjectClass->subscribe();
813
814     }
815
816     return resolveObjectModel();
817 }
818
819 bool
820 HLAFederate::readRTI13ObjectModelTemplate(const std::string& objectModel)
821 {
822     SG_LOG(SG_IO, SG_ALERT, "HLA version RTI13 not yet(!?) supported.");
823     return false;
824 }
825
826 bool
827 HLAFederate::readRTI1516ObjectModelTemplate(const std::string& objectModel)
828 {
829     // The XML version of the federate object model.
830     // This one covers the generic attributes, parameters and data types.
831     HLAOMTXmlVisitor omtXmlVisitor;
832     try {
833         readXML(objectModel, omtXmlVisitor);
834     } catch (const sg_throwable& e) {
835         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
836                << e.getMessage());
837         return false;
838     } catch (...) {
839         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
840         return false;
841     }
842
843     omtXmlVisitor.setToFederate(*this);
844
845     return resolveObjectModel();
846 }
847
848 bool
849 HLAFederate::readRTI1516EObjectModelTemplate(const std::string& objectModel)
850 {
851     SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
852     return false;
853 }
854
855 bool
856 HLAFederate::resolveObjectModel()
857 {
858     if (!_rtiFederate.valid()) {
859         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
860         return false;
861     }
862
863     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
864         RTIInteractionClass* rtiInteractionClass = _rtiFederate->createInteractionClass(i->second->getName(), i->second.get());
865         if (!rtiInteractionClass) {
866             SG_LOG(SG_NETWORK, SG_ALERT, "HLAFederate::_insertInteractionClass(): "
867                    "No RTIInteractionClass found for \"" << i->second->getName() << "\"!");
868             return false;
869         }
870         i->second->_setRTIInteractionClass(rtiInteractionClass);
871     }
872
873     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
874         RTIObjectClass* rtiObjectClass = _rtiFederate->createObjectClass(i->second->getName(), i->second.get());
875         if (!rtiObjectClass) {
876             SG_LOG(SG_NETWORK, SG_ALERT, "HLAFederate::_insertObjectClass(): "
877                    "No RTIObjectClass found for \"" << i->second->getName() << "\"!");
878             return false;
879         }
880         i->second->_setRTIObjectClass(rtiObjectClass);
881     }
882
883     return true;
884 }
885
886 const HLADataType*
887 HLAFederate::getDataType(const std::string& name) const
888 {
889     DataTypeMap::const_iterator i = _dataTypeMap.find(name);
890     if (i == _dataTypeMap.end())
891         return 0;
892     return i->second.get();
893 }
894
895 bool
896 HLAFederate::insertDataType(const std::string& name, const SGSharedPtr<HLADataType>& dataType)
897 {
898     if (!dataType.valid())
899         return false;
900     if (_dataTypeMap.find(name) != _dataTypeMap.end()) {
901         SG_LOG(SG_IO, SG_ALERT, "HLAFederate::insertDataType: data type with name \""
902                << name << "\" already known to federate!");
903         return false;
904     }
905     _dataTypeMap.insert(DataTypeMap::value_type(name, dataType));
906     return true;
907 }
908
909 void
910 HLAFederate::recomputeDataTypeAlignment()
911 {
912     // Finish alignment computations
913     bool changed;
914     do {
915         changed = false;
916         for (DataTypeMap::iterator i = _dataTypeMap.begin(); i != _dataTypeMap.end(); ++i) {
917             if (i->second->recomputeAlignment())
918                 changed = true;
919         }
920     } while (changed);
921 }
922
923 HLAInteractionClass*
924 HLAFederate::getInteractionClass(const std::string& name)
925 {
926     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
927     if (i == _interactionClassMap.end())
928         return 0;
929     return i->second.get();
930 }
931
932 const HLAInteractionClass*
933 HLAFederate::getInteractionClass(const std::string& name) const
934 {
935     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
936     if (i == _interactionClassMap.end())
937         return 0;
938     return i->second.get();
939 }
940
941 HLAInteractionClass*
942 HLAFederate::createInteractionClass(const std::string& name)
943 {
944     return new HLAInteractionClass(name, this);
945 }
946
947 HLAObjectClass*
948 HLAFederate::getObjectClass(const std::string& name)
949 {
950     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
951     if (i == _objectClassMap.end())
952         return 0;
953     return i->second.get();
954 }
955
956 const HLAObjectClass*
957 HLAFederate::getObjectClass(const std::string& name) const
958 {
959     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
960     if (i == _objectClassMap.end())
961         return 0;
962     return i->second.get();
963 }
964
965 HLAObjectClass*
966 HLAFederate::createObjectClass(const std::string& name)
967 {
968     return new HLAObjectClass(name, this);
969 }
970
971 HLAObjectInstance*
972 HLAFederate::getObjectInstance(const std::string& name)
973 {
974     ObjectInstanceMap::const_iterator i = _objectInstanceMap.find(name);
975     if (i == _objectInstanceMap.end())
976         return 0;
977     return i->second.get();
978 }
979
980 const HLAObjectInstance*
981 HLAFederate::getObjectInstance(const std::string& name) const
982 {
983     ObjectInstanceMap::const_iterator i = _objectInstanceMap.find(name);
984     if (i == _objectInstanceMap.end())
985         return 0;
986     return i->second.get();
987 }
988
989 HLAObjectInstance*
990 HLAFederate::createObjectInstance(HLAObjectClass* objectClass, const std::string& name)
991 {
992     return new HLAObjectInstance(objectClass);
993 }
994
995 void
996 HLAFederate::setDone(bool done)
997 {
998     _done = done;
999 }
1000
1001 bool
1002 HLAFederate::getDone() const
1003 {
1004     return _done;
1005 }
1006
1007 bool
1008 HLAFederate::readObjectModel()
1009 {
1010     // Depending on the actual version, try to find an apropriate
1011     // file format for the given file. The first one is always the
1012     // version native object model file format.
1013     switch (getVersion()) {
1014     case RTI13:
1015         if (readRTI13ObjectModelTemplate(getFederationObjectModel()))
1016             return true;
1017         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1018             return true;
1019         return readRTI1516EObjectModelTemplate(getFederationObjectModel());
1020     case RTI1516:
1021         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1022             return true;
1023         if (readRTI1516EObjectModelTemplate(getFederationObjectModel()))
1024             return true;
1025         return readRTI13ObjectModelTemplate(getFederationObjectModel());
1026     case RTI1516E:
1027         if (readRTI1516EObjectModelTemplate(getFederationObjectModel()))
1028             return true;
1029         if (readRTI1516ObjectModelTemplate(getFederationObjectModel()))
1030             return true;
1031         return readRTI13ObjectModelTemplate(getFederationObjectModel());
1032     default:
1033         return false;
1034     }
1035 }
1036
1037 bool
1038 HLAFederate::subscribe()
1039 {
1040     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
1041         if (!i->second->subscribe())
1042             return false;
1043     }
1044
1045     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
1046         if (!i->second->subscribe())
1047             return false;
1048     }
1049
1050     return true;
1051 }
1052
1053 bool
1054 HLAFederate::publish()
1055 {
1056     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i) {
1057         if (!i->second->publish())
1058             return false;
1059     }
1060
1061     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i) {
1062         if (!i->second->publish())
1063             return false;
1064     }
1065
1066     return true;
1067 }
1068
1069 bool
1070 HLAFederate::init()
1071 {
1072     // We need to talk to the rti
1073     if (!connect())
1074         return false;
1075     // Join ...
1076     if (_createFederationExecution) {
1077         if (!createJoinFederationExecution())
1078             return false;
1079     } else {
1080         if (!join())
1081             return false;
1082     }
1083     // Read the xml file containing the object model
1084     if (!readObjectModel()) {
1085         shutdown();
1086         return false;
1087     }
1088     // start being time constrained if required
1089     if (_timeConstrained) {
1090         if (!enableTimeConstrained()) {
1091             shutdown();
1092             return false;
1093         }
1094     }
1095     // Now that we are potentially time constrained, we can subscribe.
1096     // This is to make sure we do not get any time stamped message
1097     // converted to a non time stamped message by the rti.
1098     if (!subscribe()) {
1099         shutdown();
1100         return false;
1101     }
1102     // Before we publish anything start getting regulating if required
1103     if (_timeRegulating) {
1104         if (!enableTimeRegulation()) {
1105             shutdown();
1106             return false;
1107         }
1108     }
1109     // Note that starting from here, we need to be careful with things
1110     // requireing unbounded time. The rest of the federation might wait
1111     // for us to finish!
1112     
1113     // Compute the time offset from the system time to the simulation time
1114     if (_timeConstrainedByLocalClock) {
1115         if (!enableTimeConstrainedByLocalClock()) {
1116             SG_LOG(SG_NETWORK, SG_WARN, "Cannot enable time constrained by local clock!");
1117             shutdown();
1118             return false;
1119         }
1120     }
1121     
1122     // Publish what we want to write
1123     if (!publish()) {
1124         shutdown();
1125         return false;
1126     }
1127     
1128     return true;
1129 }
1130
1131 bool
1132 HLAFederate::update()
1133 {
1134     return timeAdvanceBy(_timeIncrement);
1135 }
1136
1137 bool
1138 HLAFederate::shutdown()
1139 {
1140     // On shutdown, just try all in order.
1141     // If something goes wrong, continue and try to get out here as good as possible.
1142     bool ret = true;
1143     
1144     if (_createFederationExecution) {
1145         if (!resignDestroyFederationExecution())
1146             ret = false;
1147     } else {
1148         if (!resign())
1149             ret = false;
1150     }
1151     
1152     if (!disconnect())
1153         ret = false;
1154     
1155     return ret;
1156 }
1157
1158 bool
1159 HLAFederate::exec()
1160 {
1161     if (!init())
1162         return false;
1163     
1164     while (!getDone()) {
1165         if (!update()) {
1166             shutdown();
1167             return false;
1168         }
1169     }
1170     
1171     if (!shutdown())
1172         return false;
1173     
1174     return true;
1175 }
1176
1177 void
1178 HLAFederate::_clearRTI()
1179 {
1180     for (InteractionClassMap::iterator i = _interactionClassMap.begin(); i != _interactionClassMap.end(); ++i)
1181         i->second->_clearRTIInteractionClass();
1182     for (ObjectInstanceMap::iterator i = _objectInstanceMap.begin(); i != _objectInstanceMap.end(); ++i)
1183         i->second->_clearRTIObjectInstance();
1184     for (ObjectClassMap::iterator i = _objectClassMap.begin(); i != _objectClassMap.end(); ++i)
1185         i->second->_clearRTIObjectClass();
1186
1187     _rtiFederate = 0;
1188 }
1189
1190 bool
1191 HLAFederate::_insertInteractionClass(const SGSharedPtr<HLAInteractionClass>& interactionClass)
1192 {
1193     if (!interactionClass.valid())
1194         return false;
1195     if (_interactionClassMap.find(interactionClass->getName()) != _interactionClassMap.end()) {
1196         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertInteractionClass: object instance with name \""
1197                << interactionClass->getName() << "\" already known to federate!");
1198         return false;
1199     }
1200     _interactionClassMap.insert(InteractionClassMap::value_type(interactionClass->getName(), interactionClass));
1201     return true;
1202 }
1203
1204 bool
1205 HLAFederate::_insertObjectClass(const SGSharedPtr<HLAObjectClass>& objectClass)
1206 {
1207     if (!objectClass.valid())
1208         return false;
1209     if (_objectClassMap.find(objectClass->getName()) != _objectClassMap.end()) {
1210         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertObjectClass: object instance with name \""
1211                << objectClass->getName() << "\" already known to federate!");
1212         return false;
1213     }
1214     _objectClassMap.insert(ObjectClassMap::value_type(objectClass->getName(), objectClass));
1215     return true;
1216 }
1217
1218 bool
1219 HLAFederate::_insertObjectInstance(const SGSharedPtr<HLAObjectInstance>& objectInstance)
1220 {
1221     if (!objectInstance.valid())
1222         return false;
1223     if (objectInstance->getName().empty()) {
1224         SG_LOG(SG_IO, SG_ALERT, "HLA: _insertObjectInstance: trying to insert object instance with empty name!");
1225         return false;
1226     }
1227     if (_objectInstanceMap.find(objectInstance->getName()) != _objectInstanceMap.end()) {
1228         SG_LOG(SG_IO, SG_WARN, "HLA: _insertObjectInstance: object instance with name \""
1229                << objectInstance->getName() << "\" already known to federate!");
1230         return false;
1231     }
1232     _objectInstanceMap.insert(ObjectInstanceMap::value_type(objectInstance->getName(), objectInstance));
1233     return true;
1234 }
1235
1236 void
1237 HLAFederate::_eraseObjectInstance(const std::string& name)
1238 {
1239     ObjectInstanceMap::iterator i = _objectInstanceMap.find(name);
1240     if (i == _objectInstanceMap.end()) {
1241         SG_LOG(SG_IO, SG_WARN, "HLA: _eraseObjectInstance: object instance with name \""
1242                << name << "\" not known to federate!");
1243         return;
1244     }
1245     _objectInstanceMap.erase(i);
1246 }
1247
1248 } // namespace simgear