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

Last change on this file since 528 was 528, checked in by rlacroix, 8 years ago

Add the ability to append data to existing output file(s).

By default existing file(s) will still be overwritten. Set the new file attribute "append" to true if you wish to append data to existing NetCDF file(s).

Note that the append mode is currently not supported when file splitting is used and that the structure of the output file cannot be changed.

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