source: XIOS/trunk/src/node/file.cpp @ 526

Last change on this file since 526 was 526, checked in by rlacroix, 9 years ago

Convert some attributes to enumerations:

  • file: par_access
  • context: calendar_type

Those changes should have no effect on existing XML configuration files and ensure that a proper error message is always displayed during parsing if the value is not supported.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 28.1 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "data_output.hpp"
8#include "context.hpp"
9#include "context_server.hpp"
10#include "nc4_data_output.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xmlioserver_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
19namespace xios {
20
21   /// ////////////////////// Définitions ////////////////////// ///
22
23   CFile::CFile(void)
24      : CObjectTemplate<CFile>(), CFileAttributes()
25      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
26   {
27     setVirtualFieldGroup() ;
28     setVirtualVariableGroup() ;
29   }
30
31   CFile::CFile(const StdString & id)
32      : CObjectTemplate<CFile>(id), CFileAttributes()
33      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
34    {
35      setVirtualFieldGroup() ;
36      setVirtualVariableGroup() ;
37    }
38
39   CFile::~CFile(void)
40   { /* Ne rien faire de plus */ }
41
42   ///---------------------------------------------------------------
43  //! Get name of file
44   StdString CFile::GetName(void)   { return (StdString("file")); }
45   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
46   ENodeType CFile::GetType(void)   { return (eFile); }
47
48   //----------------------------------------------------------------
49   /*!
50   \brief Get data that will be written out.
51   Each enabled file in xml represents a physical netcdf file.
52   This function allows to access to data to be written out into netcdf file
53   \return data written out.
54   */
55   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
56   {
57      return (data_out);
58   }
59
60   /*!
61   \brief Get virtual field group
62      In each file, there always exists a field group which is the ancestor of all
63   fields in the file. This is considered be virtual because it is created automatically during
64   file initialization and it normally doesn't appear on xml file
65   \return Pointer to field group
66   */
67   CFieldGroup* CFile::getVirtualFieldGroup(void) const
68   {
69      return (this->vFieldGroup);
70   }
71
72   /*!
73   \brief Get virtual variable group
74      In each file, there always exists a variable group which is the ancestor of all
75   variable in the file. This is considered be virtual because it is created automatically during
76   file initialization and it normally doesn't appear on xml file
77   \return Pointer to variable group
78   */
79   CVariableGroup* CFile::getVirtualVariableGroup(void) const
80   {
81      return (this->vVariableGroup);
82   }
83
84   //! Get all fields of a file
85   std::vector<CField*> CFile::getAllFields(void) const
86   {
87      return (this->vFieldGroup->getAllChildren());
88   }
89
90   //! Get all variables of a file
91   std::vector<CVariable*> CFile::getAllVariables(void) const
92   {
93      return (this->vVariableGroup->getAllChildren());
94   }
95
96   //----------------------------------------------------------------
97   /*!
98   \brief Get all enabled fields of file
99      A field is considered to be enabled if it fullfil these conditions: it is enabled, inside a enabled file
100   and its own level is not larger than file output level.
101   \param [in] default_outputlevel default value output level of file
102   \param [in] default_level default value level of field
103   \param [in] default_enabled flag determine by default if field is enabled
104   \return Vector of pointers of enabled fields
105   */
106   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel,
107                                                int default_level,
108                                                bool default_enabled)
109   {
110      if (!this->enabledFields.empty())
111         return (this->enabledFields);
112
113      const int _outputlevel =
114         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
115      std::vector<CField*>::iterator it;
116      this->enabledFields = this->getAllFields();
117
118      std::vector<CField*> newEnabledFields;
119
120      for ( it = this->enabledFields.begin() ; it != this->enabledFields.end(); it++ )
121      {
122         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est défini ...
123         {
124            if (! (*it)->enabled.getValue()) continue;
125//            { it--; this->enabledFields.erase(it+1); continue; }
126         }
127         else // Si l'attribut 'enabled' n'est pas défini ...
128         {
129            if (!default_enabled) continue ;
130//            { it--; this->enabledFields.erase(it+1); continue; }
131         }
132
133         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est défini ...
134         {
135            if ((*it)->level.getValue() > _outputlevel) continue ;
136//            { it--; this->enabledFields.erase(it+1); continue; }
137         }
138         else // Si l'attribut 'level' n'est pas défini ...
139         {
140            if (default_level > _outputlevel) continue ;
141//            { it--; this->enabledFields.erase(it+1); continue; }
142         }
143
144//         CField* field_tmp=(*it).get() ;
145//         shared_ptr<CField> sptfield=*it ;
146//         field_tmp->refObject.push_back(sptfield) ;
147         newEnabledFields.push_back(*it) ;
148         // Le champ est finalement actif, on y ajoute sa propre reference.
149//         (*it)->refObject.push_back(*it);
150         // Le champ est finalement actif, on y ajoute la référence au champ de base.
151         (*it)->setRelFile(CFile::get(this));
152//         (*it)->baseRefObject->refObject.push_back(*it);
153         // A faire, ajouter les references intermediaires...
154      }
155      enabledFields=newEnabledFields ;
156
157      return (this->enabledFields);
158   }
159
160   //----------------------------------------------------------------
161   //! Change virtual field group to a new one
162   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
163   {
164      this->vFieldGroup = newVFieldGroup;
165   }
166
167   //! Change virtual variable group to new one
168   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
169   {
170      this->vVariableGroup = newVVariableGroup;
171   }
172
173   //----------------------------------------------------------------
174   //! Create virtual field group, which is done normally on initializing file
175   void CFile::setVirtualFieldGroup(void)
176   {
177      this->setVirtualFieldGroup(CFieldGroup::create());
178   }
179
180   //! Create virtual variable group, which is done normally on initializing file
181   void CFile::setVirtualVariableGroup(void)
182   {
183      this->setVirtualVariableGroup(CVariableGroup::create());
184   }
185
186   //----------------------------------------------------------------
187   bool CFile::isSyncTime(void)
188   {
189     CContext* context = CContext::getCurrent() ;
190     CDate& currentDate=context->calendar->getCurrentDate() ;
191     if (! sync_freq.isEmpty())
192     {
193       if (*lastSync+syncFreq < currentDate)
194       {
195         *lastSync=currentDate ;
196         return true ;
197        }
198      }
199      return false ;
200    }
201
202   //! Initialize a file in order to write into it
203   void CFile::initFile(void)
204   {
205      CContext* context = CContext::getCurrent() ;
206      CDate& currentDate=context->calendar->getCurrentDate() ;
207      CContextServer* server=context->server ;
208
209      if (! sync_freq.isEmpty()) syncFreq = CDuration::FromString(sync_freq.getValue());
210      if (! split_freq.isEmpty()) splitFreq = CDuration::FromString(split_freq.getValue());
211      if (! output_freq.isEmpty()) outputFreq = CDuration::FromString(output_freq.getValue());
212      lastSync=new CDate(currentDate) ;
213      lastSplit=new CDate(currentDate) ;
214      isOpen=false ;
215
216      allDomainEmpty=true ;
217      set<CDomain*> setDomain ;
218
219      std::vector<CField*>::iterator it, end = this->enabledFields.end();
220      for (it = this->enabledFields.begin() ;it != end; it++)
221      {
222         CField* field = *it;
223         allDomainEmpty&=field->grid->domain->isEmpty() ;
224         setDomain.insert(field->grid->domain) ;
225      }
226      nbDomain=setDomain.size() ;
227
228      // create sub communicator for file
229      int color=allDomainEmpty?0:1 ;
230      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
231      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
232      //
233
234    }
235
236    //! Verify state of a file
237    void CFile::checkFile(void)
238    {
239      if (!isOpen) createHeader() ;
240      checkSync() ;
241      checkSplit() ;
242    }
243
244
245    /*!
246    \brief Verify if synchronisation should be done
247        If syn option is enabled, syn frequence and current time will be used to
248    calculate the moment to syn file(s)
249    \return True if it is the moment to synchronize file, otherwise false
250    */
251   bool CFile::checkSync(void)
252   {
253     CContext* context = CContext::getCurrent() ;
254     CDate& currentDate=context->calendar->getCurrentDate() ;
255     if (! sync_freq.isEmpty())
256     {
257       if (*lastSync+syncFreq <= currentDate)
258       {
259         *lastSync=currentDate ;
260         data_out->syncFile() ;
261         return true ;
262        }
263      }
264      return false ;
265    }
266
267    /*!
268    \brief Verify if splitting should be done
269        If split option is enabled, split frequence and current time will be used to
270    calculate the moment to split file
271    \return True if it is the moment to split file, otherwise false
272    */
273    bool CFile::checkSplit(void)
274    {
275      CContext* context = CContext::getCurrent() ;
276      CDate& currentDate=context->calendar->getCurrentDate() ;
277      if (! split_freq.isEmpty())
278      {
279        if (currentDate > *lastSplit+splitFreq)
280        {
281          *lastSplit=*lastSplit+splitFreq ;
282          std::vector<CField*>::iterator it, end = this->enabledFields.end();
283          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
284          createHeader() ;
285          return true ;
286        }
287      }
288      return false ;
289    }
290
291   /*!
292   \brief Create header of netcdf file
293   There are some information to fill in header of each netcdf.
294   */
295   void CFile::createHeader(void)
296   {
297      CContext* context = CContext::getCurrent() ;
298      CContextServer* server=context->server ;
299
300      if (!allDomainEmpty)
301      {
302         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
303         StdOStringStream oss;
304         oss << filename;
305         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
306//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
307//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStr("%y_%mo_%d")<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr("%y_%mo_%d");
308         if (!split_freq.isEmpty())
309         {
310           string splitFormat ;
311           if (split_freq_format.isEmpty())
312           {
313             if (splitFreq.second!=0) splitFormat="%y%mo%d%h%mi%s";
314             else if (splitFreq.minute!=0) splitFormat="%y%mo%d%h%mi";
315             else if (splitFreq.hour!=0) splitFormat="%y%mo%d%h";
316             else if (splitFreq.day!=0) splitFormat="%y%mo%d";
317             else if (splitFreq.month!=0) splitFormat="%y%mo";
318             else splitFormat="%y";
319           }
320           else splitFormat=split_freq_format ;
321           oss<<"_"<<lastSplit->getStr(splitFormat)<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr(splitFormat);
322         }
323
324         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
325
326         bool multifile=true ;
327         if (!type.isEmpty())
328         {
329           if (type==type_attr::one_file) multifile=false ;
330           else if (type==type_attr::multiple_file) multifile=true ;
331
332         }
333#ifndef USING_NETCDF_PAR
334         if (!multifile)
335         {
336            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
337            multifile=true ;
338          }
339#endif
340         if (multifile)
341         {
342            int commSize, commRank ;
343            MPI_Comm_size(fileComm,&commSize) ;
344            MPI_Comm_rank(fileComm,&commRank) ;
345
346            if (server->intraCommSize > 1)
347            {
348              oss << "_"  ;
349              int width=0 ; int n=commSize-1 ;
350              while(n != 0) { n=n/10 ; width++ ;}
351              if (!min_digits.isEmpty())
352                if (width<min_digits) width=min_digits ;
353              oss.width(width) ;
354              oss.fill('0') ;
355              oss<<right<< commRank;
356            }
357         }
358         oss << ".nc";
359
360         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
361
362         if (isOpen) data_out->closeFile();
363
364         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, useClassicFormat,
365                                                             fileComm, multifile, isCollective));
366         isOpen=true ;
367
368         data_out->writeFile(CFile::get(this));
369         std::vector<CField*>::iterator it, end = this->enabledFields.end();
370         for (it = this->enabledFields.begin() ;it != end; it++)
371         {
372            CField* field = *it;
373            this->data_out->writeFieldGrid(field);
374         }
375         this->data_out->writeTimeDimension();
376
377         for (it = this->enabledFields.begin() ;it != end; it++)
378         {
379            CField* field = *it;
380            this->data_out->writeField(field);
381         }
382
383         vector<CVariable*> listVars = getAllVariables() ;
384         for (vector<CVariable*>::iterator it = listVars.begin() ;it != listVars.end(); it++) this-> data_out-> writeAttribute(*it) ;
385
386         this->data_out->definition_end();
387      }
388   }
389
390   //! Close file
391   void CFile::close(void)
392   {
393     delete lastSync ;
394     delete lastSplit ;
395     if (!allDomainEmpty)
396       if (isOpen)
397       {
398         this->data_out->closeFile();
399       }
400      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
401   }
402   //----------------------------------------------------------------
403
404   /*!
405   \brief Parse xml file and write information into file object
406   \param [in] node xmld node corresponding in xml file
407   */
408   void CFile::parse(xml::CXMLNode & node)
409   {
410      SuperClass::parse(node);
411
412      if (node.goToChildElement())
413      {
414        do
415        {
416           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
417           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
418        } while (node.goToNextElement()) ;
419        node.goToParentElement();
420      }
421
422   }
423   //----------------------------------------------------------------
424
425   /*!
426   \brief Represent a file in form of string with all its info
427   \return String
428   */
429   StdString CFile::toString(void) const
430   {
431      StdOStringStream oss;
432
433      oss << "<" << CFile::GetName() << " ";
434      if (this->hasId())
435         oss << " id=\"" << this->getId() << "\" ";
436      oss << SuperClassAttribute::toString() << ">" << std::endl;
437      if (this->getVirtualFieldGroup() != NULL)
438         oss << *this->getVirtualFieldGroup() << std::endl;
439      oss << "</" << CFile::GetName() << " >";
440      return (oss.str());
441   }
442
443   //----------------------------------------------------------------
444
445   /*!
446   \brief Find all inheritace among objects in a file.
447   \param [in] apply (true) write attributes of parent into ones of child if they are empty
448                     (false) write attributes of parent into a new container of child
449   \param [in] parent
450   */
451   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
452   {
453      SuperClassAttribute::setAttributes(parent,apply);
454      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
455      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
456   }
457
458   //----------------------------------------------------------------
459
460//   void CFile::processEnabledFile(void)
461//   {
462//     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
463//                                       <<"File attribute <<output_freq>> is undefined");
464//     solveFieldRefInheritance(true) ;
465//     getEnabledFields() ;
466//     processEnabledFields() ;
467//   }
468
469//   void CFile::processEnabledFields(void)
470//   {
471//      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
472//      {
473//        this->enabledFields[i]->processEnabledField() ;
474//      }
475//   }
476
477   /*!
478   \brief Resolve all reference of active fields.
479      In order to know exactly which data each active field has, a search for all its
480   reference to find its parents or/and its base reference object must be done. Moreover
481   during this search, there are some information that can only be sent to server AFTER
482   all information of active fields are created on server side, e.g: checking mask or index
483   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
484   */
485   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
486   {
487     int size = this->enabledFields.size();
488     for (int i = 0; i < size; ++i)
489     {
490       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
491     }
492   }
493
494   /*!
495   \brief Contruct all expression related to active fields.
496      Each field can do some expressions which appear on the xml file, and itself can be
497   a result of an expression among some other fields. This function builds all possible expression
498   relating to active fields.
499   */
500   void CFile::buildAllExpressionOfEnabledFields()
501   {
502     int size = this->enabledFields.size();
503     for (int i = 0; i < size; ++i)
504     {
505       this->enabledFields[i]->buildAllExpressionEnabledField();
506     }
507   }
508
509   void CFile::solveFieldRefInheritance(bool apply)
510   {
511      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
512      std::vector<CField*> allF = this->getAllFields();
513      for (unsigned int i = 0; i < allF.size(); i++)
514         allF[i]->solveRefInheritance(apply);
515   }
516
517   //----------------------------------------------------------------
518
519   void CFile::solveEFGridRef(void)
520   {
521      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
522         this->enabledFields[i]->solveGridReference();
523   }
524
525   //----------------------------------------------------------------
526
527   void CFile::solveEFOperation(void)
528   {
529      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
530         this->enabledFields[i]->solveOperation();
531   }
532
533   void CFile::solveEFExpression(void)
534   {
535      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
536         this->enabledFields[i]->buildExpression();
537   }
538
539   /*!
540   \brief Add a field into file.
541      A field is added into file and it will be written out if the file is enabled and
542   level of this field is smaller than level_output. A new field won't be created if one
543   with id has already existed
544   \param [in] id String identity of new field
545   \return Pointer to added (or already existed) field
546   */
547   CField* CFile::addField(const string& id)
548   {
549     return vFieldGroup->createChild(id) ;
550   }
551
552   /*!
553   \brief Add a field group into file.
554      A field group is added into file and it will play a role as parents for fields.
555   A new field group won't be created if one with id has already existed
556   \param [in] id String identity of new field group
557   \return Pointer to added (or already existed) field group
558   */
559   CFieldGroup* CFile::addFieldGroup(const string& id)
560   {
561     return vFieldGroup->createChildGroup(id) ;
562   }
563
564   /*!
565   \brief Add a variable into file.
566      A variable is added into file and if one with id has already existed, pointer to
567   it will be returned.
568      Variable as long as attributes are information container of file.
569   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
570   to fill in (extra) information for a file.
571   \param [in] id String identity of new variable
572   \return Pointer to added (or already existed) variable
573   */
574   CVariable* CFile::addVariable(const string& id)
575   {
576     return vVariableGroup->createChild(id) ;
577   }
578
579   /*!
580   \brief Add a variable group into file.
581      A variable group is added into file and it will play a role as parents for variables.
582   A new variable group won't be created if one with id has already existed
583   \param [in] id String identity of new variable group
584   \return Pointer to added (or already existed) variable group
585   */
586   CVariableGroup* CFile::addVariableGroup(const string& id)
587   {
588     return vVariableGroup->createChildGroup(id) ;
589   }
590
591   /*!
592   \brief Send a message to create a field on server side
593   \param[in] id String identity of field that will be created on server
594   */
595   void CFile::sendAddField(const string& id)
596   {
597    CContext* context=CContext::getCurrent() ;
598
599    if (! context->hasServer )
600    {
601       CContextClient* client=context->client ;
602
603       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;
604       if (client->isServerLeader())
605       {
606         CMessage msg ;
607         msg<<this->getId() ;
608         msg<<id ;
609         event.push(client->getServerLeader(),1,msg) ;
610         client->sendEvent(event) ;
611       }
612       else client->sendEvent(event) ;
613    }
614
615   }
616
617   /*!
618   \brief Send a message to create a field group on server side
619   \param[in] id String identity of field group that will be created on server
620   */
621   void CFile::sendAddFieldGroup(const string& id)
622   {
623    CContext* context=CContext::getCurrent() ;
624    if (! context->hasServer )
625    {
626       CContextClient* client=context->client ;
627
628       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;
629       if (client->isServerLeader())
630       {
631         CMessage msg ;
632         msg<<this->getId() ;
633         msg<<id ;
634         event.push(client->getServerLeader(),1,msg) ;
635         client->sendEvent(event) ;
636       }
637       else client->sendEvent(event) ;
638    }
639
640   }
641
642   /*!
643   \brief Receive a message annoucing the creation of a field on server side
644   \param[in] event Received event
645   */
646   void CFile::recvAddField(CEventServer& event)
647   {
648
649      CBufferIn* buffer=event.subEvents.begin()->buffer;
650      string id;
651      *buffer>>id ;
652      get(id)->recvAddField(*buffer) ;
653   }
654
655   /*!
656   \brief Receive a message annoucing the creation of a field on server side
657   \param[in] buffer Buffer containing message
658   */
659   void CFile::recvAddField(CBufferIn& buffer)
660   {
661      string id ;
662      buffer>>id ;
663      addField(id) ;
664   }
665
666   /*!
667   \brief Receive a message annoucing the creation of a field group on server side
668   \param[in] event Received event
669   */
670   void CFile::recvAddFieldGroup(CEventServer& event)
671   {
672
673      CBufferIn* buffer=event.subEvents.begin()->buffer;
674      string id;
675      *buffer>>id ;
676      get(id)->recvAddFieldGroup(*buffer) ;
677   }
678
679   /*!
680   \brief Receive a message annoucing the creation of a field group on server side
681   \param[in] buffer Buffer containing message
682   */
683   void CFile::recvAddFieldGroup(CBufferIn& buffer)
684   {
685      string id ;
686      buffer>>id ;
687      addFieldGroup(id) ;
688   }
689
690   /*!
691   \brief Send messages to duplicate all variables on server side
692      Because each variable has also its attributes. So first thing to do is replicate
693   all these attributes on server side. Because variable can have a value, the second thing
694   is to duplicate this value on server, too.
695   */
696   void CFile::sendAddAllVariables()
697   {
698     if (!getAllVariables().empty())
699     {
700       // Firstly, it's necessary to add virtual variable group
701       sendAddVariableGroup(getVirtualVariableGroup()->getId());
702
703       // Okie, now we can add to this variable group
704       std::vector<CVariable*> allVar = getAllVariables();
705       std::vector<CVariable*>::const_iterator it = allVar.begin();
706       std::vector<CVariable*>::const_iterator itE = allVar.end();
707
708       for (; it != itE; ++it)
709       {
710         this->sendAddVariable((*it)->getId());
711         (*it)->sendAllAttributesToServer();
712         (*it)->sendValue();
713       }
714     }
715   }
716
717   /*!
718   \brief Send a message to create a variable on server side
719      A variable always belongs to a variable group
720   \param[in] id String identity of variable that will be created on server
721   */
722   void CFile::sendAddVariable(const string& id)
723   {
724    CContext* context=CContext::getCurrent() ;
725
726    if (! context->hasServer )
727    {
728       CContextClient* client=context->client ;
729
730       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;
731       if (client->isServerLeader())
732       {
733         CMessage msg ;
734         msg<<this->getId() ;
735         msg<<id ;
736         event.push(client->getServerLeader(),1,msg) ;
737         client->sendEvent(event) ;
738       }
739       else client->sendEvent(event) ;
740    }
741
742   }
743
744   /*!
745   \brief Send a message to create a variable group on server side
746   \param[in] id String identity of variable group that will be created on server
747   */
748   void CFile::sendAddVariableGroup(const string& id)
749   {
750    CContext* context=CContext::getCurrent() ;
751    if (! context->hasServer )
752    {
753       CContextClient* client=context->client ;
754
755       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;
756       if (client->isServerLeader())
757       {
758         CMessage msg ;
759         msg<<this->getId() ;
760         msg<<id ;
761         event.push(client->getServerLeader(),1,msg) ;
762         client->sendEvent(event) ;
763       }
764       else client->sendEvent(event) ;
765    }
766
767   }
768
769   /*!
770   \brief Receive a message annoucing the creation of a variable on server side
771   \param[in] event Received event
772   */
773   void CFile::recvAddVariable(CEventServer& event)
774   {
775
776      CBufferIn* buffer=event.subEvents.begin()->buffer;
777      string id;
778      *buffer>>id ;
779      get(id)->recvAddVariable(*buffer) ;
780   }
781
782   /*!
783   \brief Receive a message annoucing the creation of a variable on server side
784   \param[in] buffer Buffer containing message
785   */
786   void CFile::recvAddVariable(CBufferIn& buffer)
787   {
788      string id ;
789      buffer>>id ;
790      addVariable(id) ;
791   }
792
793   /*!
794   \brief Receive a message annoucing the creation of a variable group on server side
795   \param[in] event Received event
796   */
797   void CFile::recvAddVariableGroup(CEventServer& event)
798   {
799
800      CBufferIn* buffer=event.subEvents.begin()->buffer;
801      string id;
802      *buffer>>id ;
803      get(id)->recvAddVariableGroup(*buffer) ;
804   }
805
806   /*!
807   \brief Receive a message annoucing the creation of a variable group on server side
808   \param[in] buffer Buffer containing message
809   */
810   void CFile::recvAddVariableGroup(CBufferIn& buffer)
811   {
812      string id ;
813      buffer>>id ;
814      addVariableGroup(id) ;
815   }
816
817   /*!
818     \brief Sending all active (enabled) fields from client to server.
819   Each field is identified uniquely by its string identity. Not only should we
820   send the id to server but also we need to send ids of reference domain and reference axis.
821   With these two id, it's easier to make reference to grid where all data should be written.
822   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
823   */
824   void CFile::sendEnabledFields()
825   {
826     int size = this->enabledFields.size();
827     CField* fieldPtr(0);
828     for (int i = 0; i < size; ++i)
829     {
830       fieldPtr = this->enabledFields[i];
831       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
832       this->sendAddField(fieldPtr->getId());
833       fieldPtr->sendAllAttributesToServer();
834       fieldPtr->sendAddAllVariables();
835     }
836   }
837
838   /*!
839   \brief Dispatch event received from client
840      Whenever a message is received in buffer of server, it will be processed depending on
841   its event type. A new event type should be added in the switch list to make sure
842   it processed on server side.
843   \param [in] event: Received message
844   */
845   bool CFile::dispatchEvent(CEventServer& event)
846   {
847      if (SuperClass::dispatchEvent(event)) return true ;
848      else
849      {
850        switch(event.type)
851        {
852           case EVENT_ID_ADD_FIELD :
853             recvAddField(event) ;
854             return true ;
855             break ;
856
857           case EVENT_ID_ADD_FIELD_GROUP :
858             recvAddFieldGroup(event) ;
859             return true ;
860             break ;
861
862            case EVENT_ID_ADD_VARIABLE :
863             recvAddVariable(event) ;
864             return true ;
865             break ;
866
867           case EVENT_ID_ADD_VARIABLE_GROUP :
868             recvAddVariableGroup(event) ;
869             return true ;
870             break ;
871           default :
872              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
873           return false ;
874        }
875      }
876   }
877
878
879
880
881   ///---------------------------------------------------------------
882
883} // namespace xios
Note: See TracBrowser for help on using the repository browser.