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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: web_algo.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 20:56:13  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: web_algo.cpp,v 1000.2 2004/06/01 20:56:13 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:  Josh Cherry
  35.  *
  36.  * File Description:  Plugin to call remote procedure via cgi
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. // http stuff
  42. #include <connect/ncbi_conn_stream.hpp>
  43. #include <connect/ncbi_core_cxx.hpp>
  44. #include <connect/ncbi_util.h>
  45. #include "../basic/output_dlg.hpp"
  46. #include <gui/core/idocument.hpp>
  47. #include <gui/core/plugin_utils.hpp>
  48. #include <gui/plugin/PluginRequest.hpp>
  49. #include <gui/plugin/PluginInfo.hpp>
  50. #include <gui/plugin/PluginCommandSet.hpp>
  51. #include <gui/plugin/PluginValueConstraint.hpp>
  52. #include <gui/core/version.hpp>
  53. #include <gui/objutils/utils.hpp>
  54. #include <gui/utils/browser_utils.hpp>
  55. #include "web_algo.hpp"
  56. #include "plugin_args_as_strs.hpp"
  57. #include <objmgr/util/sequence.hpp>
  58. #include <objmgr/scope.hpp>
  59. #include <objmgr/seq_vector.hpp>
  60. #include <objmgr/util/sequence.hpp>
  61. #include <objtools/readers/readfeat.hpp>
  62. #include <objects/seqloc/Seq_loc.hpp>
  63. #include <objects/general/Object_id.hpp>
  64. #include <connect/ncbi_pipe.hpp>
  65. #include <serial/serial.hpp>
  66. #include <serial/objostr.hpp>
  67. #include <serial/objistr.hpp>
  68. #include <cgi/ncbicgi.hpp>
  69. #include <util/regexp.hpp>
  70. BEGIN_NCBI_SCOPE
  71. USING_SCOPE(objects);
  72. void CAlgoWebService::GetInfo(CPluginInfo& info)
  73. {
  74.     info.Reset();
  75.     // version info macro
  76.     info.SetInfo(CPluginVersion::eMajor, CPluginVersion::eMinor, 0,
  77.                  string(__DATE__) + " " + string(__TIME__),
  78.                  "CAlgoWebService", "", "", "");
  79.     // command info
  80.     CPluginCommandSet& cmds = info.SetCommands();
  81.     CPluginCommand&    args = cmds.AddAlgoCommand(eAlgoCommand_run);
  82.     args.AddArgument("locs", "Sequences to evaluate",
  83.                      CSeq_loc::GetTypeInfo(),
  84.                      CPluginArg::TData::e_Array);
  85.     args.SetConstraint("locs",
  86.                        *CPluginValueConstraint::CreateSeqSameMol());
  87.     args.AddArgument("__url", "url",
  88.                      CPluginArg::eString);
  89. }
  90. void CAlgoWebService::RunCommand(CPluginMessage& msg)
  91. {
  92.     const CPluginCommand& args = msg.GetRequest().GetCommand();
  93.     CPluginReply& reply = msg.SetReply();
  94.     _TRACE("CAlgoWebService::Run()");
  95.     if ( !m_OutputDlg.get() ) {
  96.         m_OutputDlg.reset(new COutputDlg());
  97.     }
  98.     m_OutputDlg->SetTitle("Results of calling web algorithm");
  99.     const CPluginArgSet::Tdata& argset = args.GetArgs().Get();
  100.     vector<string> keys, values;
  101.     try {
  102.         PluginArgsAsStrs(argset, keys, values);
  103.     }
  104.     catch (exception& e) {
  105.         LOG_POST(Info << "CAlgoWebService: couldn't convert to string rep: "
  106.                  << e.what());
  107.         reply.SetStatus(eMessageStatus_failed);
  108.         return;
  109.     }
  110.     catch (...) {
  111.         LOG_POST(Info << "CAlgoWebService: couldn't convert to string rep");
  112.         reply.SetStatus(eMessageStatus_failed);
  113.         return;
  114.     }
  115.     keys.push_back("action");
  116.     values.push_back("run");
  117.     string query;
  118.     for (unsigned int i = 0;  i < keys.size();  i++) {
  119.         if (i > 0) {
  120.             query += '&';
  121.         }
  122.         query += URL_EncodeString(keys[i]) + "=" + URL_EncodeString(values[i]);
  123.     }
  124.     
  125.     string body;
  126.     string headers;
  127.     string base;
  128.     if (args.HasArgument("__url")  &&
  129.         CPluginUtils::IsValid(args["__url"])) {
  130.         x_DoPost(args["__url"].AsString(), query,
  131.                  body, headers);
  132.         base = args["__url"].AsString();
  133.     } else {
  134.         throw runtime_error("CAlgoWebService::run:  no url");
  135.     }
  136.     // see if we have a Content-type; if so, act appropriately
  137.     string content_type = x_GetContentType(headers);
  138.     if (content_type == "chemical/ncbi-asn1-ascii" ||
  139.         content_type == "chemical/ncbi-asn1-binary" ||
  140.         content_type == "chemical/ncbi-xml" ||
  141.         content_type == "chemical/ncbi-five-col") {
  142.         // in these cases we'll try to make an annot
  143.         CRef<CSeq_annot> annot;
  144.         CNcbiIstrstream is(body.c_str(), body.size());
  145.         if (content_type == "chemical/ncbi-asn1-ascii" ||
  146.         content_type == "chemical/ncbi-asn1-binary" ||
  147.         content_type == "chemical/ncbi-xml") {
  148.             ESerialDataFormat serial_format;
  149.             if (content_type == "chemical/ncbi-asn1-ascii") {
  150.                 serial_format = eSerial_AsnText;
  151.             } else if (content_type == "chemical/ncbi-asn1-binary") {
  152.                 serial_format = eSerial_AsnBinary;
  153.             } else if (content_type == "chemical/ncbi-xml") {
  154.                 serial_format = eSerial_Xml;
  155.             }
  156.             auto_ptr<CObjectIStream>
  157.                 istr(CObjectIStream::Open(serial_format, is));
  158.             annot.Reset(new CSeq_annot);
  159.             *istr >> *annot;
  160.         } else if (content_type == "chemical/ncbi-five-col") {
  161.             annot = CFeature_table_reader::ReadSequinFeatureTable(is);
  162.         }
  163.         try {
  164.             x_DealWithAnnot(annot, args, reply);
  165.         }
  166.         catch (exception& e) {
  167.             LOG_POST(Error << e.what());
  168.             reply.SetStatus(eMessageStatus_failed);
  169.             return;
  170.         }
  171.         reply.AddAction(CPluginReplyAction::e_Add_to_document);
  172.     } else if (content_type == "text/html") {
  173.         if (!base.empty()) {
  174.             CBrowserUtils::AddBaseTag(body, base);
  175.         }
  176.         CBrowserUtils::SendToBrowser(body);
  177.     } else if (content_type == "text/plain" ||
  178.                content_type.empty()) {
  179.         string str;
  180.         str += "Output:nn";
  181.         str += body + "nn";
  182.         m_OutputDlg->SetText(str);
  183.         m_OutputDlg->Show();
  184.     } else {
  185.         CBrowserUtils::SendToBrowser(body, content_type);
  186.     }
  187.     reply.SetStatus(eMessageStatus_success);
  188. }
  189. void CAlgoWebService::x_DealWithAnnot(CRef<CSeq_annot> annot,
  190.                                const CPluginCommand& args,
  191.                                CPluginReply& reply)
  192. {
  193.     // figure out which argument this annot belongs to
  194.     CSeq_annot::TData::TFtable& ftable = annot->SetData().SetFtable();
  195.     const CSeq_id& orig_id = sequence::GetId(ftable.front()->GetLocation());
  196.     const string& orig_id_str = orig_id.GetLocal().GetStr();
  197.     const CSeq_loc *loc;
  198.     const IDocument *doc;
  199.     // if it has the form name[integer], interpret it as array member
  200.     CRegexp re("(.*)\[ *([0-9]+) *\]");
  201.     if (!re.GetMatch(orig_id_str.c_str(), 0).empty()) {
  202.         const int *name_range = re.GetResults(1);
  203.         string name = orig_id_str.substr(name_range[0], name_range[1]);
  204.         const int *index_range = re.GetResults(2);
  205.         unsigned int index = 
  206.             NStr::StringToInt(orig_id_str
  207.                               .substr(index_range[0],
  208.                                       index_range[1] - index_range[0]));
  209.         plugin_args::TLocList loc_list;
  210.         GetArgValue(args[name], loc_list);
  211.         if (index > loc_list.size() - 1) {
  212.             throw runtime_error(orig_id_str + " does not exist; "
  213.                                 + name + " has only " + 
  214.                                 NStr::IntToString(loc_list.size())
  215.                                 + " elements");
  216.         }
  217.         plugin_args::TLocList::iterator iter = loc_list.begin();
  218.         advance(iter, index);
  219.         loc = iter->second;
  220.         doc = iter->first;
  221.     } else {
  222.         const CPluginArg& arg = args[orig_id_str];
  223.         loc = dynamic_cast<const CSeq_loc*> (&arg.AsObject());
  224.         doc = arg.GetDocument();
  225.     }
  226.     // now set the ids and remap
  227.     NON_CONST_ITERATE (list<CRef<CSeq_feat> >, feat, ftable) {
  228.         CSeq_loc& feat_loc = (*feat)->SetLocation();
  229.         feat_loc.SetId(sequence::GetId(*loc));
  230.         (*feat)->SetLocation(*CSeqUtils::RemapChildToParent(*loc, feat_loc));
  231.     }
  232.     
  233.     reply.AddObject(*doc, *annot);
  234.     m_OutputDlg->SetText("Annotations added to " + doc->GetShortTitle());
  235.     m_OutputDlg->Show();
  236. }
  237. string CAlgoWebService::x_GetContentType(const string& headers)
  238. {
  239.     list<string> lines;
  240.     string content_type;
  241.     NStr::Split(headers, "n", lines);
  242.     ITERATE (list<string>, line, lines) {
  243.         if (NStr::StartsWith(*line, "content-type:", NStr::eNocase)) {
  244.             content_type = line->substr(string("content-type:").size());
  245.             content_type = NStr::TruncateSpaces(content_type);
  246.             NStr::ToLower(content_type);
  247.             break;
  248.         }
  249.     }
  250.     return content_type;
  251. }
  252. void CAlgoWebService::x_DoPost(const string& url, const string& query,
  253.                            string& body, string& headers)
  254. {
  255.     body.erase();
  256.     headers.erase();
  257.     SConnNetInfo* net_info = ConnNetInfo_Create(0);
  258.     if (!net_info) {
  259.         throw runtime_error("ConnNetInfo_Create(0) returned null");
  260.     }
  261.     ConnNetInfo_ParseURL(net_info, url.c_str());
  262.     net_info->req_method = eReqMethod_Post;
  263.     // pretend to be a 'real' web browser; some servers
  264.     // care about this
  265.     string user_header =
  266.         "User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; "
  267.         "Windows NT 5.0; (R1 1.1))";
  268.     user_header = "Content-type: application/x-www-form-urlencodedn";
  269.     CConn_HttpStream http(net_info, user_header,
  270.                           fHCC_AutoReconnect | fHCC_KeepHeader);
  271.     ConnNetInfo_Destroy(net_info);
  272.     // write the query string to server
  273.     http << query;
  274.     // now read
  275.     char buf[1024];
  276.     string line;
  277.     while (getline(http, line)) {
  278.         if (line.find_first_not_of(" tnrfv") == string::npos) {
  279.             break;
  280.         }
  281.         headers += line + 'n';
  282.     }
  283.     while (!http.fail()) {
  284.         http.read(buf, 1024);
  285.         body.append(buf, http.gcount());
  286.     }
  287. }
  288. END_NCBI_SCOPE
  289. /*
  290.  * ===========================================================================
  291.  * $Log: web_algo.cpp,v $
  292.  * Revision 1000.2  2004/06/01 20:56:13  gouriano
  293.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
  294.  *
  295.  * Revision 1.7  2004/05/21 22:27:47  gorelenk
  296.  * Added PCH ncbi_pch.hpp
  297.  *
  298.  * Revision 1.6  2004/05/03 13:05:42  dicuccio
  299.  * gui/utils --> gui/objutils where needed
  300.  *
  301.  * Revision 1.5  2004/01/27 18:45:25  dicuccio
  302.  * Added missing header files
  303.  *
  304.  * Revision 1.4  2003/12/19 18:38:18  jcherry
  305.  * Alert the user when annotations are added
  306.  *
  307.  * Revision 1.3  2003/12/01 23:22:00  jcherry
  308.  * Added registry file format for plugin info
  309.  *
  310.  * Revision 1.2  2003/11/26 17:13:08  dicuccio
  311.  * Lots of code clean-up.  CHanged names of algorithms to CAlgoWebServices{Init}
  312.  *
  313.  * Revision 1.1  2003/11/25 19:08:50  jcherry
  314.  * Initial version
  315.  *
  316.  * ===========================================================================
  317.  */