]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
- adding total umber of events to the HLTGlobalTriggerDecision counters
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
1 // $Id$
2 /**************************************************************************
3  * This file is property of and copyright by the ALICE HLT Project        *
4  * ALICE Experiment at CERN, All rights reserved.                         *
5  *                                                                        *
6  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
7  *                  for The ALICE HLT Project.                            *
8  *                                                                        *
9  * Permission to use, copy, modify and distribute this software and its   *
10  * documentation strictly for non-commercial purposes is hereby granted   *
11  * without fee, provided that the above copyright notice appears in all   *
12  * copies and that both the copyright notice and this permission notice   *
13  * appear in the supporting documentation. The authors make no claims     *
14  * about the suitability of this software for any purpose. It is          *
15  * provided "as is" without express or implied warranty.                  *
16  **************************************************************************/
17
18 /// @file   AliHLTGlobalTriggerComponent.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
20 /// @date   26 Nov 2008
21 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
22 ///
23 /// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
24 /// trigger information produced by components deriving from AliHLTTrigger.
25
26 #include "AliHLTGlobalTriggerComponent.h"
27 #include "AliHLTGlobalTriggerDecision.h"
28 #include "AliHLTGlobalTrigger.h"
29 #include "AliHLTGlobalTriggerConfig.h"
30 #include "AliHLTTriggerMenu.h"
31 #include "AliCDBManager.h"
32 #include "AliCDBStorage.h"
33 #include "AliCDBEntry.h"
34 #include "TUUID.h"
35 #include "TROOT.h"
36 #include "TSystem.h"
37 #include "TRegexp.h"
38 #include "TClonesArray.h"
39 #include "TObjString.h"
40 #include "TSystem.h"
41 #include "TInterpreter.h"
42 #include "TDatime.h"
43 #include <fstream>
44 #include <cerrno>
45
46 ClassImp(AliHLTGlobalTriggerComponent)
47
48 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
49
50
51 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
52         AliHLTTrigger(),
53         fTrigger(NULL),
54         fDebugMode(false),
55         fCodeFileName()
56 {
57   // Default constructor.
58   
59   ClearInfoForNewEvent(false);
60 }
61
62
63 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
64 {
65   // Default destructor.
66   
67   if (fTrigger != NULL) delete fTrigger;
68 }
69
70
71 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
72 {
73   // Returns the output data size estimate.
74
75   constBase = sizeof(AliHLTGlobalTriggerDecision);
76   inputMultiplier = 1;
77 }
78
79
80 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
81 {
82   // Initialises the global trigger component.
83   
84   fDebugMode = false;
85   const char* configFileName = NULL;
86   const char* codeFileName = NULL;
87   TString classname;
88   TClonesArray includePaths(TObjString::Class());
89   TClonesArray includeFiles(TObjString::Class());
90   
91   for (int i = 0; i < argc; i++)
92   {
93     if (strcmp(argv[i], "-config") == 0)
94     {
95       if (configFileName != NULL)
96       {
97         HLTWarning("Trigger configuration macro was already specified."
98                    " Will replace previous value given by -config."
99         );
100       }
101       if (argc <= i+1)
102       {
103         HLTError("The trigger configuration macro filename was not specified." );
104         return -EINVAL;
105       }
106       configFileName = argv[i+1];
107       i++;
108       continue;
109     }
110     
111     if (strcmp(argv[i], "-includepath") == 0)
112     {
113       if (argc <= i+1)
114       {
115         HLTError("The include path was not specified." );
116         return -EINVAL;
117       }
118       new (includePaths[includePaths.GetEntriesFast()]) TObjString(argv[i+1]);
119       i++;
120       continue;
121     }
122     
123     if (strcmp(argv[i], "-include") == 0)
124     {
125       if (argc <= i+1)
126       {
127         HLTError("The include file name was not specified." );
128         return -EINVAL;
129       }
130       new (includeFiles[includeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
131       i++;
132       continue;
133     }
134     
135     if (strcmp(argv[i], "-debug") == 0)
136     {
137       if (fDebugMode == true)
138       {
139         HLTWarning("The debug flag was already specified. Ignoring this instance.");
140       }
141       fDebugMode = true;
142       i++;
143       continue;
144     }
145     
146     if (strcmp(argv[i], "-usecode") == 0)
147     {
148       if (codeFileName != NULL)
149       {
150         HLTWarning("Custom trigger code file was already specified."
151                    " Will replace previous value given by -usecode."
152         );
153       }
154       if (argc <= i+1)
155       {
156         HLTError("The custom trigger code filename was not specified." );
157         return -EINVAL;
158       }
159       codeFileName = argv[i+1];
160       if (argc <= i+2)
161       {
162         HLTError("The custom trigger class name was not specified." );
163         return -EINVAL;
164       }
165       classname = argv[i+2];
166       i += 2;
167       continue;
168     }
169     
170     HLTError("Unknown option '%s'.", argv[i]);
171     return -EINVAL;
172   } // for loop
173   
174   const AliHLTTriggerMenu* menu = NULL;
175   if (configFileName != NULL)
176   {
177     TString cmd = ".x ";
178     cmd += configFileName;
179     gROOT->ProcessLine(cmd);
180     menu = AliHLTGlobalTriggerConfig::Menu();
181   }
182   
183   // Try load the trigger menu from the CDB if it is not loaded yet with the
184   // -config option
185   if (menu == NULL and AliCDBManager::Instance() != NULL)
186   {
187     AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
188     if (store == NULL)
189     {
190       HLTError("Could not get the the default storage for the CDB.");
191       return -EIO;
192     }
193     Int_t version = store->GetLatestVersion(fgkTriggerMenuCDBPath, GetRunNo());
194     Int_t subVersion = store->GetLatestSubVersion(fgkTriggerMenuCDBPath, GetRunNo(), version);
195     AliCDBEntry* entry = AliCDBManager::Instance()->Get(fgkTriggerMenuCDBPath, GetRunNo(), version, subVersion);
196     if (entry == NULL)
197     {
198       HLTError("Could not get the CDB entry for \"%s\".", fgkTriggerMenuCDBPath);
199       return -EIO;
200     }
201     TObject* obj = entry->GetObject();
202     if (obj == NULL)
203     {
204       HLTError("Configuration object for \"%s\" is missing.", fgkTriggerMenuCDBPath);
205       return -ENOENT;
206     }
207     if (obj->IsA() != AliHLTTriggerMenu::Class())
208     {
209       HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
210                fgkTriggerMenuCDBPath, obj->ClassName()
211       );
212       return -EPROTO;
213     }
214     menu = dynamic_cast<AliHLTTriggerMenu*>(obj);
215   }
216   
217   if (menu == NULL)
218   {
219     HLTError("No trigger menu configuration found or specified.");
220     return -ENOENT;
221   }
222   
223   int result = 0;
224   if (codeFileName == NULL)
225   {
226     HLTDebug("Generating custom HLT trigger class.");
227     result = GenerateTrigger(menu, classname, includePaths, includeFiles);
228   }
229   else
230   {
231     HLTDebug("Loading HLT trigger class from file '%s'.", codeFileName);
232     result = LoadTriggerClass(codeFileName, includePaths);
233   }
234   if (result != 0) return result;
235   
236   fTrigger = AliHLTGlobalTrigger::CreateNew(classname.Data());
237   if (fTrigger == NULL)
238   {
239     HLTError("Could not create a new instance of '%s'.", classname.Data());
240     return -EIO;
241   }
242   
243   fTrigger->FillFromMenu(*menu);
244   fTrigger->ResetCounters(menu->NumberOfItems());
245   
246   // Set the default values from the trigger menu.
247   SetDescription(menu->DefaultDescription());
248   SetTriggerDomain(menu->DefaultTriggerDomain());
249   
250   return 0;
251 }
252
253
254 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
255 {
256   // Cleans up the global trigger component.
257   
258   if (fTrigger != NULL)
259   {
260     delete fTrigger;
261     fTrigger = NULL;
262   }
263
264   if (!fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
265     fCodeFileName.ReplaceAll(".cxx", "*");
266     TString command="rm "; command+=fCodeFileName;
267     gSystem->Exec(command);
268   }
269   fCodeFileName="";
270   
271   return 0;
272 }
273
274
275 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
276 {
277   // Creates a new object instance.
278   
279   return new AliHLTGlobalTriggerComponent;
280 }
281
282
283 int AliHLTGlobalTriggerComponent::DoTrigger()
284 {
285   // This method will apply the global trigger decision.
286
287   if (fTrigger == NULL)
288   {
289     HLTFatal("Global trigger implementation object is NULL!");
290     return -EIO;
291   }
292   
293   fTrigger->NewEvent();
294   
295   // Fill in the input data.
296   const TObject* obj = GetFirstInputObject();
297   while (obj != NULL)
298   {
299     fTrigger->Add(obj, GetDataType(), GetSpecification());
300     obj = GetNextInputObject();
301   }
302
303   // Calculate the global trigger result and trigger domain, then create and push
304   // back the new global trigger decision object.
305   TString description;
306   AliHLTTriggerDomain triggerDomain;
307   bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
308   
309   AliHLTGlobalTriggerDecision decision(
310       triggerResult,
311       // The following will cause the decision to be generated with default values
312       // (set in fTriggerDomain and fDescription) if the trigger result is false.
313       (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
314       (triggerResult == true) ? description.Data() : GetDescription()
315     );
316   decision.SetCounters(fTrigger->Counters(), GetEventCount()+1);
317   static UInt_t lastTime=0;
318   TDatime time;
319   if (time.Get()-lastTime>5) {
320     lastTime=time.Get();
321     ULong64_t count=0;
322     for (int i=0; i<fTrigger->Counters().GetSize(); i++) {
323       count+=fTrigger->Counters()[i];
324     }
325     HLTInfo("total events: %lu - triggered events: %lu", GetEventCount()+1, count);
326   }
327   
328   // Add the input objects used to the global decision.
329   obj = GetFirstInputObject();
330   while (obj != NULL)
331   {
332     if (obj->IsA() == AliHLTTriggerDecision::Class())
333     {
334       decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
335     }
336     else
337     {
338       decision.AddInputObject(obj);
339     }
340     obj = GetNextInputObject();
341   }
342   
343   TriggerEvent(&decision);
344   return 0;
345 }
346
347
348 int AliHLTGlobalTriggerComponent::GenerateTrigger(
349     const AliHLTTriggerMenu* menu, TString& name,
350     const TClonesArray& includePaths, const TClonesArray& includeFiles
351   )
352 {
353   // Generates the global trigger class that will implement the specified trigger menu.
354   // See header for more details.
355   
356   // Create a new UUID and replace the '-' characters with '_' to make it a valid
357   // C++ symbol name.
358   TUUID uuid;
359   TString uuidstr = uuid.AsString();
360   for (Int_t i = 0; i < uuidstr.Length(); i++)
361   {
362     if (uuidstr[i] == '-') uuidstr[i] = '_';
363   }
364   
365   // Create the name of the new class.
366   name = "AliHLTGlobalTriggerImpl_";
367   name += uuidstr;
368   fCodeFileName = name + ".cxx";
369   
370   // Open a text file to write the code and generate the new class.
371   fstream code(fCodeFileName.Data(), ios_base::out | ios_base::trunc);
372   if (not code.good())
373   {
374     HLTError("Could not open file '%s' for writing.", fCodeFileName.Data());
375     return -EIO;
376   }
377   
378   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
379   int result = BuildSymbolList(menu, symbols);
380   if (result != 0) return result;
381   
382   code << "#include <cstring>" << endl;
383   code << "#include \"TString.h\"" << endl;
384   code << "#include \"TClonesArray.h\"" << endl;
385   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
386   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
387   code << "#include \"AliHLTDomainEntry.h\"" << endl;
388   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
389   code << "#include \"AliHLTReadoutList.h\"" << endl;
390   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
391   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
392   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
393   
394   // Add any include files that were specified on the command line.
395   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
396   {
397     TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
398     code << "#include \"" << file.Data() << "\"" << endl;
399   }
400   
401   code << "class " << name << " : public AliHLTGlobalTrigger" << endl;
402   code << "{" << endl;
403   code << "public:" << endl;
404   
405   code << "  " << name << "() : AliHLTGlobalTrigger()";
406   // Write the symbols in the trigger menu in the initialisation list.
407   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
408   {
409     code << "," << endl;
410     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
411     code << "    " << symbol->Name() << "()," << endl;
412     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
413     {
414       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
415     }
416     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
417   }
418   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
419   {
420     code << "," << endl << "    fMenuItemDescription" << i << "()";
421   }
422   code << endl << "  {" << endl;
423   if (fDebugMode)
424   {
425     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
426     code << "    HLTInfo(\"Creating new instance at %p.\", this);" << endl;
427   }
428   code << "  }" << endl;
429   
430   code << "  virtual ~" << name << "() {" << endl;
431   if (fDebugMode)
432   {
433     code << "    HLTInfo(\"Deleting instance at %p.\", this);" << endl;
434   }
435   code << "  }" << endl;
436   
437   // Generate the FillFromMenu method.
438   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
439   if (fDebugMode)
440   {
441     code << "    HLTDebug(\"Filling description entries from trigger menu for global trigger %p.\", this);" << endl;
442   }
443   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
444   {
445     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
446          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
447   }
448   if (fDebugMode)
449   {
450     code << "    HLTDebug(\"Finished filling description entries from trigger menu.\");" << endl;
451     code << "    HLTDebug(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this);" << endl;
452   }
453   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
454   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
455            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
456   code << "      if (symbol == NULL) continue;" << endl;
457   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
458   {
459     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
460     code << "      if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl;
461     if (fDebugMode)
462     {
463       code << "        HLTDebug(\"Assinging domain entry value to match for symbol '%s' to '%s'.\","
464               " symbol->Name(), symbol->BlockType().AsString().Data());" << endl;
465     }
466     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
467     code << "        continue;" << endl;
468     code << "      }" << endl;
469   }
470   code << "    }" << endl;
471   if (fDebugMode)
472   {
473     code << "    HLTDebug(\"Finished filling domain entries from trigger menu symbols.\");" << endl;
474   }
475   code << "  }" << endl;
476   
477   // Generate the NewEvent method.
478   code << "  virtual void NewEvent() {" << endl;
479   if (fDebugMode)
480   {
481     code << "    HLTDebug(\"New event for global trigger object %p, initialising variables to default values.\", this);" << endl;
482   }
483   // Write code to initialise the symbols in the trigger menu to their default values.
484   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
485   {
486     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
487     code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
488     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
489     {
490       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
491     }
492   }
493   if (fDebugMode)
494   {
495     code << "    HLTDebug(\"Finished initialising variables.\");" << endl;
496   }
497   code << "  }" << endl;
498   
499   // Generate the Add method.
500   code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
501   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
502   if (fDebugMode)
503   {
504     code << "    HLTDebug(\"Adding TObject %p, with class name '%s' from data block"
505             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
506             " _type_spec_.AsString().Data(), this);" << endl;
507     code << "    _object_->Print();" << endl;
508     code << "    bool _object_assigned_ = false;" << endl;
509   }
510   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
511   {
512     // Write code to check if the block type, specification and class name is correct.
513     // Then write code to assign the variable from the input object.
514     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
515     TString expr = symbol->AssignExpression();
516     if (expr == "") continue; // Skip entries that have no assignment expression.
517     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
518     if (fDebugMode)
519     {
520       if (isTrigDecision)
521       {
522         code << "    HLTDebug(\"Trying to match input object to class '"
523              << symbol->ObjectClass() << "', trigger name '" << symbol->Name()
524              << "' and block type '%s'\", " << symbol->Name()
525              << "DomainEntry.AsString().Data());" << endl;
526       }
527       else
528       {
529         code << "    HLTDebug(\"Trying to match input object to class '"
530              << symbol->ObjectClass() << "' and block type '%s'\", "
531              << symbol->Name() << "DomainEntry.AsString().Data());" << endl;
532       }
533     }
534     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name()
535          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
536          << "*>(_object_);" << endl;
537     code << "    if (" << symbol->Name() << "_object_ != NULL and ";
538     if (isTrigDecision)
539     {
540       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
541            << symbol->Name() << "\") == 0 and ";
542     }
543     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
544     TString fullname = symbol->Name();
545     fullname += "_object_";
546     expr.ReplaceAll("this", fullname);
547     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
548     if (isTrigDecision)
549     {
550       code << "      this->" << symbol->Name() << "TriggerDomain = "
551            << fullname.Data() << "->TriggerDomain();" << endl;
552     }
553     if (fDebugMode)
554     {
555       code << "      HLTDebug(\"Added TObject %p with class name '%s' to variable "
556            << symbol->Name() << "\", _object_, _object_->ClassName());" << endl;
557       code << "      _object_assigned_ = true;" << endl;
558     }
559     code << "    }" << endl;
560   }
561   if (fDebugMode)
562   {
563     code << "    if (not _object_assigned_) HLTDebug(\"Did not assign TObject %p"
564             " with class name '%s' to any variable.\", _object_, _object_->ClassName());"
565          << endl;
566   }
567   code << "  }" << endl;
568   
569   // Generate the CalculateTriggerDecision method.
570   code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
571   if (fDebugMode)
572   {
573     code << "    HLTDebug(\"Calculating global HLT trigger result with trigger object at %p.\", this);" << endl;
574   }
575   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
576   {
577     const AliHLTTriggerMenuItem* item = menu->Item(i);
578     TString mergeExpr = item->MergeExpression();
579     for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
580     {
581       AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
582       if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") != 0) continue;
583       TString newname = symbol->Name();
584       newname += "TriggerDomain";
585       mergeExpr.ReplaceAll(symbol->Name(), newname);
586     }
587     if (fDebugMode)
588     {
589       code << "    HLTDebug(\"Trying trigger condition " << i
590            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());"
591            << endl;
592     }
593     code << "    if (" << item->TriggerCondision() << ") {" << endl;
594     code << "      IncrementCounter(" << i << ");" << endl;
595     const char* indentation = "";
596     if (item->PreScalar() != 0)
597     {
598       indentation = "  ";
599       code << "      if ((GetCounter(" << i << ") % " << item->PreScalar() << ") == 1) {" << endl;
600     }
601     code << indentation << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
602     code << indentation << "      _description_ = fMenuItemDescription" << i << ";" << endl;
603     if (fDebugMode)
604     {
605       code << indentation << "      HLTDebug(\"Matched trigger condition " << i
606            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" << endl;
607     }
608     code << indentation << "      return true;" << endl;
609     if (item->PreScalar() != 0)
610     {
611       code << "      }" << endl;
612     }
613     code << "    }" << endl;
614   }
615   code << "    return false;" << endl;
616   code << "  }" << endl;
617   
618   // Generate the custom Factory class.
619   code << "  class FactoryImpl : public AliHLTGlobalTrigger::Factory" << endl;
620   code << "  {" << endl;
621   code << "  public:" << endl;
622   code << "    virtual const char* ClassName() const {" << endl;
623   code << "      return \"" << name << "\";" << endl;
624   code << "    }" << endl;
625   code << "    virtual AliHLTGlobalTrigger* New() const {" << endl;
626   code << "      return new " << name << "();" << endl;
627   code << "    }" << endl;
628   code << "  };" << endl;
629   
630   code << "private:" << endl;
631   // Add the symbols in the trigger menu to the list of private variables.
632   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
633   {
634     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
635     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
636     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
637     {
638       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
639     }
640     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
641   }
642   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
643   {
644     code << "  TString fMenuItemDescription" << i << ";" << endl;
645   }
646   code << "};" << endl;
647   
648   // Write a global object for the Factory class for automatic registration.
649   code << "namespace {" << endl;
650   code << "  const " << name << "::FactoryImpl gkFactoryImpl;" << endl;
651   code << "};" << endl;
652   
653   code.close();
654   
655   // Now we need to compile and load the new class.
656   result = LoadTriggerClass(fCodeFileName, includePaths);
657   return result;
658 }
659
660
661 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
662     const char* filename, const TClonesArray& includePaths
663   )
664 {
665   // Loads the code for a custom global trigger class implementation on the fly.
666   
667   TString compiler = gSystem->GetBuildCompilerVersion();
668   if (compiler.Contains("gcc") or compiler.Contains("icc"))
669   {
670     TString includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
671     // Add any include paths that were specified on the command line.
672     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
673     {
674       TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
675       includePath += " ";
676       includePath += path;
677     }
678     gSystem->SetIncludePath(includePath);
679     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
680     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
681     
682     int result = kTRUE;
683     if (fDebugMode)
684     {
685       result = gSystem->CompileMacro(filename, "g");
686     }
687     else
688     {
689       result = gSystem->CompileMacro(filename, "O");
690     }
691     if (result != kTRUE)
692     {
693       HLTFatal("Could not compile and load global trigger menu implementation.");
694       return -ENOENT;
695     }
696   }
697   else
698   {
699     // If we do not support the compiler then try interpret the class instead.
700     TString cmd = ".L ";
701     cmd += filename;
702     Int_t errorcode = TInterpreter::kNoError;
703     gROOT->ProcessLine(cmd, &errorcode);
704     if (errorcode != TInterpreter::kNoError)
705     {
706       HLTFatal("Could not load interpreted global trigger menu implementation"
707                " (Interpreter error code = %d).",
708                errorcode
709       );
710       return -ENOENT;
711     }
712   }
713   
714   return 0;
715 }
716
717
718 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
719 {
720   // Searches for the named symbol in the given list.
721   // See header for more details.
722   
723   for (int i = 0; i < list.GetEntriesFast(); i++)
724   {
725     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
726     if (symbol == NULL) continue;
727     if (strcmp(symbol->Name(), name) == 0) return i;
728   }
729   return -1;
730 }
731
732
733 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
734 {
735   // Builds the list of symbols to use in the custom global trigger menu
736   // implementation class.
737   // See header for more details.
738   
739   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
740   {
741     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
742     if (FindSymbol(symbol->Name(), list) != -1)
743     {
744       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
745       return -EIO;
746     }
747     new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
748   }
749   
750   TRegexp exp("[_a-zA-Z][_a-zA-Z0-9]*");
751   TRegexp hexexp("x[a-fA-F0-9]+");
752   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
753   {
754     const AliHLTTriggerMenuItem* item = menu->Item(i);
755     TString str = item->TriggerCondision();
756     Ssiz_t start = 0;
757     do
758     {
759       Ssiz_t length = 0;
760       Ssiz_t pos = exp.Index(str, &length, start);
761       if (pos == kNPOS) break;
762       start = pos+length;
763       
764       // Check if there is a numerical character before the found
765       // regular expression. If so, then the symbol is not a valid one
766       // and should be skipped.
767       if (pos > 0)
768       {
769         bool notValid = false;
770         switch (str[pos-1])
771         {
772         case '0': case '1': case '2': case '3': case '4':
773         case '5': case '6': case '7': case '8': case '9':
774           notValid = true;
775           break;
776         default:
777           notValid = false;
778           break;
779         }
780         if (notValid) continue;
781       }
782       TString s = str(pos, length);
783       
784       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
785           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
786           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
787           s == "false"
788          )
789       {
790         // Ignore iso646.h and other keywords.
791         continue;
792       }
793
794       if (FindSymbol(s.Data(), list) == -1)
795       {
796         AliHLTTriggerMenuSymbol newSymbol;
797         newSymbol.Name(s.Data());
798         newSymbol.Type("bool");
799         newSymbol.ObjectClass("AliHLTTriggerDecision");
800         newSymbol.AssignExpression("this->Result()");
801         newSymbol.DefaultValue("false");
802         new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
803       }
804     }
805     while (start < str.Length());
806   }
807   
808   return 0;
809 }
810