Diana Software
QModuleFactory.cc
Go to the documentation of this file.
1 #include "QOptions.hh"
2 #include "QMessage.hh"
3 #include "QModuleFactory.hh"
4 #include "QStringHandler.hh"
5 #include "QGeneralFactory.hh"
6 #include "QGlobalRWFactory.hh"
7 #include "QWriter.hh"
8 #include "QReader.hh"
9 #include "QFilter.hh"
10 #include "QDriver.hh"
11 #include "QModule.hh"
12 
13 
14 #include <stdexcept>
15 #include <iostream>
16 #include <fstream>
17 
18 using namespace QStringHandler;
19 
21 
22 QModuleFactory *QModuleFactory::me = 0;
23 
24 // singleton
25  QModuleFactory *QModuleFactory::Get() {
26  if (!me)
27  me = new QModuleFactory();
28  return me;
29  }
30 
31 // dtor
33 }
34 
35 
36 // private ctor; it does nothing
37 QModuleFactory::QModuleFactory() : QNamed("QModuleFactory"), init_done(false){
38 }
39 
41 {
42  std::list<QSequence*>::iterator it;
43  for(it = sequences.begin(); it != sequences.end(); it++)
44  if((*it)->GetName() == s) return *it;
45  return NULL;
46 }
47 
48 void QModuleFactory::LoadLoadable(const std::string& n)
49 {
50  QGlobalRWFactory::GetInstance().LoadPlugin(std::string("L") + n);
51 }
52 
53 // function that creates readers
55 {
56 
57  // dynamic loader
58  QReader* reader = QGeneralFactory::GetInstance().CreateReader(std::string("M") + n,s);
59  if(reader) return reader;
60  else QMessageHandler::Panic(GetName(),std::string("UNKNOWN reader: ") + n);
61  return NULL;
62 }
63 
65 {
66  // dynamic loader
67  QFilter* filter = QGeneralFactory::GetInstance().CreateFilter(std::string("M") + n,s);
68  if(filter) return filter;
69  else QMessageHandler::Panic(GetName(),std::string("UNKNOWN filter: ")+ n);
70  return NULL;
71 }
72 
74 {
75  // dynamic loader
76  QDriver* driver = QGeneralFactory::GetInstance().CreateDriver(std::string("M") + n,s);
77  if(driver) return driver;
78  else QMessageHandler::Panic(GetName(),std::string("UNKNOWN driver: ")+ n);
79  return NULL;
80 }
81 
82 // function that creates writers
84 {
85  // dynamic loader
86  QWriter* writer = QGeneralFactory::GetInstance().CreateWriter(std::string("M") + n,s);
87  if(writer) return writer;
88  else QMessageHandler::Panic(GetName(),std::string("UNKNOWN writer: ") + n);
89  return NULL;
90 }
91 
92 
93 // function that creates real modules
94 QModule* QModuleFactory::CreateModule(const std::string& n, QSequence *s)
95 {
96  // dynamic loader
97  QModule* module = QGeneralFactory::GetInstance().CreateModule(std::string("M") + n,s);
98  if(module) return module;
99  else QMessageHandler::Panic(GetName(),std::string("UNKNOWN module: ")+ n);
100  return NULL;
101 }
102 
103 // initialization of factory and load modules
105  if ( init_done ){
106  return;
107  }
108 
109 
110  std::string fname;
111  std::string line;
112  size_t lineCounter = 0;
113 
114  std::map<std::string,std::string> userConfigFile;
115  try {
116  fname = QOptions::GetInstance().GetString("General.UserConfigFile");
117  } catch(...){
118  }
119  if(!fname.empty()) {
120  std::ifstream in2(fname.c_str());
121 
122  if (!in2.good()) {
123  QMessageHandler::Get()->Send(PanicMsg,"QModuleFactory","User config file \"" + fname +"\" not found. .");
124  }
125  try {
126  lineCounter = 0;
127 
128  while(getline(in2,line)) {
129  lineCounter++;
130  size_t pos;
131  std::string s="";
132 
133  // erase comments
134  pos=line.find('#');
135  if ( pos != std::string::npos )
136  line.erase(pos);
137 
138  // swallow spaces at the beginning of the line
139  line = SwallowSpaces(line);
140  line = RSwallowSpaces(line);
141 
142  // skip blank lines
143  if ( line.empty() )
144  continue;
145 
146  pos = line.find('=');
147  if ( pos != std::string::npos ) {
148  std::string key = line.substr(0,line.find('='));
149  key = SwallowSpaces(key);
150  key = RSwallowSpaces(key);
151  std::string value = line.substr(line.find('=')+1,std::string::npos);
152  value = SwallowSpaces(value);
153  value = RSwallowSpaces(value);
154  userConfigFile[key] = ReplaceCFGVar(value);
155  } else {
156  char cfgerr[128];
157  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)lineCounter,line.c_str());
158  throw std::runtime_error(cfgerr);
159  }
160 
161  }
162  }
163 
164  catch(std::exception& ex) {
165  char buf[512];
166  snprintf(buf,512,"Syntax error in pfg file: %s",ex.what());
167  QMessageHandler::Panic(GetName(),buf);
168  }
169  catch(...) { QMessageHandler::Panic(GetName(),"Syntax error in pfg file"); }
170  }
171  fname = "";
172  fname = QOptions::GetInstance().GetString("General.MainConfigFile");
173  std::ifstream in(fname.c_str());
174  if (!in) {
175  throw std::runtime_error("Cannot find configuration file: " + fname );
176  }
177 
178  // read in file to a string vector instead of dynamically, so it can be modified,
179  // and save line number with each line
180  std::vector<std::pair<std::string, int> > cfgFileLines;
181  int lineno = 1;
182  while(getline(in,line)) {
183  cfgFileLines.push_back(std::make_pair(line, lineno));
184  lineno++;
185  };
186 
187  std::string frameworkSection = "";
188  std::string current_loader = "";
189  std::string current_var = "";
190  std::string current_module="";
191  std::string current_sequence="";
192  std::string current_group="";
193  std::vector<std::pair<std::string, std::string> > current_group_options;
194  std::vector<std::string> alias_files;
195  QBaseModule *p_Module=NULL;
196  QSequence *p_Sequence=NULL;
197 
198  // keep evaluating cfgFileLines.size(), since the number of lines can change
199  for(size_t lineCounter = 0; lineCounter < cfgFileLines.size(); lineCounter++) {
200  std::string line = cfgFileLines[lineCounter].first;
201  int fileLineNum = cfgFileLines[lineCounter].second;
202  size_t pos;
203  std::string s="";
204 
205  // erase comments
206  pos=line.find('#');
207  if ( pos != std::string::npos )
208  line.erase(pos);
209 
210  // swallow spaces at the beginning of the line
211  line = SwallowSpaces(line);
212  line = RSwallowSpaces(line);
213 
214  // skip blank lines
215  if ( line.empty() )
216  continue;
217  // search for the "framework" section
218  if(frameworkSection == "") {
219  if (current_loader != "") {
220  char cfgerr[128];
221  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
222  throw std::runtime_error(cfgerr);
223  }
224  s = line;
225  if( s == "framework") {
226  frameworkSection = "framework";
227  goto end_while;
228  } else {
229  // throw std::runtime_error("Syntax error in configuration file: 1");
230  }
231  } else if (current_loader == "" || current_var == "") {
232  if(line == "endfw") {
233  current_loader = ".";
234  current_var = ".";
235  goto end_while;
236  }
237  s = line.substr(0,line.find(' '));
238  if ( s == "load" ) {
239  current_loader = line.substr(line.find(' ')+1,std::string::npos);
240  LoadLoadable(current_loader);
241  current_loader = "";
242  goto end_while;
243  }
244  else if ( s == "cfgvar" ) {
245  std::string key = line.substr(line.find(' '),std::string::npos);
246  key = key.substr(0,key.find('='));
247  key = SwallowSpaces(key);
248  key = RSwallowSpaces(key);
249  std::string value = line.substr(line.find('=')+1,std::string::npos);
250  value = SwallowSpaces(value);
251  value = RSwallowSpaces(value);
252  QMessageHandler::Get()->Send(DebugMsg,"QModuleFactory","Defined variable \"" + key +"\" value \""+value+"\"");
253  std::string fullname = std::string("CFGVar.")+key;
254 
255  try {
256  QOptions::GetInstance().GetParameter(fullname);
257  }
258  catch(...) {
259  QOptions::GetInstance().SetParameter(fullname,value);
260  }
261 
262  current_var = "";
263  goto end_while;
264  } else if ( s == "groupfile" ) {
265  std::string file_name = line.substr(line.find(' ')+1,std::string::npos);
266  alias_files.push_back(ReplaceCFGVar(file_name));
267  QMessageHandler::Get()->Send(DebugMsg,"QModuleFactory","Using group file \"" + file_name +"\"");
268  goto end_while;
269  } else {
270  char cfgerr[128];
271  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
272  QMessageHandler::Get()->Send(PanicMsg,"QModuleFactory",cfgerr);
273  }
274  }
275  //search for the "sequence" section
276  if ( current_sequence == "") {
277 
278  if (current_module != "") {
279  char cfgerr[128];
280  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
281  throw std::runtime_error(cfgerr);
282  }
283 
284  s = line.substr(0,line.find(' '));
285  if ( s == "sequence" ) {
286  current_sequence = line.substr(line.find(' ') + 1, std::string::npos);
287 
288  // check that sequence does not exist yet
289  if ( FindSequence(current_sequence) != NULL ) {
290  throw std::runtime_error("Sequence: "+current_sequence+" already exist!");
291  }
292  else {
293  if (!p_Sequence) {
294  p_Sequence = new QSequence(current_sequence);
295  p_Sequence->fConfig.fFilename = fname;
296  size_t slashpos = p_Sequence->fConfig.fFilename.find_last_of('/');
297  if(slashpos != std::string::npos) p_Sequence->fConfig.fFilename = p_Sequence->fConfig.fFilename.substr(slashpos+1,std::string::npos);
298  std::string driver = QOptions::GetInstance().GetString("General.Driver");
299  if(!driver.empty()) {
300 
301  QMessageHandler::Get()->Send(InfoMsg,"QModuleFactory","Adding driver \"" + driver +"\"");
302  p_Sequence->p_Driver = CreateDriver(driver, p_Sequence);
303  QOptions::GetInstance().SetParameter(current_sequence,driver,p_Sequence->p_Driver->GetOccurrence(),"enable", true);
304 
305  }
306  } else {
307  char cfgerr[128];
308  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
309  throw std::runtime_error(cfgerr);
310  }
311  sequences.push_back(p_Sequence);
312  goto end_while;
313  }
314 
315  } else {
316  char cfgerr[128];
317  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
318  throw std::runtime_error(cfgerr);
319  }
320  }
321  else {
322  if (current_module == "") {
323  if (line=="endseq") {
324  current_sequence="";
325  p_Sequence = 0;
326  goto end_while;
327  }
328 
329  s = line.substr(0,line.find(' '));
330  if ( s == "module" ) {
331  current_module = line.substr(line.find(' ')+1,std::string::npos);
332  p_Sequence->modules.push_back(CreateModule(current_module, p_Sequence));
333  p_Module = p_Sequence->modules.back();
334  goto end_while;
335  }
336  if ( s == "reader" ) {
337  current_module = line.substr(line.find(' ')+1,std::string::npos);
338  p_Sequence->p_Reader = CreateReader(current_module, p_Sequence);
339  p_Module = p_Sequence->p_Reader;
340  goto end_while;
341  }
342  if ( s == "writer" ) {
343  current_module = line.substr(line.find(' ')+1,std::string::npos);
344  p_Sequence->p_Writer = CreateWriter(current_module, p_Sequence);
345  p_Module = p_Sequence->p_Writer;
346  goto end_while;
347  }
348  if ( s == "filter" ) {
349  current_module = line.substr(line.find(' ')+1,std::string::npos);
350  p_Sequence->modules.push_back(CreateFilter(current_module, p_Sequence));
351  p_Module = p_Sequence->modules.back();
352  goto end_while;
353  }
354  if ( s == "includegroup" ) {
355  current_module = "includegroup";
356  current_group = line.substr(line.find(' ')+1,std::string::npos);
357  goto end_while;
358  }
359  if ( s == "driver" ) {
360  current_module = line.substr(line.find(' ')+1,std::string::npos);
361  p_Sequence->p_Driver = CreateDriver(current_module, p_Sequence);
362  p_Module = p_Sequence->p_Driver;
363  goto end_while;
364  }
365  }
366  else {
367  pos = line.find('=');
368  if ( pos != std::string::npos ) {
369  std::string key = line.substr(0,line.find('='));
370  key = SwallowSpaces(key);
371  key = RSwallowSpaces(key);
372  std::string value = line.substr(line.find('=')+1,std::string::npos);
373  value = SwallowSpaces(value);
374  value = RSwallowSpaces(value);
375 
376  if (current_module == "includegroup") {
377  current_group_options.push_back(make_pair(key, value));
378  } else {
379  // replace vars for module
380  try {
381  std::cout.flush();
382  value = ReplaceCFGVar(value);
383  QOptions::GetInstance().SetParameter(current_sequence,current_module,p_Module->GetOccurrence(),key, value);
384  }
385  catch(QError& err) {
386 
387  char obuf[128];
388  snprintf(obuf,128,"%u",(unsigned int)p_Module->GetOccurrence());
389  std::string upk = current_sequence+"."+current_module+"."+obuf+"."+key;
390  // if not overwritten by user raise exception
391  if(userConfigFile.find(upk) == userConfigFile.end()) {
392  char buf[256];
393  snprintf(buf,256,"Syntax error in cfg file, line %u: %s",(unsigned int)fileLineNum,err.GetDescription().c_str());
394  QMessageHandler::Panic(GetName(),buf);
395  }
396  }
397  catch(std::exception& ex) {
398  char obuf[128];
399  snprintf(obuf,128,"%u",(unsigned int)p_Module->GetOccurrence());
400  std::string upk = current_sequence+"."+current_module+"."+obuf+"."+key;
401  // if not overwritten by user raise exception
402  if(userConfigFile.find(upk) == userConfigFile.end()) {
403  char buf[512];
404  snprintf(buf,512,"Syntax error in cfg file, line %u: %s",(unsigned int)fileLineNum,ex.what());
405  QMessageHandler::Panic(GetName(),buf);
406  }
407  }
408  }
409 
410  goto end_while;
411  }
412  else {
413  if ( line == "endmod") {
414  // if this "module" was a group alias, substitute in the cfg lines now
415  if (current_module == "includegroup") {
416  AddAliasGroup(cfgFileLines, lineCounter, alias_files, current_group, current_group_options);
417  }
418  current_module = "";
419  p_Module = 0;
420  goto end_while;
421  } else {
422  char cfgerr[128];
423  snprintf(cfgerr,128,"Syntax error in cfg file, line %u: \"%s\"",(unsigned int)fileLineNum,line.c_str());
424  throw std::runtime_error(cfgerr);
425  }
426  }
427  }
428  }
429  // label
430 end_while:
431  ;
432 
433  }
434  QOptions::GetInstance().SetFirstSequence(sequences.front()->GetName());
435  QOptions::GetInstance().SetLastSequence(sequences.back()->GetName());
436 
437  // read user file to override parameters
438  std::map<std::string,std::string>::const_iterator up = userConfigFile.begin();
439  while(up != userConfigFile.end()) {
440  QOptions::GetInstance().SetParameter(up->first,QVdt(up->second));
441  up++;
442  }
443  // last step: override parameters with command line options
444  QOptions::GetInstance().ReplaceUserParams();
445 
446  std::stringstream msg;
447  Dump(msg);
448  QMessageHandler::Get()->Send(DebugMsg,"QModuleFactory",msg.str());
449 
450 
451  QOptions::GetInstance().Dump(QMessageHandler::Get()->GetLogFile());
452  // config done
453  init_done = true;
454 }
455 
456 // dump list of sequences and modules
457 void QModuleFactory::Dump(std::ostream& o) {
458  std::list<QSequence* >::iterator it;
459  for( it = sequences.begin(); it != sequences.end(); it++) {
460  (*it)->Dump( o );
461  o << std::endl;
462  }
463 }
464 
465 std::string QModuleFactory::ReplaceCFGVar(const std::string& value)
466 {
467  std::string retstring = value;
468  size_t rightbr = std::string::npos;
469  do {
470  size_t leftbr = retstring.find("${");
471  rightbr = std::string::npos;
472  if(leftbr != std::string::npos) {
473  rightbr = retstring.find_first_of("}");
474  }
475  if(rightbr != std::string::npos) {
476  std::string varname = retstring.substr(leftbr+2,rightbr-leftbr-2);
477  std::string fullname = "CFGVar.";
478  fullname += varname;
479  std::string varval = QOptions::GetInstance().GetParameter(fullname).GetString();
480  retstring.replace(leftbr,rightbr-leftbr+1,varval);
481  }
482  } while(rightbr != std::string::npos);
483  return retstring;
484 }
485 
487  std::vector<std::pair<std::string, int> >& cfgFileLines, int location,
488  const std::vector<std::string>& alias_files, const std::string& group,
489  const std::vector<std::pair<std::string, std::string> >& group_options) {
490  std::vector<std::pair<std::string, int> > lines_to_add;
491  std::vector<std::string>::const_iterator fname;
492  for (fname = alias_files.begin(); fname != alias_files.end(); ++fname) {
493  if ((*fname).empty())
494  continue;
495  bool ingroup = false;
496  std::ifstream in((*fname).c_str());
497  if (!in.good()) {
498  QMessageHandler::Get()->Send(PanicMsg,"QModuleFactory","Group alias file \"" + *fname +"\" not found. .");
499  return;
500  }
501  std::string line;
502  while(getline(in,line)) {
503  // keep moving through file until we get to right group
504  std::string target_line = "group " + group;
505  if (!ingroup && line != target_line)
506  continue;
507  if (line == target_line) {
508  ingroup = true;
509  continue;
510  } else {
511  if (line == "endgroup") {
512  // we've finished the group, so we're done here
513  ingroup = false;
514  break;
515  }
516  // we're in the group and reading files
517  if (line == "endmod") {
518  // we're at the end of a "module", so add in extra options
519  std::vector<std::pair<std::string, std::string> >::const_iterator option;
520  for (option = group_options.begin(); option != group_options.end(); ++option) {
521  lines_to_add.push_back(make_pair((*option).first + "=" + (*option).second, location));
522  }
523  }
524  lines_to_add.push_back(make_pair(line, -1));
525  }
526  }
527  if (ingroup) {
528  QMessageHandler::Get()->Send(PanicMsg,"QModuleFactory","Group file \"" + *fname +"\" is missing an endgroup.");
529  return;
530  }
531  }
532  if (lines_to_add.size())
533  cfgFileLines.insert(cfgFileLines.begin() + location + 1, lines_to_add.begin(), lines_to_add.end());
534  else
535  QMessageHandler::Get()->Send(PanicMsg,"QModuleFactory","Unable to find group \"" + group +"\" in group files, or no group file given.");
536 }
537 
err
Definition: CheckOF.C:114
dm Dump(cout)
#define Q_END_NAMESPACE
Definition: QDiana.hh:22
#define Q_BEGIN_NAMESPACE
Definition: QDiana.hh:20
@ DebugMsg
Definition: QMessageDefs.hh:6
@ PanicMsg
Definition: QMessageDefs.hh:10
@ InfoMsg
Definition: QMessageDefs.hh:7
unsigned int GetOccurrence() const
get the number of times the same module is loaded inside a QSequence
Definition: QBaseModule.hh:125
Base class for diana drivers.
Definition: QDriver.hh:32
error class with error type and description
Definition: QError.hh:115
Base class for diana filters.
Definition: QFilter.hh:57
QFilter * CreateFilter(const std::string &name, QSequence *s)
static QGeneralFactory & GetInstance()
QWriter * CreateWriter(const std::string &name, QSequence *s)
QModule * CreateModule(const std::string &name, QSequence *s)
QReader * CreateReader(const std::string &name, QSequence *s)
QDriver * CreateDriver(const std::string &name, QSequence *s)
static QGlobalRWFactory & GetInstance()
void LoadPlugin(const std::string &name)
static QMessageHandler * Get()
Definition: QMessage.cc:24
static void Panic(const std::string &sender, const std::string &msg)
Definition: QMessage.hh:43
virtual ~QModuleFactory()
void Dump(std::ostream &)
QFilter * CreateFilter(const std::string &n, QSequence *)
void LoadLoadable(const std::string &n)
void AddAliasGroup(std::vector< std::pair< std::string, int > > &cfgFileLines, int location, const std::vector< std::string > &alias_files, const std::string &group, const std::vector< std::pair< std::string, std::string > > &group_options)
std::string ReplaceCFGVar(const std::string &value)
QModule * CreateModule(const std::string &n, QSequence *)
static QModuleFactory * Get()
QDriver * CreateDriver(const std::string &n, QSequence *)
static QModuleFactory * me
QReader * CreateReader(const std::string &n, QSequence *)
QWriter * CreateWriter(const std::string &n, QSequence *)
QSequence * FindSequence(const std::string &s)
Base class for diana modules.
Definition: QModule.hh:54
base class for anything that has a name
Definition: QNamed.hh:14
static QOptions & GetInstance()
Definition: QOptions.cc:23
Base class for diana event readers.
Definition: QReader.hh:50
std::string fFilename
file name of this sequence
Diana Reconstruction program.
Definition: QSequence.hh:40
QDriver * p_Driver
Pointer to a driver.
Definition: QSequence.hh:110
std::vector< QBaseModule * > modules
The list of the modules.
Definition: QSequence.hh:112
QWriter * p_Writer
Pointer to the writer.
Definition: QSequence.hh:108
QReader * p_Reader
Pointer to the reader.
Definition: QSequence.hh:106
QSequenceConfig fConfig
Sequence config data.
Definition: QSequence.hh:133
Variable Data Type.
Definition: QVdt.hh:26
Abstract class for diana writers.
Definition: QWriter.hh:30
general purpose string manipulation functions
std::string & RSwallowSpaces(std::string &s)
remove spaces and tabs from the end of s
std::string & SwallowSpaces(std::string &s)
remove spaces and tabs from the beginning of s