source: XIOS/trunk/src/node/context.cpp @ 445

Last change on this file since 445 was 445, checked in by ymipsl, 11 years ago

Add possibility to make inheritance of attributes and reference before closing the context definition.
New fortran fonction : xios_solve inheritance()
After this call, the value of attribute have the inherited value of their parent.

YM

File size: 17.5 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xmlioserver_spl.hpp"
16
17namespace xios {
18 
19  shared_ptr<CContextGroup> CContext::root ;
20   
21   /// ////////////////////// Définitions ////////////////////// ///
22
23   CContext::CContext(void)
24      : CObjectTemplate<CContext>(), CContextAttributes()
25      , calendar(),hasClient(false),hasServer(false)
26   { /* Ne rien faire de plus */ }
27
28   CContext::CContext(const StdString & id)
29      : CObjectTemplate<CContext>(id), CContextAttributes()
30      , calendar(),hasClient(false),hasServer(false)
31   { /* Ne rien faire de plus */ }
32
33   CContext::~CContext(void)
34   { 
35     if (hasClient) delete client ;
36     if (hasServer) delete server ;
37   }
38
39   //----------------------------------------------------------------
40
41   StdString CContext::GetName(void)   { return (StdString("context")); }
42   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
43   ENodeType CContext::GetType(void)   { return (eContext); }
44
45   //----------------------------------------------------------------
46
47   CContextGroup* CContext::getRoot(void)
48   { 
49      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName())) ;
50      return root.get(); 
51   }
52   
53
54   //----------------------------------------------------------------
55
56   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
57   {
58      return (this->calendar);
59   }
60   
61   //----------------------------------------------------------------
62   
63   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
64   {
65      this->calendar = newCalendar;
66      calendar_type.setValue(this->calendar->getId());
67      start_date.setValue(this->calendar->getInitDate().toString());
68   }
69   
70   //----------------------------------------------------------------
71
72   void CContext::solveCalendar(void)
73   {
74      if (this->calendar.get() != NULL) return;
75      if (calendar_type.isEmpty() || start_date.isEmpty())
76         ERROR(" CContext::solveCalendar(void)",
77               << "[ context id = " << this->getId() << " ] "
78               << "Impossible to define a calendar (an attribute is missing).");
79
80#define DECLARE_CALENDAR(MType  , mtype)                              \
81   if (calendar_type.getValue().compare(#mtype) == 0)                 \
82   {                                                                  \
83      if (time_origin.isEmpty())                                       \
84        this->calendar =  boost::shared_ptr<CCalendar>          \
85           (new C##MType##Calendar(start_date.getValue()));     \
86      else this->calendar =  boost::shared_ptr<CCalendar>       \
87           (new C##MType##Calendar(start_date.getValue(),time_origin.getValue()));     \
88      if (!this->timestep.isEmpty())                                  \
89       this->calendar->setTimeStep                                    \
90          (CDuration::FromString(this->timestep.getValue()));   \
91      return;                                                         \
92   }
93#include "calendar_type.conf"
94
95      ERROR("CContext::solveCalendar(void)",
96            << "[ calendar_type = " << calendar_type.getValue() << " ] "
97            << "The calendar is not defined !");
98   }
99   
100   //----------------------------------------------------------------
101
102   void CContext::parse(xml::CXMLNode & node)
103   {
104      CContext::SuperClass::parse(node);
105
106      // PARSING POUR GESTION DES ENFANTS
107      xml::THashAttributes attributes = node.getAttributes();
108
109      if (attributes.end() != attributes.find("src"))
110      {
111         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
112         if (!ifs.good())
113            ERROR("CContext::parse(xml::CXMLNode & node)",
114                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
115         xml::CXMLParser::ParseInclude(ifs, *this);
116      }
117
118      if (node.getElementName().compare(CContext::GetName()))
119         DEBUG("Le noeud is wrong defined but will be considered as a context !");
120
121      if (!(node.goToChildElement()))
122      {
123         DEBUG("Le context ne contient pas d'enfant !");
124      }
125      else
126      {
127         do { // Parcours des contextes pour traitement.
128
129            StdString name = node.getElementName();
130            attributes.clear();
131            attributes = node.getAttributes();
132
133            if (attributes.end() != attributes.find("id"))
134            { DEBUG(<< "Definition node has an id,"
135                    << "it will not be taking account !"); }
136
137#define DECLARE_NODE(Name_, name_)    \
138   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
139   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node) ; continue; }
140#define DECLARE_NODE_PAR(Name_, name_)
141#include "node_type.conf"
142
143            DEBUG(<< "The element \'"     << name
144                  << "\' in the context \'" << CContext::getCurrent()->getId()
145                  << "\' is not a definition !");
146
147         } while (node.goToNextElement());
148
149         node.goToParentElement(); // Retour au parent
150      }
151   }
152
153   //----------------------------------------------------------------
154
155   void CContext::ShowTree(StdOStream & out)
156   {
157      StdString currentContextId = CContext::getCurrent() -> getId() ;
158      std::vector<CContext*> def_vector =
159         CContext::getRoot()->getChildList();
160      std::vector<CContext*>::iterator
161         it = def_vector.begin(), end = def_vector.end();
162
163      out << "<? xml version=\"1.0\" ?>" << std::endl;
164      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
165     
166      for (; it != end; it++)
167      {
168         CContext* context = *it;         
169         CContext::setCurrent(context->getId());         
170         out << *context << std::endl;
171      }
172     
173      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
174      CContext::setCurrent(currentContextId); 
175   }
176   
177   //----------------------------------------------------------------
178/*
179   void CContext::toBinary(StdOStream & os) const
180   {
181      SuperClass::toBinary(os);
182
183#define DECLARE_NODE(Name_, name_)                                         \
184   {                                                                       \
185      ENodeType renum = C##Name_##Definition::GetType();                   \
186      bool val = C##Name_##Definition::has(C##Name_##Definition::GetDefName()); \
187      os.write (reinterpret_cast<const char*>(&renum), sizeof(ENodeType)); \
188      os.write (reinterpret_cast<const char*>(&val), sizeof(bool));        \
189      if (val) C##Name_##Definition::get(C##Name_##Definition::GetDefName())->toBinary(os);   \
190   }   
191#define DECLARE_NODE_PAR(Name_, name_)
192#include "node_type.conf"
193   }
194*/
195   //----------------------------------------------------------------
196/*
197   void CContext::fromBinary(StdIStream & is)
198   {
199      SuperClass::fromBinary(is);
200#define DECLARE_NODE(Name_, name_)                                         \
201   {                                                                       \
202      bool val = false;                                                    \
203      ENodeType renum = Unknown;                                           \
204      is.read (reinterpret_cast<char*>(&renum), sizeof(ENodeType));        \
205      is.read (reinterpret_cast<char*>(&val), sizeof(bool));               \
206      if (renum != C##Name_##Definition::GetType())                        \
207         ERROR("CContext::fromBinary(StdIStream & is)",                    \
208               << "[ renum = " << renum << "] Bad type !");                \
209      if (val) C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> fromBinary(is); \
210   }   
211#define DECLARE_NODE_PAR(Name_, name_)
212#include "node_type.conf"
213     
214   }
215 */
216   
217   //----------------------------------------------------------------
218
219   StdString CContext::toString(void) const
220   {
221      StdOStringStream oss;
222      oss << "<" << CContext::GetName()
223          << " id=\"" << this->getId() << "\" "
224          << SuperClassAttribute::toString() << ">" << std::endl;
225      if (!this->hasChild())
226      {
227         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
228      }
229      else
230      {
231
232#define DECLARE_NODE(Name_, name_)    \
233   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
234   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
235#define DECLARE_NODE_PAR(Name_, name_)
236#include "node_type.conf"
237
238      }
239
240      oss << "</" << CContext::GetName() << " >";
241
242      return (oss.str());
243   }
244
245   //----------------------------------------------------------------
246
247   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
248   {
249#define DECLARE_NODE(Name_, name_)    \
250   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
251     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
252#define DECLARE_NODE_PAR(Name_, name_)
253#include "node_type.conf"
254   }
255
256   //----------------------------------------------------------------
257
258   bool CContext::hasChild(void) const
259   {
260      return (
261#define DECLARE_NODE(Name_, name_)    \
262   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
263#define DECLARE_NODE_PAR(Name_, name_)
264#include "node_type.conf"
265      false);
266}
267
268   //----------------------------------------------------------------
269
270   void CContext::solveFieldRefInheritance(bool apply)
271   {
272      if (!this->hasId()) return;
273      vector<CField*> allField = CField::getAll() ;
274//              = CObjectTemplate<CField>::GetAllVectobject(this->getId());
275      std::vector<CField*>::iterator
276         it = allField.begin(), end = allField.end();
277           
278      for (; it != end; it++)
279      {
280         CField* field = *it;
281         field->solveRefInheritance(apply);
282      }
283   }
284
285   //----------------------------------------------------------------
286
287   void CContext::CleanTree(void)
288   {
289#define DECLARE_NODE(Name_, name_) C##Name_##Group::ClearAllAttributes();
290#define DECLARE_NODE_PAR(Name_, name_)
291#include "node_type.conf"
292   }
293   ///---------------------------------------------------------------
294   
295   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm)
296   {
297     hasClient=true ;
298     client = new CContextClient(this,intraComm, interComm) ;
299   } 
300
301   void CContext::initServer(MPI_Comm intraComm,MPI_Comm interComm)
302   {
303     hasServer=true ;
304     server = new CContextServer(this,intraComm,interComm) ;
305   } 
306
307   bool CContext::eventLoop(void)
308   {
309     return server->eventLoop() ;
310   } 
311   
312   void CContext::finalize(void)
313   {
314      if (hasClient && !hasServer)
315      {
316         client->finalize() ;
317      }
318      if (hasServer)
319      {
320        closeAllFile() ;
321      }
322   }
323       
324       
325 
326   
327   void CContext::closeDefinition(void)
328   {
329      if (hasClient && !hasServer) sendCloseDefinition() ;
330     
331      solveCalendar();         
332         
333      // Résolution des héritages pour le context actuel.
334      this->solveAllInheritance();
335
336      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
337      this->findEnabledFiles();
338
339      //Recherche des champs à sortir (enable à true + niveau de sortie correct)
340      // pour chaque fichier précédemment listé.
341      this->findAllEnabledFields();
342
343      // Résolution des références de grilles pour chacun des champs.
344      this->solveAllGridRef();
345
346      // Traitement des opérations.
347      this->solveAllOperation();
348
349      // Nettoyage de l'arborescence
350      CleanTree();
351      if (hasClient) sendCreateFileHeader() ;
352   }
353   
354   void CContext::findAllEnabledFields(void)
355   {
356     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
357     (void)this->enabledFiles[i]->getEnabledFields();
358   }
359
360   void CContext::solveAllGridRef(void)
361   {
362     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
363     this->enabledFiles[i]->solveEFGridRef();
364   }
365
366   void CContext::solveAllOperation(void)
367   {
368      for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
369      this->enabledFiles[i]->solveEFOperation();
370   }
371
372   void CContext::solveAllInheritance(bool apply)
373   {
374     // Résolution des héritages descendants (càd des héritages de groupes)
375     // pour chacun des contextes.
376      solveDescInheritance(apply);
377
378     // Résolution des héritages par référence au niveau des fichiers.
379      const vector<CFile*> allFiles=CFile::getAll() ;
380
381      for (unsigned int i = 0; i < allFiles.size(); i++)
382         allFiles[i]->solveFieldRefInheritance(apply);
383   }
384
385   void CContext::findEnabledFiles(void)
386   {
387      const std::vector<CFile*> allFiles = CFile::getAll();
388
389      for (unsigned int i = 0; i < allFiles.size(); i++)
390         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
391         {
392            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
393               enabledFiles.push_back(allFiles[i]);
394         }
395         else enabledFiles.push_back(allFiles[i]); // otherwise true by default
396               
397
398      if (enabledFiles.size() == 0)
399         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
400               << getId() << "\" !");
401   }
402
403   void CContext::closeAllFile(void)
404   {
405     std::vector<CFile*>::const_iterator
406            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
407         
408     for (; it != end; it++)
409     {
410       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
411       (*it)->close();
412     }
413   }
414   
415   bool CContext::dispatchEvent(CEventServer& event)
416   {
417     
418      if (SuperClass::dispatchEvent(event)) return true ;
419      else
420      {
421        switch(event.type)
422        {
423           case EVENT_ID_CLOSE_DEFINITION :
424             recvCloseDefinition(event) ;
425             return true ;
426             break ;
427           case EVENT_ID_UPDATE_CALENDAR :
428             recvUpdateCalendar(event) ;
429             return true ;
430             break ;
431           case EVENT_ID_CREATE_FILE_HEADER :
432             recvCreateFileHeader(event) ;
433             return true ;
434             break ;
435           default :
436             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
437                    <<"Unknown Event") ;
438           return false ;
439         }
440      }
441   }
442   
443   void CContext::sendCloseDefinition(void)
444   {
445
446     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION) ;   
447     if (client->isServerLeader())
448     {
449       CMessage msg ;
450       msg<<this->getId() ;
451       event.push(client->getServerLeader(),1,msg) ;
452       client->sendEvent(event) ;
453     }
454     else client->sendEvent(event) ;
455   }
456   
457   void CContext::recvCloseDefinition(CEventServer& event)
458   {
459     
460      CBufferIn* buffer=event.subEvents.begin()->buffer;
461      string id;
462      *buffer>>id ;
463      get(id)->closeDefinition() ;
464   }
465   
466   void CContext::sendUpdateCalendar(int step)
467   {
468     if (!hasServer)
469     {
470       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR) ;   
471       if (client->isServerLeader())
472       {
473         CMessage msg ;
474         msg<<this->getId()<<step ;
475         event.push(client->getServerLeader(),1,msg) ;
476         client->sendEvent(event) ;
477       }
478       else client->sendEvent(event) ;
479     }
480   }
481   
482   void CContext::recvUpdateCalendar(CEventServer& event)
483   {
484     
485      CBufferIn* buffer=event.subEvents.begin()->buffer;
486      string id;
487      *buffer>>id ;
488      get(id)->recvUpdateCalendar(*buffer) ;
489   }
490   
491   void CContext::recvUpdateCalendar(CBufferIn& buffer)
492   {
493      int step ;
494      buffer>>step ;
495      updateCalendar(step) ;
496   }
497   
498   void CContext::sendCreateFileHeader(void)
499   {
500
501     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER) ;   
502     if (client->isServerLeader())
503     {
504       CMessage msg ;
505       msg<<this->getId() ;
506       event.push(client->getServerLeader(),1,msg) ;
507       client->sendEvent(event) ;
508     }
509     else client->sendEvent(event) ;
510   }
511   
512   void CContext::recvCreateFileHeader(CEventServer& event)
513   {
514     
515      CBufferIn* buffer=event.subEvents.begin()->buffer;
516      string id;
517      *buffer>>id ;
518      get(id)->recvCreateFileHeader(*buffer) ;
519   }
520   
521   void CContext::recvCreateFileHeader(CBufferIn& buffer)
522   {
523      createFileHeader() ;
524   }
525   
526   void CContext::updateCalendar(int step)
527   {
528      info(50)<<"updateCalendar : before : "<<calendar->getCurrentDate()<<endl ;
529      calendar->update(step) ;
530      info(50)<<"updateCalendar : after : "<<calendar->getCurrentDate()<<endl ;
531   }
532 
533   void CContext::createFileHeader(void )
534   {
535      vector<CFile*>::const_iterator it ;
536         
537      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
538      {
539         (*it)->initFile();
540      }
541   } 
542   
543   CContext* CContext::getCurrent(void)
544   {
545     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get() ;
546   }
547   
548   void CContext::setCurrent(const string& id)
549   {
550     CObjectFactory::SetCurrentContextId(id);
551     CGroupFactory::SetCurrentContextId(id);
552   }
553   
554  CContext* CContext::create(const StdString& id)
555  {
556    CContext::setCurrent(id) ;
557 
558    bool hasctxt = CContext::has(id);
559    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
560    getRoot() ;
561    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
562
563#define DECLARE_NODE(Name_, name_) \
564    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
565#define DECLARE_NODE_PAR(Name_, name_)
566#include "node_type.conf"
567
568    return (context);
569  }
570} // namespace xios
Note: See TracBrowser for help on using the repository browser.