JANA
|
00001 // $Id: JFactory.h 1733 2006-05-02 17:17:32Z davidl $ 00002 00003 00004 #ifndef _JFACTORY_H_ 00005 #define _JFACTORY_H_ 00006 00007 00008 00009 #include "JObject.h" 00010 00011 00012 #include <vector> 00013 #include <string> 00014 using std::vector; 00015 using std::string; 00016 00017 #include "JEventLoop.h" 00018 #include "JFactory_base.h" 00019 #include "JEvent.h" 00020 00021 // The following is here just so we can use ROOT's THtml class to generate documentation. 00022 #ifdef __CINT__ 00023 class pthread_mutex_t; 00024 typedef unsigned long pthread_t; 00025 typedef unsigned long oid_t; 00026 #endif 00027 00028 // Place everything in JANA namespace 00029 namespace jana{ 00030 00031 /// 00032 /// JANA Data Factory (base class for algorithms) 00033 /// 00034 /// All data (except that read from the data source) must 00035 /// be derived from the data that was read from the source. 00036 /// One JFactory object should exist for each type of data 00037 /// that is "generated". For example: Clusters in a calorimeter 00038 /// are generated from individual "Hits" in the calorimeter. 00039 /// 00040 /// JFactory is the templated base class which all factories 00041 /// are derived from. 00042 /// 00043 /// At the user level, factory classes will be defined 00044 /// which inherit from this templated base class. By 00045 /// inheriting from a template, the derived factory class 00046 /// will automatically have a high degree of type safety 00047 /// since the "_data" vector will be specific to the type 00048 /// of objects the factory produces. This class (JFactory) 00049 /// inherits from JFactory_base so that all factories can 00050 /// be treated equally (polymorphism) by the JEventLoop object. 00051 /// 00052 /// Instantiating a JFactory<T> object itself would be pointless 00053 /// since they would use the default init(), brun(),evnt(),erun(), 00054 /// and fini() 00055 /// methods from JEventProcessor which do nothing. Instead, 00056 /// A new class should be derived from this one which implements 00057 /// its own init(), brun(),evnt(),erun(), and fini() methods. 00058 00059 //----------------------- 00060 // class JFactory 00061 //----------------------- 00062 template<class T> 00063 class JFactory:public JFactory_base{ 00064 00065 public: 00066 JFactory(const char *tag=""); 00067 ~JFactory(); 00068 00069 enum data_origin_t{ 00070 ORIGIN_NONE, 00071 ORIGIN_FACTORY, 00072 ORIGIN_EXTERNAL 00073 }; 00074 00075 vector<void*>& Get(void); 00076 jerror_t Get(vector<const T*> &d); 00077 int GetNrows(void); 00078 data_origin_t GetDataOrigin(void){return data_origin;} 00079 inline const char* className(void){return T::static_className();} 00080 inline const char* GetDataClassName(void){return className();} 00081 inline void toStrings(vector<vector<pair<string,string> > > &items, bool append_types=false) const; 00082 virtual const char* Tag(void){return tag_str;} 00083 inline int GetDataClassSize(void){return sizeof(T);} 00084 inline int GetEventCalled(void){return evnt_called;} 00085 inline int GetCheckSourceFirst(void){return !use_factory;} 00086 jerror_t CopyFrom(vector<const T*> &data); 00087 jerror_t CopyTo(vector<T*> &data); 00088 const T* GetByIDT(JObject::oid_t id); 00089 const JObject* GetByID(JObject::oid_t id){return dynamic_cast<const JObject*>(GetByIDT(id));} 00090 00091 00092 protected: 00093 vector<T*> _data; 00094 vector<void*>_vdata; 00095 int use_factory; 00096 const char* tag_str; 00097 00098 jerror_t Reset(void); 00099 jerror_t HardReset(void); 00100 00101 data_origin_t data_origin; 00102 }; 00103 00104 00105 // The following is here just so we can use ROOT's THtml class to generate documentation. 00106 #ifndef __CINT__ 00107 00108 //------------- 00109 // JFactory 00110 //------------- 00111 template<class T> 00112 JFactory<T>::JFactory(const char *tag) 00113 { 00114 /// This is a base class that specific factories inherit from. 00115 /// my_devent will be kept and used to allow this factory to 00116 /// access other factories. 00117 00118 // make sure vector is empty 00119 _data.clear(); // probably unnecessary 00120 00121 // clear flags 00122 flags = WRITE_TO_OUTPUT; 00123 use_factory = 0; 00124 busy = 0; 00125 tag_str = tag; 00126 Ncalls_to_Get = 0; 00127 Ncalls_to_evnt = 0; 00128 00129 // Allow any factory to have its debug_level set via environment variable 00130 debug_level = 0; 00131 string envar = string() + "DEBUG_" + GetDataClassName(); 00132 char *ptr = getenv(envar.c_str()); 00133 if(ptr)debug_level = atoi(ptr); 00134 } 00135 00136 //------------- 00137 // ~JFactory 00138 //------------- 00139 template<class T> 00140 JFactory<T>::~JFactory() 00141 { 00142 /// Delete all objects in _data container. 00143 HardReset(); 00144 } 00145 00146 //------------- 00147 // Get 00148 //------------- 00149 template<class T> 00150 vector<void*>& JFactory<T>::Get(void) 00151 { 00152 /// Return a STL vector of pointers to the objects produced by the 00153 /// factory. The pointers are type cast as void* so this can be 00154 /// accessed through the JFactory_base base class. This just 00155 /// dispatches to the type specific Get(vector<const T*> &) 00156 /// method. 00157 vector<const T*> d; 00158 Get(d); 00159 00160 // Copy the pointers into a vector of void*s. 00161 _vdata.clear(); 00162 for(unsigned int i=0;i<_data.size();i++)_vdata.push_back((void*)_data[i]); 00163 00164 return _vdata; 00165 } 00166 00167 //------------- 00168 // Get 00169 //------------- 00170 template<class T> 00171 jerror_t JFactory<T>::Get(vector<const T*> &d) 00172 { 00173 /// Copy pointers to the objects produced by the factory into 00174 /// the vector reference passed. 00175 /// Note that this method is accessed primarily from two places: 00176 /// This main one is JEventLoop::GetFromFactory which is called 00177 /// from JEventLoop::Get , the primary access method for factories 00178 /// and event processors. 00179 /// The second is through the JFactory<T>::Get() which is called 00180 /// through the JFactory_base::Get virtual method. 00181 /// That is used mainly by things that need to loop over all 00182 /// objects of all factories. 00183 /// 00184 /// This method will check first to make sure this factory hasn't 00185 /// already been called for this event. 00186 /// 00187 /// This also uses a busy flag to ensure we're not called 00188 /// recursively. i.e. we call a factory who calls another 00189 /// factory who eventually calls us. An exception is thrown 00190 /// (type jerror_t) with a value INFINITE_RECURSION if that 00191 /// situation is detected. 00192 00193 00194 // If evnt_called is set, then just copy the pointers and return 00195 if(evnt_called)return CopyFrom(d); 00196 00197 // Check for infinite recursion through factory dependancies 00198 if(busy)throw(INFINITE_RECURSION); 00199 busy++; 00200 if(busy!=1)throw(INFINITE_RECURSION); // Should we use a mutex here? 00201 00202 // Grab the current event and run numbers 00203 int event_number = eventLoop->GetJEvent().GetEventNumber(); 00204 int run_number = eventLoop->GetJEvent().GetRunNumber(); 00205 00206 // Make sure we're initialized 00207 if(!init_called){ 00208 init(); 00209 init_called = 1; 00210 } 00211 00212 // Call brun routine if run number has changed or it's not been called 00213 if(run_number!=brun_runnumber){ 00214 if(brun_called && !erun_called){ 00215 erun(); 00216 erun_called = 1; 00217 } 00218 brun_called = 0; 00219 } 00220 if(!brun_called){ 00221 brun(eventLoop, run_number); 00222 brun_called = 1; 00223 erun_called = 0; 00224 brun_runnumber = run_number; 00225 } 00226 00227 // Call evnt routine to generate data 00228 try{ 00229 Ncalls_to_evnt++; 00230 evnt(eventLoop, event_number); 00231 CopyFrom(d); 00232 }catch(JException *exception){ 00233 JEventLoop::error_call_stack_t cs; 00234 cs.factory_name = GetDataClassName(); 00235 cs.tag = Tag(); 00236 cs.filename = __FILE__; 00237 cs.line = __LINE__; 00238 eventLoop->AddToErrorCallStack(cs); 00239 throw exception; 00240 } 00241 evnt_called = 1; 00242 busy=0; 00243 00244 return NOERROR; 00245 } 00246 00247 //------------- 00248 // GetNrows 00249 //------------- 00250 template<class T> 00251 int JFactory<T>::GetNrows(void) 00252 { 00253 /// Return the number of objects for this factory for the 00254 /// current event. If the objects have not yet been created 00255 /// for the event, this will cause them to be generated 00256 /// (or retreived from the source). 00257 if(!evnt_called){ 00258 // In order to get the objects from the source, the Get() method 00259 // of the JEventLoop object must be called. This may seem 00260 // convoluted, but it's neccessary for things like janadump 00261 // that only have a list of JFactory_base pointers and 00262 // are not able to call the templated JEventLoop::Get() 00263 // method directly. 00264 // Note that we must use the Tag() method so it will pass 00265 // the tag from the subclass (if any). The tag_str member 00266 // is only in JFactory for when sources must auto-instantiate 00267 // a JFactory<> class. 00268 vector<const T*> d; // dummy placeholder 00269 eventLoop->Get(d,Tag()); 00270 } 00271 00272 return _data.size(); 00273 } 00274 00275 //------------- 00276 // Reset 00277 //------------- 00278 template<class T> 00279 jerror_t JFactory<T>::Reset(void) 00280 { 00281 /// Clear out the factories current contents unless the 00282 /// PERSISTANT flag is set. 00283 if(flags & (unsigned int)PERSISTANT)return NOERROR; 00284 00285 // don't reset the evnt_called flag for persistent data because this 00286 // will force evnt to be called next event therby regenerating 00287 // the data 00288 00289 return HardReset(); 00290 } 00291 00292 //------------- 00293 // HardReset 00294 //------------- 00295 template<class T> 00296 jerror_t JFactory<T>::HardReset(void) 00297 { 00298 00299 /// Clear out the factories current contents. 00300 if(!TestFactoryFlag(NOT_OBJECT_OWNER)){ 00301 for(unsigned int i=0;i<_data.size();i++){ 00302 delete _data[i]; 00303 } 00304 } 00305 _data.clear(); 00306 00307 evnt_called = 0; 00308 00309 return NOERROR; 00310 } 00311 00312 //------------- 00313 // CopyTo 00314 //------------- 00315 template<class T> 00316 jerror_t JFactory<T>::CopyTo(vector<T*> &data) 00317 { 00318 /// Copy object pointers into factory. Object ownership is 00319 /// transferred to the factory here so the caller should not 00320 /// delete the objects after calling this unless the factory's 00321 /// NOT_OBJECT OWNER flag is set (see 00322 /// SetFactoryFlag(JFactory_base::NOT_OBJECT_OWNER)) 00323 /// This is how an external source such as a file can create 00324 /// the objects and put them in the factory. The objects will 00325 /// then be treated as though they were generated by the factory. 00326 /// i.e. they will be returned in subsequent calls to Get() 00327 /// and deleted at the start of the next event (sans 00328 /// the NOT_OBJECT_OWNER or PERSISTANT flags). 00329 00330 // Set flag so subsequent calls for this event will return this 00331 // data. 00332 evnt_called = 1; 00333 00334 // Just copy into the _vdata vector since _data is not used outside 00335 // of the factory. 00336 _data.clear(); 00337 for(unsigned int i=0;i<data.size();i++){ 00338 _data.push_back(data[i]); 00339 } 00340 00341 return NOERROR; 00342 } 00343 00344 //------------- 00345 // CopyFrom 00346 //------------- 00347 template<class T> 00348 jerror_t JFactory<T>::CopyFrom(vector<const T*> &data) 00349 { 00350 /// Copy object pointers from private vector into "data" 00351 /// vector. This does not check if the evnt() routine 00352 /// was called, and it does not generate the data objects 00353 /// (use the Get(vector<const T*>) method for that). 00354 /// This only copies pointers to already existing objects. 00355 for(unsigned int i=0;i<_data.size(); i++)data.push_back(_data[i]); 00356 Ncalls_to_Get++; 00357 00358 return NOERROR; 00359 } 00360 00361 //------------- 00362 // GetByIDT 00363 //------------- 00364 template<class T> 00365 const T* JFactory<T>::GetByIDT(JObject::oid_t id) 00366 { 00367 for(unsigned int i=0;i<_data.size();i++) 00368 if(_data[i]->id == id)return (const T*)_data[i]; 00369 return NULL; 00370 } 00371 00372 //------------- 00373 // toStrings 00374 //------------- 00375 template<class T> 00376 void JFactory<T>::toStrings(vector<vector<pair<string,string> > > &items, bool append_types) const 00377 { 00378 /// Get the data for all objects already created by this factory for the 00379 /// given event by calling the toStrings() method of each one. 00380 /// 00381 /// Note that this will not activate the factory to generate the objects 00382 /// if they do not already exist. 00383 /// 00384 /// The value of <i>append_types</i> is used to set the append_types 00385 /// flag for each of the objects prior to calling its <i>toStrings</i> 00386 /// method. Afterwards, the value of the objects' append_types flag 00387 /// is reset to whatever value it had upon entry. Please see the documentation 00388 /// of the AddString method of JObject for more details on what this 00389 /// flag does. 00390 /// 00391 /// The items vector is cleared upon entry. 00392 00393 items.clear(); 00394 00395 for(unsigned int i=0;i<_data.size();i++){ 00396 vector<pair<string, string> > myitems; 00397 bool save_append_types = _data[i]->GetAppendTypes(); 00398 _data[i]->SetAppendTypes(append_types); 00399 _data[i]->toStrings(myitems); 00400 _data[i]->SetAppendTypes(save_append_types); 00401 if(myitems.size()>0)items.push_back(myitems); 00402 } 00403 } 00404 00405 #endif //__CINT__ 00406 00407 00408 } // Close JANA namespace 00409 00410 00411 00412 #endif // _JFACTORY_H_