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 break ;
00183 default:
00184 break;
00185 }
00186 }
00187 if ( m_outName.empty() ) {
00188 log << MSG::ERROR << "Failed to analyze output specs:" << m_output << endmsg;
00189 return StatusCode::FAILURE;
00190 }
00191 if ( fun.length() > 0 || m_criteria.length() > 0 ) {
00192 if ( m_criteria.length() > 0 && fun.length() == 0 ) fun = "NTuple::Selector";
00193 m_selectorName = fun;
00194 return StatusCode::SUCCESS;
00195 }
00196 return sc;
00197 }
00198 log << MSG::ERROR << "Failed to access service \""
00199 << m_tupleSvc << "\"." << endmsg;
00200 return sc;
00201 }
00202
00204 virtual StatusCode finalize() {
00205 if ( m_dataSvc ) m_dataSvc->release();
00206 m_dataSvc = 0;
00207 return StatusCode::SUCCESS;
00208 }
00209
00211 virtual StatusCode execute() {
00212 StatusCode status = connect();
00213 if ( status.isSuccess() ) {
00214 status = mergeInputTuples();
00215 }
00216 return status;
00217 }
00218
00220 virtual StatusCode book(const NTuple::Tuple* nt) {
00221 MsgStream log(msgSvc(), name());
00222 const INTuple::ItemContainer& items = nt->items();
00223 StatusCode status = StatusCode::SUCCESS;
00224 INTuple::ItemContainer::const_iterator i;
00225 NTuple::Tuple* tuple = m_dataSvc->book(m_outName, nt->clID(), nt->title());
00226 for (i = items.begin(); i != items.end(); ++i) {
00227 long type = (*i)->type();
00228 switch(type) {
00229 case DataTypeInfo::UCHAR:
00230 status = createItem(log, tuple, *i, (unsigned char)0);
00231 break;
00232 case DataTypeInfo::USHORT:
00233 status = createItem(log, tuple, *i, (unsigned short)0);
00234 break;
00235 case DataTypeInfo::UINT:
00236 status = createItem(log, tuple, *i, (unsigned int)0);
00237 break;
00238 case DataTypeInfo::ULONG:
00239 status = createItem(log, tuple, *i, (unsigned long)0);
00240 break;
00241 case DataTypeInfo::CHAR:
00242 status = createItem(log, tuple, *i, char(0));
00243 break;
00244 case DataTypeInfo::SHORT:
00245 status = createItem(log, tuple, *i, short(0));
00246 break;
00247 case DataTypeInfo::INT:
00248 status = createItem(log, tuple, *i, int(0));
00249 break;
00250 case DataTypeInfo::LONG:
00251 status = createItem(log, tuple, *i, long(0));
00252 break;
00253 case DataTypeInfo::BOOL:
00254 status = createItem(log, tuple, *i, false);
00255 break;
00256 case DataTypeInfo::FLOAT:
00257 status = createItem(log, tuple, *i, float(0.0));
00258 break;
00259 case DataTypeInfo::DOUBLE:
00260 status = createItem(log, tuple, *i, double(0.0));
00261 break;
00262 case DataTypeInfo::OBJECT_ADDR:
00263 status = createItem(log, tuple, *i, (IOpaqueAddress*)0);
00264 break;
00265 case DataTypeInfo::POINTER:
00266 status = createItem(log, tuple, *i, (void*)0);
00267 break;
00268 case DataTypeInfo::STRING:
00269
00270
00271 case DataTypeInfo::NTCHAR:
00272
00273
00274 case DataTypeInfo::UNKNOWN:
00275 default:
00276 status = StatusCode::FAILURE;
00277 break;
00278 }
00279 }
00280 return status;
00281 }
00282
00283
00284 virtual StatusCode checkInput(const NTuple::Tuple* clone, const NTuple::Tuple* src) {
00285 MsgStream log(msgSvc(), name());
00286 if ( 0 != clone && 0 != src ) {
00287 const INTuple::ItemContainer& clone_items = clone->items();
00288 const std::string clone_id = clone->registry()->identifier();
00289 const std::string src_id = src->registry()->identifier();
00290
00291 INTuple::ItemContainer::const_iterator i;
00292 log << MSG::ERROR;
00293 for (i = clone_items.begin(); i != clone_items.end(); ++i) {
00294 const INTupleItem* itm = *i;
00295 const std::string& nam = itm->name();
00296 const INTupleItem* src_itm = src->find(nam);
00297 if ( !src_itm ) {
00298 log << "Tuple item " << nam << " not present in " << src_id << endmsg;
00299 return StatusCode::FAILURE;
00300 }
00301 if ( itm->type() != src_itm->type() ) {
00302 log << "Tuple item " << nam << " are of different types in "
00303 << src_id << ":" << src_itm->typeName() << " <-> "
00304 << clone_id << ":" << itm->typeName() << endmsg;
00305 return StatusCode::FAILURE;
00306 }
00307 if ( itm->ndim() != src_itm->ndim() ) {
00308 log << "Tuple item " << nam << " have different dimensions in "
00309 << src_id << ":" << src_itm->ndim() << " <-> "
00310 << clone_id << ":" << itm->ndim() << endmsg;
00311 return StatusCode::FAILURE;
00312 }
00313 for (int j=0; j<itm->ndim(); ++j) {
00314 if ( src_itm->dim(j) != itm->dim(j) ) {
00315 log << "Tuple item " << nam << " have different dimensions in "
00316 << src_id << "[" << j << "]:" << src_itm->dim(j) << " <-> "
00317 << clone_id << "[" << j << "]:" << itm->dim(j) << endmsg;
00318 return StatusCode::FAILURE;
00319 }
00320 }
00321 if ( itm->hasIndex() != src_itm->hasIndex() ) {
00322 log << "Tuple item " << nam << " has different index colums "
00323 << src_id << ":" << src_itm->hasIndex() << " <-> "
00324 << clone_id << ":" << itm->hasIndex() << endmsg;
00325 return StatusCode::FAILURE;
00326 }
00327 if ( itm->hasIndex() ) {
00328 if ( itm->index() != src_itm->index() ) {
00329 log << "Tuple item " << nam << " has different index colums "
00330 << src_id << ":" << src_itm->index() << " <-> "
00331 << clone_id << ":" << itm->index() << endmsg;
00332 return StatusCode::FAILURE;
00333 }
00334 }
00335 }
00336 return StatusCode::SUCCESS;
00337 }
00338 return StatusCode::FAILURE;
00339 }
00340
00342 StatusCode mergeEntries(const std::string& input) {
00343 MsgStream log(msgSvc(), name());
00344 NTuplePtr out(m_dataSvc, m_outName);
00345 if ( 0 != out ) {
00346 const INTuple::ItemContainer& clone_items = out->items();
00347 std::vector<GenericAddress> addrVector(clone_items.size());
00348 StatusCode status = StatusCode::SUCCESS;
00349 NTuplePtr nt(m_dataSvc, input);
00350 size_t k = 0, nentry = 0;
00351 if ( 0 != nt ) {
00352 const INTuple::ItemContainer& source_items = nt->items();
00353 for (k=0; k < source_items.size(); ++k ) {
00354 if ( source_items[k]->type() == DataTypeInfo::OBJECT_ADDR ) {
00355 *(IOpaqueAddress**)source_items[k]->buffer() = &addrVector[k];
00356 }
00357 }
00358 while ( status.isSuccess() ) {
00359 status = m_dataSvc->readRecord(nt.ptr());
00360 if ( status.isSuccess() ) {
00361 INTuple::ItemContainer::const_iterator i;
00362 nentry++;
00363 for (k=0,i = source_items.begin(); i != source_items.end(); ++i,++k) {
00364 const INTupleItem* src_itm = *i;
00365 const INTupleItem* out_itm = out->find(src_itm->name());
00366 size_t size = 0;
00367 switch((*i)->type()) {
00368 case DataTypeInfo::UCHAR:
00369 size = sizeof(unsigned char);
00370 break;
00371 case DataTypeInfo::USHORT:
00372 size = sizeof(unsigned short);
00373 break;
00374 case DataTypeInfo::UINT:
00375 size = sizeof(unsigned int);
00376 break;
00377 case DataTypeInfo::ULONG:
00378 size = sizeof(unsigned long);
00379 break;
00380 case DataTypeInfo::CHAR:
00381 size = sizeof(char);
00382 break;
00383 case DataTypeInfo::SHORT:
00384 size = sizeof(short);
00385 break;
00386 case DataTypeInfo::INT:
00387 size = sizeof(int);
00388 break;
00389 case DataTypeInfo::LONG:
00390 size = sizeof(long);
00391 break;
00392 case DataTypeInfo::BOOL:
00393 size = sizeof(bool);
00394 break;
00395 case DataTypeInfo::FLOAT:
00396 size = sizeof(float);
00397 break;
00398 case DataTypeInfo::DOUBLE:
00399 size = sizeof(double);
00400 break;
00401 case DataTypeInfo::STRING:
00402 *(std::string*)out_itm->buffer() = *(std::string*)src_itm->buffer();
00403 size = 0;
00404 break;
00405 case DataTypeInfo::NTCHAR:
00406 size = ::strlen((const char*)src_itm->buffer())+1;
00407 break;
00408 case DataTypeInfo::POINTER:
00409 {
00410 *(void**)out_itm->buffer() = *(void**)src_itm->buffer();
00411 size = 0;
00412 }
00413 break;
00414 case DataTypeInfo::OBJECT_ADDR:
00415 {
00416 IOpaqueAddress* ppA1 = &addrVector[k];
00417 IOpaqueAddress** ppA2 = (IOpaqueAddress**)out_itm->buffer();
00418 *ppA2 = ppA1;
00419 size = 0;
00420 }
00421 break;
00422 case DataTypeInfo::UNKNOWN:
00423 default:
00424 size = 0;
00425 break;
00426 }
00427 if ( size > 0 ) {
00428 ::memcpy((void*)out_itm->buffer(), src_itm->buffer(), size*src_itm->length());
00429 }
00430 }
00431 status = m_dataSvc->writeRecord(out.ptr());
00432 if ( !status.isSuccess() ) {
00433 log << MSG::ERROR << "Failed to write record " << nentry
00434 << " from " << input << " to " << m_outName << endmsg;
00435 }
00436 }
00437 }
00438 log << MSG::INFO << "End of reading tuple " << input
00439 << " after " << nentry << " entries." << endmsg;
00440
00441 if ( nentry > 0 || m_selectorName != "" ) {
00442 return StatusCode::SUCCESS;
00443 }
00444 return StatusCode::FAILURE;
00445 }
00446 log << MSG::ERROR << "Failed to access input: " << input << endmsg;
00447 }
00448 return StatusCode::FAILURE;
00449 }
00450
00452 StatusCode connect() {
00453 StatusCode status = StatusCode::SUCCESS;
00454 for (size_t i=0; i < m_inputs.size(); ++i) {
00455 NTuplePtr nt(m_dataSvc, m_inputs[i]);
00456 if ( !(0 == nt) ) {
00457 NTuplePtr out(m_dataSvc, m_outName);
00458 if ( 0 == out ) {
00459 status = book(nt);
00460 }
00461 else {
00462 status = checkInput(out, nt);
00463 }
00464 if ( !status.isSuccess() ) {
00465 return status;
00466 }
00467 else if ( m_selectorName != "" ) {
00468 SmartIF<ISelectStatement> stmt(ROOT::Reflex::PluginService::Create<IInterface*>(m_selectorName,serviceLocator()));
00469 if ( stmt.isValid( ) ) {
00470 if ( m_criteria.length() > 0 ) stmt->setCriteria(m_criteria);
00471 nt->attachSelector(stmt);
00472 }
00473 else {
00474 MsgStream log(msgSvc(), name());
00475 log << MSG::ERROR << "Failed to attach tuple selector to " << m_inputs[i] << endmsg;
00476 return StatusCode::FAILURE;
00477 }
00478 }
00479 }
00480 else {
00481 MsgStream log(msgSvc(), name());
00482 log << MSG::ERROR << "Failed to access tuple: " << m_inputs[i] << endmsg;
00483 return StatusCode::FAILURE;
00484 }
00485 }
00486 return StatusCode::SUCCESS;
00487 }
00488
00490 StatusCode mergeInputTuples() {
00491 MsgStream log(msgSvc(), name());
00492 for (size_t inp=0; inp < m_inputs.size(); ++inp) {
00493 StatusCode sc = mergeEntries(m_inputs[inp]);
00494 if ( !sc.isSuccess() ) {
00495 log << MSG::ERROR << "Failed to merge tuple:" << m_inputs[inp] << endmsg;
00496 return sc;
00497 }
00498 }
00499 return StatusCode::SUCCESS;
00500 }
00501 };
00502 DECLARE_ALGORITHM_FACTORY(CollectionCloneAlg)