00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "GaudiKernel/IDataProviderSvc.h"
00010 #include "GaudiKernel/ISelectStatement.h"
00011 #include "GaudiKernel/IDataManagerSvc.h"
00012 #include "GaudiKernel/GenericAddress.h"
00013 #include "GaudiKernel/SmartDataPtr.h"
00014 #include "GaudiKernel/AlgFactory.h"
00015 #include "GaudiKernel/Tokenizer.h"
00016 #include "GaudiKernel/IRegistry.h"
00017 #include "GaudiKernel/Algorithm.h"
00018 #include "GaudiKernel/MsgStream.h"
00019 #include "GaudiKernel/SmartIF.h"
00020 #include "GaudiKernel/NTuple.h"
00021 #include <vector>
00022
00023 namespace {
00024 template <class T> static long upper(const INTupleItem* item) {
00025 const NTuple::_Data<T>* it = dynamic_cast<const NTuple::_Data<T>*>(item);
00026 return long(it->range().upper());
00027 }
00028
00029 template<class TYP> static
00030 StatusCode createItem (MsgStream& log,
00031 INTuple* tuple,
00032 INTupleItem* src,
00033 const TYP& null)
00034 {
00035 NTuple::_Data<TYP>* source = dynamic_cast<NTuple::_Data<TYP>*>(src);
00036 TYP low = source->range().lower();
00037 TYP high = source->range().upper();
00038 long hasIdx = source->hasIndex();
00039 long ndim = source->ndim();
00040 const std::string& name = source->name();
00041 std::string idxName;
00042 long dim[4], idxLen = 0;
00043 long dim1 = 1, dim2 = 1;
00044 INTupleItem* it = 0;
00045 for ( int i = 0; i < ndim; i++ )
00046 dim[i] = source->dim(i);
00048 if ( hasIdx ) {
00049 const INTupleItem* index = source->indexItem();
00050 idxName = index->name();
00051 switch( index->type() ) {
00052 case DataTypeInfo::UCHAR:
00053 idxLen = upper<unsigned char>(index);
00054 break;
00055 case DataTypeInfo::USHORT:
00056 idxLen = upper<unsigned short>(index);
00057 break;
00058 case DataTypeInfo::UINT:
00059 idxLen = upper<unsigned int>(index);
00060 break;
00061 case DataTypeInfo::ULONG:
00062 idxLen = upper<unsigned long>(index);
00063 break;
00064 case DataTypeInfo::CHAR:
00065 idxLen = upper<char>(index);
00066 break;
00067 case DataTypeInfo::SHORT:
00068 idxLen = upper<short>(index);
00069 break;
00070 case DataTypeInfo::INT:
00071 idxLen = upper<int>(index);
00072 break;
00073 case DataTypeInfo::LONG:
00074 idxLen = upper<long>(index);
00075 break;
00076 default:
00077 log << MSG::ERROR << "Column " << idxName
00078 << " is not a valid index column!" << endmsg;
00079 return StatusCode::FAILURE;
00080 }
00081 }
00082 switch( ndim ) {
00083 case 0:
00084 it = NTuple::_Item<TYP>::create (tuple, name, typeid(TYP), low, high, null);
00085 break;
00086 case 1:
00087 dim1 = (hasIdx) ? idxLen : dim[0];
00088 it = NTuple::_Array<TYP>::create (tuple,
00089 name,
00090 typeid(TYP),
00091 idxName,
00092 dim1,
00093 low,
00094 high,
00095 null);
00096 break;
00097 case 2:
00098 dim1 = (hasIdx) ? idxLen : dim[0];
00099 dim2 = (hasIdx) ? dim[0] : dim[1];
00100 it = NTuple::_Matrix<TYP>::create ( tuple,
00101 name,
00102 typeid(TYP),
00103 idxName,
00104 dim1,
00105 dim2,
00106 low,
00107 high,
00108 null);
00109 break;
00110 default:
00111 return StatusCode::FAILURE;
00112 }
00113 return tuple->add(it);
00114 }
00115 }
00116
00127 class CollectionCloneAlg : public Algorithm {
00129 INTupleSvc* m_dataSvc;
00131 std::string m_tupleSvc;
00133 std::string m_output;
00135 std::vector<std::string> m_inputs;
00137 std::string m_rootName;
00139 std::string m_outName;
00141 std::string m_criteria;
00143 std::string m_selectorName;
00144 public:
00145
00147 CollectionCloneAlg(const std::string& name, ISvcLocator* pSvcLocator)
00148 : Algorithm(name, pSvcLocator), m_dataSvc(0)
00149 {
00150 declareProperty("EvtTupleSvc", m_tupleSvc="EvtTupleSvc");
00151 declareProperty("Input", m_inputs);
00152 declareProperty("Output", m_output);
00153 }
00155 virtual ~CollectionCloneAlg() {
00156 }
00157
00159 virtual StatusCode initialize() {
00160 MsgStream log(msgSvc(), name());
00161 m_rootName = "";
00162 m_outName = "";
00163 m_criteria = "";
00164 m_selectorName = "";
00165 StatusCode sc = service(m_tupleSvc, m_dataSvc, true);
00166 if ( sc.isSuccess() ) {
00167 std::string fun;
00168 Tokenizer tok(true);
00169 tok.analyse(m_output, " ", "", "", "=", "'", "'");
00170 for ( Tokenizer::Items::iterator i = tok.items().begin(); i != tok.items().end(); i++ ) {
00171 const std::string& tag = (*i).tag();
00172 const std::string& val = (*i).value();
00173 switch( ::toupper(tag[0]) ) {
00174 case 'D':
00175 m_outName = val;
00176 break;
00177 case 'S':
00178 m_criteria = val;
00179 break;
00180 case 'F':
00181 fun = val;
00182 default:
00183 break;
00184 }
00185 }
00186 if ( m_outName.empty() ) {
00187 log << MSG::ERROR << "Failed to analyze output specs:" << m_output << endmsg;
00188 return StatusCode::FAILURE;
00189 }
00190 if ( fun.length() > 0 || m_criteria.length() > 0 ) {
00191 if ( m_criteria.length() > 0 && fun.length() == 0 ) fun = "NTuple::Selector";
00192 m_selectorName = fun;
00193 return StatusCode::SUCCESS;
00194 }
00195 return sc;
00196 }
00197 log << MSG::ERROR << "Failed to access service \""
00198 << m_tupleSvc << "\"." << endmsg;
00199 return sc;
00200 }
00201
00203 virtual StatusCode finalize() {
00204 if ( m_dataSvc ) m_dataSvc->release();
00205 m_dataSvc = 0;
00206 return StatusCode::SUCCESS;
00207 }
00208
00210 virtual StatusCode execute() {
00211 StatusCode status = connect();
00212 if ( status.isSuccess() ) {
00213 status = mergeInputTuples();
00214 }
00215 return status;
00216 }
00217
00219 virtual StatusCode book(const NTuple::Tuple* nt) {
00220 MsgStream log(msgSvc(), name());
00221 const INTuple::ItemContainer& items = nt->items();
00222 StatusCode status = StatusCode::SUCCESS;
00223 INTuple::ItemContainer::const_iterator i;
00224 NTuple::Tuple* tuple = m_dataSvc->book(m_outName, nt->clID(), nt->title());
00225 for (i = items.begin(); i != items.end(); ++i) {
00226 long type = (*i)->type();
00227 switch(type) {
00228 case DataTypeInfo::UCHAR:
00229 status = createItem(log, tuple, *i, (unsigned char)0);
00230 break;
00231 case DataTypeInfo::USHORT:
00232 status = createItem(log, tuple, *i, (unsigned short)0);
00233 break;
00234 case DataTypeInfo::UINT:
00235 status = createItem(log, tuple, *i, (unsigned int)0);
00236 break;
00237 case DataTypeInfo::ULONG:
00238 status = createItem(log, tuple, *i, (unsigned long)0);
00239 break;
00240 case DataTypeInfo::CHAR:
00241 status = createItem(log, tuple, *i, char(0));
00242 break;
00243 case DataTypeInfo::SHORT:
00244 status = createItem(log, tuple, *i, short(0));
00245 break;
00246 case DataTypeInfo::INT:
00247 status = createItem(log, tuple, *i, int(0));
00248 break;
00249 case DataTypeInfo::LONG:
00250 status = createItem(log, tuple, *i, long(0));
00251 break;
00252 case DataTypeInfo::BOOL:
00253 status = createItem(log, tuple, *i, false);
00254 break;
00255 case DataTypeInfo::FLOAT:
00256 status = createItem(log, tuple, *i, float(0.0));
00257 break;
00258 case DataTypeInfo::DOUBLE:
00259 status = createItem(log, tuple, *i, double(0.0));
00260 break;
00261 case DataTypeInfo::OBJECT_ADDR:
00262 status = createItem(log, tuple, *i, (IOpaqueAddress*)0);
00263 break;
00264 case DataTypeInfo::POINTER:
00265 status = createItem(log, tuple, *i, (void*)0);
00266 break;
00267 case DataTypeInfo::STRING:
00268
00269
00270 case DataTypeInfo::NTCHAR:
00271
00272
00273 case DataTypeInfo::UNKNOWN:
00274 default:
00275 status = StatusCode::FAILURE;
00276 break;
00277 }
00278 }
00279 return status;
00280 }
00281
00282
00283 virtual StatusCode checkInput(const NTuple::Tuple* clone, const NTuple::Tuple* src) {
00284 MsgStream log(msgSvc(), name());
00285 if ( 0 != clone && 0 != src ) {
00286 const INTuple::ItemContainer& clone_items = clone->items();
00287 const std::string clone_id = clone->registry()->identifier();
00288 const std::string src_id = src->registry()->identifier();
00289
00290 INTuple::ItemContainer::const_iterator i;
00291 log << MSG::ERROR;
00292 for (i = clone_items.begin(); i != clone_items.end(); ++i) {
00293 const INTupleItem* itm = *i;
00294 const std::string& nam = itm->name();
00295 const INTupleItem* src_itm = src->find(nam);
00296 if ( !src_itm ) {
00297 log << "Tuple item " << nam << " not present in " << src_id << endmsg;
00298 return StatusCode::FAILURE;
00299 }
00300 if ( itm->type() != src_itm->type() ) {
00301 log << "Tuple item " << nam << " are of different types in "
00302 << src_id << ":" << src_itm->typeName() << " <-> "
00303 << clone_id << ":" << itm->typeName() << endmsg;
00304 return StatusCode::FAILURE;
00305 }
00306 if ( itm->ndim() != src_itm->ndim() ) {
00307 log << "Tuple item " << nam << " have different dimensions in "
00308 << src_id << ":" << src_itm->ndim() << " <-> "
00309 << clone_id << ":" << itm->ndim() << endmsg;
00310 return StatusCode::FAILURE;
00311 }
00312 for (int j=0; j<itm->ndim(); ++j) {
00313 if ( src_itm->dim(j) != itm->dim(j) ) {
00314 log << "Tuple item " << nam << " have different dimensions in "
00315 << src_id << "[" << j << "]:" << src_itm->dim(j) << " <-> "
00316 << clone_id << "[" << j << "]:" << itm->dim(j) << endmsg;
00317 return StatusCode::FAILURE;
00318 }
00319 }
00320 if ( itm->hasIndex() != src_itm->hasIndex() ) {
00321 log << "Tuple item " << nam << " has different index colums "
00322 << src_id << ":" << src_itm->hasIndex() << " <-> "
00323 << clone_id << ":" << itm->hasIndex() << endmsg;
00324 return StatusCode::FAILURE;
00325 }
00326 if ( itm->hasIndex() ) {
00327 if ( itm->index() != src_itm->index() ) {
00328 log << "Tuple item " << nam << " has different index colums "
00329 << src_id << ":" << src_itm->index() << " <-> "
00330 << clone_id << ":" << itm->index() << endmsg;
00331 return StatusCode::FAILURE;
00332 }
00333 }
00334 }
00335 return StatusCode::SUCCESS;
00336 }
00337 return StatusCode::FAILURE;
00338 }
00339
00341 StatusCode mergeEntries(const std::string& input) {
00342 MsgStream log(msgSvc(), name());
00343 NTuplePtr out(m_dataSvc, m_outName);
00344 if ( 0 != out ) {
00345 const INTuple::ItemContainer& clone_items = out->items();
00346 std::vector<GenericAddress> addrVector(clone_items.size());
00347 StatusCode status = StatusCode::SUCCESS;
00348 NTuplePtr nt(m_dataSvc, input);
00349 size_t k = 0, nentry = 0;
00350 if ( 0 != nt ) {
00351 const INTuple::ItemContainer& source_items = nt->items();
00352 for (k=0; k < source_items.size(); ++k ) {
00353 if ( source_items[k]->type() == DataTypeInfo::OBJECT_ADDR ) {
00354 *(IOpaqueAddress**)source_items[k]->buffer() = &addrVector[k];
00355 }
00356 }
00357 while ( status.isSuccess() ) {
00358 status = m_dataSvc->readRecord(nt.ptr());
00359 if ( status.isSuccess() ) {
00360 INTuple::ItemContainer::const_iterator i;
00361 nentry++;
00362 for (k=0,i = source_items.begin(); i != source_items.end(); ++i,++k) {
00363 const INTupleItem* src_itm = *i;
00364 const INTupleItem* out_itm = out->find(src_itm->name());
00365 size_t size = 0;
00366 switch((*i)->type()) {
00367 case DataTypeInfo::UCHAR:
00368 size = sizeof(unsigned char);
00369 break;
00370 case DataTypeInfo::USHORT:
00371 size = sizeof(unsigned short);
00372 break;
00373 case DataTypeInfo::UINT:
00374 size = sizeof(unsigned int);
00375 break;
00376 case DataTypeInfo::ULONG:
00377 size = sizeof(unsigned long);
00378 break;
00379 case DataTypeInfo::CHAR:
00380 size = sizeof(char);
00381 break;
00382 case DataTypeInfo::SHORT:
00383 size = sizeof(short);
00384 break;
00385 case DataTypeInfo::INT:
00386 size = sizeof(int);
00387 break;
00388 case DataTypeInfo::LONG:
00389 size = sizeof(long);
00390 break;
00391 case DataTypeInfo::BOOL:
00392 size = sizeof(bool);
00393 break;
00394 case DataTypeInfo::FLOAT:
00395 size = sizeof(float);
00396 break;
00397 case DataTypeInfo::DOUBLE:
00398 size = sizeof(double);
00399 break;
00400 case DataTypeInfo::STRING:
00401 *(std::string*)out_itm->buffer() = *(std::string*)src_itm->buffer();
00402 size = 0;
00403 break;
00404 case DataTypeInfo::NTCHAR:
00405 size = ::strlen((const char*)src_itm->buffer())+1;
00406 break;
00407 case DataTypeInfo::POINTER:
00408 {
00409 *(void**)out_itm->buffer() = *(void**)src_itm->buffer();
00410 size = 0;
00411 }
00412 break;
00413 case DataTypeInfo::OBJECT_ADDR:
00414 {
00415 IOpaqueAddress* ppA1 = &addrVector[k];
00416 IOpaqueAddress** ppA2 = (IOpaqueAddress**)out_itm->buffer();
00417 *ppA2 = ppA1;
00418 size = 0;
00419 }
00420 break;
00421 case DataTypeInfo::UNKNOWN:
00422 default:
00423 size = 0;
00424 break;
00425 }
00426 if ( size > 0 ) {
00427 ::memcpy((void*)out_itm->buffer(), src_itm->buffer(), size*src_itm->length());
00428 }
00429 }
00430 status = m_dataSvc->writeRecord(out.ptr());
00431 if ( !status.isSuccess() ) {
00432 log << MSG::ERROR << "Failed to write record " << nentry
00433 << " from " << input << " to " << m_outName << endmsg;
00434 }
00435 }
00436 }
00437 log << MSG::INFO << "End of reading tuple " << input
00438 << " after " << nentry << " entries." << endmsg;
00439
00440 if ( nentry > 0 || m_selectorName != "" ) {
00441 return StatusCode::SUCCESS;
00442 }
00443 return StatusCode::FAILURE;
00444 }
00445 log << MSG::ERROR << "Failed to access input: " << input << endmsg;
00446 }
00447 return StatusCode::FAILURE;
00448 }
00449
00451 StatusCode connect() {
00452 StatusCode status = StatusCode::SUCCESS;
00453 for (size_t i=0; i < m_inputs.size(); ++i) {
00454 NTuplePtr nt(m_dataSvc, m_inputs[i]);
00455 if ( !(0 == nt) ) {
00456 NTuplePtr out(m_dataSvc, m_outName);
00457 if ( 0 == out ) {
00458 status = book(nt);
00459 }
00460 else {
00461 status = checkInput(out, nt);
00462 }
00463 if ( !status.isSuccess() ) {
00464 return status;
00465 }
00466 else if ( m_selectorName != "" ) {
00467 SmartIF<ISelectStatement> stmt(ROOT::Reflex::PluginService::Create<IInterface*>(m_selectorName,serviceLocator()));
00468 if ( stmt.isValid( ) ) {
00469 if ( m_criteria.length() > 0 ) stmt->setCriteria(m_criteria);
00470 nt->attachSelector(stmt);
00471 }
00472 else {
00473 MsgStream log(msgSvc(), name());
00474 log << MSG::ERROR << "Failed to attach tuple selector to " << m_inputs[i] << endmsg;
00475 return StatusCode::FAILURE;
00476 }
00477 }
00478 }
00479 else {
00480 MsgStream log(msgSvc(), name());
00481 log << MSG::ERROR << "Failed to access tuple: " << m_inputs[i] << endmsg;
00482 return StatusCode::FAILURE;
00483 }
00484 }
00485 return StatusCode::SUCCESS;
00486 }
00487
00489 StatusCode mergeInputTuples() {
00490 MsgStream log(msgSvc(), name());
00491 for (size_t inp=0; inp < m_inputs.size(); ++inp) {
00492 StatusCode sc = mergeEntries(m_inputs[inp]);
00493 if ( !sc.isSuccess() ) {
00494 log << MSG::ERROR << "Failed to merge tuple:" << m_inputs[inp] << endmsg;
00495 return sc;
00496 }
00497 }
00498 return StatusCode::SUCCESS;
00499 }
00500 };
00501 DECLARE_ALGORITHM_FACTORY(CollectionCloneAlg)