|
NCBI C++ ToolKit
|
00001 /* $Id: net_blast_ui_data_source.cpp 25238 2012-02-14 16:11:43Z ucko $ 00002 * =========================================================================== 00003 * 00004 * PUBLIC DOMAIN NOTICE 00005 * National Center for Biotechnology Information 00006 * 00007 * This software/database is a "United States Government Work" under the 00008 * terms of the United States Copyright Act. It was written as part of 00009 * the author's official duties as a United States Government employee and 00010 * thus cannot be copyrighted. This software/database is freely available 00011 * to the public for use. The National Library of Medicine and the U.S. 00012 * Government have not placed any restriction on its use or reproduction. 00013 * 00014 * Although all reasonable efforts have been taken to ensure the accuracy 00015 * and reliability of the software and data, the NLM and the U.S. 00016 * Government do not and cannot warrant the performance or results that 00017 * may be obtained by using this software or data. The NLM and the U.S. 00018 * Government disclaim all warranties, express or implied, including 00019 * warranties of performance, merchantability or fitness for any particular 00020 * purpose. 00021 * 00022 * Please cite the author in any work or product based on this material. 00023 * 00024 * =========================================================================== 00025 * 00026 * Authors: Andrey Yazhuk, Anatoliy Kuznetsov 00027 * 00028 */ 00029 00030 #include <ncbi_pch.hpp> 00031 00032 #include <corelib/ncbi_system.hpp> 00033 00034 #include <gui/packages/pkg_alignment/net_blast_ui_data_source.hpp> 00035 00036 #include <gui/packages/pkg_alignment/net_blast_ui_load_manager.hpp> 00037 #include <gui/packages/pkg_alignment/blast_search_task.hpp> 00038 00039 #include <gui/core/app_explorer_service.hpp> 00040 #include <gui/core/data_mining_service.hpp> 00041 #include <gui/core/data_mining_view.hpp> 00042 #include <gui/core/app_tasks.hpp> 00043 #include <gui/core/download_job.hpp> 00044 00045 #include <gui/utils/app_job_impl.hpp> 00046 00047 #include <gui/framework/workbench.hpp> 00048 #include <gui/framework/app_task_service.hpp> 00049 #include <gui/framework/view_manager_service.hpp> 00050 00051 #include <gui/widgets/wx/ui_command.hpp> 00052 00053 #include <gui/objutils/registry.hpp> 00054 00055 #include <gui/utils/extension_impl.hpp> 00056 #include <gui/widgets/wx/sys_path.hpp> 00057 00058 #include <objects/general/Object_id.hpp> 00059 00060 #include <objects/blast/blastclient.hpp> 00061 #include <objects/blast/Blast4_database.hpp> 00062 #include <objects/blast/Blast4_database_info.hpp> 00063 #include <objects/taxon1/taxon1.hpp> 00064 00065 #include <wx/menu.h> 00066 #include <wx/msgdlg.h> 00067 #include <wx/stopwatch.h> 00068 #include <wx/filename.h> 00069 #include <wx/datetime.h> 00070 00071 //#include <gui/packages/pkg_alignment/blast_winmask_dialog.hpp> 00072 00073 BEGIN_NCBI_SCOPE 00074 USING_SCOPE(objects); 00075 00076 /////////////////////////////////////////////////////////////////////////////// 00077 /// 00078 00079 class CNetBlastLoadDBListJob : public CAppJob 00080 { 00081 public: 00082 CNetBlastLoadDBListJob(CNetBLASTUIDataSource* blast_ds); 00083 ~CNetBlastLoadDBListJob(); 00084 00085 virtual EJobState Run(); 00086 private: 00087 CRef<CNetBLASTUIDataSource> m_BlastDS; 00088 CRef<objects::CBlast4_get_databases_reply> m_Databases; 00089 }; 00090 00091 CNetBlastLoadDBListJob::CNetBlastLoadDBListJob(CNetBLASTUIDataSource* blast_ds) 00092 : m_BlastDS(blast_ds) 00093 { 00094 } 00095 00096 00097 CNetBlastLoadDBListJob::~CNetBlastLoadDBListJob() 00098 { 00099 } 00100 00101 IAppJob::EJobState CNetBlastLoadDBListJob::Run() 00102 { 00103 try { 00104 CBlast4Client client; 00105 client.SetRetryLimit(2); // TODO: make it configurable 00106 m_Databases = client.AskGet_databases(); 00107 00108 if (m_Databases) { 00109 /// serialize the last successful result - this will be used 00110 /// the next time through if the call to retrieve the databases fails 00111 wxString path = CSysPath::ResolvePath( wxT("<home>/blast-dbs.asn") ); 00112 CNcbiOfstream ostr(path.fn_str(), 00113 ios::out | ios::binary); 00114 ostr << MSerial_AsnBinary << *m_Databases; 00115 } 00116 00117 // attach database list to the data source 00118 m_BlastDS->x_SetDataBases(m_Databases); 00119 } 00120 catch (CException&) { 00121 m_Databases.Reset(); 00122 m_BlastDS->x_SetDBLoadJobId(0); 00123 return eFailed; 00124 } 00125 return eCompleted; 00126 } 00127 00128 00129 /////////////////////////////////////////////////////////////////////////////// 00130 /// CNetBlastDSEvtHandler - wxEvtHandler-derived adapter for Net BLAST data source. 00131 /// This class translates menu commands into Net BLAST data source method calls. 00132 00133 class CNetBlastDSEvtHandler : public wxEvtHandler 00134 { 00135 DECLARE_EVENT_TABLE(); 00136 public: 00137 CNetBlastDSEvtHandler(CNetBLASTUIDataSource& ds) 00138 : m_NetBlastDS(&ds) 00139 {}; 00140 00141 CNetBlastDSEvtHandler(CNetBLASTUIDataSource& ds, CNetBLASTUIDataSource::TJobDescrVec& jobs) 00142 : m_NetBlastDS(&ds), m_Jobs(jobs) 00143 {}; 00144 00145 ~CNetBlastDSEvtHandler() 00146 { 00147 } 00148 00149 void OnRetrieve(wxCommandEvent& event) 00150 { 00151 m_NetBlastDS->StartRetrievingTask(m_Jobs); 00152 } 00153 void OnMonitor(wxCommandEvent& event) 00154 { 00155 m_NetBlastDS->StartMonitoringTask(m_Jobs); 00156 } 00157 void OnDelete(wxCommandEvent& event) 00158 { 00159 m_NetBlastDS->DeleteJobDescriptors(m_Jobs); 00160 } 00161 void OnExplore(wxCommandEvent& event) 00162 { 00163 m_NetBlastDS->OnExplore(); 00164 } 00165 void OnLoadRIDs(wxCommandEvent& event) 00166 { 00167 m_NetBlastDS->OnLoadRIDs(); 00168 } 00169 00170 public: 00171 CRef<CNetBLASTUIDataSource> m_NetBlastDS; 00172 CNetBLASTUIDataSource::TJobDescrVec m_Jobs; 00173 }; 00174 00175 BEGIN_EVENT_TABLE(CNetBlastDSEvtHandler, wxEvtHandler) 00176 EVT_MENU(eCmdRetriveBlastJobs, CNetBlastDSEvtHandler::OnRetrieve) 00177 EVT_MENU(eCmdMonitorBlastJobs, CNetBlastDSEvtHandler::OnMonitor) 00178 EVT_MENU(eCmdDeleteBlastJobs, CNetBlastDSEvtHandler::OnDelete) 00179 EVT_MENU(eCmdExploreNetBLAST, CNetBlastDSEvtHandler::OnExplore) 00180 EVT_MENU(eCmdLoadRIDs, CNetBlastDSEvtHandler::OnLoadRIDs) 00181 END_EVENT_TABLE(); 00182 00183 /////////////////////////////////////////////////////////////////////////////// 00184 /// CNetBLASTUIDataSource 00185 00186 static const char* kNetBLAST_DS_Icon = "icon::gb_data_source"; //TODO 00187 //static const char* kNetBlastCmdContributor = "net_blast_cmd_contributor"; 00188 static const char* kCmdExtPoint = "scoped_objects::cmd_contributor"; 00189 static const char* kAppExpCmdExtPoint = "project_tree_view::context_menu::item_cmd_contributor"; 00190 00191 00192 CNetBLASTUIDataSource::CNetBLASTUIDataSource(CNetBLASTUIDataSourceType& type) 00193 : m_Descr("NCBI Net BLAST", kNetBLAST_DS_Icon), 00194 m_Type(&type), 00195 m_SrvLocator(NULL), 00196 m_Open(false) 00197 { 00198 m_DBLoadJobId = 0; 00199 } 00200 00201 00202 CNetBLASTUIDataSource::~CNetBLASTUIDataSource() 00203 { 00204 _ASSERT(! m_Open); 00205 } 00206 00207 00208 string CNetBLASTUIDataSource::GetExtensionIdentifier() const 00209 { 00210 return "net_blast_data_source"; 00211 } 00212 00213 00214 string CNetBLASTUIDataSource::GetExtensionLabel() const 00215 { 00216 return "Net BLAST Data Source"; 00217 } 00218 00219 00220 void CNetBLASTUIDataSource::SetServiceLocator(IServiceLocator* locator) 00221 { 00222 m_SrvLocator = locator; 00223 } 00224 00225 //static const char* kCNetBLASTUIRootKey = "NetBlastUI"; 00226 //static const char* kLocalMaskPath = "LocalMaskPath"; 00227 //static const char* kRemoteMaskURL = "RemoteMaskURL"; 00228 00229 void CNetBLASTUIDataSource::SetRegistryPath( const string& path ) 00230 { 00231 m_RegPath = path; 00232 } 00233 00234 void CNetBLASTUIDataSource::SaveSettings() const 00235 { 00236 _ASSERT(! m_RegPath.empty() ); 00237 00238 if( !m_RegPath.empty() ){ 00239 CGuiRegistry& gui_reg = CGuiRegistry::GetInstance(); 00240 CGuiRegistry::TReadWriteView view = gui_reg.GetReadWriteView(m_RegPath); 00241 } 00242 } 00243 00244 00245 void CNetBLASTUIDataSource::LoadSettings() 00246 { 00247 _ASSERT(! m_RegPath.empty()); 00248 00249 if( ! m_RegPath.empty()) { 00250 CGuiRegistry& gui_reg = CGuiRegistry::GetInstance(); 00251 CGuiRegistry::TReadView view = gui_reg.GetReadView(m_RegPath); 00252 } 00253 } 00254 00255 IUIDataSourceType& CNetBLASTUIDataSource::GetType() const 00256 { 00257 return *m_Type; 00258 } 00259 00260 00261 const IUIObject& CNetBLASTUIDataSource::GetDescr() 00262 { 00263 return m_Descr; 00264 } 00265 00266 00267 bool CNetBLASTUIDataSource::IsOpen() 00268 { 00269 return m_Open; 00270 } 00271 00272 00273 bool CNetBLASTUIDataSource::Open() 00274 { 00275 if ( !m_Open ) { 00276 ERR_POST(Info <<"Opening Net BLAST Data Source..."); 00277 00278 CStopWatch sw; 00279 sw.Start(); 00280 00281 /// register itself as menu contributor 00282 CIRef<IExtensionRegistry> reg = CExtensionRegistry::GetInstance(); 00283 reg->AddExtension(kCmdExtPoint, *this); 00284 reg->AddExtension(kAppExpCmdExtPoint, *this); 00285 00286 x_InitDatabases(); 00287 00288 x_LoadJobDescriptors(); 00289 00290 x_AutoStartMonitoring(); 00291 00292 m_Open = true; 00293 00294 string t = NStr::DoubleToString(sw.Elapsed(), 3); 00295 ERR_POST(Info << "Registered Net BLAST Data Source - " << t << " sec"); 00296 return true; 00297 } else { 00298 return false; 00299 } 00300 } 00301 00302 00303 bool CNetBLASTUIDataSource::Close() 00304 { 00305 if(m_Open) { 00306 x_SaveJobDescriptors(); 00307 m_JobDescrs.clear(); 00308 00309 x_ClearDatabases(); 00310 00311 /// remove itself from menu contribution points 00312 CIRef<IExtensionRegistry> reg = CExtensionRegistry::GetInstance(); 00313 reg->RemoveExtension(kCmdExtPoint, *this); 00314 reg->RemoveExtension(kAppExpCmdExtPoint, *this); 00315 00316 m_Open = false; 00317 return true; 00318 } else return false; 00319 } 00320 00321 00322 void CNetBLASTUIDataSource::EditProperties() 00323 { 00324 //TODO 00325 } 00326 00327 00328 IUIToolManager* CNetBLASTUIDataSource::GetLoadManager() 00329 { 00330 // TODO may need to link the manager to this particular datasource 00331 return new CNetBLASTUILoadManager(*this); //TODO ? 00332 } 00333 00334 IObjectCmdContributor::TContribution 00335 CNetBLASTUIDataSource::GetMenu(TConstScopedObjects& objects) 00336 { 00337 wxMenu* menu = NULL; 00338 wxEvtHandler* handler = NULL; 00339 00340 if( ! objects.empty()) { 00341 // examine data 00342 int retrieve = 0; 00343 int monitor = 0; 00344 CNetBLASTUIDataSource::TJobDescrVec jobs; 00345 00346 NON_CONST_ITERATE(TConstScopedObjects, it, objects) { 00347 const CObject* obj = it->object.GetPointer(); 00348 const CNetBlastJobDescriptor* const_descr = 00349 dynamic_cast<const CNetBlastJobDescriptor*>(obj); 00350 CNetBlastJobDescriptor* descr = const_cast<CNetBlastJobDescriptor*>(const_descr); 00351 00352 if(descr) { 00353 jobs.push_back(CRef<CNetBlastJobDescriptor>(descr)); 00354 00355 CNetBlastJobDescriptor::EState state = descr->GetState(); 00356 00357 switch(state) { 00358 case CNetBlastJobDescriptor::eCompleted: 00359 case CNetBlastJobDescriptor::eRetrieved: 00360 retrieve++; 00361 break; 00362 case CNetBlastJobDescriptor::eSubmitted: 00363 monitor++; 00364 break; 00365 default: 00366 break; 00367 } 00368 } 00369 } 00370 00371 CUICommandRegistry& cmd_reg = CUICommandRegistry::GetInstance(); 00372 00373 menu = new wxMenu; 00374 menu->Append(wxID_SEPARATOR, wxT("Top Actions")); 00375 if(retrieve > 0) { 00376 cmd_reg.AppendMenuItem(*menu, eCmdRetriveBlastJobs); 00377 } 00378 if(monitor > 0) { 00379 cmd_reg.AppendMenuItem(*menu, eCmdMonitorBlastJobs); 00380 } 00381 if( ! jobs.empty()) { 00382 cmd_reg.AppendMenuItem(*menu, eCmdDeleteBlastJobs); 00383 handler = new CNetBlastDSEvtHandler(*this, jobs); 00384 } 00385 } 00386 00387 return IObjectCmdContributor::TContribution(menu, handler); 00388 } 00389 00390 00391 IExplorerItemCmdContributor::TContribution 00392 CNetBLASTUIDataSource::GetMenu(TItemRefVector& items, 00393 CAppExplorerService& app_service) 00394 { 00395 IExplorerItemCmdContributor::TContribution contrib; 00396 if(items.size() != 1) { 00397 return contrib; 00398 } 00399 00400 CUICommandRegistry& cmd_reg = CUICommandRegistry::GetInstance(); 00401 00402 CExplorerItem* item = items[0].GetPointer(); 00403 int type = app_service.GetItemType(*item); 00404 00405 if(type == CAppExplorerService::eDataSource) { 00406 CAppExplorerService::TDataSourceTreeItem* ds_item = 00407 dynamic_cast<CAppExplorerService::TDataSourceTreeItem*>(item); 00408 00409 if(ds_item) { 00410 CIRef<IUIDataSource> ds = ds_item->GetData(); 00411 CNetBLASTUIDataSource* blast_ds = dynamic_cast<CNetBLASTUIDataSource*>(ds.GetPointer()); 00412 00413 if(blast_ds) { 00414 wxMenu* menu = new wxMenu; 00415 menu->Append(wxID_SEPARATOR, wxT("Top Actions")); 00416 cmd_reg.AppendMenuItem(*menu, eCmdExploreNetBLAST); 00417 cmd_reg.AppendMenuItem(*menu, eCmdLoadRIDs); 00418 00419 contrib.first = menu; 00420 contrib.second = new CNetBlastDSEvtHandler(*this); 00421 } 00422 } 00423 } 00424 return contrib; 00425 } 00426 00427 00428 const CNetBLASTUIDataSource::TDbMap& CNetBLASTUIDataSource::GetDbMap(bool nuc) const 00429 { 00430 { 00431 CFastMutexGuard guard(m_DBLoadMutex); 00432 return nuc ? m_NucDbMap : m_ProtDbMap; 00433 } 00434 } 00435 00436 00437 string CNetBLASTUIDataSource::GetDefaultDB(bool nuc_db) const 00438 { 00439 { 00440 CFastMutexGuard guard(m_DBLoadMutex); 00441 return nuc_db ? m_Nuc_DefDB : m_Prot_DefDB; 00442 } 00443 } 00444 00445 void CNetBLASTUIDataSource::WaitReady() 00446 { 00447 x_WaitForDBLoadJob(); 00448 } 00449 00450 void CNetBLASTUIDataSource::GetDefaultMRU_DBs(bool nuc_db, list<string>& mru_dbs) 00451 { 00452 const vector<string>& dbs = nuc_db ? m_Nuc_DefMRU_DBs : m_Prot_DefMRU_DBs; 00453 ITERATE(vector<string>, it, dbs) { 00454 mru_dbs.push_back(*it); 00455 } 00456 } 00457 00458 00459 CRef<CNetBlastJobDescriptor> 00460 CNetBLASTUIDataSource::CreateJobDescriptor(const CBLASTParams& params) 00461 { 00462 CFastMutexGuard guard(m_JobDescrMutex); 00463 00464 CRef<CNetBlastJobDescriptor> descr(new CNetBlastJobDescriptor()); 00465 descr->Init(params, *this); 00466 m_JobDescrs.push_back(descr); 00467 return descr; 00468 } 00469 00470 00471 CRef<CNetBlastJobDescriptor> 00472 CNetBLASTUIDataSource::CreateJobDescriptor(const string& rid) 00473 { 00474 CFastMutexGuard guard(m_JobDescrMutex); 00475 00476 CRef<CNetBlastJobDescriptor> descr(new CNetBlastJobDescriptor()); 00477 descr->Init(rid, *this); 00478 m_JobDescrs.push_back(descr); 00479 return descr; 00480 } 00481 00482 00483 void CNetBLASTUIDataSource::GetJobDescriptors(vector< CRef<CNetBlastJobDescriptor> >& descriptors) 00484 { 00485 CFastMutexGuard guard(m_JobDescrMutex); 00486 00487 for( size_t i = 0; i < m_JobDescrs.size(); i++ ) { 00488 CRef<CNetBlastJobDescriptor>& descr = m_JobDescrs[i]; 00489 if( ! descr->IsDeleted()) { 00490 descriptors.push_back(descr); 00491 } 00492 } 00493 } 00494 00495 00496 CRef<CNetBlastJobDescriptor> CNetBLASTUIDataSource::FindJobDescriptor(const string& rid) 00497 { 00498 CFastMutexGuard guard(m_JobDescrMutex); 00499 00500 CRef<CNetBlastJobDescriptor> result; 00501 for( size_t i = 0; i < m_JobDescrs.size(); i++ ) { 00502 CRef<CNetBlastJobDescriptor>& descr = m_JobDescrs[i]; 00503 if(descr->GetRID() == rid) { 00504 result = descr; 00505 break; 00506 } 00507 } 00508 return result; 00509 } 00510 00511 00512 static const wxChar* kBLAST_DBsPath = wxT("<home>/blast-dbs.asn"); 00513 00514 bool CNetBLASTUIDataSource::x_NeedToRefreshCachedDBs() 00515 { 00516 bool refresh = true; 00517 00518 wxString path = CSysPath::ResolvePath(kBLAST_DBsPath); 00519 wxFileName fname(path); 00520 00521 if (fname.FileExists()) { 00522 wxDateTime dtMod = fname.GetModificationTime(); 00523 wxDateTime now = wxDateTime::Now(); 00524 wxTimeSpan diff = now.Subtract(dtMod); 00525 if (diff.IsShorterThan(wxTimeSpan::Hours(8))) 00526 refresh = false; 00527 } 00528 return refresh; 00529 } 00530 00531 // TODO rework error handling and messages 00532 void CNetBLASTUIDataSource::x_ReadCachedDBs() 00533 { 00534 CFastMutexGuard guard(m_DBLoadMutex); 00535 00536 string msg; 00537 00538 wxString path = CSysPath::ResolvePath(kBLAST_DBsPath); 00539 wxFileName fname(path); 00540 00541 if (fname.FileExists()) { 00542 try { 00543 ESerialDataFormat fmts[] = { 00544 eSerial_AsnBinary, 00545 eSerial_AsnText 00546 }; 00547 const size_t size_limit = sizeof(fmts) / sizeof(ESerialDataFormat); 00548 for (size_t i = 0; i < size_limit; ++i) { 00549 m_Databases.Reset(new CBlast4_get_databases_reply); 00550 try { 00551 CNcbiIfstream istr(path.fn_str(), ios::in | ios::binary); 00552 auto_ptr<CObjectIStream> is 00553 (CObjectIStream::Open(fmts[i], istr)); 00554 *is >> *m_Databases; 00555 00556 break; 00557 } 00558 catch (CSerialException&) { 00559 m_Databases.Reset(); 00560 } 00561 } 00562 00563 if ( !m_Databases ) { 00564 NCBI_THROW(CException, eUnknown, 00565 "failed to read cached databases"); 00566 } 00567 00568 wxDateTime dtMod = fname.GetModificationTime(); 00569 msg += "The previously cached version from "; 00570 msg += ToStdString(dtMod.Format(wxT("%B %d, %Y"))); 00571 msg += " will be used.\nSome of the databases listed may not be available."; 00572 LOG_POST(Info << msg); 00573 } catch (CException&) { 00574 ::wxRemoveFile(path); 00575 m_Databases.Reset(); 00576 msg += "The previously cached version could not be read. " 00577 "The BLAST4 service will be unavailable."; //TODO error reporting 00578 } 00579 } else { 00580 msg += "No cached databases were found. " 00581 "The BLAST4 service will be unavailable."; //TODO 00582 } 00583 00584 if ( !m_Databases ) { 00585 NCBI_THROW(CException, eUnknown, msg); 00586 } 00587 } 00588 00589 00590 /// Loads user fields describing BLAST DB hierarchy 00591 void CNetBLASTUIDataSource::x_GetDBTree(TUserFields& fields) 00592 { 00593 CStopWatch sw; 00594 sw.Start(); 00595 wxString path = CSysPath::ResolvePath( wxT("<std>/etc/blastdb-spec/blast-db-tree.asn") ); 00596 00597 if (wxFileName::FileExists(path )) { 00598 try { 00599 CRef<CUser_field> field(new CUser_field()); 00600 CNcbiIfstream istr(path.fn_str()); 00601 istr >> MSerial_AsnText >> *field; 00602 00603 /// flatten the hierarchy a bit - this is a triple-nested item 00604 ITERATE (CUser_field::TData::TFields, outer_it, field->GetData().GetFields()) { 00605 ITERATE (CUser_field::TData::TFields, inner_it, (*outer_it)->GetData().GetFields()) { 00606 ITERATE (CUser_field::TData::TFields, it, (*inner_it)->GetData().GetFields()) { 00607 fields.push_back(*it); 00608 } 00609 } 00610 } 00611 } 00612 catch (CException& e) { 00613 // TODO error reporting 00614 LOG_POST(Error << "Error while loading blast-db-tree.asn: " << e.GetMsg()); 00615 } 00616 } 00617 LOG_POST(Info << NCBI_CURRENT_FUNCTION << ": " << sw.Elapsed() << " seconds"); 00618 } 00619 00620 00621 static const wxChar* kJobDescrPath = wxT("<home>/net_blast_jobs.asn"); 00622 static const char* kJobsTag = "Jobs"; 00623 00624 void CNetBLASTUIDataSource::x_SaveJobDescriptors() 00625 { 00626 LOG_POST(Info << "Net BLAST Data Source - saving job descriptors..."); 00627 00628 try { 00629 00630 vector< CRef<CUser_object> > jobs; 00631 00632 for( size_t i = 0; i < m_JobDescrs.size(); i++ ) { 00633 try { 00634 CNetBlastJobDescriptor& descr = *m_JobDescrs[i]; 00635 00636 // do not save Descriptors marked as deleted, we preserve them 00637 // at run-time, but purge between application sessions 00638 if( ! descr.IsDeleted()) { 00639 CRef<CUser_object> job_obj(descr.ToUserObject()); 00640 jobs.push_back(job_obj); 00641 } 00642 } catch(CException& e) { 00643 LOG_POST(Error << "Saving Net BLAST jobs - exception while saving a job - " << e.GetMsg()); 00644 } 00645 } 00646 00647 CRef<CUser_object> container(new CUser_object()); 00648 container->SetType().SetStr(kJobsTag); 00649 container->AddField(kJobsTag, jobs); 00650 00651 wxString path = CSysPath::ResolvePath(kJobDescrPath); 00652 CNcbiOfstream ostr(path.fn_str()); 00653 ostr << MSerial_AsnText << *container; 00654 00655 LOG_POST(Info << "Net BLAST Data Source - finished saving job descriptors"); 00656 } catch(CException& e) { 00657 LOG_POST(Info << "Net BLAST Data Source - failed to save jobs - " << e.GetMsg()); 00658 } 00659 } 00660 00661 00662 void CNetBLASTUIDataSource::x_LoadJobDescriptors() 00663 { 00664 LOG_POST(Info << "Net BLAST Data Source - loading job descriptors..."); 00665 00666 wxString path = CSysPath::ResolvePath(kJobDescrPath); 00667 00668 if (wxFileName::FileExists(path)) { 00669 try { 00670 CRef<CUser_object> container(new CUser_object()); 00671 CNcbiIfstream istr(path.fn_str()); 00672 istr >> MSerial_AsnText >> *container; 00673 00674 const CUser_field& field = container->GetField(kJobsTag); 00675 const vector< CRef<CUser_object> >& jobs = field.GetData().GetObjects(); 00676 00677 m_JobDescrs.clear(); 00678 for( size_t i = 0; i < jobs.size(); i++ ) { 00679 const CUser_object& job_obj = *jobs[i]; 00680 00681 CRef<CNetBlastJobDescriptor> descr(new CNetBlastJobDescriptor(*this)); 00682 descr->FromUserObject(job_obj); 00683 00684 if(descr->GetState() != CNetBlastJobDescriptor::eInvalidState) { 00685 m_JobDescrs.push_back(descr); 00686 } 00687 } 00688 00689 LOG_POST(Info << "Net BLAST Data Source - finished loading job descriptors"); 00690 } 00691 catch (CException& e) { 00692 LOG_POST(Error << "Net BLAST Data Source - failed to load job descriptors" << e.GetMsg()); 00693 } 00694 } 00695 } 00696 00697 00698 void sPrepareDBDescr(string& db_desc) 00699 { 00700 /// escape slashes in the description 00701 db_desc = NStr::Replace(db_desc, "/", "\\/"); 00702 00703 /// strip off external quotes 00704 string::size_type pos = db_desc.find_first_not_of("\"'"); 00705 if (pos != string::npos) { 00706 db_desc.erase(0, pos); 00707 } 00708 pos = db_desc.find_last_not_of("\"'"); 00709 if (pos != string::npos) { 00710 pos += 1; 00711 if (pos < db_desc.size()) { 00712 db_desc.erase(pos); 00713 } 00714 } 00715 } 00716 00717 00718 /// Fills sm_ProtDbMap and sm_NucDbMap maps. 00719 /// The keys in the maps represent paths in the DB hierarchy. 00720 void CNetBLASTUIDataSource::x_CategorizeDBs() 00721 { 00722 TDbMap valid_db_names; 00723 00724 typedef CBlast4_get_databases_reply::Tdata TDBData; 00725 CBlast4_get_databases_reply::Tdata& db_data = m_Databases->Set(); 00726 00727 // iterate by all available Databases 00728 NON_CONST_ITERATE (TDBData, it, db_data) { 00729 const CBlast4_database_info& info = **it; 00730 const string& db_name = info.GetDatabase().GetName(); 00731 00732 // insert DB record into a temporary map 00733 valid_db_names.insert(TDbMap::value_type(db_name, *it)); 00734 } 00735 00736 NON_CONST_ITERATE (TDBData, it, db_data) { 00737 const CBlast4_database_info& info = **it; 00738 const string& db_name = info.GetDatabase().GetName(); 00739 string db_desc = info.GetDescription(); 00740 00741 sPrepareDBDescr(db_desc); 00742 00743 string name = db_name; 00744 string visible_name = db_name; 00745 if ( ! db_desc.empty() && db_name.find(db_desc) == string::npos) { 00746 name += " (" + db_desc + ")"; 00747 string db_desc_trimmed(db_desc); 00748 visible_name += " (" + db_desc_trimmed + ")"; 00749 } 00750 00751 /// 'nr' and 'nt' should never be subcategorized 00752 if (db_name == "nr" || db_name == "nt") { 00753 bool prot = false; 00754 if (db_name == "nr") { 00755 prot = (info.GetDatabase().GetType() == eBlast4_residue_type_protein); 00756 } 00757 TDbMap& db = prot ? m_ProtDbMap : m_NucDbMap; 00758 db.insert(TDbMap::value_type(visible_name, *it)); 00759 00760 // TODO temp workaround 00761 vector<string>& dbs = prot ? m_Prot_DefMRU_DBs : m_Nuc_DefMRU_DBs; 00762 dbs.push_back(visible_name); 00763 continue; 00764 } 00765 } 00766 00767 // use categorization information to build the final maps 00768 x_AddCategorizedDBs(valid_db_names); 00769 00770 NON_CONST_ITERATE (TDbMap, it, valid_db_names) { 00771 it->second.Reset(); 00772 } 00773 00774 valid_db_names.clear(); 00775 } 00776 00777 00778 void CNetBLASTUIDataSource::x_AddCategorizedDBs(const TDbMap& valid_db_names) 00779 { 00780 CStopWatch sw; sw.Start(); 00781 00782 TUserFields fields; 00783 x_GetDBTree(fields); 00784 00785 ITERATE (list< CConstRef<CUser_field> >, it, fields) { 00786 try { 00787 const CUser_field& f = **it; 00788 string label = f.GetLabel().GetStr(); 00789 string db = f.GetField("Db").GetData().GetStr(); 00790 string desc = f.GetField("Descr").GetData().GetStr(); 00791 00792 db = NStr::Replace(db, "//", "/"); 00793 00794 TDbMap::const_iterator dbname_iter = valid_db_names.find(db); 00795 if (dbname_iter == valid_db_names.end()) { 00796 // TODO 00797 LOG_POST(Warning << "dropping invalid BLAST database: " << db << " (" << desc << ")"); 00798 } else{ 00799 CRef<objects::CBlast4_database_info> info(dbname_iter->second); 00800 bool prot = (info->GetDatabase().GetType() == eBlast4_residue_type_protein); 00801 TDbMap& db = prot ? m_ProtDbMap : m_NucDbMap; 00802 db.insert(TDbMap::value_type(desc, info)); 00803 } 00804 } 00805 catch (CException& e) { 00806 //TODO error reporting 00807 LOG_POST(Error << "error processing BLAST databases: " << e.GetMsg()); 00808 } 00809 } 00810 } 00811 00812 00813 //TODO synchronize 00814 void CNetBLASTUIDataSource::x_InitDatabases() 00815 { 00816 x_ClearDatabases(); 00817 00818 /// check if we need to refresh this file 00819 bool refresh = x_NeedToRefreshCachedDBs(); 00820 if ( !refresh ) { 00821 /// try and deserialize the saved portion 00822 x_ReadCachedDBs(); 00823 } 00824 00825 if ( !m_Databases ) { 00826 CIRef<IAppJob> job(new CNetBlastLoadDBListJob(this)); 00827 CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance(); 00828 00829 try { 00830 m_DBLoadJobId = disp.StartJob(*job, "ThreadPool", *this, 1, true); 00831 } catch(CAppJobException& e) { 00832 ERR_POST("CNetBLASTUIDataSource::x_InitDatabases() - Failed to start BLAST DBs loading job"); 00833 e.ReportAll(); 00834 } 00835 } else { 00836 /// hack: categorize databases a bit 00837 x_CategorizeDBs(); 00838 } 00839 00840 if( ! m_Nuc_DefMRU_DBs.empty()) { 00841 m_Nuc_DefDB = m_Nuc_DefMRU_DBs[0]; 00842 } 00843 if( ! m_Prot_DefMRU_DBs.empty()) { 00844 m_Prot_DefDB = m_Prot_DefMRU_DBs[0]; 00845 } 00846 } 00847 00848 void CNetBLASTUIDataSource::x_SetDBLoadJobId(CAppJobDispatcher::TJobID job_id) 00849 { 00850 CFastMutexGuard guard(m_DBLoadMutex); 00851 m_DBLoadJobId = job_id; 00852 } 00853 00854 void CNetBLASTUIDataSource::x_SetDataBases(CRef<objects::CBlast4_get_databases_reply> dbs) 00855 { 00856 CFastMutexGuard guard(m_DBLoadMutex); 00857 00858 m_Databases = dbs; 00859 /// hack: categorize databases a bit 00860 x_CategorizeDBs(); 00861 00862 m_DBLoadJobId = 0; 00863 } 00864 00865 void CNetBLASTUIDataSource::x_WaitForDBLoadJob() 00866 { 00867 LOG_POST(Info << "Wait-check for Blast BD background job finished."); 00868 for (unsigned i = 0; i < 2000; ++i) { // spin-lock, waiting for the job 00869 { 00870 CFastMutexGuard guard(m_DBLoadMutex); 00871 if (m_DBLoadJobId == 0) { // DB load job finished 00872 LOG_POST(Info << "Blast BD background job complete!"); 00873 return; 00874 } 00875 } 00876 SleepMilliSec(100); 00877 } 00878 // we should never see this... 00879 LOG_POST(Error << "Blast BD background timeout expiration!"); 00880 } 00881 00882 00883 void CNetBLASTUIDataSource::x_ClearDatabases() 00884 { 00885 m_Nuc_DefMRU_DBs.clear(); 00886 m_Prot_DefMRU_DBs.clear(); 00887 00888 m_Nuc_DefDB.clear(); 00889 m_Prot_DefDB.clear(); 00890 00891 m_NucDbMap .clear(); 00892 m_ProtDbMap.clear(); 00893 00894 m_Databases.Reset(); 00895 } 00896 00897 00898 void CNetBLASTUIDataSource::x_OnJobDescrChanged(CNetBlastJobDescriptor& descr) 00899 { 00900 // notify asynchronously 00901 x_NotifyObservers(); 00902 } 00903 00904 00905 void CNetBLASTUIDataSource::StartRetrievingTask(TJobDescrVec& jobs) 00906 { 00907 vector<string> RIDs; 00908 for( size_t i = 0; i < jobs.size(); i++) { 00909 CNetBlastJobDescriptor& descr = *jobs[i]; 00910 RIDs.push_back(descr.GetRID()); 00911 } 00912 00913 CRef<CBlastSearchTask> task(new CBlastSearchTask(m_SrvLocator, *this, "Net BLAST Search")); 00914 task->Init_RetrieveRID(RIDs); 00915 00916 x_StartTask(*task); 00917 } 00918 00919 00920 void CNetBLASTUIDataSource::StartMonitoringTask(TJobDescrVec& jobs) 00921 { 00922 CRef<CBlastSearchTask> task(new CBlastSearchTask(m_SrvLocator, *this, "Net BLAST Search")); 00923 task->Init_Monitoring(jobs); 00924 00925 x_StartTask(*task); 00926 } 00927 00928 00929 void CNetBLASTUIDataSource::DeleteJobDescriptors(TJobDescrVec& descriptors) 00930 { 00931 LockUpdates(); 00932 00933 for( size_t i = 0; i < descriptors.size(); i++) { 00934 CNetBlastJobDescriptor& descr = *descriptors[i]; 00935 descr.MarkDeleted(true); 00936 } 00937 00938 UnlockUpdates(); 00939 } 00940 00941 00942 void CNetBLASTUIDataSource::OnExplore() 00943 { 00944 if(m_SrvLocator) { 00945 /// first show the view 00946 IViewManagerService* view_srv = m_SrvLocator->GetServiceByType<IViewManagerService>(); 00947 CIRef<IView> view = view_srv->ShowSingletonView("Search View"); 00948 00949 // here - send command to the view 00950 CDataMiningView* dm_view = dynamic_cast<CDataMiningView*>(view.GetPointer()); 00951 if(dm_view) { 00952 dm_view->SelectToolByName(NET_BLAST_DM_TOOL_NAME); 00953 } 00954 } 00955 } 00956 00957 00958 void CNetBLASTUIDataSource::OnLoadRIDs() 00959 { 00960 /// TODO this is not a good solution, but simple 00961 IWorkbench* workbench = dynamic_cast<IWorkbench*>(m_SrvLocator); 00962 00963 if(workbench) { 00964 COpenDlgTask* task = new COpenDlgTask(workbench, NET_BLAST_LOADER_LABEL); 00965 00966 CAppTaskService* task_srv = m_SrvLocator->GetServiceByType<CAppTaskService>(); 00967 task_srv->AddTask(*task); 00968 } 00969 } 00970 00971 void CNetBLASTUIDataSource::x_StartTask(CBlastSearchTask& task) 00972 { 00973 CDataLoadingOptions options; 00974 options.Set_DecideLater(); 00975 task.SetLoadingOptions(options); 00976 00977 CAppTaskService* task_srv = m_SrvLocator->GetServiceByType<CAppTaskService>(); 00978 task_srv->AddTask(task); 00979 } 00980 00981 00982 // start monitoring task for all jobs that are still in progress 00983 void CNetBLASTUIDataSource::x_AutoStartMonitoring() 00984 { 00985 TJobDescrVec monitor_jobs; 00986 {{ 00987 CFastMutexGuard guard(m_JobDescrMutex); 00988 00989 // get jobs that have "Submitted" status 00990 for( size_t i = 0; i < m_JobDescrs.size(); i++) { 00991 CRef<CNetBlastJobDescriptor>& descr = m_JobDescrs[i]; 00992 if(descr->GetState() == CNetBlastJobDescriptor::eSubmitted) { 00993 monitor_jobs.push_back(descr); 00994 } 00995 } 00996 }} 00997 00998 size_t n = monitor_jobs.size(); 00999 if(n > 0) { 01000 LOG_POST(Info << "Net BLAST start monitoring for " << n << " jobs"); 01001 StartMonitoringTask(monitor_jobs); 01002 } 01003 } 01004 01005 01006 /////////////////////////////////////////////////////////////////////////////// 01007 /// CNetBLASTUIDataSourceType 01008 CNetBLASTUIDataSourceType::CNetBLASTUIDataSourceType() 01009 : m_Descr( "Net BLAST Client Service", "", "", "", "NetBlastUI" ) 01010 { 01011 //wxFileArtProvider* provider = GetDefaultFileArtProvider(); 01012 //TODO provider->RegisterFileAlias(kNetBLAST_DS_Icon, "net_blast_data_source.png"); 01013 } 01014 01015 01016 const IUIObject& CNetBLASTUIDataSourceType::GetDescr() 01017 { 01018 return m_Descr; 01019 } 01020 01021 01022 IUIDataSource* CNetBLASTUIDataSourceType::CreateDataSource() 01023 { 01024 return new CNetBLASTUIDataSource(*this); 01025 } 01026 01027 01028 bool CNetBLASTUIDataSourceType::AutoCreateDefaultDataSource() 01029 { 01030 return true; // create NCBI Net BLAST by default 01031 } 01032 01033 01034 string CNetBLASTUIDataSourceType::GetExtensionIdentifier() const 01035 { 01036 static string ext_id("net_blast_data_source_type"); 01037 return ext_id; 01038 } 01039 01040 01041 string CNetBLASTUIDataSourceType::GetExtensionLabel() const 01042 { 01043 return m_Descr.GetLabel(); 01044 } 01045 01046 01047 END_NCBI_SCOPE
1.7.5.1
Modified on Wed May 23 13:27:21 2012 by modify_doxy.py rev. 337098