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

Last change on this file since 509 was 509, checked in by mhnguyen, 9 years ago

Implementing buffer size auto-detection for mode client -server

+) Process xml tree in client side then send all the information to server
+) Only information enabled fields in enabled files are sent to server
+) Some important change in structure of code which must be refactored

Test
+) On Curie
+) Only mode client-server
+) Passed for all tests

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