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

Go to the SVN repository for this file.

1 /* $Id: smart_save_to_client.cpp 46196 2021-02-02 11:17:48Z choi $
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: Yoon Choi
27  *
28  */
29 
30 
31 #include <ncbi_pch.hpp>
33 
35 #include <objects/general/Date.hpp>
39 #include <objmgr/seq_entry_ci.hpp>
40 #include <objmgr/seqdesc_ci.hpp>
41 #include <objmgr/bioseq_ci.hpp>
42 
47 #include <corelib/ncbi_system.hpp>
48 
49 
52 
53 
54 const size_t cPipeSize = 10*1024;
55 const size_t cDefaultTimeout_Seconds = 5;
56 
57 
59 {
60  const CBioseq_Handle::TId& bioseq_ids = bh.GetId();
61  for (auto const& id : bioseq_ids) {
62  if (id.Which() == CSeq_id::e_General) {
63  CConstRef<CSeq_id> seq_id = id.GetSeqIdOrNull();
64  if (seq_id) {
65  const CDbtag& dbtag = seq_id->GetGeneral();
66  if (dbtag.IsSetDb() && dbtag.GetDb() == "TMSMART") {
67  return true;
68  }
69  }
70  }
71  }
72  return false;
73 }
74 
75 
77 {
78  if (!eh || !eh.IsSet())
79  return;
80 
81  CBioseq_set_Handle bioseq_set_h = eh.GetSet();
82  if (!bioseq_set_h.IsSetClass() || bioseq_set_h.GetClass() != CBioseq_set::eClass_genbank ||
83  !bioseq_set_h.GetCompleteBioseq_set()->IsSetSeq_set() || bioseq_set_h.GetCompleteBioseq_set()->GetSeq_set().empty())
84  return;
85 
86  vector<CRef<CSeqdesc> > descs;
87  vector<const CSeqdesc*> to_remove;
88  CSeqdesc_CI desc_ci( eh, CSeqdesc::e_not_set, 1);
89  for( ; desc_ci; ++desc_ci )
90  {
92  continue;
93 
94  descs.push_back(CRef<CSeqdesc>( SerialClone(*desc_ci) ) );
95  to_remove.push_back(&*desc_ci);
96  }
97  for (const auto desc : to_remove)
98  {
99  eh.RemoveSeqdesc(*desc);
100  }
101 
102  // copy to all immediate children
103  CSeq_entry_CI direct_child_ci( bioseq_set_h, CSeq_entry_CI::eNonRecursive );
104  for( ; direct_child_ci; ++direct_child_ci )
105  {
106  CSeq_entry_EditHandle eseh = direct_child_ci->GetEditHandle();
107  for (size_t i = 0; i < descs.size(); i++)
108  {
109  CRef<CSeqdesc> new_desc(new CSeqdesc);
110  new_desc->Assign(*descs[i]);
111  bool found(false);
113  {
114  if ((*desc_it)->Equals(*new_desc))
115  {
116  found = true;
117  break;
118  }
119  }
120  if (!found)
121  eseh.AddSeqdesc(*new_desc);
122  }
123  }
124 }
125 
126 
127 // per SMUPD-86, do not update update-date for external records
129 {
130  if (id.IsEmbl() || id.IsPir() || id.IsSwissprot() ||
131  id.IsDdbj() || id.IsPrf() || id.IsPdb() ||
132  id.IsTpe() || id.IsTpd()) {
133  return true;
134  } else {
135  return false;
136  }
137 }
138 
139 
141 {
142  for (auto id : bsh.GetId()) {
143  if(s_IsExternalRecord(*(id.GetSeqId()))) {
144  return true;
145  }
146  }
147  return false;
148 }
149 
150 
152 {
153  CBioseq_CI bi(seh);
154  while (bi) {
155  if (s_IsExternalRecord(*bi)) {
156  return true;
157  }
158  ++bi;
159  }
160  return false;
161 }
162 
163 
165 {
166  if (!eh || !eh.IsSet())
167  return;
168 
169  CBioseq_set_Handle bioseq_set_h = eh.GetSet();
170 
171  CRef<CSeqdesc> update_date_desc(new CSeqdesc);
173 
174  // set it to all immediate children
175  CSeq_entry_CI child_ci(bioseq_set_h, CSeq_entry_CI::eNonRecursive);
176  for (; child_ci; ++child_ci) {
177  CSeq_entry_EditHandle eseh = child_ci->GetEditHandle();
178 
179  // remove old update time desc
180  vector<const CSeqdesc*> to_remove;
182  if ((*desc_it)->Which() == CSeqdesc::e_Update_date) {
183  to_remove.push_back(*desc_it);
184  }
185  }
186  for (const auto desc : to_remove) {
187  eseh.RemoveSeqdesc(*desc);
188  }
189 
190  // add new update time desc
191  CRef<CSeqdesc> new_desc(new CSeqdesc);
192  new_desc->Assign(*update_date_desc);
193  eseh.AddSeqdesc(*new_desc);
194  }
195 }
196 
197 static void s_DoSmartProcessing(const CSeq_entry* entry, CScope& scope)
198 {
199  CSeq_entry_Handle seh = scope.GetSeq_entryEditHandle(*entry);
200 
201  try {
202  // Perform BasicCleanup
204  CConstRef<CCleanupChange> changes = cleanup.BasicCleanup(const_cast<CSeq_entry& >(*(seh.GetCompleteSeq_entry())));
205 
206  CSeq_entry_EditHandle eh(seh);
207  // For smupd, wrap single sequence in genbank set
208  if (seh.IsSeq() && !s_FindSmartSeqId(seh.GetSeq())) {
210  }
211 
213  if (!s_IsExternalRecord(seh)) {
215  }
216  }
217  catch (CException& e) {
218  LOG_POST(Error << "error in cleanup: " << e.GetMsg());
219  }
220 }
221 
222 static EIO_Status s_ConnectToNamedPipe(CNamedPipeClient& cli, const string& pipe_name)
223 {
224  STimeout timeout = { cDefaultTimeout_Seconds, 0 };
225  CDeadline deadline(g_STimeoutToCTimeout(&timeout));
226 
227  EIO_Status status;
228  for (;;) {
229  // Wait for server
230  status = cli.Open(pipe_name, &timeout, cPipeSize);
231  if (status == eIO_Success) {
232  break;
233  }
234  if(deadline.IsExpired() || status != eIO_Closed) {
235  NCBI_THROW(CException, eUnknown, "SaveToSmartClient: cannot connect to pipe server");
236  }
237  SleepMilliSec(500);
238  }
239  return status;
240 }
241 
242 static size_t s_WriteBuffer(CNamedPipeClient& cli, const char* buf, size_t datasize)
243 {
244  // write out the chunk incrementally until the entire chunk is written
245  size_t x_written = 0;
246  size_t n_written_chunk = 0;
247  EIO_Status status;
248  do {
249  status = cli.Write(buf + n_written_chunk, datasize - n_written_chunk, &x_written);
250  n_written_chunk += x_written;
251  } while (status == eIO_Success && n_written_chunk < datasize);
252 
253  return n_written_chunk;
254 }
255 
256 
258 
260  // destroy the previous client pipe if any before creating a new one
261  if (client) delete client;
262  client = new CNamedPipeClient;
263  return *client;
264 }
265 
266 
267 static void s_WriteToNamedPipe(const string& pipe_name, const string& msg)
268 {
269  size_t chunks = msg.size() / cPipeSize;
270  const char* buf = nullptr;
271 
272  size_t total_written = 0;
273 
275 
276  if (s_ConnectToNamedPipe(cli, pipe_name) != eIO_Success) {
277  throw runtime_error("Failed to connect to named pipe");
278  }
279 
280  // if msg size exceeds buffer size, do the write in chunks
281  for (size_t i = 0; i < chunks; ++i) {
282  buf = msg.data() + (i * cPipeSize);
283  total_written += s_WriteBuffer(cli, buf, cPipeSize);
284  }
285 
286  // write either the initial data (if msg size was smaller than buffer size)
287  // or the residual chunk leftover from above chunked writes
288  if (total_written < msg.size()) {
289  buf = msg.data() + total_written;
290  total_written += s_WriteBuffer(cli, buf, msg.size() - total_written);
291  }
292 
293  if (total_written != msg.size()) {
294  throw runtime_error("Failed to write to named pipe");
295  }
296 }
297 
298 static void s_SaveToSmartClient(CScope* scope, const CProjectItem& projitem)
299 {
300  if (!scope) NCBI_THROW(CException, eUnknown, "SaveToSmartClient: scope is NULL");
301 
302  const CSerialObject* so = projitem.GetObject();
303 
304  string pipe;
305  CProjectItemExtra::GetStr(projitem, "SmartPipe", pipe);
306  if (pipe.empty())
307  NCBI_THROW(CException, eUnknown, "SaveToSmartClient: Empty pipe name");
308 
309  // Perform post-processing before sending data back to smart.
310  const CSeq_submit* submit = dynamic_cast<const CSeq_submit *>(so);
311  if (submit && submit->IsSetData() && submit->IsEntrys()) {
313  s_DoSmartProcessing(*it, *scope);
314  }
315  }
316  const CSeq_entry* entry = dynamic_cast<const CSeq_entry *>(so);
317  if (entry) {
318  s_DoSmartProcessing(entry, *scope);
319  }
320 
321  vector<string> tokens;
322  NStr::Split(pipe, ":", tokens, NStr::fSplit_Tokenize);
323  if (tokens.size() != 2)
324  NCBI_THROW(CException, eUnknown, "SaveToSmartClient: Invalid pipe name: " + pipe);
325  string pipe_name = tokens[0], objId = tokens[1];
326 
327  CNcbiOstrstream ostr;
328  ostr << "smart:update:" << objId << '\0';
329  ostr << MSerial_AsnText << *so;
330  string msg = CNcbiOstrstreamToString(ostr);
331 
332  s_WriteToNamedPipe(pipe_name, msg);
333 }
334 
335 
336 static void s_CancelEditingSession(const CProjectItem& projitem)
337 {
338  string pipe;
339  CProjectItemExtra::GetStr(projitem, "SmartPipe", pipe);
340  if (pipe.empty())
341  NCBI_THROW(CException, eUnknown, "SaveToSmartClient: Empty pipe name");
342 
343  vector<string> tokens;
344  NStr::Split(pipe, ":", tokens, NStr::fSplit_Tokenize);
345  if (tokens.size() != 2)
346  NCBI_THROW(CException, eUnknown, "SaveToSmartClient: Invalid pipe name: " + pipe);
347  string pipe_name = tokens[0], objId = tokens[1];
348 
349  CNcbiOstrstream ostr;
350  ostr << "smart:cancel:" << objId << '\0';
351  ostr << MSerial_AsnText;
352  string msg = CNcbiOstrstreamToString(ostr);
353 
354  s_WriteToNamedPipe(pipe_name, msg);
355 }
356 
357 
358 void CSmartClient::SendResult(objects::CScope* scope,
359  const objects::CProjectItem& projitem,
360  EResultType result_type) {
361  switch (result_type) {
362  case eUpdate:
363  s_SaveToSmartClient(scope, projitem);
364  break;
365  case eCancel:
366  s_CancelEditingSession(projitem);
367  break;
368  default:
369  throw runtime_error("Unknown result type.");
370  }
371 }
372 
373 
375 
User-defined methods of the data storage class.
User-defined methods of the data storage class.
CBioseq_CI –.
Definition: bioseq_ci.hpp:69
CBioseq_Handle –.
CBioseq_set_Handle –.
void SetToTime(const CTime &time, EPrecision prec=ePrecision_second)
Definition: Date.cpp:57
@ ePrecision_day
Definition: Date.hpp:58
Definition: Dbtag.hpp:53
CDeadline.
Definition: ncbitime.hpp:1830
CNamedPipeClient –.
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
static bool GetStr(const objects::CProjectItem &pi, const string &tag, string &value)
const CSerialObject * GetObject() const
retrieve the object pointed to as a CObject*
static bool ShouldStayInPlace(const objects::CSeqdesc &desc)
CScope –.
Definition: scope.hpp:92
CSeq_entry_CI –.
CSeq_entry_Handle –.
CSeq_entry_Handle –.
Definition: Seq_entry.hpp:56
bool IsEntrys(void) const
Definition: Seq_submit.cpp:54
CSeqdesc_CI –.
Definition: seqdesc_ci.hpp:65
Base class for all serializable objects.
Definition: serialbase.hpp:150
static void SendResult(objects::CScope *scope, const objects::CProjectItem &projitem, EResultType result_type)
CTime –.
Definition: ncbitime.hpp:296
static void cleanup(void)
Definition: ct_dynamic.c:30
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#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
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
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
@ eUnknown
Definition: app_popup.hpp:72
virtual void Assign(const CSerialObject &source, ESerialRecursionMode how=eRecursive)
Set object to copy of another one.
C * SerialClone(const C &src)
Create on heap a clone of the source object.
Definition: serialbase.hpp:512
#define MSerial_AsnText
I/O stream manipulators –.
Definition: serialbase.hpp:696
CSeq_entry_EditHandle GetSeq_entryEditHandle(const CSeq_entry &entry)
Definition: scope.cpp:207
vector< CSeq_id_Handle > TId
TClass GetClass(void) const
CRef< CSeqdesc > RemoveSeqdesc(const CSeqdesc &v) const
TSet GetSet(void) const
TSet ConvertSeqToSet(TClass set_class=CBioseq_set::eClass_not_set) const
Convert the entry from Bioseq to Bioseq-set.
CConstRef< CBioseq_set > GetCompleteBioseq_set(void) const
Return the complete bioseq-set object.
TSeq GetSeq(void) const
CSeq_entry_EditHandle GetEditHandle(void) const
Get 'edit' version of handle.
bool IsSetClass(void) const
CConstRef< CSeq_entry > GetCompleteSeq_entry(void) const
Complete and get const reference to the seq-entry.
bool IsSet(void) const
bool AddSeqdesc(CSeqdesc &v) const
const TId & GetId(void) const
bool IsSeq(void) const
@ eNonRecursive
Deprecated.
EIO_Status Open(const string &pipename, const STimeout *timeout=kDefaultTimeout, size_t pipesize=0, TFlags flags=0)
Open a client-side pipe connection.
EIO_Status Write(const void *buf, size_t count, size_t *n_written=0)
Write data to the pipe.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
@ fSplit_Tokenize
All delimiters are merged and trimmed, to get non-empty tokens only.
Definition: ncbistr.hpp:2508
bool IsExpired(void) const
Check if the deadline is expired.
Definition: ncbitime.hpp:1856
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
EIO_Status
I/O status.
Definition: ncbi_core.h:132
CTimeout g_STimeoutToCTimeout(const STimeout *sto)
Convert STimeout to CTimeout.
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
bool IsSetDb(void) const
name of database or system Check if a value has been assigned to Db data member.
Definition: Dbtag_.hpp:208
const TDb & GetDb(void) const
Get the Db member data.
Definition: Dbtag_.hpp:220
const TGeneral & GetGeneral(void) const
Get the variant data.
Definition: Seq_id_.cpp:369
@ e_General
for other databases
Definition: Seq_id_.hpp:105
bool IsSetSeq_set(void) const
Check if a value has been assigned to Seq_set data member.
const TSeq_set & GetSeq_set(void) const
Get the Seq_set member data.
@ eClass_genbank
converted genbank
TUpdate_date & SetUpdate_date(void)
Select the variant.
Definition: Seqdesc_.cpp:500
@ e_Update_date
date of last update
Definition: Seqdesc_.hpp:129
@ e_not_set
No variant selected.
Definition: Seqdesc_.hpp:110
bool IsSetData(void) const
Check if a value has been assigned to Data data member.
list< CRef< CSeq_entry > > TEntrys
const TEntrys & GetEntrys(void) const
Get the variant data.
const TData & GetData(void) const
Get the Data member data.
char * buf
int i
Portable interprocess named pipe API for: UNIX, MS-Win.
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
static bool GetSeqId(const T &d, set< string > &labels, const string name="", bool detect=false, bool found=false)
Utility macros and typedefs for exploring NCBI objects from seqset.asn.
#define FOR_EACH_SEQDESC_ON_SEQENTRY(Itr, Var)
FOR_EACH_SEQDESC_ON_SEQENTRY EDIT_EACH_SEQDESC_ON_SEQENTRY.
static EIO_Status s_ConnectToNamedPipe(CNamedPipeClient &cli, const string &pipe_name)
USING_SCOPE(objects)
bool s_IsExternalRecord(const CSeq_id &id)
static CNamedPipeClient & CreateClientPipe()
static void s_DescriptorPropagateDown(CSeq_entry_EditHandle eh)
static void s_WriteToNamedPipe(const string &pipe_name, const string &msg)
static void s_DoSmartProcessing(const CSeq_entry *entry, CScope &scope)
static void s_SaveToSmartClient(CScope *scope, const CProjectItem &projitem)
const size_t cPipeSize
static void s_ActualizeUpdateDate(CSeq_entry_EditHandle eh)
static size_t s_WriteBuffer(CNamedPipeClient &cli, const char *buf, size_t datasize)
static void s_CancelEditingSession(const CProjectItem &projitem)
static CNamedPipeClient * client
const size_t cDefaultTimeout_Seconds
static bool s_FindSmartSeqId(CBioseq_Handle bh)
Timeout structure.
Definition: ncbi_types.h:76
Modified on Wed Apr 17 13:09:48 2024 by modify_doxy.py rev. 669887