NCBI C++ ToolKit
eutils_client.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: eutils_client.cpp 101116 2023-11-01 14:02:50Z mozese2 $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Mike DiCuccio
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
34 #include <corelib/ncbi_system.hpp>
35 #include <corelib/ncbistr.hpp>
40 #include <connect/ncbi_socket.hpp>
41 #include <misc/error_codes.hpp>
42 
43 #include <cmath>
44 #include <sstream>
45 #include <iterator>
46 #include <algorithm>
47 #include <type_traits>
48 
49 #define NCBI_USE_ERRCODE_X Misc_EutilsClient
50 
52 
53 using namespace objects;
54 
55 
56 //////////////////////////////////////////////////////////////////////////////
57 
58 namespace edirect {
59 
60  // Authors: Jonathan Kans, Aaron Ucko
61 
62  string Execute (
63  const string& cmmd,
64  const vector<string>& args,
65  const string& data
66  )
67 
68  {
69  static const STimeout five_seconds = { 5, 0 };
70  CConn_PipeStream ps(cmmd.c_str(), args, CPipe::fStdErr_Share, 0, &five_seconds);
71 
72  if ( ! data.empty() ) {
73  ps << data;
74  if (! NStr::EndsWith(data, "\n")) {
75  ps << "\n";
76  }
77  }
78 
79  ps.flush();
81 
82  string str;
83  NcbiStreamToString(&str, ps);
84 
85  return str;
86  }
87 }
88 
89 
90 static const char*
92 {
93  switch ( err_code ) {
95  return "Phrase not found";
97  return "Field not found";
99  return "Phrase ignored";
101  return "Quoted phrase not found";
103  return "Output message";
104  default:
105  return "Unknown error";
106  }
107 }
108 
109 template<class T> static void s_FormatIds(ostream& osm, const vector<T>& uids) {
110  osm << "&id=";
111  if (!uids.empty()) {
112  osm << uids.front();
113  for (auto it = uids.begin()+1; it != uids.end(); ++it) {
114  osm << ',' << *it;
115  }
116  }
117 }
118 
119 template<> void s_FormatIds<CSeq_id_Handle>(ostream& osm, const vector<CSeq_id_Handle>& uids) {
120  osm << "&id=";
122  for (auto it = uids.begin(); it != uids.end(); ++it) {
123  if (it != uids.begin()) {
124  osm << ',';
125  }
126  auto& seh = *it;
127  if (seh.Which() == CSeq_id::e_Gi) {
128  if (type != CSeq_id::e_Gi && type != CSeq_id::e_not_set) {
130  "Argument list contains seq-ids of mixed types");
131  }
133  osm << seh.GetGi();
134  } else {
135  if (type != CSeq_id::e_not_set && type != seh.Which()) {
137  "Argument list contains seq-ids of mixed types");
138  }
139  type = seh.Which();
140  osm << seh.GetSeqId()->GetSeqIdString(true);
141  }
142  }
143  osm << "&idtype=" << (type == CSeq_id::e_Gi ? "gi" : "acc");
144 }
145 
146 template<> void s_FormatIds<string>(ostream& osm, const vector<string>& uids)
147 {
148  osm << "&id=";
149  if (!uids.empty()) {
150  osm << uids.front();
151  for (auto it = uids.begin()+1; it != uids.end(); ++it) {
152  osm << ',' << *it;
153  }
154  }
155  osm << "&idtype=acc";
156 }
157 
158 template<class T> static inline T s_ParseId(const string& str)
159 {
160  return NStr::StringToNumeric<T>(str);
161 }
162 
163 template<> inline CSeq_id_Handle s_ParseId<CSeq_id_Handle>(const string& str)
164 {
166 }
167 
168 template<> inline string s_ParseId<string>(const string& str)
169 {
170  return str;
171 }
172 
173 
174 const char* CEUtilsException::GetErrCodeString(void) const
175 {
176  return s_GetErrCodeString(GetErrCode());
177 }
178 
179 
181 {
182 public:
183  virtual void HandleMessage(EDiagSev severity,
185  const string & message) const
186  {
188  << " - " << s_GetErrCodeString(err_code)
189  << ": " << message);
190  }
191 };
192 
193 
195 {
196 public:
197  virtual void HandleMessage(EDiagSev severity,
199  const string& message) const
200  {
201  // ERR_POST, but with severity as a variable.
202  CNcbiDiag(DIAG_COMPILE_INFO, severity).GetRef()
203  << s_GetErrCodeString(err_code)
204  << ": "
205  << message << Endm;
206  }
207 };
208 
209 
211 {
212 public:
213  virtual void HandleMessage(EDiagSev severity,
215  const string& message) const
216  {
217  switch(severity) {
218  case eDiag_Error:
219  case eDiag_Critical:
220  case eDiag_Fatal:
221  if (err_code != CEUtilsException::ePhraseNotFound ||
222  !IsTaxidQuery(message))
223  {
224  // NCBI_THROW, but wth err_code as a variable.
225  throw CEUtilsException(DIAG_COMPILE_INFO, 0, err_code, message);
226  }
227 
228  // This is a taxid query that happens to be be found in database;
229  // treat as warning
230 
232 
233  default:
234  // ERR_POST, but with severity as a variable.
235  CNcbiDiag(DIAG_COMPILE_INFO, severity).GetRef()
236  << s_GetErrCodeString(err_code)
237  << ": "
238  << message << Endm;
239  }
240  }
241 
242 private:
243 
244  bool IsTaxidQuery(const string &message) const {
245  /// Taxid queries are of form "txid<number>[orgn]" or "txid<number>[progn"}
246  /// The best way to check this would be using class CRegexp, but that
247  /// could create a circular library dependency, so using more primitive
248  /// string checking methods
249  if (!NStr::StartsWith(message, "txid") ||
250  (!NStr::EndsWith(message, "[orgn]") &&
251  !NStr::EndsWith(message, "[porgn]")))
252  {
253  return false;
254  }
255  try {
256  NStr::StringToUInt(message.substr(4, message.find('[')-4));
257  } catch (CStringException &) {
258  /// "taxid" string is not a number
259  return false;
260  }
261  return true;
262  }
263 };
264 
265 
267 {
268 public:
270  : m_HasError(false)
271  {
272  }
273 
274  bool HasError(void) const { return m_HasError; }
275  void GetErrors(list<string>& errors) { errors = m_Errors; }
276 
277 protected:
278  bool error(const string& message)
279  {
280  ERR_POST(Error << "parse error: " << message);
281  return false;
282  }
283 
284  bool start_element(const string& name,
285  const attrs_type& attrs)
286  {
287  m_Text_chunks.clear();
288 
289  if ( !m_Path.empty() ) {
290  m_Path += "/";
291  }
292  m_Path += name;
293  return true;
294  }
295 
296  bool end_element(const string& name)
297  {
298  bool result = OnEndElement();
299 
300  string::size_type pos = m_Path.find_last_of("/");
301  if (pos != string::npos) {
302  m_Path.erase(pos);
303  }
304  return result;
305  }
306 
307  bool text(const string& contents)
308  {
309  m_Text_chunks.push_back(contents);
310  return true;
311  }
312 
313  virtual bool OnEndElement(void) { return true; }
314 
315  string GetText(void) const { return NStr::Join(m_Text_chunks, ""); }
316 
317 protected:
318  string m_Path;
319  /// List of parsing errors.
320  /// @note Parsing errors deal with the syntax of a
321  /// reply from E-Utils. Parsing errors should be
322  /// distinguished from errors encountered in
323  /// processing a data request.
324  list<string> m_Errors;
326  // Accumulator of text chunks.
327  list<string> m_Text_chunks;
328 };
329 
330 
331 template<class T>
333 {
334 public:
335  CESearchParser(vector<T>& uids,
336  CEutilsClient::CMessageHandler& message_handler)
337  : m_MessageHandler(message_handler)
338  , m_Count(0)
339  , m_Uids(uids)
340  { }
341 
343  {
344  ProcessMessages();
345  }
346 
347  Uint8 GetCount(void) const { return m_Count; }
348 
349  /// Processes the warning and error messages from
350  /// E-Utils, delivering them to the message handler
351  /// and clearing them from the queue.
352  ///
353  /// The XML parser does not like exceptions thrown
354  /// during the parse, so the messages are queued.
355  void ProcessMessages(void)
356  {
357  // Process warnings first; it's better to emit
358  // as many messages as possible, and errors are
359  // more likely to lead to premature exit.
360  ITERATE(list<TMessage>, i, m_ResultWarnings) {
361  m_MessageHandler.HandleMessage(eDiag_Warning,
362  i->first, i->second);
363  }
364  m_ResultWarnings.clear();
365  ITERATE(list<TMessage>, i, m_ResultErrors) {
366  m_MessageHandler.HandleMessage(eDiag_Error,
367  i->first, i->second);
368  }
369  m_ResultErrors.clear();
370  }
371 
372 protected:
373  typedef pair<CEUtilsException::EErrCode, string> TMessage;
374 
375  bool x_IsSuffix(const string& s,
376  const char* suffix)
377  {
378  string::size_type pos = s.rfind(suffix);
379  return (pos != string::npos && pos == s.size() - strlen(suffix));
380  }
381 
382 
383  bool OnEndElement(void)
384  {
385  string contents = GetText();
386 
387  if (m_Path == "eSearchResult/Count") {
388  m_Count = NStr::StringToUInt8(contents);
389  }
390  else if (x_IsSuffix(m_Path, "/IdList/Id")) {
391  m_Uids.push_back(s_ParseId<T>(contents));
392  }
393  else if (x_IsSuffix(m_Path, "/ErrorList/PhraseNotFound")) {
394  TMessage message(CEUtilsException::ePhraseNotFound, contents);
395  m_ResultErrors.push_back(message);
396  }
397  else if (x_IsSuffix(m_Path, "/ErrorList/FieldNotFound")) {
398  TMessage message(CEUtilsException::eFieldNotFound, contents);
399  m_ResultErrors.push_back(message);
400  }
401  else if (x_IsSuffix(m_Path, "/WarningList/PhraseIgnored")) {
402  TMessage message(CEUtilsException::ePhraseIgnored, contents);
403  m_ResultWarnings.push_back(message);
404  }
405  else if (x_IsSuffix(m_Path, "/WarningList/QuotedPhraseNotFound")) {
407  m_ResultWarnings.push_back(message);
408  }
409  else if (x_IsSuffix(m_Path, "/WarningList/OutputMessage")) {
410  TMessage message(CEUtilsException::eOutputMessage, contents);
411  m_ResultWarnings.push_back(message);
412  }
413  else if (m_Path == "ERROR" || m_Path == "eSearchResult/ERROR") {
414  m_HasError = true;
415  m_Errors.push_back(contents);
416  return false;
417  }
418  return true;
419  }
420 
421 private:
424  vector<T>& m_Uids;
425 
426  /// List of error messages from the E-Utils request.
427  /// These are distinct from errors in parsing the
428  /// E-Utils reply.
429  list<TMessage> m_ResultErrors;
430 
431  /// List of warning messages from the E-Utils request.
432  /// These are distinct from errors in parsing the
433  /// E-Utils reply.
434  list<TMessage> m_ResultWarnings;
435 };
436 
437 
438 template<class T>
440 {
441 public:
442  CELinkParser(const string& dbfrom, const string& dbto,
443  vector<T>& uids)
444  : m_LinkName(dbfrom + "_" + dbto)
445  , m_Uids(uids)
446  , m_InLinkSet(false)
447  {
448  NStr::ToLower(m_LinkName);
449  }
450 
451  void SetLinkName(const string& link_name)
452  {
453  m_LinkName = link_name;
454  NStr::ToLower(m_LinkName);
455  }
456 
457 protected:
458 
459  bool end_element(const string& name)
460  {
462  if (name == "LinkSetDb") {
463  m_InLinkSet = false;
464  }
465  return true;
466  }
467 
468  bool OnEndElement(void)
469  {
470  if ( !m_InLinkSet && NStr::EndsWith(m_Path, "/LinkName") ) {
471  if ( GetText() == m_LinkName) {
472  m_InLinkSet = true;
473  }
474  }
475  else if (m_InLinkSet && NStr::EndsWith(m_Path, "/Link/Id") ) {
476  m_Uids.push_back(s_ParseId<T>( GetText() ));
477  }
478  return true;
479  }
480 
481 private:
482  string m_LinkName;
483  vector<T>& m_Uids;
485 };
486 
487 
488 
489 //////////////////////////////////////////////////////////////////////////////
490 
491 
493  : m_CachedHostNameCount(0), m_RetMax(kMax_Int)
494 {
495  class CInPlaceConnIniter : protected CConnIniter
496  {
497  } conn_initer; /*NCBI_FAKE_WARNING*/
499 }
500 
501 CEutilsClient::CEutilsClient(const string& host)
502  : m_CachedHostNameCount(0),
503  m_HostName(host),
504  m_RetMax(kMax_Int)
505 {
506  class CInPlaceConnIniter : protected CConnIniter
507  {
508  } conn_initer; /*NCBI_FAKE_WARNING*/
510 }
511 
513 {
515 }
516 
518 {
520 }
521 
523 {
525 }
526 
528 {
529  m_MessageHandler.Reset(&message_handler);
530 }
531 
532 void CEutilsClient::SetUserTag(const string& tag)
533 {
534  m_UrlTag = tag;
535 }
536 
538 {
540 }
541 
542 void CEutilsClient::AddParameter(const string &name, const string &value)
543 {
545 }
546 
547 void CEutilsClient::SetLinkName(const string& link_name)
548 {
549  m_LinkName = link_name;
550 }
551 
553 {
554  m_RetMax = ret_max;
555 }
556 
557 
558 //////////////////////////////////////////////////////////////////////////////
559 
560 
561 Uint8 CEutilsClient::Count(const string& db,
562  const string& term)
563 {
564  string params;
565  params += "db=" + NStr::URLEncode(db);
566  params += "&term=" + NStr::URLEncode(term);
567  params += "&retmode=xml&retmax=1";
568  if ( !m_UrlTag.empty() ) {
569  params += "&user=" + NStr::URLEncode(m_UrlTag);
570  }
572 
573  Uint8 count = 0;
574  LOG_POST(Trace << "Executing: db=" << db << " query=" << term);
575  bool success = false;
576  m_Url.clear();
577  m_Time.clear();
578  for (int retries = 0; retries < 10; ++retries) {
579  try {
580  string path = "/entrez/eutils/esearch.fcgi";
581  string hostname = x_GetHostName();
582  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
583  m_Url.push_back(x_BuildUrl(hostname, path, params));
584  istr << params;
585  m_Time.push_back(CTime(CTime::eCurrent));
586  vector<Int8> uids;
587  CESearchParser<Int8> parser(uids, *m_MessageHandler);
588 
589  xml::error_messages msgs;
590  parser.parse_stream(istr, &msgs);
591 
592  if (msgs.has_errors() || msgs.has_fatal_errors()) {
594  "error parsing xml: " + msgs.print());
595  }
596 
597  parser.ProcessMessages();
598  count = parser.GetCount();
599 
600  success = true;
601  break;
602  }
603  catch (CException& e) {
604  ERR_POST_X(1, Warning << "failed on attempt " << retries + 1
605  << ": " << e);
606  }
607 
608  int sleep_secs = ::sqrt(retries);
609  if (sleep_secs) {
610  SleepSec(sleep_secs);
611  }
612  }
613 
614  if ( !success ) {
616  "failed to execute query: " + term);
617  }
618 
619  return count;
620 }
621 
622 #ifdef NCBI_INT8_GI
624  vector<int>& uids)
625 {
626  return x_ParseSearchResults(istr, uids);
627 }
628 #endif
629 
631  vector<CSeq_id_Handle>& uids)
632 {
633  return x_ParseSearchResults(istr, uids);
634 }
635 
637  vector<string>& uids)
638 {
639  return x_ParseSearchResults(istr, uids);
640 }
641 
643  vector<TEntrezId>& uids)
644 {
645  return x_ParseSearchResults(istr, uids);
646 }
647 
648 template<class T>
650  vector<T>& uids)
651 {
652  CESearchParser<T> parser(uids, *m_MessageHandler);
653  xml::error_messages msgs;
654  parser.parse_stream(istr, &msgs);
655 
656  if (msgs.has_errors() || msgs.has_fatal_errors()) {
658  "error parsing xml: " + msgs.print());
659  }
660 
661  if (parser.HasError()) {
662  list<string> errs;
663  parser.GetErrors(errs);
664 
665  string msg = NStr::Join(errs, "; ");
667  "error returned from query: " + msg);
668  }
669 
670  parser.ProcessMessages();
671  return parser.GetCount();
672 }
673 
674 #ifdef NCBI_INT8_GI
675 Uint8 CEutilsClient::ParseSearchResults(const string& xml_file,
676  vector<int>& uids)
677 {
678  return x_ParseSearchResults(xml_file, uids);
679 }
680 #endif
681 
682 Uint8 CEutilsClient::ParseSearchResults(const string& xml_file,
683  vector<CSeq_id_Handle>& uids)
684 {
685  return x_ParseSearchResults(xml_file, uids);
686 }
687 
689  vector<string>& uids)
690 {
691  return x_ParseSearchResults(xml_file, uids);
692 }
693 
695  vector<TEntrezId>& uids)
696 {
697  return x_ParseSearchResults(xml_file, uids);
698 }
699 
700 template<class T>
702  vector<T>& uids)
703 {
704  CNcbiIfstream istr(xml_file.c_str());
705  if ( !istr ) {
707  "failed to open file: " + xml_file);
708  }
709  return ParseSearchResults(istr, uids);
710 }
711 
712 #ifdef NCBI_INT8_GI
713 Uint8 CEutilsClient::Search(const string& db,
714  const string& term,
715  vector<int>& uids,
716  const string& xml_path)
717 {
718  return x_Search(db, term, uids, xml_path);
719 }
720 #endif
721 
722 Uint8 CEutilsClient::Search(const string& db,
723  const string& term,
724  vector<CSeq_id_Handle>& uids,
725  const string& xml_path)
726 {
727  return x_Search(db, term, uids, xml_path);
728 }
729 
730 Uint8 CEutilsClient::Search(const string& db,
731  const string& term,
732  vector<string>& uids,
733  const string& xml_path)
734 {
735  return x_Search(db, term, uids, xml_path);
736 }
737 
738 
739 Uint8 CEutilsClient::Search(const string& db,
740  const string& term,
741  vector<TEntrezId>& uids,
742  const string& xml_path)
743 {
744  return x_Search(db, term, uids, xml_path);
745 }
746 
747 template<class T>
749  const string& term,
750  vector<T>& uids,
751  const string& xml_path)
752 {
753  string params;
754  params += "db=" + NStr::URLEncode(db);
755  params += "&term=" + NStr::URLEncode(term);
756  params += "&retmode=xml";
757  if (m_RetMax) {
758  params += "&retmax=" + NStr::NumericToString(m_RetMax);
759  }
760  if ( !m_UrlTag.empty() ) {
761  params += "&user=" + NStr::URLEncode(m_UrlTag);
762  }
764  params += "&idtype=gi";
765  } else {
766  params += "&idtype=acc";
767  }
769 
770  Uint8 count = 0;
771 
772  LOG_POST(Trace << "Executing: db=" << db << " query=" << term);
773  bool success = false;
774  m_Url.clear();
775  m_Time.clear();
776  for (int retries = 0; retries < 10; ++retries) {
777  try {
778  string path = "/entrez/eutils/esearch.fcgi";
779  string hostname = x_GetHostName();
780  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
781  m_Url.push_back(x_BuildUrl(hostname, path, params));
782  istr << params;
783  m_Time.push_back(CTime(CTime::eCurrent));
784 
785  if(!xml_path.empty()) {
786  string xml_file
787  = xml_path + '.' + NStr::NumericToString(retries + 1);
788  CNcbiOfstream ostr(xml_file.c_str());
789  if (ostr.good()) {
790  NcbiStreamCopy(ostr, istr);
791  ostr.close();
792 
793  if(!ostr || 200 != istr.GetStatusCode()) {
795  "Failure while writing entrez xml response"
796  " to file: " + xml_file);
797  }
798 
799  count = ParseSearchResults(xml_file, uids);
800  }
801  else {
802  ERR_POST(Error << "Unable to open file for writing: "
803  + xml_file);
804  count = ParseSearchResults(istr, uids);
805  }
806  }
807  else {
808  count = ParseSearchResults(istr, uids);
809  }
810 
811  success = true;
812  break;
813  }
814  catch (CException& e) {
815  ERR_POST_X(2, Warning << "failed on attempt " << retries + 1
816  << ": " << e);
817  }
818 
819  int sleep_secs = ::sqrt(retries);
820  if (sleep_secs) {
821  SleepSec(sleep_secs);
822  }
823  }
824 
825  if ( !success ) {
827  "failed to execute query: " + term);
828  }
829  return count;
830 }
831 
832 void CEutilsClient::Search(const string& db,
833  const string& term,
834  CNcbiOstream& ostr,
835  EUseHistory use_history)
836 {
837  ostringstream oss;
838  oss << "db=" << NStr::URLEncode(db)
839  << "&term=" << NStr::URLEncode(term)
840  << "&retmode=xml";
841  if (m_RetMax) {
842  oss << "&retmax="
843  << m_RetMax;
844  }
845 
846  if ( use_history == eUseHistoryEnabled ) {
847  oss << "&usehistory=y";
848  }
849 
850  x_Get("/entrez/eutils/esearch.fcgi", oss.str(), ostr);
851 }
852 
853 static void s_SearchHistoryQuery(ostringstream& oss,
854  const string& db,
855  const string& term,
856  const string& web_env,
857  int retstart,
858  int retmax)
859 {
860  oss << "db=" << NStr::URLEncode(db)
861  << "&term=" << NStr::URLEncode(term)
862  << "&retmode=xml";
863  if ( retstart ) {
864  oss << "&retstart="
865  << retstart;
866  }
867  if (retmax) {
868  oss << "&retmax="
869  << retmax;
870  }
871 
872  oss << "&usehistory=y"
873  << "&WebEnv="
874  << web_env;
875 }
876 
877 void CEutilsClient::SearchHistory(const string& db,
878  const string& term,
879  const string& web_env,
880  Int8 query_key,
881  int retstart,
882  CNcbiOstream& ostr)
883 {
884  ostringstream oss;
885  s_SearchHistoryQuery(oss, db, term, web_env, retstart, m_RetMax);
886  if ( query_key > 0 ) {
887  oss << "&query_key="
888  << query_key;
889  }
890 
891  x_Get("/entrez/eutils/esearch.fcgi", oss.str(), ostr);
892 }
893 
894 void CEutilsClient::SearchHistory(const string& db,
895  const string& term,
896  const string& web_env,
897  CSeq_id_Handle query_key,
898  int retstart,
899  CNcbiOstream& ostr)
900 {
901  ostringstream oss;
902  s_SearchHistoryQuery(oss, db, term, web_env, retstart, m_RetMax);
903  oss << "&query_key=" << query_key << "&idtype=acc";
904 
905  x_Get("/entrez/eutils/esearch.fcgi", oss.str(), ostr);
906 }
907 
908 void CEutilsClient::SearchHistory(const string& db,
909  const string& term,
910  const string& web_env,
911  const string& query_key,
912  int retstart,
913  CNcbiOstream& ostr)
914 {
915  ostringstream oss;
916  s_SearchHistoryQuery(oss, db, term, web_env, retstart, m_RetMax);
917  oss << "&query_key=" << query_key << "&idtype=acc";
918 
919  x_Get("/entrez/eutils/esearch.fcgi", oss.str(), ostr);
920 }
921 
922 
923 #define HOST_NAME_REFRESH_FREQ 100
924 
925 const string& CEutilsClient::x_GetHostName(void) const
926 {
927  if (!m_HostName.empty()) {
928  return m_HostName;
929  }
930 
932  m_CachedHostName.clear();
934  }
935 
936  if (!m_CachedHostName.empty()) {
937  return m_CachedHostName;
938  }
939 
940  // See also: objtools/eutils/api/eutils.cpp
941  static const char kEutils[] = "eutils.ncbi.nlm.nih.gov";
942  static const char kEutilsLB[] = "eutils_lb";
943 
944  string host;
945  SConnNetInfo* net_info = ConnNetInfo_Create(kEutilsLB);
946  SSERV_Info* info = SERV_GetInfo(kEutilsLB, fSERV_Dns,
947  SERV_ANYHOST, net_info);
948  ConnNetInfo_Destroy(net_info);
949  if (info) {
950  if (info->host) {
951  host = CSocketAPI::ntoa(info->host);
952  }
953  free(info);
954  }
955 
956  string scheme("http");
957  if (host.empty()) {
958  char buf[80];
959  const char* web = ConnNetInfo_GetValue(kEutilsLB, REG_CONN_HOST,
960  buf, sizeof(buf), kEutils);
961  host = string(web && *web ? web : kEutils);
962  scheme += 's';
963  }
964  _ASSERT(!host.empty());
965  m_CachedHostName = scheme + "://" + host;
966  return m_CachedHostName;
967 }
968 
969 
970 void CEutilsClient::x_Get(string const& path,
971  string const& params,
972  CNcbiOstream& ostr)
973 {
974  bool success = false;
975  m_Url.clear();
976  m_Time.clear();
977  string extra_params{ params };
978  x_AddAdditionalParameters(extra_params);
979  for (int retries = 0; retries < 10; ++retries) {
980  try {
981  string hostname = x_GetHostName();
982  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
983  m_Url.push_back(x_BuildUrl(hostname, path, extra_params));
984  istr << extra_params;
985  m_Time.push_back(CTime(CTime::eCurrent));
986  ostringstream reply;
987  if (NcbiStreamCopy(reply, istr) && 200 == istr.GetStatusCode()) {
988  string reply_str = reply.str();
989  istringstream reply_istr(reply.str());
990  vector<TEntrezId> uids;
991  /// We don't actually need the uids, but parse the reply anyway
992  /// in order to catch errors
993  ParseSearchResults(reply_istr, uids);
994 
995  /// No errors found in reply; copy to output stream
996  ostr << reply_str;
997  success = true;
998  break;
999  }
1000  }
1001  catch (CException& e) {
1002  ERR_POST_X(3, Warning << "failed on attempt " << retries + 1
1003  << ": " << e);
1004  }
1005 
1006  int sleep_secs = ::sqrt(retries);
1007  if (sleep_secs) {
1008  SleepSec(sleep_secs);
1009  }
1010  }
1011 
1012  if ( !success ) {
1013  ostringstream msg;
1014  msg << "Failed to execute request: "
1015  << path
1016  << "?"
1017  << params;
1018  NCBI_THROW(CException, eUnknown, msg.str());
1019  }
1020 }
1021 
1022 
1023 //////////////////////////////////////////////////////////////////////////////
1024 
1025 #ifdef NCBI_INT8_GI
1026 void CEutilsClient::Link(const string& db_from,
1027  const string& db_to,
1028  const vector<int>& uids_from,
1029  vector<int>& uids_to,
1030  const string& xml_path,
1031  const string& command)
1032 
1033 {
1034  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1035 }
1036 #endif
1037 
1038 void CEutilsClient::Link(const string& db_from,
1039  const string& db_to,
1040  const vector<CSeq_id_Handle>& uids_from,
1041  vector<CSeq_id_Handle>& uids_to,
1042  const string& xml_path,
1043  const string& command)
1044 {
1045  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1046 }
1047 
1048 void CEutilsClient::Link(const string& db_from,
1049  const string& db_to,
1050  const vector<string>& uids_from,
1051  vector<string>& uids_to,
1052  const string& xml_path,
1053  const string& command)
1054 {
1055  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1056 }
1057 
1058 void CEutilsClient::Link(const string& db_from,
1059  const string& db_to,
1060  const vector<TEntrezId>& uids_from,
1061  vector<TEntrezId>& uids_to,
1062  const string& xml_path,
1063  const string& command)
1064 {
1065  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1066 }
1067 
1068 #ifdef NCBI_INT8_GI
1069 void CEutilsClient::Link(const string& db_from,
1070  const string& db_to,
1071  const vector<int>& uids_from,
1072  vector<TEntrezId>& uids_to,
1073  const string& xml_path,
1074  const string& command)
1075 {
1076  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1077 }
1078 
1079 void CEutilsClient::Link(const string& db_from,
1080  const string& db_to,
1081  const vector<TEntrezId>& uids_from,
1082  vector<int>& uids_to,
1083  const string& xml_path,
1084  const string& command)
1085 {
1086  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1087 }
1088 #endif
1089 
1090 void CEutilsClient::Link(const string& db_from,
1091  const string& db_to,
1092  const vector<TEntrezId>& uids_from,
1093  vector<CSeq_id_Handle>& uids_to,
1094  const string& xml_path,
1095  const string& command)
1096 {
1097  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1098 }
1099 
1100 void CEutilsClient::Link(const string& db_from,
1101  const string& db_to,
1102  const vector<CSeq_id_Handle>& uids_from,
1103  vector<TEntrezId>& uids_to,
1104  const string& xml_path,
1105  const string& command)
1106 {
1107  x_Link(db_from, db_to, uids_from, uids_to, xml_path, command);
1108 }
1109 
1110 template<class T1, class T2>
1111 void CEutilsClient::x_Link(const string& db_from,
1112  const string& db_to,
1113  const vector<T1>& uids_from,
1114  vector<T2>& uids_to,
1115  const string& xml_path,
1116  const string& command)
1117 {
1118  std::ostringstream oss;
1119 
1120  oss << "db=" << NStr::URLEncode(db_to)
1121  << "&dbfrom=" << NStr::URLEncode(db_from)
1122  << "&retmode=xml"
1123  << "&cmd=" << NStr::URLEncode(command);
1124  s_FormatIds(oss, uids_from);
1125  string params = oss.str();
1126  x_AddAdditionalParameters(params);
1127 
1128  bool success = false;
1129  m_Url.clear();
1130  m_Time.clear();
1131  for (int retries = 0; retries < 10; ++retries) {
1132  try {
1133  string path = "/entrez/eutils/elink.fcgi";
1134  string hostname = x_GetHostName();
1135  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
1136  m_Url.push_back(x_BuildUrl(hostname, path, params));
1137  istr << params;
1138  m_Time.push_back(CTime(CTime::eCurrent));
1139  CELinkParser<T2> parser(db_from, db_to, uids_to);
1140  if ( !m_LinkName.empty() ) {
1141  parser.SetLinkName(m_LinkName);
1142  }
1143  xml::error_messages msgs;
1144  if(!xml_path.empty()) {
1145  string xml_file
1146  = xml_path + '.' + NStr::NumericToString(retries + 1);
1147 
1148  CNcbiOfstream ostr(xml_file.c_str());
1149  if(ostr.good()) {
1150  NcbiStreamCopy(ostr, istr);
1151  ostr.close();
1152  parser.parse_file(xml_file.c_str(), &msgs);
1153  if(!ostr || 200 != istr.GetStatusCode()) {
1155  "Failure while writing entrez xml response"
1156  " to file: " + xml_file);
1157  }
1158  }
1159  else {
1160  ERR_POST(Error << "Unable to open file for writing: "
1161  + xml_file);
1162  parser.parse_stream(istr, &msgs);
1163  }
1164  }
1165  else {
1166  parser.parse_stream(istr, &msgs);
1167  }
1168 
1169  if (msgs.has_errors() || msgs.has_fatal_errors()) {
1171  "error parsing xml: " + msgs.print());
1172  }
1173  success = true;
1174  break;
1175  }
1176  catch (CException& e) {
1177  ERR_POST_X(4, Warning << "failed on attempt " << retries + 1
1178  << ": " << e);
1179  }
1180 
1181  int sleep_secs = ::sqrt(retries);
1182  if (sleep_secs) {
1183  SleepSec(sleep_secs);
1184  }
1185  }
1186 
1187  if ( !success ) {
1189  "failed to execute elink request: " + params);
1190  }
1191 }
1192 
1193 #ifdef NCBI_INT8_GI
1194 void CEutilsClient::Link(const string& db_from,
1195  const string& db_to,
1196  const vector<int>& uids_from,
1197  CNcbiOstream& ostr,
1198  const string& command)
1199 {
1200  x_Link(db_from, db_to, uids_from, ostr, command);
1201 }
1202 #endif
1203 
1204 void CEutilsClient::Link(const string& db_from,
1205  const string& db_to,
1206  const vector<CSeq_id_Handle>& uids_from,
1207  CNcbiOstream& ostr,
1208  const string& command)
1209 {
1210  x_Link(db_from, db_to, uids_from, ostr, command);
1211 }
1212 
1213 void CEutilsClient::Link(const string& db_from,
1214  const string& db_to,
1215  const vector<string>& uids_from,
1216  CNcbiOstream& ostr,
1217  const string& command)
1218 {
1219  x_Link(db_from, db_to, uids_from, ostr, command);
1220 }
1221 
1222 void CEutilsClient::Link(const string& db_from,
1223  const string& db_to,
1224  const vector<TEntrezId>& uids_from,
1225  CNcbiOstream& ostr,
1226  const string& command)
1227 {
1228  x_Link(db_from, db_to, uids_from, ostr, command);
1229 }
1230 
1231 template<class T>
1232 void CEutilsClient::x_Link(const string& db_from,
1233  const string& db_to,
1234  const vector<T>& uids_from,
1235  CNcbiOstream& ostr,
1236  const string& command)
1237 {
1238  std::ostringstream oss;
1239 
1240  oss << "db=" << NStr::URLEncode(db_to)
1241  << "&dbfrom=" << NStr::URLEncode(db_from)
1242  << "&retmode=xml"
1243  << "&cmd=" + NStr::URLEncode(command);
1244  s_FormatIds(oss, uids_from);
1245  string params = oss.str();
1246  x_AddAdditionalParameters(params);
1247 
1248  bool success = false;
1249  m_Url.clear();
1250  m_Time.clear();
1251  for (int retries = 0; retries < 10; ++retries) {
1252  try {
1253  string path = "/entrez/eutils/elink.fcgi";
1254  string hostname = x_GetHostName();
1255  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
1256  m_Url.push_back(x_BuildUrl(hostname, path, params));
1257  istr << params;
1258  m_Time.push_back(CTime(CTime::eCurrent));
1259  if (NcbiStreamCopy(ostr, istr) && 200 == istr.GetStatusCode()) {
1260  success = true;
1261  break;
1262  }
1263  }
1264  catch (CException& e) {
1265  ERR_POST_X(5, Warning << "failed on attempt " << retries + 1
1266  << ": " << e);
1267  }
1268 
1269  int sleep_secs = ::sqrt(retries);
1270  if (sleep_secs) {
1271  SleepSec(sleep_secs);
1272  }
1273  }
1274 
1275  if ( !success ) {
1277  "failed to execute elink request: " + params);
1278  }
1279 }
1280 
1281 void CEutilsClient::LinkHistory(const string& db_from,
1282  const string& db_to,
1283  const string& web_env,
1284  Int8 query_key,
1285  CNcbiOstream& ostr)
1286 {
1287  std::ostringstream oss;
1288 
1289  oss << "db=" << NStr::URLEncode(db_to)
1290  << "&dbfrom=" << NStr::URLEncode(db_from)
1291  << "&retmode=xml"
1292  << "&WebEnv=" << web_env
1293  << "&query_key=" << query_key;
1294 
1295  x_Get("/entrez/eutils/elink.fcgi", oss.str(), ostr);
1296 }
1297 
1298 void CEutilsClient::LinkHistory(const string& db_from,
1299  const string& db_to,
1300  const string& web_env,
1301  CSeq_id_Handle query_key,
1302  CNcbiOstream& ostr)
1303 {
1304  std::ostringstream oss;
1305 
1306  oss << "db=" << NStr::URLEncode(db_to)
1307  << "&dbfrom=" << NStr::URLEncode(db_from)
1308  << "&retmode=xml"
1309  << "&WebEnv=" << web_env
1310  << "&query_key=" << query_key
1311  << "&idtype=acc";
1312 
1313  x_Get("/entrez/eutils/elink.fcgi", oss.str(), ostr);
1314 }
1315 
1316 void CEutilsClient::LinkHistory(const string& db_from,
1317  const string& db_to,
1318  const string& web_env,
1319  const string& query_key,
1320  CNcbiOstream& ostr)
1321 {
1322  std::ostringstream oss;
1323 
1324  oss << "db=" << NStr::URLEncode(db_to)
1325  << "&dbfrom=" << NStr::URLEncode(db_from)
1326  << "&retmode=xml"
1327  << "&WebEnv=" << web_env
1328  << "&query_key=" << query_key
1329  << "&idtype=acc";
1330 
1331  x_Get("/entrez/eutils/elink.fcgi", oss.str(), ostr);
1332 }
1333 
1334 #ifdef NCBI_INT8_GI
1335 void CEutilsClient::LinkOut(const string& db,
1336  const vector<int>& uids,
1337  xml::document& doc,
1338  const string& cmd)
1339 {
1340  x_LinkOut(db, uids, doc, cmd);
1341 }
1342 
1343 #endif
1344 
1345 void CEutilsClient::LinkOut(const string& db,
1346  const vector<objects::CSeq_id_Handle>& uids,
1347  xml::document& doc,
1348  const string& cmd)
1349 {
1350  x_LinkOut(db, uids, doc, cmd);
1351 }
1352 
1353 void CEutilsClient::LinkOut(const string& db,
1354  const vector<string>& uids,
1355  xml::document& doc,
1356  const string& cmd)
1357 {
1358  x_LinkOut(db, uids, doc, cmd);
1359 }
1360 
1361 void CEutilsClient::LinkOut(const string& db,
1362  const vector<TEntrezId>& uids,
1363  xml::document& doc,
1364  const string& cmd)
1365 {
1366  x_LinkOut(db, uids, doc, cmd);
1367 }
1368 
1369 template<class T> void CEutilsClient::x_LinkOut(const string& db,
1370  const vector<T>& uids,
1371  xml::document& doc,
1372  const string& cmd)
1373 {
1374  ostringstream oss;
1375  oss << "dbfrom=" << NStr::URLEncode(db)
1376  << "&cmd=" << NStr::URLEncode(cmd)
1377  << "&retmode=xml";
1378  s_FormatIds(oss, uids);
1379  string params = oss.str();
1380  x_AddAdditionalParameters(params);
1381 
1382  bool success = false;
1383  m_Url.clear();
1384  m_Time.clear();
1385  for (int retries = 0; retries < 10; ++retries) {
1386  try {
1387  string path = "/entrez/eutils/elink.fcgi?";
1388  string hostname = x_GetHostName();
1389  string url = x_BuildUrl(hostname, path, params);
1390  LOG_POST(Trace << "query: " << url);
1391  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
1392  m_Url.push_back(url);
1393  istr << params;
1394  m_Time.push_back(CTime(CTime::eCurrent));
1395  // slurp up all the output.
1396  stringbuf sb;
1397  istr >> &sb;
1398  if (200 == istr.GetStatusCode()) {
1399  string docstr(sb.str());
1400 
1401  // LOG_POST(Info << "Raw results: " << docstr );
1402 
1403  // turn it into an xml::document
1404  xml::error_messages msgs;
1405  xml::document xmldoc(docstr.data(), docstr.size(), &msgs );
1406 
1407  doc.swap(xmldoc);
1408  success = true;
1409  break;
1410  }
1411  }
1412  catch (const xml::parser_exception& e) {
1413  ERR_POST_X(6, Warning << "failed on attempt " << retries + 1
1414  << ": error parsing xml: " << e.what());
1415  }
1416  catch (CException& e) {
1417  ERR_POST_X(6, Warning << "failed on attempt " << retries + 1
1418  << ": " << e);
1419  }
1420 
1421  int sleep_secs = ::sqrt(retries);
1422  if (sleep_secs) {
1423  SleepSec(sleep_secs);
1424  }
1425  }
1426 
1427  if ( !success ) {
1429  "failed to execute esummary request: " + params);
1430  }
1431 }
1432 
1433 
1434 #ifdef NCBI_INT8_GI
1435 void CEutilsClient::Summary(const string& db,
1436  const vector<int>& uids,
1437  xml::document& docsums,
1438  const string& version)
1439 {
1440  x_Summary(db, uids, docsums, version);
1441 }
1442 #endif
1443 
1444 void CEutilsClient::Summary(const string& db,
1445  const vector<CSeq_id_Handle>& uids,
1446  xml::document& docsums,
1447  const string& version)
1448 {
1449  x_Summary(db, uids, docsums, version);
1450 }
1451 
1452 void CEutilsClient::Summary(const string& db,
1453  const vector<string>& uids,
1454  xml::document& docsums,
1455  const string& version)
1456 {
1457  x_Summary(db, uids, docsums, version);
1458 }
1459 
1460 void CEutilsClient::Summary(const string& db,
1461  const vector<TEntrezId>& uids,
1462  xml::document& docsums,
1463  const string& version)
1464 {
1465  x_Summary(db, uids, docsums, version);
1466 }
1467 
1468 template<class T>
1469 void CEutilsClient::x_Summary(const string& db,
1470  const vector<T>& uids,
1471  xml::document& docsums,
1472  const string& version)
1473 {
1474  ostringstream oss;
1475  oss << "db=" << NStr::URLEncode(db)
1476  << "&retmode=xml";
1477  if ( !version.empty() ) {
1478  oss << "&version="
1479  << version;
1480  }
1481  s_FormatIds(oss, uids);
1482  string params = oss.str();
1483  x_AddAdditionalParameters(params);
1484 
1485  bool success = false;
1486  m_Url.clear();
1487  m_Time.clear();
1488  for (int retries = 0; retries < 10; ++retries) {
1489  try {
1490  string path = "/entrez/eutils/esummary.fcgi?";
1491  string hostname = x_GetHostName();
1492  string url = x_BuildUrl(hostname, path, params);
1493  LOG_POST(Trace << "query: " << url);
1494  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
1495  m_Url.push_back(url);
1496  istr << params;
1497  m_Time.push_back(CTime(CTime::eCurrent));
1498  // slurp up all the output.
1499  stringbuf sb;
1500  istr >> &sb;
1501  if (200 == istr.GetStatusCode()) {
1502  string docstr(sb.str());
1503 
1504  // LOG_POST(Info << "Raw results: " << docstr );
1505 
1506  // turn it into an xml::document
1507  xml::error_messages msgs;
1508  xml::document xmldoc(docstr.data(), docstr.size(), &msgs );
1509 
1510  docsums.swap(xmldoc);
1511  success = true;
1512  break;
1513  }
1514  }
1515  catch (const xml::parser_exception& e) {
1516  ERR_POST_X(6, Warning << "failed on attempt " << retries + 1
1517  << ": error parsing xml: " << e.what());
1518  }
1519  catch (CException& e) {
1520  ERR_POST_X(6, Warning << "failed on attempt " << retries + 1
1521  << ": " << e);
1522  }
1523 
1524  int sleep_secs = ::sqrt(retries);
1525  if (sleep_secs) {
1526  SleepSec(sleep_secs);
1527  }
1528  }
1529 
1530  if ( !success ) {
1532  "failed to execute esummary request: " + params);
1533  }
1534 }
1535 
1536 static inline void s_SummaryHistoryQuery(ostream& oss,
1537  const string& db,
1538  const string& web_env,
1539  int retstart,
1540  const string version,
1541  int retmax)
1542 {
1543  oss << "db=" << NStr::URLEncode(db)
1544  << "&retmode=xml"
1545  << "&WebEnv=" << web_env;
1546 
1547  if ( retstart > 0 ) {
1548  oss << "&retstart=" << retstart;
1549  }
1550 
1551  if ( retmax ) {
1552  oss << "&retmax=" << retmax;
1553  }
1554 
1555  if ( !version.empty() ) {
1556  oss << "&version="
1557  << version;
1558  }
1559 }
1560 
1561 void CEutilsClient::SummaryHistory(const string& db,
1562  const string& web_env,
1563  Int8 query_key,
1564  int retstart,
1565  const string& version,
1566  CNcbiOstream& ostr)
1567 {
1568  ostringstream oss;
1569  s_SummaryHistoryQuery(oss, db, web_env, retstart, version, m_RetMax);
1570  oss << "&query_key=" << query_key;
1571  x_Get("/entrez/eutils/esummary.fcgi?", oss.str(), ostr);
1572 }
1573 
1574 void CEutilsClient::SummaryHistory(const string& db,
1575  const string& web_env,
1576  CSeq_id_Handle query_key,
1577  int retstart,
1578  const string& version,
1579  CNcbiOstream& ostr)
1580 {
1581  ostringstream oss;
1582  s_SummaryHistoryQuery(oss, db, web_env, retstart, version, m_RetMax);
1583  oss << "&query_key=" << query_key
1584  << "&idtype=acc";
1585  x_Get("/entrez/eutils/esummary.fcgi?", oss.str(), ostr);
1586 }
1587 
1588 void CEutilsClient::SummaryHistory(const string& db,
1589  const string& web_env,
1590  const string& query_key,
1591  int retstart,
1592  const string& version,
1593  CNcbiOstream& ostr)
1594 {
1595  ostringstream oss;
1596  s_SummaryHistoryQuery(oss, db, web_env, retstart, version, m_RetMax);
1597  oss << "&query_key=" << query_key
1598  << "&idtype=acc";
1599  x_Get("/entrez/eutils/esummary.fcgi?", oss.str(), ostr);
1600 }
1601 
1602 #ifdef NCBI_INT8_GI
1603 void CEutilsClient::Fetch(const string& db,
1604  const vector<int>& uids,
1605  CNcbiOstream& ostr,
1606  const string& retmode)
1607 {
1608  x_Fetch(db, uids, ostr, retmode);
1609 }
1610 #endif
1611 
1612 void CEutilsClient::Fetch(const string& db,
1613  const vector<CSeq_id_Handle>& uids,
1614  CNcbiOstream& ostr,
1615  const string& retmode)
1616 {
1617  x_Fetch(db, uids, ostr, retmode);
1618 }
1619 
1620 void CEutilsClient::Fetch(const string& db,
1621  const vector<string>& uids,
1622  CNcbiOstream& ostr,
1623  const string& retmode)
1624 {
1625  x_Fetch(db, uids, ostr, retmode);
1626 }
1627 
1628 void CEutilsClient::Fetch(const string& db,
1629  const vector<TEntrezId>& uids,
1630  CNcbiOstream& ostr,
1631  const string& retmode)
1632 {
1633  x_Fetch(db, uids, ostr, retmode);
1634 }
1635 
1636 template<class T>
1637 void CEutilsClient::x_Fetch(const string& db,
1638  const vector<T>& uids,
1639  CNcbiOstream& ostr,
1640  const string& retmode)
1641 {
1642  ostringstream oss;
1643  oss << "db=" << NStr::URLEncode(db)
1644  << "&retmode=" << NStr::URLEncode(retmode);
1645 
1646  s_FormatIds(oss, uids);
1647  string params = oss.str();
1648  x_AddAdditionalParameters(params);
1649 
1650  bool success = false;
1651  m_Url.clear();
1652  m_Time.clear();
1653  for (int retries = 0; retries < 10; ++retries) {
1654  try {
1655  string path = "/entrez/eutils/efetch.fcgi";
1656  string hostname = x_GetHostName();
1657  CConn_HttpStream istr(x_BuildUrl(hostname, path, kEmptyStr));
1658  m_Url.push_back(x_BuildUrl(hostname, path, params));
1659  istr << params;
1660  m_Time.push_back(CTime(CTime::eCurrent));
1661  if (NcbiStreamCopy(ostr, istr) && 200 == istr.GetStatusCode()) {
1662  success = true;
1663  break;
1664  }
1665  }
1666  catch (CException& e) {
1667  ERR_POST(Warning << "failed on attempt " << retries + 1
1668  << ": " << e);
1669  }
1670 
1671  int sleep_secs = ::sqrt(retries);
1672  if (sleep_secs) {
1673  SleepSec(sleep_secs);
1674  }
1675  }
1676 
1677  if ( !success ) {
1679  "failed to execute efetch request: " + params);
1680  }
1681 }
1682 
1683 static inline string s_GetContentType(CEutilsClient::EContentType content_type)
1684 {
1685  switch (content_type) {
1687  return "xml";
1689  return "text";
1691  return "html";
1693  return "asn.1";
1694  default:
1695  break;
1696  }
1697  // Default content type
1698  return "xml";
1699 }
1700 
1701 static inline void s_FetchHistoryQuery(ostream& oss,
1702  const string& db,
1703  const string& web_env,
1704  int retstart,
1705  int retmax,
1706  CEutilsClient::EContentType content_type)
1707 {
1708  oss << "db=" << NStr::URLEncode(db)
1709  << "&retmode=" << s_GetContentType(content_type)
1710  << "&WebEnv=" << web_env;
1711  if ( retstart > 0 ) {
1712  oss << "&retstart=" << retstart;
1713  }
1714 
1715  if ( retmax ) {
1716  oss << "&retmax=" << retmax;
1717  }
1718 }
1719 
1720 void CEutilsClient::FetchHistory(const string& db,
1721  const string& web_env,
1722  Int8 query_key,
1723  int retstart,
1724  EContentType content_type,
1725  CNcbiOstream& ostr)
1726 {
1727  ostringstream oss;
1728  s_FetchHistoryQuery(oss, db, web_env, retstart, m_RetMax, content_type);
1729  oss << "&query_key=" << query_key;
1730 
1731  x_Get("/entrez/eutils/efetch.fcgi", oss.str(), ostr);
1732 }
1733 
1734 void CEutilsClient::FetchHistory(const string& db,
1735  const string& web_env,
1736  CSeq_id_Handle query_key,
1737  int retstart,
1738  EContentType content_type,
1739  CNcbiOstream& ostr)
1740 {
1741  ostringstream oss;
1742  s_FetchHistoryQuery(oss, db, web_env, retstart, m_RetMax, content_type);
1743  oss << "&query_key=" << query_key
1744  << "&idtype=acc";
1745 
1746  x_Get("/entrez/eutils/efetch.fcgi", oss.str(), ostr);
1747 }
1748 
1749 void CEutilsClient::FetchHistory(const string& db,
1750  const string& web_env,
1751  const string& query_key,
1752  int retstart,
1753  EContentType content_type,
1754  CNcbiOstream& ostr)
1755 {
1756  ostringstream oss;
1757  s_FetchHistoryQuery(oss, db, web_env, retstart, m_RetMax, content_type);
1758  oss << "&query_key=" << query_key
1759  << "&idtype=acc";
1760 
1761  x_Get("/entrez/eutils/efetch.fcgi", oss.str(), ostr);
1762 }
1763 
1764 const list<string> CEutilsClient::GetUrl() const
1765 {
1766  return m_Url;
1767 }
1768 
1769 const list<CTime> CEutilsClient::GetTime() const
1770 {
1771  return m_Time;
1772 }
1773 
1774 string CEutilsClient::x_BuildUrl(const string& host, const string &path,
1775  const string &params)
1776 {
1777  string url = host + path;
1778  if(!params.empty()) {
1779  url += '?' + params;
1780  }
1781  return url;
1782 }
1783 
1784 inline void CEutilsClient::x_AddAdditionalParameters(string &params)
1785 {
1786  if (m_AdditionalParams.empty())
1787  return;
1788  ostringstream oss;
1789  for (const TParamList::value_type &param : m_AdditionalParams) {
1790  oss << '&' << param.first << '=' << param.second;
1791  }
1792  params += oss.str();
1793 }
1794 
#define false
Definition: bool.h:36
Helper hook-up class that installs default logging/registry/locking (but only if they have not yet be...
This stream exchanges data with an HTTP server located at the URL: http[s]://host[:port]/path[?...
CConn_PipeStream for command piping.
void SetLinkName(const string &link_name)
bool end_element(const string &name)
CELinkParser(const string &dbfrom, const string &dbto, vector< T > &uids)
vector< T > & m_Uids
bool OnEndElement(void)
pair< CEUtilsException::EErrCode, string > TMessage
bool OnEndElement(void)
CEutilsClient::CMessageHandler & m_MessageHandler
list< TMessage > m_ResultErrors
List of error messages from the E-Utils request.
Uint8 GetCount(void) const
bool x_IsSuffix(const string &s, const char *suffix)
vector< T > & m_Uids
CESearchParser(vector< T > &uids, CEutilsClient::CMessageHandler &message_handler)
void ProcessMessages(void)
Processes the warning and error messages from E-Utils, delivering them to the message handler and cle...
list< TMessage > m_ResultWarnings
List of warning messages from the E-Utils request.
virtual const char * GetErrCodeString(void) const override
Get error code interpreted as text.
bool end_element(const string &name)
void GetErrors(list< string > &errors)
virtual bool OnEndElement(void)
bool text(const string &contents)
string GetText(void) const
bool start_element(const string &name, const attrs_type &attrs)
list< string > m_Errors
List of parsing errors.
list< string > m_Text_chunks
bool error(const string &message)
bool HasError(void) const
Subclass this to override how messages (warnings and errors) are handled.
const list< CTime > GetTime(void) const
list< CTime > m_Time
void LinkOut(const string &db, const vector< objects::CSeq_id_Handle > &uids, xml::document &docsums, const string &cmd="llinks")
void Fetch(const string &db, const vector< objects::CSeq_id_Handle > &uids, CNcbiOstream &ostr, const string &retmode="xml")
void SetMaxReturn(int ret_max)
CRef< CMessageHandler > m_MessageHandler
void SearchHistory(const string &db, const string &term, const string &web_env, Int8 query_key, int retstart, CNcbiOstream &ostr)
string m_CachedHostName
Uint8 Search(const string &db, const string &term, vector< objects::CSeq_id_Handle > &uids, const string &xml_path=kEmptyStr)
TParamList m_AdditionalParams
const list< string > GetUrl(void) const
static string x_BuildUrl(const string &host, const string &path, const string &params)
void x_AddAdditionalParameters(string &params)
void x_Fetch(const string &db, const vector< T > &uids, CNcbiOstream &ostr, const string &retmode="xml")
void x_Summary(const string &db, const vector< T > &uids, xml::document &docsums, const string &version="")
void AddParameter(const string &name, const string &value)
void Summary(const string &db, const vector< objects::CSeq_id_Handle > &uids, xml::document &docsums, const string &version="")
void SetLinkName(const string &link_name)
void ClearAddedParameters()
void x_Link(const string &db_from, const string &db_to, const vector< T1 > &uids_from, vector< T2 > &uids_to, const string &xml_path, const string &command)
Uint8 x_Search(const string &db, const string &term, vector< T > &uids, const string &xml_path=kEmptyStr)
void SetMessageHandlerDiagPost(void)
Equivalent to: ERR_POST(Warning|Error << ...).
void x_Get(string const &path, string const &params, CNcbiOstream &ostr)
Uint8 x_ParseSearchResults(const string &xml_file, vector< T > &uids)
void SetMessageHandlerThrowOnError(void)
Equivalent to: NCBI_THROW, ERR_POST, LOG_POST as appropriate.
void Link(const string &db_from, const string &db_to, const vector< objects::CSeq_id_Handle > &uids_from, vector< objects::CSeq_id_Handle > &uids_to, const string &xml_path=kEmptyStr, const string &command="neighbor")
const string & x_GetHostName(void) const
void SetMessageHandler(CMessageHandler &message_handler)
Set custom message handler.
void SetMessageHandlerDefault(void)
Default is to log all messages at informational level.
void SetUserTag(const string &tag)
Uint8 ParseSearchResults(CNcbiIstream &istr, vector< objects::CSeq_id_Handle > &uids)
void FetchHistory(const string &db, const string &web_env, Int8 query_key, int retstart, EContentType content_type, CNcbiOstream &ostr)
void LinkHistory(const string &db_from, const string &db_to, const string &web_env, Int8 query_key, CNcbiOstream &ostr)
Uint8 Count(const string &db, const string &term)
list< string > m_Url
void SummaryHistory(const string &db, const string &web_env, Int8 query_key, int retstart, const string &version, CNcbiOstream &ostr)
void x_LinkOut(const string &db, const vector< T > &uids, xml::document &doc, const string &cmd)
virtual void HandleMessage(EDiagSev severity, CEUtilsException::EErrCode err_code, const string &message) const
Pure virtual function, to be implemented by subclass.
virtual void HandleMessage(EDiagSev severity, CEUtilsException::EErrCode err_code, const string &message) const
Pure virtual function, to be implemented by subclass.
bool IsTaxidQuery(const string &message) const
virtual void HandleMessage(EDiagSev severity, CEUtilsException::EErrCode err_code, const string &message) const
Pure virtual function, to be implemented by subclass.
CNcbiDiag –.
Definition: ncbidiag.hpp:924
CStringException –.
Definition: ncbistr.hpp:4505
CTime –.
Definition: ncbitime.hpp:296
bool empty() const
Definition: map.hpp:149
void clear()
Definition: map.hpp:169
The xml::document class is used to hold the XML tree and various bits of information about it.
Definition: document.hpp:80
void swap(document &other)
Swap one xml::document object for another.
Definition: document.cpp:530
The xml::error_messages class is used to store all the error message which are collected while parsin...
Definition: errors.hpp:137
bool has_fatal_errors(void) const
Check if there are fatal errors in the error messages.
Definition: errors.cpp:126
bool has_errors(void) const
Check if there are errors in the error messages.
Definition: errors.cpp:122
std::string print(void) const
Convert error messages into a single printable string.
Definition: errors.cpp:130
The xml::event_parser is used to parse an XML document by calling member functions when certain thing...
std::map< std::string, std::string > attrs_type
a type for holding XML node attributes
bool parse_stream(std::istream &stream, error_messages *messages, warnings_as_errors_type how=type_warnings_not_errors)
Parse what ever data that can be read from the given stream.
bool parse_file(const char *filename, error_messages *messages, warnings_as_errors_type how=type_warnings_not_errors)
Call this member function to parse the given file.
The xml::parser_exception class is used to store parsing and validating exception information.
Definition: errors.hpp:214
virtual const char * what() const noexcept
Convert error messages into a printable C-style string.
Definition: errors.cpp:160
char value[7]
Definition: config.c:431
The NCBI C++ standard methods for dealing with std::string.
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
#define T(s)
Definition: common.h:230
void s_FormatIds< string >(ostream &osm, const vector< string > &uids)
static const char * s_GetErrCodeString(CEUtilsException::TErrCode err_code)
string s_ParseId< string >(const string &str)
void s_FormatIds< CSeq_id_Handle >(ostream &osm, const vector< CSeq_id_Handle > &uids)
static void s_SearchHistoryQuery(ostringstream &oss, const string &db, const string &term, const string &web_env, int retstart, int retmax)
CSeq_id_Handle s_ParseId< CSeq_id_Handle >(const string &str)
static string s_GetContentType(CEutilsClient::EContentType content_type)
static void s_FetchHistoryQuery(ostream &oss, const string &db, const string &web_env, int retstart, int retmax, CEutilsClient::EContentType content_type)
#define HOST_NAME_REFRESH_FREQ
static void s_SummaryHistoryQuery(ostream &oss, const string &db, const string &web_env, int retstart, const string version, int retmax)
static void s_FormatIds(ostream &osm, const vector< T > &uids)
static T s_ParseId(const string &str)
This file contains the definition of the xml::event_parser class.
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
string
Definition: cgiapp.hpp:687
int GetStatusCode(void) const
Get the last seen HTTP status code, if available.
CPipe & GetPipe(void)
Return an underlying CPipe; it's valid for as long as the stream exists.
#define DIAG_COMPILE_INFO
Make compile time diagnostic information object to use in CNcbiDiag and CException.
Definition: ncbidiag.hpp:170
const CNcbiDiag & GetRef(void) const
Some compilers (e.g.
Definition: ncbidiag.hpp:946
static const char * SeverityName(EDiagSev sev)
Get a common symbolic name for the severity levels.
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
EDiagSev
Severity level for the posted diagnostics.
Definition: ncbidiag.hpp:650
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
@ eDiag_Error
Error message.
Definition: ncbidiag.hpp:653
@ eDiag_Warning
Warning message.
Definition: ncbidiag.hpp:652
@ eDiag_Fatal
Fatal error – guarantees exit(or abort)
Definition: ncbidiag.hpp:655
@ eDiag_Critical
Critical error message.
Definition: ncbidiag.hpp:654
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Trace(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1179
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
int TErrCode
Definition: ncbiexpt.hpp:889
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
@ eUnknown
Definition: app_popup.hpp:72
static CSeq_id_Handle GetHandle(const CSeq_id &id)
Normal way of getting a handle, works for any seq-id.
EIO_Status CloseHandle(EChildIOHandle handle)
Close the specified child's pipe handle (even for CPipe opened with OpenSelf()).
Definition: ncbi_pipe.cpp:1941
@ fStdIn
Definition: ncbi_pipe.hpp:115
@ fStdErr_Share
Keep stderr (share it with child)
Definition: ncbi_pipe.hpp:91
#define NCBI_FALLTHROUGH
#define kMax_Int
Definition: ncbi_limits.h:184
int64_t Int8
8-byte (64-bit) signed integer
Definition: ncbitype.h:104
uint64_t Uint8
8-byte (64-bit) unsigned integer
Definition: ncbitype.h:105
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define SERV_ANYHOST
Definition: ncbi_service.h:55
SSERV_Info * SERV_GetInfo(const char *service, TSERV_Type types, unsigned int preferred_host, const SConnNetInfo *net_info)
Same as "SERV_GetInfoEx(., ., ., ., 0, 0, 0)" – i.e.
Definition: ncbi_service.c:872
@ fSERV_Dns
static string ntoa(unsigned int host)
BSD-like API. NB: when int, "host" must be in network byte order.
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
bool NcbiStreamCopy(CNcbiOstream &os, CNcbiIstream &is)
Copy the entire contents of stream "is" to stream "os".
Definition: ncbistre.cpp:211
size_t NcbiStreamToString(string *s, CNcbiIstream &is, size_t pos=0)
Input the entire contents of an istream into a string (NULL causes drain).
Definition: ncbistre.cpp:296
#define kEmptyStr
Definition: ncbistr.hpp:123
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5429
static string Join(const TContainer &arr, const CTempString &delim)
Join strings using the specified delimiter.
Definition: ncbistr.hpp:2697
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5411
static Uint8 StringToUInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Uint8.
Definition: ncbistr.cpp:873
static unsigned int StringToUInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to unsigned int.
Definition: ncbistr.cpp:642
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string URLEncode(const CTempString str, EUrlEncode flag=eUrlEnc_SkipMarkChars)
URL-encode string.
Definition: ncbistr.cpp:6058
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
#define REG_CONN_HOST
const char * ConnNetInfo_GetValue(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
SConnNetInfo * ConnNetInfo_Create(const char *service)
void ConnNetInfo_Destroy(SConnNetInfo *net_info)
E_Choice
Choice variants.
Definition: Seq_id_.hpp:93
@ e_Gi
GenInfo Integrated Database.
Definition: Seq_id_.hpp:106
@ e_not_set
No variant selected.
Definition: Seq_id_.hpp:94
char * buf
int i
static MDB_envinfo info
Definition: mdb_load.c:37
static int version
Definition: mdb_load.c:29
string Execute(const string &cmmd, const vector< string > &args, const string &data=kEmptyStr)
const char * tag
void SleepSec(unsigned long sec, EInterruptOnSignal onsignal=eRestartOnSignal)
Sleep.
const char * command
static const char * suffix[]
Definition: pcregrep.c:408
static const char * str(char *buf, int n)
Definition: stats.c:84
Timeout structure.
Definition: ncbi_types.h:76
Definition: type.c:6
#define _ASSERT
else result
Definition: token2.c:20
void free(voidpf ptr)
Modified on Sat Dec 09 04:44:30 2023 by modify_doxy.py rev. 669887