bes  Updated for version 3.19.1
StandAloneClient.cc
1 // StandAloneClient.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 //
6 // Copyright (c) 2014 OPeNDAP, Inc.
7 //
8 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
9 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact University Corporation for Atmospheric Research at
26 // 3080 Center Green Drive, Boulder, CO 80301
27 
28 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
29 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
30 //
31 // Authors:
32 //
33 // pwest Patrick West <pwest@ucar.edu>
34 // jgarcia Jose Garcia <jgarcia@ucar.edu>
35 // hyoklee Hyo-Kyung Lee <hyoklee@hdfgroup.org>
36 
37 #include "config.h"
38 
39 #include <cstdlib>
40 #include <iostream>
41 #include <fstream>
42 #include <sstream>
43 
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 
48 using std::cout;
49 using std::endl;
50 using std::cerr;
51 using std::ofstream;
52 using std::ios;
53 using std::flush;
54 using std::ostringstream;
55 
56 #ifdef HAVE_LIBREADLINE
57 # if defined(HAVE_READLINE_READLINE_H)
58 # include <readline/readline.h>
59 # elif defined(HAVE_READLINE_H)
60 # include <readline.h>
61 # else /* !defined(HAVE_READLINE_H) */
62 extern "C" {
63  char *readline(const char *);
64 }
65 # endif /* !defined(HAVE_READLINE_H) */
66 char *cmdline = NULL;
67 #else /* !defined(HAVE_READLINE_READLINE_H) */
68 /* no readline */
69 #endif /* HAVE_LIBREADLINE */
70 
71 #ifdef HAVE_READLINE_HISTORY
72 # if defined(HAVE_READLINE_HISTORY_H)
73 # include <readline/history.h>
74 # elif defined(HAVE_HISTORY_H)
75 # include <history.h>
76 # else /* !defined(HAVE_HISTORY_H) */
77 extern "C" {
78  int add_history(const char *);
79  int write_history(const char *);
80  int read_history(const char *);
81 }
82 # endif /* defined(HAVE_READLINE_HISTORY_H) */
83 /* no history */
84 #endif /* HAVE_READLINE_HISTORY */
85 
86 
87 #define SIZE_COMMUNICATION_BUFFER 4096*4096
88 
89 #include "BESXMLInterface.h"
90 #include "BESStopWatch.h"
91 #include "BESError.h"
92 #include "BESDebug.h"
93 
94 #include "StandAloneClient.h"
95 #include "CmdTranslation.h"
96 
97 StandAloneClient::~StandAloneClient()
98 {
99  if (_strmCreated && _strm) {
100  _strm->flush();
101  delete _strm;
102  _strm = 0;
103  }
104  else if (_strm) {
105  _strm->flush();
106  }
107 }
108 
125 void StandAloneClient::setOutput(ostream * strm, bool created)
126 {
127  if (_strmCreated && _strm) {
128  _strm->flush();
129  delete _strm;
130  }
131  else if (_strm) {
132  _strm->flush();
133  }
134  _strm = strm;
135  _strmCreated = created;
136 }
137 
150 {
151  string suppress = "suppress";
152  if (cmd.compare(0, suppress.length(), suppress) == 0) {
153  setOutput( NULL, false);
154  return;
155  }
156 
157  string output = "output to";
158  if (cmd.compare(0, output.length(), output) == 0) {
159  string subcmd = cmd.substr(output.length() + 1);
160  string screen = "screen";
161  if (subcmd.compare(0, screen.length(), screen) == 0) {
162  setOutput(&cout, false);
163  }
164  else {
165  // subcmd is the name of the file - then semicolon
166  string file = subcmd.substr(0, subcmd.length() - 1);
167  ofstream *fstrm = new ofstream(file.c_str(), ios::app);
168  if (fstrm && !(*fstrm)) {
169  delete fstrm;
170  cerr << "Unable to set client output to file " << file << endl;
171  }
172  else {
173  setOutput(fstrm, true);
174  }
175  }
176  return;
177  }
178 
179  // load commands from an input file and run them
180  string load = "load";
181  if (cmd.compare(0, load.length(), load) == 0) {
182  string file = cmd.substr(load.length() + 1, cmd.length() - load.length() - 2);
183  ifstream fstrm(file.c_str());
184  if (!fstrm) {
185  cerr << "Unable to load commands from file " << file << ": file does not exist or failed to open file"
186  << endl;
187  }
188  else {
189  executeCommands(fstrm, 1);
190  }
191 
192  return;
193  }
194 
195  cerr << "Improper client command " << cmd << endl;
196 }
197 
210 void StandAloneClient::executeCommand(const string & cmd, int repeat)
211 {
212  string client = "client";
213  if (cmd.compare(0, client.length(), client) == 0) {
214  executeClientCommand(cmd.substr(client.length() + 1));
215  }
216  else {
217  if (repeat < 1) repeat = 1;
218  for (int i = 0; i < repeat; i++) {
219  ostringstream *show_stream = 0;
220  if (CmdTranslation::is_show()) {
221  show_stream = new ostringstream;
222  }
223 
224  BESDEBUG( "standalone", "cmd client sending " << cmd << endl );
225 
226  BESStopWatch sw;
227  if (BESISDEBUG(TIMING_LOG)) sw.start("StandAloneClient::executeCommand");
228 
229  BESXMLInterface *interface = 0;
230  if (show_stream) {
231  interface = new BESXMLInterface(cmd, show_stream);
232  }
233  else {
234  interface = new BESXMLInterface(cmd, _strm);
235  }
236 
237  int status = interface->execute_request("standalone");
238 
239  if (status == 0) {
240  BESDEBUG( "standalone", "BESServerHandler::execute - "
241  << "executed successfully" << endl );
242  }
243  else
244  {
245  // an error has occurred.
246  BESDEBUG( "standalone", "BESServerHandler::execute - "
247  "error occurred" << endl );
248 
249  // flush what we have in the stream to the client
250  *_strm << flush;
251 
252  // transmit the error message. finish_with_error will transmit
253  // the error
254  interface->finish_with_error( status );
255 
256  switch (status)
257  {
258  case BES_INTERNAL_FATAL_ERROR:
259  {
260  cerr << "BES server " << getpid()
261  << ": Status not OK, dispatcher returned value "
262  << status << endl;
263  exit( 1 );
264  }
265  break;
266  case BES_INTERNAL_ERROR:
267  case BES_SYNTAX_USER_ERROR:
268  case BES_FORBIDDEN_ERROR:
269  case BES_NOT_FOUND_ERROR:
270 
271  default:
272  break;
273  }
274  }
275  delete interface;
276  interface = 0;
277 
278  if (show_stream) {
279  *(_strm) << show_stream->str() << endl;
280  delete show_stream;
281  show_stream = 0;
282  }
283 
284  _strm->flush();
285  }
286  }
287 }
288 
305 void StandAloneClient::executeCommands(const string &cmd_list, int repeat)
306 {
307  _isInteractive = true;
308  if (repeat < 1) repeat = 1;
309 
310  CmdTranslation::set_show(false);
311  try {
312  string doc = CmdTranslation::translate(cmd_list);
313  if (!doc.empty()) {
314  executeCommand(doc, repeat);
315  }
316  }
317  catch (BESError &e) {
318  CmdTranslation::set_show(false);
319  _isInteractive = false;
320  throw e;
321  }
322  CmdTranslation::set_show(false);
323  _isInteractive = false;
324 }
325 
344 void StandAloneClient::executeCommands(ifstream & istrm, int repeat)
345 {
346  _isInteractive = false;
347  if (repeat < 1) repeat = 1;
348  for (int i = 0; i < repeat; i++) {
349  istrm.clear();
350  istrm.seekg(0, ios::beg);
351  string cmd;
352  string line;
353  while (getline(istrm, line)) {
354  cmd += line;
355  }
356  this->executeCommand(cmd, 1);
357  }
358 }
359 
376 {
377  _isInteractive = true;
378 
379  cout << endl << endl << "Type 'exit' to exit the command line client and 'help' or '?' "
380  << "to display the help screen" << endl << endl;
381 
382  bool done = false;
383  while (!done) {
384  string message = "";
385  size_t len = this->readLine(message);
386  if ( /*len == -1 || */message == "exit" || message == "exit;") {
387  done = true;
388  }
389  else if (message == "help" || message == "help;" || message == "?") {
390  this->displayHelp();
391  }
392  else if (message.length() > 6 && message.substr(0, 6) == "client") {
393  this->executeCommand(message, 1);
394  }
395  else if (len != 0 && message != "") {
396  CmdTranslation::set_show(false);
397  try {
398  string doc = CmdTranslation::translate(message);
399  if (!doc.empty()) {
400  this->executeCommand(doc, 1);
401  }
402  }
403  catch (BESError &e) {
404  CmdTranslation::set_show(false);
405  _isInteractive = false;
406  throw e;
407  }
408  CmdTranslation::set_show(false);
409  }
410  }
411  _isInteractive = false;
412 }
413 
419 size_t StandAloneClient::readLine(string & msg)
420 {
421  size_t len = 0;
422  char *buf = (char *) NULL;
423  buf = ::readline("BESClient> ");
424  if (buf && *buf) {
425  len = strlen(buf);
426 #ifdef HAVE_READLINE_HISTORY
427  add_history(buf);
428 #endif
429  if (len > SIZE_COMMUNICATION_BUFFER) {
430  cerr << __FILE__ << __LINE__ <<
431  ": incoming data buffer exceeds maximum capacity with lenght " << len << endl;
432  exit(1);
433  }
434  else {
435  msg = buf;
436  }
437  }
438  else {
439  if (!buf) {
440  // If a null buffer is returned then this means that EOF is
441  // returned. This is different from the user just hitting enter,
442  // which means a character buffer is returned, but is empty.
443 
444  // Problem: len is unsigned.
445  len = -1;
446  }
447  }
448  if (buf) {
449  free(buf);
450  buf = (char *) NULL;
451  }
452  return len;
453 }
454 
457 void StandAloneClient::displayHelp()
458 {
459  cout << endl;
460  cout << endl;
461  cout << "BES Command Line Client Help" << endl;
462  cout << endl;
463  cout << "Client commands available:" << endl;
464  cout << " exit - exit the command line interface" << endl;
465  cout << " help - display this help screen" << endl;
466  cout << " client suppress; - suppress output from the server" << endl;
467  cout << " client output to screen; - display server output to the screen" << endl;
468  cout << " client output to <file>; - display server output to specified file" << endl;
469  cout << endl;
470  cout << "Any commands beginning with 'client' must end with a semicolon" << endl;
471  cout << endl;
472  cout << "To display the list of commands available from the server " << "please type the command 'show help;'"
473  << endl;
474  cout << endl;
475  cout << endl;
476 }
477 
484 void StandAloneClient::dump(ostream & strm) const
485 {
486  strm << BESIndent::LMarg << "StandAloneClient::dump - (" << (void *) this << ")" << endl;
487  BESIndent::Indent();
488  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
489  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
490  BESIndent::UnIndent();
491 }
void executeCommands(const string &cmd_list, int repeat)
Send the command(s) specified to the BES server after wrapping in request document.
void setOutput(ostream *strm, bool created)
Set the output stream for responses from the BES server.
virtual void dump(ostream &strm) const
dumps information about this object
virtual bool start(string name)
Definition: BESStopWatch.cc:57
Abstract exception class for the BES with basic string message.
Definition: BESError.h:56
void interact()
An interactive BES client that takes BES requests on the command line.
Entry point into BES using xml document requests.
virtual int execute_request(const string &from)
The entry point for command execution; called by BESServerHandler::execute()
void executeClientCommand(const string &cmd)
Executes a client side command.