NCBI C++ ToolKit
net_blast_ui_data_source.cpp
Go to the documentation of this file.
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
Modified on Wed May 23 13:27:21 2012 by modify_doxy.py rev. 337098