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

Last change on this file since 462 was 462, checked in by ymipsl, 10 years ago

Enhancement :

  • Improving error message occuring along the xml parsing : position (line number, column) is now indicated
  • New executable : parse_xml.exe : parse the xml files and reports potential error

YM

File size: 16.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.rdstate() & std::ifstream::failbit ) != 0 )
113            ERROR("void CContext::parse(xml::CXMLNode & node)",
114                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
115         if (!ifs.good())
116            ERROR("CContext::parse(xml::CXMLNode & node)",
117                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
118         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
119      }
120
121      if (node.getElementName().compare(CContext::GetName()))
122         DEBUG("Le noeud is wrong defined but will be considered as a context !");
123
124      if (!(node.goToChildElement()))
125      {
126         DEBUG("Le context ne contient pas d'enfant !");
127      }
128      else
129      {
130         do { // Parcours des contextes pour traitement.
131
132            StdString name = node.getElementName();
133            attributes.clear();
134            attributes = node.getAttributes();
135
136            if (attributes.end() != attributes.find("id"))
137            { DEBUG(<< "Definition node has an id,"
138                    << "it will not be taking account !"); }
139
140#define DECLARE_NODE(Name_, name_)    \
141   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
142   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node) ; continue; }
143#define DECLARE_NODE_PAR(Name_, name_)
144#include "node_type.conf"
145
146            DEBUG(<< "The element \'"     << name
147                  << "\' in the context \'" << CContext::getCurrent()->getId()
148                  << "\' is not a definition !");
149
150         } while (node.goToNextElement());
151
152         node.goToParentElement(); // Retour au parent
153      }
154   }
155
156   //----------------------------------------------------------------
157
158   void CContext::ShowTree(StdOStream & out)
159   {
160      StdString currentContextId = CContext::getCurrent() -> getId() ;
161      std::vector<CContext*> def_vector =
162         CContext::getRoot()->getChildList();
163      std::vector<CContext*>::iterator
164         it = def_vector.begin(), end = def_vector.end();
165
166      out << "<? xml version=\"1.0\" ?>" << std::endl;
167      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
168     
169      for (; it != end; it++)
170      {
171         CContext* context = *it;         
172         CContext::setCurrent(context->getId());         
173         out << *context << std::endl;
174      }
175     
176      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
177      CContext::setCurrent(currentContextId); 
178   }
179   
180
181   //----------------------------------------------------------------
182
183   StdString CContext::toString(void) const
184   {
185      StdOStringStream oss;
186      oss << "<" << CContext::GetName()
187          << " id=\"" << this->getId() << "\" "
188          << SuperClassAttribute::toString() << ">" << std::endl;
189      if (!this->hasChild())
190      {
191         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
192      }
193      else
194      {
195
196#define DECLARE_NODE(Name_, name_)    \
197   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
198   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
199#define DECLARE_NODE_PAR(Name_, name_)
200#include "node_type.conf"
201
202      }
203
204      oss << "</" << CContext::GetName() << " >";
205
206      return (oss.str());
207   }
208
209   //----------------------------------------------------------------
210
211   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
212   {
213#define DECLARE_NODE(Name_, name_)    \
214   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
215     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
216#define DECLARE_NODE_PAR(Name_, name_)
217#include "node_type.conf"
218   }
219
220   //----------------------------------------------------------------
221
222   bool CContext::hasChild(void) const
223   {
224      return (
225#define DECLARE_NODE(Name_, name_)    \
226   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
227#define DECLARE_NODE_PAR(Name_, name_)
228#include "node_type.conf"
229      false);
230}
231
232   //----------------------------------------------------------------
233
234   void CContext::solveFieldRefInheritance(bool apply)
235   {
236      if (!this->hasId()) return;
237      vector<CField*> allField = CField::getAll() ;
238//              = CObjectTemplate<CField>::GetAllVectobject(this->getId());
239      std::vector<CField*>::iterator
240         it = allField.begin(), end = allField.end();
241           
242      for (; it != end; it++)
243      {
244         CField* field = *it;
245         field->solveRefInheritance(apply);
246      }
247   }
248
249   //----------------------------------------------------------------
250
251   void CContext::CleanTree(void)
252   {
253#define DECLARE_NODE(Name_, name_) C##Name_##Group::ClearAllAttributes();
254#define DECLARE_NODE_PAR(Name_, name_)
255#include "node_type.conf"
256   }
257   ///---------------------------------------------------------------
258   
259   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm)
260   {
261     hasClient=true ;
262     client = new CContextClient(this,intraComm, interComm) ;
263   } 
264
265   bool CContext::isInitialized(void)
266   {
267     return hasClient ;
268   }
269   
270   void CContext::initServer(MPI_Comm intraComm,MPI_Comm interComm)
271   {
272     hasServer=true ;
273     server = new CContextServer(this,intraComm,interComm) ;
274   } 
275
276   bool CContext::eventLoop(void)
277   {
278     return server->eventLoop() ;
279   } 
280   
281   void CContext::finalize(void)
282   {
283      if (hasClient && !hasServer)
284      {
285         client->finalize() ;
286      }
287      if (hasServer)
288      {
289        closeAllFile() ;
290      }
291   }
292       
293       
294 
295   
296   void CContext::closeDefinition(void)
297   {
298      if (hasClient && !hasServer) sendCloseDefinition() ;
299     
300      solveCalendar();         
301         
302      // Résolution des héritages pour le context actuel.
303      this->solveAllInheritance();
304
305      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
306      this->findEnabledFiles();
307
308       
309      this->processEnabledFiles() ;
310
311/*       
312      //Recherche des champs à sortir (enable à true + niveau de sortie correct)
313      // pour chaque fichier précédemment listé.
314      this->findAllEnabledFields();
315
316      // Résolution des références de grilles pour chacun des champs.
317      this->solveAllGridRef();
318
319      // Traitement des opérations.
320      this->solveAllOperation();
321
322      // Traitement des expressions.
323      this->solveAllExpression();
324*/
325      // Nettoyage de l'arborescence
326      CleanTree();
327      if (hasClient) sendCreateFileHeader() ;
328   }
329   
330   void CContext::findAllEnabledFields(void)
331   {
332     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
333     (void)this->enabledFiles[i]->getEnabledFields();
334   }
335   
336    void CContext::processEnabledFiles(void)
337   {
338     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
339     this->enabledFiles[i]->processEnabledFile();
340   }
341 
342
343   void CContext::solveAllGridRef(void)
344   {
345     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
346     this->enabledFiles[i]->solveEFGridRef();
347   }
348
349   void CContext::solveAllOperation(void)
350   {
351      for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
352      this->enabledFiles[i]->solveEFOperation();
353   }
354
355   void CContext::solveAllExpression(void)
356   {
357      for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
358      this->enabledFiles[i]->solveEFExpression();
359   }
360   
361   void CContext::solveAllInheritance(bool apply)
362   {
363     // Résolution des héritages descendants (càd des héritages de groupes)
364     // pour chacun des contextes.
365      solveDescInheritance(apply);
366
367     // Résolution des héritages par référence au niveau des fichiers.
368      const vector<CFile*> allFiles=CFile::getAll() ;
369
370      for (unsigned int i = 0; i < allFiles.size(); i++)
371         allFiles[i]->solveFieldRefInheritance(apply);
372   }
373
374   void CContext::findEnabledFiles(void)
375   {
376      const std::vector<CFile*> allFiles = CFile::getAll();
377
378      for (unsigned int i = 0; i < allFiles.size(); i++)
379         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
380         {
381            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
382               enabledFiles.push_back(allFiles[i]);
383         }
384         else enabledFiles.push_back(allFiles[i]); // otherwise true by default
385               
386
387      if (enabledFiles.size() == 0)
388         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
389               << getId() << "\" !");
390   }
391
392   void CContext::closeAllFile(void)
393   {
394     std::vector<CFile*>::const_iterator
395            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
396         
397     for (; it != end; it++)
398     {
399       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
400       (*it)->close();
401     }
402   }
403   
404   bool CContext::dispatchEvent(CEventServer& event)
405   {
406     
407      if (SuperClass::dispatchEvent(event)) return true ;
408      else
409      {
410        switch(event.type)
411        {
412           case EVENT_ID_CLOSE_DEFINITION :
413             recvCloseDefinition(event) ;
414             return true ;
415             break ;
416           case EVENT_ID_UPDATE_CALENDAR :
417             recvUpdateCalendar(event) ;
418             return true ;
419             break ;
420           case EVENT_ID_CREATE_FILE_HEADER :
421             recvCreateFileHeader(event) ;
422             return true ;
423             break ;
424           default :
425             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
426                    <<"Unknown Event") ;
427           return false ;
428         }
429      }
430   }
431   
432   void CContext::sendCloseDefinition(void)
433   {
434
435     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION) ;   
436     if (client->isServerLeader())
437     {
438       CMessage msg ;
439       msg<<this->getId() ;
440       event.push(client->getServerLeader(),1,msg) ;
441       client->sendEvent(event) ;
442     }
443     else client->sendEvent(event) ;
444   }
445   
446   void CContext::recvCloseDefinition(CEventServer& event)
447   {
448     
449      CBufferIn* buffer=event.subEvents.begin()->buffer;
450      string id;
451      *buffer>>id ;
452      get(id)->closeDefinition() ;
453   }
454   
455   void CContext::sendUpdateCalendar(int step)
456   {
457     if (!hasServer)
458     {
459       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR) ;   
460       if (client->isServerLeader())
461       {
462         CMessage msg ;
463         msg<<this->getId()<<step ;
464         event.push(client->getServerLeader(),1,msg) ;
465         client->sendEvent(event) ;
466       }
467       else client->sendEvent(event) ;
468     }
469   }
470   
471   void CContext::recvUpdateCalendar(CEventServer& event)
472   {
473     
474      CBufferIn* buffer=event.subEvents.begin()->buffer;
475      string id;
476      *buffer>>id ;
477      get(id)->recvUpdateCalendar(*buffer) ;
478   }
479   
480   void CContext::recvUpdateCalendar(CBufferIn& buffer)
481   {
482      int step ;
483      buffer>>step ;
484      updateCalendar(step) ;
485   }
486   
487   void CContext::sendCreateFileHeader(void)
488   {
489
490     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER) ;   
491     if (client->isServerLeader())
492     {
493       CMessage msg ;
494       msg<<this->getId() ;
495       event.push(client->getServerLeader(),1,msg) ;
496       client->sendEvent(event) ;
497     }
498     else client->sendEvent(event) ;
499   }
500   
501   void CContext::recvCreateFileHeader(CEventServer& event)
502   {
503     
504      CBufferIn* buffer=event.subEvents.begin()->buffer;
505      string id;
506      *buffer>>id ;
507      get(id)->recvCreateFileHeader(*buffer) ;
508   }
509   
510   void CContext::recvCreateFileHeader(CBufferIn& buffer)
511   {
512      createFileHeader() ;
513   }
514   
515   void CContext::updateCalendar(int step)
516   {
517      info(50)<<"updateCalendar : before : "<<calendar->getCurrentDate()<<endl ;
518      calendar->update(step) ;
519      info(50)<<"updateCalendar : after : "<<calendar->getCurrentDate()<<endl ;
520   }
521 
522   void CContext::createFileHeader(void )
523   {
524      vector<CFile*>::const_iterator it ;
525         
526      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
527      {
528         (*it)->initFile();
529      }
530   } 
531   
532   CContext* CContext::getCurrent(void)
533   {
534     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get() ;
535   }
536   
537   void CContext::setCurrent(const string& id)
538   {
539     CObjectFactory::SetCurrentContextId(id);
540     CGroupFactory::SetCurrentContextId(id);
541   }
542   
543  CContext* CContext::create(const StdString& id)
544  {
545    CContext::setCurrent(id) ;
546 
547    bool hasctxt = CContext::has(id);
548    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
549    getRoot() ;
550    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
551
552#define DECLARE_NODE(Name_, name_) \
553    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
554#define DECLARE_NODE_PAR(Name_, name_)
555#include "node_type.conf"
556
557    return (context);
558  }
559} // namespace xios
Note: See TracBrowser for help on using the repository browser.