The Transient Wrapper BABAR Event
Application Programmer Interface
BABAR Computing

Version Information
Draft: 20th June 1997
The Transient Wrapper is one of two strategies for the Event API.
A decision on which strategy to be adopted has not yet been made.
This document is still under development. If you have any questions or comments, please address them to the authors.
This document describes the Transient Wrapper strategy for the programmer's interface to the event database. In this strategy the reconstruction or analysis programmer (referred to as the client for the
remainder of this document) is presented with the appearance of a transient event from which transient objects can be accessed or stored in a type-safe fashion. This transient event acts as a conduit to an underlying persistent event containing persistent
objects. This decouples the client from the persistent event and its persistent objects. The transient objects are only created from their persistent counterparts on request by the client. These requests can be explicit, such as attempting to access
information directly from the transient event, or may be hidden, by following references from one object to another within the transient event. Similarly, the persistent objects that correspond to the processing on the current event are only created from
their newly created transient counterparts when the event is "stored". This has the following advantages:
- The client has access to a conventional C++ API, whereas the persistent class programmer must cope with persistent class restrictions and language extensions.
- The client is presented with a flat transient event structure, where many of the objects within the event appear to be accessible directly from the event itself. In contrast the persistent event may be organized in a very
hierarchical manner in order to optimize placement of data within the database. This decoupling between the transient and persistent events means that placement strategies and implementations can be modified with no change in the client code.
- The mapping between a transient object and its persistent equivalent may be complex, allowing compression of the data or merging of separate transient objects into single persistent ones in order to optimize the storage
within the database.
- Transient objects may be used to cache information in order to improve performance without incurring a space penalty in the persistent store.
- The transient information may be modified for "what-if" style analyses without having to worry about possible inadvertant modification of the persistent information.
- An application may operate without change in an environment where the underlying OODBMS is not available (e.g. online event processing).
For each object type (class) within the event, several C++ classes and functions are necessary in order to maintain this decoupling:
- A transient class (T). This is the class that is used by the reconstruction or analysis code itself. Single instances of these classes may be associated with an event, in which case they are required to inherit
from a base class that is detailed below (AbsEvtObj), or a list of instances may be associated with the event, in which case the collection class detailed below (IfdHepAList<T>) must be used At the present time, the Rogue Wave
container classes may not be directly associated with an event [we could easily add some of them, tho'], but they can be used for expressing relationships between objects within the event.
- A persistent class (TP). Objects of this class can be retained in the persistent event store. They generally have a one-to-one relationship with the equivalent transient class but have to obey more stringent rules
and are generally simpler, consisting of only data members and accessors. These persistent classes must inherit from a base class (BdbEvtObj).
- A proxy class. An instance of this proxy must be created and used if the transient class (or a list of them) is to be directly associated with the event rather than only being accessible by navigation through other objects
within the event. The proxy must be a descendant class of IfdDataProxyTemplate<T> or IfdHepAListProxyTemplate<T> and implement the faultHandler( ) and storeHandler() function members. The fault handler is
used to locate the persistent object (or list in the case of IfdHepAListProxyTemplate<T>) within the database for the current event (or indicate that it doesn't exist), and create the equivalent transient object or list, setting its data
members according to the persistent information. This transient object or list is associated with the transient event so that it can subsequently be retrieved as needed without invoking this handler. The store handler creates the persistent object or list
if it doesn't already exist, sets its persistent information from the data members of the transient object, and associates it with the persistent event.
Two proxy classes have been created for ease of programming. BdbObjectProxy<T, P> is appropriate for individual objects within an event. BdbListProxy<T, P> deals with lists of objects. The template arguments T &
P correspond to the transient and persistent object types respectively.
Thus there is a conceptual separation between the client for an object within the event, who is only aware of the transient event and object, and the interface developer who is responsible for developing the classes and
handlers described above. This document describes the programming conventions that must be obeyed by doth developers, but focusses upon the interface developer. It should be read in the context of the AbsEvent User Guide document [does this
exist?] that describes in more detail the interfaces to the underlying dictionaries that make up the transient and persistent events.
Return to Table of Contents.
The BABAR application framework (the Framework
package) makes the transient event available to modules as an argument to the event function member:
virtual AbsEvent* event( AbsEvent* theEvent, int theMode )
The transient event is an example of a Proxy or Interface Dictionary (i.e. it inherits from IfdProxyDict). The only access to entities within the event is via the templated class Ifd<T> which provides access (both to fetch and store information) in a type-safe manner.
Return to Table of Contents.
Keys (IfdKey, IfdIntKey & IfdStrKey)
If multiple instances of objects from the same class are to be separately associated with the event, rather than being contained within a list, they must be identified by a unique key. The underlying ProxyDict classes
support several types of key (based on an abstract parent, IfdKey), but two are of interest for the client programmer, integer keys (IfdIntKey) and string keys (IfdStrKey).
IfdKey
Description
This class provides an abstract interface for keys. It is the parent of the key class hierarchy.
Inheritance Tree
IfdKey
Interface
#include "ProxyDict/IfdKey.hh"
Constructors
This class presents a pure interface and cannot be directly instantiated.
IfdIntKey
Description
This class provides an implementation of the IfdKey interface for integer keys.
Inheritance Tree
IfdIntKey > IfdKey
Interface
#include "ProxyDict/IfdIntKey.hh"
Constructors
IfdIntKey( const int i )
IfdStrKey
Description
This class provides an implementation of the IfdKey interface for string keys.
Inheritance Tree
IfdStrKey > IfdKey
Interface
#include "ProxyDict/IfdStrKey.hh"
Constructors
IfdStrKey( const HepString& s )
Return to Table of Contents.
Description
This class provides type-safe (templated) access to the objects or lists within a transient event. These objects or lists might themselves contain references to other objects, in which case the smart pointers described later provide a mechanism for delaying access to this second tier. This accessor class allows access to either individual objects (which must inherit from
AbsEvtObj), or to lists of objects. Currently IfdHepAList<T> is the only supported lost class, but other classes from the Rogue Wave library could be supported.
Inheritance Tree
Ifd<T>
Interface
#include "ProxyDict/Ifd.hh"
Constructors
This class contains static member functions only. It cannot be instantiated.
Operations
T* Ifd<T>::get( AbsEvent* ev )
T* Ifd<T>::get( AbsEvent* ev, AbsArg& a);
T* Ifd<T>::get( AbsEvent* ev, const IfdKey& k);
T* Ifd<T>::get( AbsEvent* ev, const IfdKey& k, AbsArg& a);
T* Ifd<T>::get( AbsEvent* ev, const char* s);
T* Ifd<T>::get( AbsEvent* ev, const char* s, AbsArg& a);
This templated function accesses objects within the event. Such objects may optionally be identified by a key (of type IdfKey) or character string to differentiate them from other instances of the same class. The
function value will be set to NULL if the desired object does not exist within the event. Note that an object can only be "got" once it has been associated with an event via a prior "put" of an appropriate proxy {see next section).
Arguments
AbsEvent* ev The transient event.
const IfdKey& k The optional key (see section on keys).
const char* s The optional string that acts as a key.
AbsArg& a I have no idea what this is. I'll have to reread Ed's documentation.
-----------------------------
bool Ifd<T>::put( AbsEvent* ev, IfdDataProxyTemplate<T>* p );
bool Ifd<T>::put( AbsEvent* ev, IfdDataProxyTemplate<T>* p, const IfdKey& k);
bool Ifd<T>::put( AbsEvent* ev, IfdDataProxyTemplate<T>* p, const char* s);
This templated function associates a proxy for an object with the event. Note that this does not mean that an object is inserted into the event, only that knowledge of that object type and characteristics (associated key
etc.) is added to the event. adds objects to the event. Depending on the proxy, the object might indeed be directly associated with the event if the object already exists. However, the more normal mode of operation is for the proxy to define a fault
handler that will be accessed when a client requests the associated object via a Ifd::get( ) call. This fault handler can locate the corresponding persistent information within the persistent event and create the transient object appropriately.
The transient event will normally cache the information such that subsequent calls to Ifd::get( ) will directly return the cached information. The function value will be set to true if the proxy is successfully added to the event.
Arguments
AbsEvent* ev The transient event.
IfdDataProxyTemplate<T>* p The proxy corresponding to the data to be added to the event.
IfdKey& k The optional key (see section on keys).
const char* s The optional string that acts as a key.
-----------------------------
bool Ifd<T>::markForStore(AbsEvent* ev);
bool Ifd<T>::markForStore(AbsEvent* ev, AbsArg& a );
bool Ifd<T>::markForStore(AbsEvent* ev, const IfdKey& k );
bool Ifd<T>::markForStore(AbsEvent* ev, const IfdKey& k, AbsArg& a );
bool Ifd<T>::markForStore(AbsEvent* ev, const char* s);
bool Ifd<T>::markForStore(AbsEvent* ev, const char* s, AbsArg& a );
This templated function marks objects to be stored. [more]
Return to Table of Contents.
Description
Single instances of classes associated with a transient event (as opposed to lists of such instances) must inherit from the AbsEvtObj class.
Inheritance Tree
AbsEvtObj > IfdData
Interface
#include "AbsEvent/AbsEvtObj.hh"
Constructors
AbsEvtObj( )
The constructor is protected and is only accessible from descendant classes.
Selectors
Refer to header file.
Modifiers
Refer to header file.
Operations
Refer to header file.
Return to Table of Contents.
This section will be extended to include the Rogue Wave collection classes (or IfdData-compatible descendants thereof). Currently only the IfdHepAList<T> CLHEP-compatible class is
implemented.
Description
Collections associated with the transient event must be instances of this templated class.
Inheritance Tree
IfdHepAList<T> > HepAList<T>, IfdData
Interface
#include "ProxyDict/IfdHepAList.hh"
Constructors
IfdHepAList( )Construct an empty list (a list with no objects)
Selectors
These are detailed in the interface description for HepAList<T>.
Modifiers
These are detailed in the interface description for HepAList<T>.
Operations
These are detailed in the interface description for HepAList<T>.
Return to Table of Contents.
Description
For each transient object of type T (inheriting from AbsEvtObj), a proxy object that is of type IfdDataProxy<T> or a descendant class of IfdDataProxyTemplate<T> must be
instantiated.
The former (IfdDataProxy<T>) should be used if the transient object already exists and not going to be associated of the persistent event. See the section The Persistent Event for an example of this.
The latter (a descendant class of IfdDataProxyTemplate<T>) should be used if the transient information does not yet exist (in which case a faultHandler must be supplied to derive it from persistent
information associated with the persistent event), or is to be converted into persistent information which should be associated with the persistent event (in which case a storeHandler must be supplied).
For lists of objects, the proxy object should inherit from class IfdHepAListProxy<T> or IfdHepAListProxyTemplate<T>. The former should be used if the list already exists, and the latter if a
fault and store handler are to be provided.
Inheritance Tree
IfdDataProxyTemplate<T>
Interface
#include "ProxyDict/IfdDataProxyTemplate.hh"
Constructors
IfdDataProxyTemplate( )
This class is pure virtual and instances of it cannot be instantiated. Descendants must define the following function members.
Selectors
IfdData* get( const IfdKey& k )
Modifiers
None.
Operations
T* faultHandler( IfdProxyDict* d, const IfdKey& k, AbsArg& theArg ) = 0
Default fault handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<T>::get() request. This default handler just returns a NULL object and should be redefined in descendant classes or specified in the constructor of this class. This function is pure virtual in this class and must be redefined by
descendant classes.
bool storeHandler( IfdProxyDict* d, const IfdKey& k, AbsArg& theArg, T* theT ) = 0
Default store handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<T>::get() request. The last argument (T* theT) is transient object as specified in the Ifd<T>::put() request. This function is pure virtual in this class and must be redefined by descendant classes.
void testCache( ) = 0
This function is pure virtual in this class and must be redefined by descendant classes.
Return to Table of Contents.
Description
This class implements a proxy strategy for the event store for single objects within the event. It inherits from IfdDataProxyTemplate<T> and implements the fault & store member functions. However, it
defines two new functions (get & put) that are abstract and must be defined in descendant classes. These functions access and save persistent objects in the persistent event hierarchy respectively.
Inheritance Tree
BdbObjectProxy<T, P> > IfdDataProxyTemplate<T>
Interface
#include "BdbEvent/BdbObjectProxy.hh"
Constructors
BdbObjectProxy( )
Default Constructor.
Selectors
None
Modifiers
None.
Operations
T* faultHandler( IfdProxyDict* d, const IfdKey& k, AbsArg& )
Fault handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<T>::get() request. The last argument can be ignored in this context.
bool storeHandler( IfdProxyDict* d, const IfdKey& k, AbsArg&, T* theT )
Store handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<T>::put() request. The last argument (T* theT) is transient object as specified in the Ifd<T>::put() request. The AbsArg& argument can be ignored in this context.
BdbRef(P) locate( BdbRef(BdbEvent)& theEvent ) = 0
Abstract locate function. This should be defined in descendant classes to access the P class from the persistent event.
BdbRef(P) create( BdbRef(BdbEvent)& theEvent, BdbRef(P) theP ) = 0
Abstract create function. This should be defined in descendant classes to create the P object and insert it into the persistent event.
Return to Table of Contents.
Description
This class implements a proxy strategy for the event store for lists of objects within the event. It inherits from IfdDataProxyTemplate<T> and implements the fault & store member functions. However, it
defines two new functions (create & locate) that are abstract and must be defined in descendant classes. These functions create and locate persistent objects in the persistent event hierarchy respectively.
Inheritance Tree
BdbListProxy<T, P> > IfdDataProxyTemplate<T>
Interface
#include "BdbEvent/BdbListProxy.hh"
Constructors
BdbListProxy( )
Default constructor.
Selectors
None
Modifiers
None.
Operations
IfdHepAList<T>* faultHandler( IfdProxyDict* d, const IfdKey& k, AbsArg& )
Fault handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<T>::get() request. The last arguement can be ignored in this context.
bool storeHandler( IfdProxyDict* d, const IfdKey& k, AbsArg&, IfdHepAList<T>* theTList )
Store handler. The first argument (IfdProxyDict* d) is the current proxy dictionary (transient event in this case), and the second argument (const IfdKey& k) is the secondary key as specified in the
Ifd<IfdHepAList<T> >::put() request..The last argument (IfdHepAList<T>* theTList) is transient object as specified in the Ifd<IfdHepAList<T> >::put() request. The AbsArg& argument can
be ignored in this context.
BdbRef(P) locate( BdbRef(BdbEvent)& theEvent ) = 0
Abstract locate function. This should be defined in descendant classes to locate the P class from the persistent event.
BdbRef(P) create( BdbRef(BdbEvent)& theEvent, BdbRef(P) theP ) = 0
Abstract create function. This should be defined in descendant classes to create the P object and insert it into the persistent event. [This needs work.]
Return to Table of Contents.
In the situation where a data member in one class is a pointer to another class, special care must be taken to ensure that the destination transient object exists by the time the pointer is traversed. A set of smart pointers
performs this operation for different configurations of the destination class. These smart pointers have identical semantics to the equivalent normal C++ pointer, but automatically build the destination transient information from the persistent
equivalents when necessary. The smart pointers are templated classes, having as arguments the transient type of the destination (called T in the following examples) and the corresponding persistent counterpart (called P in the
following).
The following smart pointers exist:
- BdbPtr<T, P> should be used instead of T* to reference single objects. Thus, if class A has a reference to an object of class B, having a persistent counterpart class BP,
the replacement is:
class B; // Old
B* theB;
#include "PkgB/B.hh" // New
#include "PkgB/PB.hh
BdbPtr<B, BP> theB;
- BdbHepAListPtr<T, P> replaces HepAList<T>* .
HepAList<B>* theBList; // old
BdbHepAListPtr<B, BP> theBList; // new
- BdbRWListPtr<L, T, P> replaces Rogue Wave pointer-based lists & vectors. The first argument L is the templated list type.
RWTPtrOrderedVector<B>* theBList; // old
BdbRWListPtrPtr<RWTPtrOrderedVector<B>, B, BP> theBList; // new
- BdbHashDictionaryPtr<K, T, P> replaces RWTPtrHashDictionary<K, T>* . In addition, B must be modified to supply a key( ) function that returns the desired key of type
K*.
RWTPtrHashDictionary<K, B>* theBDict; // old
BdbHashDictionaryPtrPtr<K, B, BP> theBDict; // new
Inheritance Tree
BdbPtr<T>
BdbHepAListPtr<T, P> > BdbListPtr<L, T, P>
BdbRWListPtr<L, T, P> > BdbListPtr<L, T, P>
BdbHashDictionaryPtr<K, T, P>
Interface
#include "BdbEvent/BdbPtr.hh"
#include "BdbEvent/BdbHepAListPtr.hh"
#include "BdbEvent/BdbRWListPtr.hh"
#include "BdbEvent/BdbHashDictionaryPtr.hh"
Constructors
BdbPtr<T, P>( )
BdbHepAListPtr<T, P>( )
BdbRWListPtr<L, T< P>( )
BdbHashDictionaryPtr<K, T, P>( )
Construct an empty smart pointer of the appropriate type.
BdbPtr<T, P>( T* theT )
BdbHepAListPtr<T, P>( IfdHepAList<T>* theTList )
BdbRWListPtr<L, T< P>( L* theTList )
BdbHashDictionaryPtr<K, T, P>( RWTPtrHashDictionary<K, T>* theTDict )
Construct a smart pointer referencing the transient object theT, theTList or theTDict respectively.
Selectors
None.
Modifiers
set( BdbRef(BdbRefVector<P>) theP, BdbObjectCache* theCache = 0 )
Set the persistent counterpart of ther transdient object to theP. The second argument of type BdbObjectCache is the object cache that may be retrieved from the transient event. This cache manages the
creation of transient objects from persistent ones and ensures that the one-to-one relationship between the transient object and its persistent counterpart is maintained. [Need to add a section on this cache.]
Operations
None.
Return to Table of Contents.
There is a problem when elements in a list belong not to a single class, but to different classes that all inherit from the same parent. First, the type of each element cannot intrinsically be determined by the fault
handler, and second, the persistent collection classes can only store such polymorphic elements in a BdbRefVector(P) list. If the elements are
small objects there is potentially a large space overhead in the database. We do not currently have an ideal solution to this, but are adopting the strategy of using BdbRefVector(P) lists directly, Polymorphism is maintained by the tight coupling of the
transient & persistent counterparts where each of them is responsible for the creation of the other.
[Need more on this.]
Return to Table of Contents.
Description
All persistent event objects must inherit from the abstract class BdbEvtObj, which itself inherits from the persistent base class d_Object. Coding rules for persistent objects are discussed in the
draft BABAR DDL Coding Guidelines and Hints. Descendant classes must implement the transient( ) member function, which creates a transient object corresponding to
the persistent one.
Inheritance Tree
BdbEvtObj > d_Object
Interface
#include "BdbEvent/BdbEvtObj.hh"
Constructors
BdbEvtObj( )
Default constructor.
Selectors
None.
Modifiers
None.
Operations
AbsEvtObj* transient( IfdProxyDict* theEvent )
Create a transient object corresponding to the persistent one.
Return to Table of Contents.
Description
Classes for persistent event collections. The HepVector(P) class implements an extensible vector of objects of persistent capable objects of type P. The BdbRefVector(P) class implements an extensible vector
of references to persistent capable objects of type P. In both cases the objects to be associated with the persistent collections must themselves inherit from the d_Object class. The BdbRefVector class has the advantage that the elements
exist as separate objects within the database and can be located elsewhere within the database so as to optimize access to them.
Inheritance Tree
HepVector(P)
BdbRefVector(P)
Interface
#include "RD45/Hep.h"
Constructors
Refer to BABAR DDL Coding Guidelines and Hints
Selectors
Refer to BABAR DDL Coding Guidelines and Hints
Modifiers
Refer to BABAR DDL Coding Guidelines and Hints
Operations
Refer to BABAR DDL Coding Guidelines and Hints
Return to Table of Contents.
Description
Within the fault and store handlers described in the section Transient Object Proxies, the persistent event is accessed by the
following code fragment:
BdbRef(BdbEvent) theEvent( 0 );
BdbBdbRef<BdbEvent>* theAccessor = Ifd<BdbBdbRef<BdbEvent> >::get( d, "BdbEvent" );
if ( 0 != theAccessor ) {
theEvent = *theAccessor;
}
if ( theEvent.isValid( ) ) {
[...]
The get function argument (IfdProxyDict* d) is the proxy dictionary corresponding to the transient event which was passed through as an argument to the fault and store handlers. The function returns a NULL
value if no persistent event is associated with the transient event. [We'd like to remove some of the above complexity.]
Associating the Persistent Event with the Transient Event
The persistent event is associated with the transient event through the following mechanism (by the event store Input Module).
AbsEvent* gblEvent; // Global transient event
BdbRef(BdbEvent) persEvent; // Persistent event set via Event Store access
BdbBdbRef<BdbEvent>* theAccessor = new BdbBdbRef<BdbEvent>( persEvent );
IfdDataProxy<BdbBdbRef<BdbEvent> >* myProxy;
myProxy = new IfdDataProxyTemplate<BdbBdbRef<BdbEvent> >( persEvent );
bool result = Ifd<BdbBdbRef<BdbEvent> >::put( gblEvent, myProxy, "BdbEvent" );
Return to Table of Contents.
Refer to the BABAR Event Store Reference Manual for information about accessing information from the persistent event.
Return to Table of Contents
The mechanism by which transient objects that have been associated with the transient event as a result of processing is the following:
- The function Ifd<T>::markForStore must be called for each transient class T (and key if appropriate):
Ifd<T>::markForStore( AbsEvent* ev, const IfdKey& k );
- The transient event itself must be stored by calling the AbsEvent::storeAllMarked( ) function:
AbsEvent ev;
[...]
ev->storeAllMarked( );
The act of storing the event will cause the store handlers for for all objects that have been markForStore'd to be called in order to create the corresponding persistent objects and associate them with the
persistent event.
How to handle the input objects (objects that were associated with the input event) has not yet been decided. One possible model is that the underlying persistent objects are treated as being const and therefore cannot be
modified, in which case they need not be markForStore'd. Another possibility is that the underlying persistent information should be updated to reflect any updates to the corresponding transient information, in which case they should be
explicitly markForStore'd in order to modify the persistent information.
Return to Table of Contents.
Description
These examples demonstrates use of the API for the 4 cases:
- A single object is associated with the event. The object has no references to other objects.
- A list of simple objects is associated with the event. The objects have no references to other objects.
- A single object is associated with the event. It has a refererence to another object.
- A list of objects is associated with the event. Each object has a reference to a list of other objects.
Example 1: Single Object (no references)
There is a single EvtTag object per event.
//--------------------------------------------------------
class EvtTag : public AbsEvtObj {
public:
EvtTag( );
double _x;
double _y;
double _z;
}
//--------------------------------------------------------
class EvtTagP : public BdbEvtObj {
public:
EvtTagP( );
EvtTagP( EvtTag* aTag );
AbsEvtObj* transient( IfdProxyDict* theEvent );
d_Double _x;
d_Double _y;
d_Double _z;
}
EvtTagP::EvtTagP( EvtTag* aTag ) {
_x = aTag->_x;
_y = aTag->_y;
_z = aTag->_z;
aTag->self.pers = ooThis( );
}
AbsEvtObj*
EvtTagP::transient( IfdProxyDict* theEvent ) {
EvtTag* theTag = new EvtTag;
theTag->_x = _x;
theTag->_y = _y;
theTag->_z = _z;
return theTag;
}
//--------------------------------------------------------
class EvtTagProxy : public IfdObjectProxy< EvtTag, EvtTagP > {
public:
BdbRef(EvtTagP) locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
bool create( BdbRef(EvtTagP) theTag, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
}
BdbRef(EvtTagP)
EvtTagProxy::locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
BdbRef(EvtTagP) theTag = NULL;
// Locate the EvtTagP object within the persistent event (Pavel's code)
return theTag;
}
bool
EmcGHitListProxy::create( BdbRef(EvtTagP) theTag, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
// Position the EvtTagP object within the persistent event (see Pavel's code)
return true;
}
Example 2: List of simple objects (no references)
There is a single list of EmcGHit objects per event.
//--------------------------------------------------------
class EmcGHitP : public BdbEvtObj {
public:
EmcGHitP( );
EmcGHitP( EmcGHit* aHit );
AbsEvtObj* transient( IfdProxyDict* theEvent );
d_Double _x;
d_Double _y;
d_Double _z;
d_Double _t;
d_Double _edew;
d_Double _edep;
d_Long _idnt;
d_Long _igtr;
}
EmcGHitP::EmcGHitP( EmcGHit* aHit ) {
_x = aHit->_x;
_y = aHit->_y;
_z = aHit->_z;
_t = aHit->_t;
_edew = aHit->_edew;
_edep = aHit->_edep;
_idnt = aHit->_idnt;
_igtr = aHit->_igtr;
aHit->self.pers = ooThis( );
}
AbsEvtObj*
EmcGHitP::transient( IfdProxyDict* theEvent ) {
EmcGHit* theHit = new EmcGHit;
theHit->_x = _x;
theHit->_y = _y;
theHit->_z = _z;
theHit->_t = _t;
theHit->_edew = _edew;
theHit->_edep = _edep;
theHit->_idnt = _idnt;
theHit->_igtr = _igtr;
return theHit;
}
//--------------------------------------------------------
class EmcGHitListProxy : public BdbListProxy< EmcGHit, EmcGHitP > {
public:
BdbRefVector(EmcGHitP) locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
bool create( BdbRefVector(EmcGHitP) theList, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
}
BdbRefVector(EmcGHitP)
EmcGHitListProxy::locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
BdbRefVector(EmcGHitP) thePList = NULL;
// Locate the EmcGHit list within the persistent event (Pavel's code)
return thePList;
}
bool
EmcGHitListProxy::create( BdbRefVector(EmcGHitP) theList, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
// Position theList within the persistent event (see Pavel's code)
return true;
}
Example 3: Single object (with references)
There is a single EvtTag2 object per event, which references the EvtTag object.
//--------------------------------------------------------
class EvtTag2 : public AbsEvtObj {
public:
EvtTag( );
double _x;
double _y;
double _z;
BdbPtr<EvtTag> _tag;
}
//--------------------------------------------------------
class EvtTag2P : public BdbEvtObj {
public:
EvtTag2P( );
EvtTag2P( EvtTag2* aTag );
AbsEvtObj* transient( IfdProxyDict* theEvent );
d_Double _x;
d_Double _y;
d_Double _z;
BdbRef(EvtTag) _tag;
}
EvtTag2P::EvtTag2P( EvtTag2* aTag ) {
_x = aTag->_x;
_y = aTag->_y;
_z = aTag->_z;
aTag->self.pers = ooThis( );
// Now deal with references to other objects
if ( NULL != aTag->_tag.pers ) {
_tag = aTag->_tag.pers;
}
}
AbsEvtObj*
EvtTag2P::transient( IfdProxyDict* theEvent ) {
EvtTag* theTag = new EvtTag2;
theTag->_x = _x;
theTag->_y = _y;
theTag->_z = _z;
// Now deal with references to other objects
theTag->_tag.pers = _tag;
theTag->_tag.dict = theEvent;
return theTag;
}
//--------------------------------------------------------
class EvtTag2Proxy : public IfdObjectProxy< EvtTag2, EvtTag2P > {
public:
BdbRef(EvtTag2P) locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
bool create( BdbRef(EvtTag2P) theTag, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey );
}
BdbRef(EvtTag2P)
EvtTag2Proxy::locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
BdbRef(EvtTag2P) theTag = NULL;
// Locate the EvtTag2P object within the persistent event (Pavel's code)
return theTag;
}
bool
EmcGHitListProxy::create( BdbRef(EvtTag2P) theTag, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
// Position the EvtTag2P object within the persistent event (see Pavel's code)
return true;
}
Example 4: List of objects, each with a list of references
There is a list of EmcCluster objects per event, each of which references a list of EmcDigi objects.
//--------------------------------------------------------
class EmcCluster : public AbsRecoNeut {
public:
BdbListPtr<EmcDigi> _memberAList; // Was IfdHepAlist<EmcDigi>*
int _numberOfDigis;
}
//--------------------------------------------------------
class EmcClusterP : public BdbEvtObj {
public:
EmcClusterP( );
EmcClusterP( EmcCluster* aCluster );
AbsEvtObj* transient( IfdProxyDict* theEvent );
BdbRefVector(EmcDigi) _memberAList;
d_Long _numberOfDigis;
}
EmcClusterP::EmcClusterP( EmcCluster* aCluster ) {
size_t length;
IfdHepAList<EmcCluster>* theTList;
EmcCluster* theT;
_numberOfDigis = aCluster->_numberOfDigis;
aCluster->self.pers = ooThis( );
theTList = aCluster->_memberAList
length = theTList->length( ); // or whatever
// Loop over elements in transient list, checking whether they
// already have persistent equivalents. If they don't, create the new
// persistent object, insert it into the persistent list.
// If they do, just insert it into the persistent list.
for ( i = 0; i < length; i++ ) {
theT = theTList[i];
if ( NULL == ( theP = theT->self.pers ) ) {
// Persistent hit doesn't already exist - create it
theP = HepNew( EmcClusterP )( theT );
}
// Add the persistent hit to the persistent list
_memberAList.insert( theP ); // or whatever
}
}
AbsEvtObj*
EmcClusterP::transient( IfdProxyDict* theEvent ) {
EmcCluster* theCluster = new EmcCluster;
theCluster->_numberOfDigis = _numberOfDigis;
// Now deal with references to other objects
theCluster->_memberAList.pers = _memberAList;
theCluster->_memberAList.dict = theEvent;
return theCluster;
}
//--------------------------------------------------------
class EmcClusterListProxy : public BdbListProxy< EmcCluster, EmcClusterP > {
public
IfdHepAList<EmcCluster>* fault( IfdProxyDict* theDict, const IfdKey& theKey );
bool store( IfdProxyDict* theDict, IfdHepAList<EmcCluster>* theTList, const IfdKey& theKey );
}
BdbRefVector(EmcClusterP)
EmcClusterListProxy::locate( BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
BdbRefVector(EmcClusterP) theList = NULL;
// Locate the EmcClusterP list object within the persistent event (Pavel's code)
return theList;
}
bool
EmcClusterListProxy::create(
BdbRefVector(EmcClusterP) theList, BdbRef(BdbEvent)& theEvent, const IfdKey& theKey ) {
// Position the EmcClusterP list object within the persistent event (see Pavel's code)
return true;
}

DB Home | BaBar Home | Computing | Reconstruction | Simulation |
Search

DRQuarrie@LBL.Gov
|