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

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

Convert more attributes to use the new duration type:

  • field: freq_op and freq_offset
  • file: output_freq, sync_freq and split_freq.

Remember that you now have to use the "xios_duration" type instead of strings to get/set those attributes through the Fortran interface.

  • 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.0 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 + sync_freq.getValue() < 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      lastSync=new CDate(currentDate) ;
210      lastSplit=new CDate(currentDate) ;
211      isOpen=false ;
212
213      allDomainEmpty=true ;
214      set<CDomain*> setDomain ;
215
216      std::vector<CField*>::iterator it, end = this->enabledFields.end();
217      for (it = this->enabledFields.begin() ;it != end; it++)
218      {
219         CField* field = *it;
220         allDomainEmpty&=field->grid->domain->isEmpty() ;
221         setDomain.insert(field->grid->domain) ;
222      }
223      nbDomain=setDomain.size() ;
224
225      // create sub communicator for file
226      int color=allDomainEmpty?0:1 ;
227      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
228      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
229      //
230
231    }
232
233    //! Verify state of a file
234    void CFile::checkFile(void)
235    {
236      if (!isOpen) createHeader() ;
237      checkSync() ;
238      checkSplit() ;
239    }
240
241
242    /*!
243    \brief Verify if synchronisation should be done
244        If syn option is enabled, syn frequence and current time will be used to
245    calculate the moment to syn file(s)
246    \return True if it is the moment to synchronize file, otherwise false
247    */
248   bool CFile::checkSync(void)
249   {
250     CContext* context = CContext::getCurrent() ;
251     CDate& currentDate=context->calendar->getCurrentDate() ;
252     if (!sync_freq.isEmpty())
253     {
254       if (*lastSync + sync_freq.getValue() <= currentDate)
255       {
256         *lastSync=currentDate ;
257         data_out->syncFile() ;
258         return true ;
259        }
260      }
261      return false ;
262    }
263
264    /*!
265    \brief Verify if splitting should be done
266        If split option is enabled, split frequence and current time will be used to
267    calculate the moment to split file
268    \return True if it is the moment to split file, otherwise false
269    */
270    bool CFile::checkSplit(void)
271    {
272      CContext* context = CContext::getCurrent() ;
273      CDate& currentDate=context->calendar->getCurrentDate() ;
274      if (!split_freq.isEmpty())
275      {
276        if (currentDate > *lastSplit + split_freq.getValue())
277        {
278          *lastSplit = *lastSplit + split_freq.getValue();
279          std::vector<CField*>::iterator it, end = this->enabledFields.end();
280          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
281          createHeader() ;
282          return true ;
283        }
284      }
285      return false ;
286    }
287
288   /*!
289   \brief Create header of netcdf file
290   There are some information to fill in header of each netcdf.
291   */
292   void CFile::createHeader(void)
293   {
294      CContext* context = CContext::getCurrent() ;
295      CContextServer* server=context->server ;
296
297      if (!allDomainEmpty)
298      {
299         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
300         StdOStringStream oss;
301         oss << filename;
302         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
303
304         if (!split_freq.isEmpty())
305         {
306           string splitFormat ;
307           if (split_freq_format.isEmpty())
308           {
309             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
310             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
311             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
312             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
313             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
314             else splitFormat = "%y";
315           }
316           else splitFormat=split_freq_format ;
317           oss << "_" << lastSplit->getStr(splitFormat)
318               << "-" << (*lastSplit + (split_freq.getValue() - 1 * Second)).getStr(splitFormat);
319         }
320
321        bool append = !this->append.isEmpty() && this->append.getValue();
322       
323         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
324
325         bool multifile=true ;
326         if (!type.isEmpty())
327         {
328           if (type==type_attr::one_file) multifile=false ;
329           else if (type==type_attr::multiple_file) multifile=true ;
330
331         }
332#ifndef USING_NETCDF_PAR
333         if (!multifile)
334         {
335            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
336            multifile=true ;
337          }
338#endif
339         if (multifile)
340         {
341            int commSize, commRank ;
342            MPI_Comm_size(fileComm,&commSize) ;
343            MPI_Comm_rank(fileComm,&commRank) ;
344
345            if (server->intraCommSize > 1)
346            {
347              oss << "_"  ;
348              int width=0 ; int n=commSize-1 ;
349              while(n != 0) { n=n/10 ; width++ ;}
350              if (!min_digits.isEmpty())
351                if (width<min_digits) width=min_digits ;
352              oss.width(width) ;
353              oss.fill('0') ;
354              oss<<right<< commRank;
355            }
356         }
357         oss << ".nc";
358
359         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
360
361         if (isOpen) data_out->closeFile();
362
363        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, useClassicFormat,
364                                                              fileComm, multifile, isCollective));
365        isOpen = true;
366
367        data_out->writeFile(CFile::get(this));
368
369        // Do not recreate the file structure if opening an existing file
370        if (!data_out->IsInAppendMode())
371        {
372          std::vector<CField*>::iterator it, end = this->enabledFields.end();
373          for (it = this->enabledFields.begin(); it != end; it++)
374          {
375            CField* field = *it;
376            this->data_out->writeFieldGrid(field);
377          }
378          this->data_out->writeTimeDimension();
379
380          for (it = this->enabledFields.begin(); it != end; it++)
381          {
382            CField* field = *it;
383            this->data_out->writeField(field);
384          }
385
386          vector<CVariable*> listVars = getAllVariables() ;
387          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
388            this->data_out->writeAttribute(*it);
389
390          this->data_out->definition_end();
391        }
392      }
393   }
394
395   //! Close file
396   void CFile::close(void)
397   {
398     delete lastSync ;
399     delete lastSplit ;
400     if (!allDomainEmpty)
401       if (isOpen)
402       {
403         this->data_out->closeFile();
404       }
405      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
406   }
407   //----------------------------------------------------------------
408
409   /*!
410   \brief Parse xml file and write information into file object
411   \param [in] node xmld node corresponding in xml file
412   */
413   void CFile::parse(xml::CXMLNode & node)
414   {
415      SuperClass::parse(node);
416
417      if (node.goToChildElement())
418      {
419        do
420        {
421           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
422           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
423        } while (node.goToNextElement()) ;
424        node.goToParentElement();
425      }
426
427   }
428   //----------------------------------------------------------------
429
430   /*!
431   \brief Represent a file in form of string with all its info
432   \return String
433   */
434   StdString CFile::toString(void) const
435   {
436      StdOStringStream oss;
437
438      oss << "<" << CFile::GetName() << " ";
439      if (this->hasId())
440         oss << " id=\"" << this->getId() << "\" ";
441      oss << SuperClassAttribute::toString() << ">" << std::endl;
442      if (this->getVirtualFieldGroup() != NULL)
443         oss << *this->getVirtualFieldGroup() << std::endl;
444      oss << "</" << CFile::GetName() << " >";
445      return (oss.str());
446   }
447
448   //----------------------------------------------------------------
449
450   /*!
451   \brief Find all inheritace among objects in a file.
452   \param [in] apply (true) write attributes of parent into ones of child if they are empty
453                     (false) write attributes of parent into a new container of child
454   \param [in] parent
455   */
456   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
457   {
458      SuperClassAttribute::setAttributes(parent,apply);
459      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
460      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
461   }
462
463   //----------------------------------------------------------------
464
465//   void CFile::processEnabledFile(void)
466//   {
467//     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
468//                                       <<"File attribute <<output_freq>> is undefined");
469//     solveFieldRefInheritance(true) ;
470//     getEnabledFields() ;
471//     processEnabledFields() ;
472//   }
473
474//   void CFile::processEnabledFields(void)
475//   {
476//      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
477//      {
478//        this->enabledFields[i]->processEnabledField() ;
479//      }
480//   }
481
482   /*!
483   \brief Resolve all reference of active fields.
484      In order to know exactly which data each active field has, a search for all its
485   reference to find its parents or/and its base reference object must be done. Moreover
486   during this search, there are some information that can only be sent to server AFTER
487   all information of active fields are created on server side, e.g: checking mask or index
488   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
489   */
490   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
491   {
492     int size = this->enabledFields.size();
493     for (int i = 0; i < size; ++i)
494     {
495       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
496     }
497   }
498
499   /*!
500   \brief Contruct all expression related to active fields.
501      Each field can do some expressions which appear on the xml file, and itself can be
502   a result of an expression among some other fields. This function builds all possible expression
503   relating to active fields.
504   */
505   void CFile::buildAllExpressionOfEnabledFields()
506   {
507     int size = this->enabledFields.size();
508     for (int i = 0; i < size; ++i)
509     {
510       this->enabledFields[i]->buildAllExpressionEnabledField();
511     }
512   }
513
514   void CFile::solveFieldRefInheritance(bool apply)
515   {
516      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
517      std::vector<CField*> allF = this->getAllFields();
518      for (unsigned int i = 0; i < allF.size(); i++)
519         allF[i]->solveRefInheritance(apply);
520   }
521
522   //----------------------------------------------------------------
523
524   void CFile::solveEFGridRef(void)
525   {
526      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
527         this->enabledFields[i]->solveGridReference();
528   }
529
530   //----------------------------------------------------------------
531
532   void CFile::solveEFOperation(void)
533   {
534      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
535         this->enabledFields[i]->solveOperation();
536   }
537
538   void CFile::solveEFExpression(void)
539   {
540      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
541         this->enabledFields[i]->buildExpression();
542   }
543
544   /*!
545   \brief Add a field into file.
546      A field is added into file and it will be written out if the file is enabled and
547   level of this field is smaller than level_output. A new field won't be created if one
548   with id has already existed
549   \param [in] id String identity of new field
550   \return Pointer to added (or already existed) field
551   */
552   CField* CFile::addField(const string& id)
553   {
554     return vFieldGroup->createChild(id) ;
555   }
556
557   /*!
558   \brief Add a field group into file.
559      A field group is added into file and it will play a role as parents for fields.
560   A new field group won't be created if one with id has already existed
561   \param [in] id String identity of new field group
562   \return Pointer to added (or already existed) field group
563   */
564   CFieldGroup* CFile::addFieldGroup(const string& id)
565   {
566     return vFieldGroup->createChildGroup(id) ;
567   }
568
569   /*!
570   \brief Add a variable into file.
571      A variable is added into file and if one with id has already existed, pointer to
572   it will be returned.
573      Variable as long as attributes are information container of file.
574   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
575   to fill in (extra) information for a file.
576   \param [in] id String identity of new variable
577   \return Pointer to added (or already existed) variable
578   */
579   CVariable* CFile::addVariable(const string& id)
580   {
581     return vVariableGroup->createChild(id) ;
582   }
583
584   /*!
585   \brief Add a variable group into file.
586      A variable group is added into file and it will play a role as parents for variables.
587   A new variable group won't be created if one with id has already existed
588   \param [in] id String identity of new variable group
589   \return Pointer to added (or already existed) variable group
590   */
591   CVariableGroup* CFile::addVariableGroup(const string& id)
592   {
593     return vVariableGroup->createChildGroup(id) ;
594   }
595
596   /*!
597   \brief Send a message to create a field on server side
598   \param[in] id String identity of field that will be created on server
599   */
600   void CFile::sendAddField(const string& id)
601   {
602    CContext* context=CContext::getCurrent() ;
603
604    if (! context->hasServer )
605    {
606       CContextClient* client=context->client ;
607
608       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;
609       if (client->isServerLeader())
610       {
611         CMessage msg ;
612         msg<<this->getId() ;
613         msg<<id ;
614         event.push(client->getServerLeader(),1,msg) ;
615         client->sendEvent(event) ;
616       }
617       else client->sendEvent(event) ;
618    }
619
620   }
621
622   /*!
623   \brief Send a message to create a field group on server side
624   \param[in] id String identity of field group that will be created on server
625   */
626   void CFile::sendAddFieldGroup(const string& id)
627   {
628    CContext* context=CContext::getCurrent() ;
629    if (! context->hasServer )
630    {
631       CContextClient* client=context->client ;
632
633       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;
634       if (client->isServerLeader())
635       {
636         CMessage msg ;
637         msg<<this->getId() ;
638         msg<<id ;
639         event.push(client->getServerLeader(),1,msg) ;
640         client->sendEvent(event) ;
641       }
642       else client->sendEvent(event) ;
643    }
644
645   }
646
647   /*!
648   \brief Receive a message annoucing the creation of a field on server side
649   \param[in] event Received event
650   */
651   void CFile::recvAddField(CEventServer& event)
652   {
653
654      CBufferIn* buffer=event.subEvents.begin()->buffer;
655      string id;
656      *buffer>>id ;
657      get(id)->recvAddField(*buffer) ;
658   }
659
660   /*!
661   \brief Receive a message annoucing the creation of a field on server side
662   \param[in] buffer Buffer containing message
663   */
664   void CFile::recvAddField(CBufferIn& buffer)
665   {
666      string id ;
667      buffer>>id ;
668      addField(id) ;
669   }
670
671   /*!
672   \brief Receive a message annoucing the creation of a field group on server side
673   \param[in] event Received event
674   */
675   void CFile::recvAddFieldGroup(CEventServer& event)
676   {
677
678      CBufferIn* buffer=event.subEvents.begin()->buffer;
679      string id;
680      *buffer>>id ;
681      get(id)->recvAddFieldGroup(*buffer) ;
682   }
683
684   /*!
685   \brief Receive a message annoucing the creation of a field group on server side
686   \param[in] buffer Buffer containing message
687   */
688   void CFile::recvAddFieldGroup(CBufferIn& buffer)
689   {
690      string id ;
691      buffer>>id ;
692      addFieldGroup(id) ;
693   }
694
695   /*!
696   \brief Send messages to duplicate all variables on server side
697      Because each variable has also its attributes. So first thing to do is replicate
698   all these attributes on server side. Because variable can have a value, the second thing
699   is to duplicate this value on server, too.
700   */
701   void CFile::sendAddAllVariables()
702   {
703     if (!getAllVariables().empty())
704     {
705       // Firstly, it's necessary to add virtual variable group
706       sendAddVariableGroup(getVirtualVariableGroup()->getId());
707
708       // Okie, now we can add to this variable group
709       std::vector<CVariable*> allVar = getAllVariables();
710       std::vector<CVariable*>::const_iterator it = allVar.begin();
711       std::vector<CVariable*>::const_iterator itE = allVar.end();
712
713       for (; it != itE; ++it)
714       {
715         this->sendAddVariable((*it)->getId());
716         (*it)->sendAllAttributesToServer();
717         (*it)->sendValue();
718       }
719     }
720   }
721
722   /*!
723   \brief Send a message to create a variable on server side
724      A variable always belongs to a variable group
725   \param[in] id String identity of variable that will be created on server
726   */
727   void CFile::sendAddVariable(const string& id)
728   {
729    CContext* context=CContext::getCurrent() ;
730
731    if (! context->hasServer )
732    {
733       CContextClient* client=context->client ;
734
735       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;
736       if (client->isServerLeader())
737       {
738         CMessage msg ;
739         msg<<this->getId() ;
740         msg<<id ;
741         event.push(client->getServerLeader(),1,msg) ;
742         client->sendEvent(event) ;
743       }
744       else client->sendEvent(event) ;
745    }
746
747   }
748
749   /*!
750   \brief Send a message to create a variable group on server side
751   \param[in] id String identity of variable group that will be created on server
752   */
753   void CFile::sendAddVariableGroup(const string& id)
754   {
755    CContext* context=CContext::getCurrent() ;
756    if (! context->hasServer )
757    {
758       CContextClient* client=context->client ;
759
760       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;
761       if (client->isServerLeader())
762       {
763         CMessage msg ;
764         msg<<this->getId() ;
765         msg<<id ;
766         event.push(client->getServerLeader(),1,msg) ;
767         client->sendEvent(event) ;
768       }
769       else client->sendEvent(event) ;
770    }
771
772   }
773
774   /*!
775   \brief Receive a message annoucing the creation of a variable on server side
776   \param[in] event Received event
777   */
778   void CFile::recvAddVariable(CEventServer& event)
779   {
780
781      CBufferIn* buffer=event.subEvents.begin()->buffer;
782      string id;
783      *buffer>>id ;
784      get(id)->recvAddVariable(*buffer) ;
785   }
786
787   /*!
788   \brief Receive a message annoucing the creation of a variable on server side
789   \param[in] buffer Buffer containing message
790   */
791   void CFile::recvAddVariable(CBufferIn& buffer)
792   {
793      string id ;
794      buffer>>id ;
795      addVariable(id) ;
796   }
797
798   /*!
799   \brief Receive a message annoucing the creation of a variable group on server side
800   \param[in] event Received event
801   */
802   void CFile::recvAddVariableGroup(CEventServer& event)
803   {
804
805      CBufferIn* buffer=event.subEvents.begin()->buffer;
806      string id;
807      *buffer>>id ;
808      get(id)->recvAddVariableGroup(*buffer) ;
809   }
810
811   /*!
812   \brief Receive a message annoucing the creation of a variable group on server side
813   \param[in] buffer Buffer containing message
814   */
815   void CFile::recvAddVariableGroup(CBufferIn& buffer)
816   {
817      string id ;
818      buffer>>id ;
819      addVariableGroup(id) ;
820   }
821
822   /*!
823     \brief Sending all active (enabled) fields from client to server.
824   Each field is identified uniquely by its string identity. Not only should we
825   send the id to server but also we need to send ids of reference domain and reference axis.
826   With these two id, it's easier to make reference to grid where all data should be written.
827   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
828   */
829   void CFile::sendEnabledFields()
830   {
831     int size = this->enabledFields.size();
832     CField* fieldPtr(0);
833     for (int i = 0; i < size; ++i)
834     {
835       fieldPtr = this->enabledFields[i];
836       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
837       this->sendAddField(fieldPtr->getId());
838       fieldPtr->sendAllAttributesToServer();
839       fieldPtr->sendAddAllVariables();
840     }
841   }
842
843   /*!
844   \brief Dispatch event received from client
845      Whenever a message is received in buffer of server, it will be processed depending on
846   its event type. A new event type should be added in the switch list to make sure
847   it processed on server side.
848   \param [in] event: Received message
849   */
850   bool CFile::dispatchEvent(CEventServer& event)
851   {
852      if (SuperClass::dispatchEvent(event)) return true ;
853      else
854      {
855        switch(event.type)
856        {
857           case EVENT_ID_ADD_FIELD :
858             recvAddField(event) ;
859             return true ;
860             break ;
861
862           case EVENT_ID_ADD_FIELD_GROUP :
863             recvAddFieldGroup(event) ;
864             return true ;
865             break ;
866
867            case EVENT_ID_ADD_VARIABLE :
868             recvAddVariable(event) ;
869             return true ;
870             break ;
871
872           case EVENT_ID_ADD_VARIABLE_GROUP :
873             recvAddVariableGroup(event) ;
874             return true ;
875             break ;
876           default :
877              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
878           return false ;
879        }
880      }
881   }
882
883
884
885
886   ///---------------------------------------------------------------
887
888} // namespace xios
Note: See TracBrowser for help on using the repository browser.