cn3d_cache.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:13k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: cn3d_cache.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:28:11  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.15
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: cn3d_cache.cpp,v 1000.2 2004/06/01 18:28:11 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      implements a basic cache for structures
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <objects/ncbimime/Ncbi_mime_asn1.hpp>
  47. #include <objects/ncbimime/Biostruc_seq.hpp>
  48. #include <objects/seqset/Seq_entry.hpp>
  49. #include <objects/seqset/Bioseq_set.hpp>
  50. #include <objects/mmdb1/Biostruc_id.hpp>
  51. #include <objects/mmdb1/Mmdb_id.hpp>
  52. // for file/directory manipulation stuff
  53. #ifdef __WXMSW__
  54. #include <windows.h>
  55. #include <wx/msw/winundef.h>
  56. #endif
  57. #include <wx/wx.h>
  58. #include <wx/datetime.h>
  59. #include <wx/file.h>
  60. #include <wx/filename.h>
  61. #include "cn3d_cache.hpp"
  62. #include "cn3d_tools.hpp"
  63. #include "asn_reader.hpp"
  64. #include "asn_converter.hpp"
  65. USING_NCBI_SCOPE;
  66. USING_SCOPE(objects);
  67. BEGIN_SCOPE(Cn3D)
  68. static string GetCacheFilePath(int mmdbID, EModel_type modelType)
  69. {
  70.     string cachePath;
  71.     if (RegistryGetString(REG_CACHE_SECTION, REG_CACHE_FOLDER, &cachePath)) {
  72.         wxString cacheFile;
  73.         cacheFile.Printf("%s%c%i.%i", cachePath.c_str(), wxFILE_SEP_PATH, mmdbID, modelType);
  74.         cachePath = cacheFile.c_str();
  75.     } else
  76.         ERRORMSG("Can't get cache folder from registry");
  77.     return cachePath;
  78. }
  79. static bool CreateCacheFolder(void)
  80. {
  81.     string cacheFolder;
  82.     if (!RegistryGetString(REG_CACHE_SECTION, REG_CACHE_FOLDER, &cacheFolder)) return false;
  83.     if (wxDirExists(cacheFolder.c_str())) return true;
  84.     bool okay = wxMkdir(cacheFolder.c_str());
  85.     TRACEMSG((okay ? "created" : "failed to create") << " folder " << cacheFolder);
  86.     return okay;
  87. }
  88. static void ExtractBioseqs(list < CRef < CSeq_entry > >& seqEntries, BioseqRefList *sequences)
  89. {
  90.     list < CRef < CSeq_entry > >::iterator e, ee = seqEntries.end();
  91.     for (e=seqEntries.begin(); e!=ee; ++e) {
  92.         if ((*e)->IsSeq())
  93.             sequences->push_back(CRef<CBioseq>(&((*e)->SetSeq())));
  94.         else
  95.             ExtractBioseqs((*e)->SetSet().SetSeq_set(), sequences);
  96.     }
  97. }
  98. bool ExtractBiostrucAndBioseqs(CNcbi_mime_asn1& mime,
  99.     CRef < CBiostruc >& biostruc, BioseqRefList *sequences)
  100. {
  101.     if (!mime.IsStrucseq()) {
  102.         ERRORMSG("ExtractBiostrucAndBioseqs() - expecting strucseq mime");
  103.         return false;
  104.     }
  105.     // copy mime's biostruc into existing object
  106.     biostruc.Reset(&(mime.SetStrucseq().SetStructure()));
  107.     // extract Bioseqs
  108.     if (sequences) {
  109.         sequences->clear();
  110.         ExtractBioseqs(mime.SetStrucseq().SetSequences(), sequences);
  111.     }
  112.     return true;
  113. }
  114. static CNcbi_mime_asn1 * GetStructureFromCacheFolder(int mmdbID, EModel_type modelType)
  115. {
  116.     // try to load from cache
  117.     INFOMSG("looking for " << mmdbID << " (model type " << (int) modelType << ") in cache:");
  118.     string err, cacheFile = GetCacheFilePath(mmdbID, modelType);
  119.     CRef < CNcbi_mime_asn1 > mime(new CNcbi_mime_asn1());
  120.     SetDiagPostLevel(eDiag_Fatal); // ignore all but Fatal errors while reading data
  121.     bool gotFile = ReadASNFromFile(cacheFile.c_str(), mime.GetPointer(), true, &err);
  122.     SetDiagPostLevel(eDiag_Info);
  123.     if (!gotFile) {
  124.         WARNINGMSG("failed to load " << mmdbID
  125.             << " (model type " << (int) modelType << ") from cache: " << err);
  126.         return NULL;
  127.     }
  128.     // if successful, 'touch' the file to mark it as recently used
  129.     INFOMSG("loaded " << cacheFile);
  130.     wxFileName fn(cacheFile.c_str());
  131.     if (!fn.Touch())
  132.         WARNINGMSG("error touching " << cacheFile);
  133.     return mime.Release();
  134. }
  135. static CNcbi_mime_asn1 * GetStructureViaHTTPAndAddToCache(
  136.     const string& uid, int mmdbID, EModel_type modelType)
  137. {
  138.     // construct URL
  139.     static const wxString host = "www.ncbi.nlm.nih.gov", path = "/Structure/mmdb/mmdbsrv.cgi";
  140.     wxString args;
  141.     if (mmdbID > 0)
  142.         args.Printf("uid=%i&form=6&db=t&save=Save&dopt=j&Complexity=", mmdbID);
  143.     else    // assume PDB id
  144.         args.Printf("uid=%s&form=6&db=t&save=Save&dopt=j&Complexity=", uid.c_str());
  145.     switch (modelType) {
  146.         case eModel_type_ncbi_all_atom: args += "Cn3D%20Subset"; break;
  147.         case eModel_type_pdb_model: args += "All%20Models"; break;
  148.         case eModel_type_ncbi_backbone:
  149.         default:
  150.             args += "Virtual%20Bond%20Model"; break;
  151.     }
  152.     // load from network
  153.     INFOMSG("Trying to load structure data from " << host.c_str() << path.c_str() << '?' << args.c_str());
  154.     string err;
  155.     CRef < CNcbi_mime_asn1 > mime(new CNcbi_mime_asn1());
  156.     if (!GetAsnDataViaHTTP(host.c_str(), path.c_str(), args.c_str(), mime.GetPointer(), &err) ||
  157.             !mime->IsStrucseq()) {
  158.         ERRORMSG("Failed to read structure " << uid << " from networknreason: " << err);
  159.         return NULL;
  160.     } else {
  161.         // get MMDB ID from biostruc if not already known
  162.         if (mmdbID == 0) {
  163.             if (mime->GetStrucseq().GetStructure().GetId().front()->IsMmdb_id())
  164.                 mmdbID = mime->GetStrucseq().GetStructure().GetId().front()->GetMmdb_id().Get();
  165.             else {
  166.                 ERRORMSG("Can't get MMDB ID from Biostruc!");
  167.                 return mime.Release();
  168.             }
  169.         }
  170.         bool cacheEnabled;
  171.         if (RegistryGetBoolean(REG_CACHE_SECTION, REG_CACHE_ENABLED, &cacheEnabled) && cacheEnabled) {
  172.             // add to cache
  173.             if (CreateCacheFolder() &&
  174.                 WriteASNToFile(GetCacheFilePath(mmdbID, modelType).c_str(), *mime, true, &err)) {
  175.                 INFOMSG("stored " << mmdbID << " (model type " << (int) modelType << ") in cache");
  176.                 // trim cache to appropriate size if we've added a new file
  177.                 int size;
  178.                 if (RegistryGetInteger(REG_CACHE_SECTION, REG_CACHE_MAX_SIZE, &size))
  179.                     TruncateCache(size);
  180.             } else {
  181.                 WARNINGMSG("Failed to write structure to cache folder");
  182.                 if (err.size() > 0) WARNINGMSG("reason: " << err);
  183.             }
  184.         }
  185.     }
  186.     return mime.Release();
  187. }
  188. CNcbi_mime_asn1 * LoadStructureViaCache(const std::string& uid, ncbi::objects::EModel_type modelType)
  189. {
  190.     // determine whether this is an integer MMDB ID or alphanumeric PDB ID
  191.     int mmdbID = 0;
  192.     if (uid.size() == 4 && (isalpha(uid[1]) || isalpha(uid[2]) || isalpha(uid[3]))) {
  193.         TRACEMSG("Fetching PDB " << uid);
  194.     } else {    // mmdb id
  195.         unsigned long tmp;
  196.         if (wxString(uid.c_str()).ToULong(&tmp)) {
  197.             mmdbID = (int) tmp;
  198.         } else {
  199.             ERRORMSG("LoadStructureViaCache() - invalid uid " << uid);
  200.             return false;
  201.         }
  202.         TRACEMSG("Fetching MMDB " << mmdbID);
  203.     }
  204.     // try loading from local cache folder first, if cache enabled in registry (but only with known mmdb id)
  205.     bool cacheEnabled;
  206.     CNcbi_mime_asn1 *mime = NULL;
  207.     if (mmdbID > 0 &&
  208.             RegistryGetBoolean(REG_CACHE_SECTION, REG_CACHE_ENABLED, &cacheEnabled) &&
  209.             cacheEnabled)
  210.         mime = GetStructureFromCacheFolder(mmdbID, modelType);
  211.     // otherwise, load via HTTP (and save in cache folder)
  212.     if (!mime)
  213.         mime = GetStructureViaHTTPAndAddToCache(uid, mmdbID, modelType);
  214.     return mime;
  215. }
  216. bool LoadStructureViaCache(const std::string& uid, ncbi::objects::EModel_type modelType,
  217.     CRef < CBiostruc >& biostruc, BioseqRefList *sequences)
  218. {
  219.     CRef < CNcbi_mime_asn1 > mime(LoadStructureViaCache(uid, modelType));
  220.     return (mime.NotEmpty() && ExtractBiostrucAndBioseqs(*mime, biostruc, sequences));
  221. }
  222. void TruncateCache(int maxSize)
  223. {
  224.     string cacheFolder;
  225.     if (!RegistryGetString(REG_CACHE_SECTION, REG_CACHE_FOLDER, &cacheFolder) ||
  226.         !wxDirExists(cacheFolder.c_str())) {
  227.         WARNINGMSG("can't find cache folder");
  228.         return;
  229.     }
  230.     INFOMSG("truncating cache to " << maxSize << " MB");
  231.     wxString cacheFolderFiles;
  232.     cacheFolderFiles.Printf("%s%c*", cacheFolder.c_str(), wxFILE_SEP_PATH);
  233.     // empty directory if maxSize <= 0
  234.     if (maxSize <= 0) {
  235.         wxString f;
  236.         while ((f=wxFindFirstFile(cacheFolderFiles, wxFILE)).size() > 0) {
  237.             if (!wxRemoveFile(f))
  238.                 WARNINGMSG("can't remove file " << f);
  239.         }
  240.         return;
  241.     }
  242.     // otherwise, add up file sizes and keep deleting oldest until total size <= max
  243.     unsigned long totalSize = 0;
  244.     wxString oldestFileName;
  245.     do {
  246.         // if totalSize > 0, then we've already scanned the folder and know it's too big,
  247.         // so delete oldest file
  248.         if (totalSize > 0 && !wxRemoveFile(oldestFileName))
  249.             WARNINGMSG("can't remove file " << oldestFileName);
  250.         // loop through files, finding oldest and calculating total size
  251.         totalSize = 0;
  252.         time_t oldestFileDate = wxDateTime::GetTimeNow(), date;
  253.         wxString file = wxFindFirstFile(cacheFolderFiles, wxFILE);
  254.         for (; file.size() > 0; file = wxFindNextFile()) {
  255.             date = wxFileModificationTime(file);
  256.             if (date < oldestFileDate) {
  257.                 oldestFileDate = date;
  258.                 oldestFileName = file;
  259.             }
  260.             wxFile wx_file(file, wxFile::read);
  261.             if (wx_file.IsOpened()) {
  262.                 totalSize += wx_file.Length();
  263.                 wx_file.Close();
  264.             } else
  265.                 WARNINGMSG("wxFile failed to open " << file);
  266.         }
  267.         INFOMSG("total size: " << totalSize << " oldest file: " << oldestFileName.c_str());
  268.     } while (totalSize > maxSize * 1024 * 1024);
  269. }
  270. END_SCOPE(Cn3D)
  271. /*
  272. * ---------------------------------------------------------------------------
  273. * $Log: cn3d_cache.cpp,v $
  274. * Revision 1000.2  2004/06/01 18:28:11  gouriano
  275. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.15
  276. *
  277. * Revision 1.15  2004/05/21 21:41:39  gorelenk
  278. * Added PCH ncbi_pch.hpp
  279. *
  280. * Revision 1.14  2004/03/15 18:23:01  thiessen
  281. * prefer prefix vs. postfix ++/-- operators
  282. *
  283. * Revision 1.13  2004/02/19 17:04:49  thiessen
  284. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  285. *
  286. * Revision 1.12  2004/01/17 00:17:29  thiessen
  287. * add Biostruc and network structure load
  288. *
  289. * Revision 1.11  2003/04/02 17:49:18  thiessen
  290. * allow pdb id's in structure import dialog
  291. *
  292. * Revision 1.10  2003/02/03 19:20:02  thiessen
  293. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  294. *
  295. * Revision 1.9  2002/09/30 17:13:02  thiessen
  296. * change structure import to do sequences as well; change cache to hold mimes; change block aligner vocabulary; fix block aligner dialog bugs
  297. *
  298. * Revision 1.8  2002/09/11 01:39:35  thiessen
  299. * fix cache file touch
  300. *
  301. * Revision 1.7  2002/08/15 22:13:13  thiessen
  302. * update for wx2.3.2+ only; add structure pick dialog; fix MultitextDialog bug
  303. *
  304. * Revision 1.6  2002/03/07 15:45:45  thiessen
  305. * compile fix ; extra file load messages
  306. *
  307. * Revision 1.5  2002/02/27 16:29:40  thiessen
  308. * add model type flag to general mime type
  309. *
  310. * Revision 1.4  2002/01/11 15:48:49  thiessen
  311. * update for Mac CW7
  312. *
  313. * Revision 1.3  2001/11/09 15:19:16  thiessen
  314. * wxFindFirst file fixed on wxMac; call glViewport() from OnSize()
  315. *
  316. * Revision 1.2  2001/11/01 19:01:40  thiessen
  317. * use meta key instead of ctrl on Mac
  318. *
  319. * Revision 1.1  2001/10/30 02:54:11  thiessen
  320. * add Biostruc cache
  321. *
  322. */