bes  Updated for version 3.20.8
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 using std::ostream;
56 using std::string;
57 using std::ifstream;
58 
59 #ifdef HAVE_LIBREADLINE
60 # if defined(HAVE_READLINE_READLINE_H)
61 # include <readline/readline.h>
62 # elif defined(HAVE_READLINE_H)
63 # include <readline.h>
64 # else /* !defined(HAVE_READLINE_H) */
65 extern "C" {
66  char *readline(const char *);
67 }
68 # endif /* !defined(HAVE_READLINE_H) */
69 char *cmdline = NULL;
70 #else /* !defined(HAVE_READLINE_READLINE_H) */
71 /* no readline */
72 #endif /* HAVE_LIBREADLINE */
73 
74 #ifdef HAVE_READLINE_HISTORY
75 # if defined(HAVE_READLINE_HISTORY_H)
76 # include <readline/history.h>
77 # elif defined(HAVE_HISTORY_H)
78 # include <history.h>
79 # else /* !defined(HAVE_HISTORY_H) */
80 extern "C" {
81  int add_history(const char *);
82  int write_history(const char *);
83  int read_history(const char *);
84 }
85 # endif /* defined(HAVE_READLINE_HISTORY_H) */
86 /* no history */
87 #endif /* HAVE_READLINE_HISTORY */
88 
89 
90 #define SIZE_COMMUNICATION_BUFFER 4096*4096
91 
92 #include "BESXMLInterface.h"
93 #include "BESStopWatch.h"
94 #include "BESError.h"
95 #include "BESDebug.h"
96 
97 #include "StandAloneClient.h"
98 #include "CmdTranslation.h"
99 
100 StandAloneClient::~StandAloneClient()
101 {
102  if (_strmCreated && _strm) {
103  _strm->flush();
104  delete _strm;
105  _strm = 0;
106  }
107  else if (_strm) {
108  _strm->flush();
109  }
110 }
111 
128 void StandAloneClient::setOutput(ostream * strm, bool created)
129 {
130  if (_strmCreated && _strm) {
131  _strm->flush();
132  delete _strm;
133  }
134  else if (_strm) {
135  _strm->flush();
136  }
137  _strm = strm;
138  _strmCreated = created;
139 }
140 
153 {
154  string suppress = "suppress";
155  if (cmd.compare(0, suppress.length(), suppress) == 0) {
156  setOutput( NULL, false);
157  return;
158  }
159 
160  string output = "output to";
161  if (cmd.compare(0, output.length(), output) == 0) {
162  string subcmd = cmd.substr(output.length() + 1);
163  string screen = "screen";
164  if (subcmd.compare(0, screen.length(), screen) == 0) {
165  setOutput(&cout, false);
166  }
167  else {
168  // subcmd is the name of the file - then semicolon
169  string file = subcmd.substr(0, subcmd.length() - 1);
170  ofstream *fstrm = new ofstream(file.c_str(), ios::app);
171  if (fstrm && !(*fstrm)) {
172  delete fstrm;
173  cerr << "Unable to set client output to file " << file << endl;
174  }
175  else {
176  setOutput(fstrm, true);
177  }
178  }
179  return;
180  }
181 
182  // load commands from an input file and run them
183  string load = "load";
184  if (cmd.compare(0, load.length(), load) == 0) {
185  string file = cmd.substr(load.length() + 1, cmd.length() - load.length() - 2);
186  ifstream fstrm(file.c_str());
187  if (!fstrm) {
188  cerr << "Unable to load commands from file " << file << ": file does not exist or failed to open file"
189  << endl;
190  }
191  else {
192  executeCommands(fstrm, 1);
193  }
194 
195  return;
196  }
197 
198  cerr << "Improper client command " << cmd << endl;
199 }
200 
213 void StandAloneClient::executeCommand(const string & cmd, int repeat)
214 {
215  string client = "client";
216  if (cmd.compare(0, client.length(), client) == 0) {
217  executeClientCommand(cmd.substr(client.length() + 1));
218  }
219  else {
220  if (repeat < 1) repeat = 1;
221  for (int i = 0; i < repeat; i++) {
222  ostringstream *show_stream = 0;
223  if (CmdTranslation::is_show()) {
224  show_stream = new ostringstream;
225  }
226 
227  BESDEBUG( "standalone", "StandAloneClient::executeCommand sending: " << cmd << endl );
228 
229  BESStopWatch sw;
230  if (BESDebug::IsSet(TIMING_LOG_KEY)) sw.start("StandAloneClient::executeCommand");
231 
232  BESXMLInterface *interface = 0;
233  if (show_stream) {
234  interface = new BESXMLInterface(cmd, show_stream);
235  }
236  else {
237  interface = new BESXMLInterface(cmd, _strm);
238  }
239 
240  int status = interface->execute_request("standalone");
241 
242  *_strm << flush;
243 
244  // Put the call to finish() here beacuse we're not sending chunked responses back
245  // to a client over PPT. In the BESServerHandler.cc code, we must do that and hence,
246  // break up the call to finish() for the error and no-error cases.
247  status = interface->finish(status);
248 
249  if (status == 0) {
250  BESDEBUG("standalone", "StandAloneClient::executeCommand - executed successfully" << endl);
251  }
252  else {
253  // an error has occurred.
254  BESDEBUG("standalone", "StandAloneClient::executeCommand - error occurred" << endl);
255  switch (status) {
256  case BES_INTERNAL_FATAL_ERROR: {
257  cerr << "Status not OK, dispatcher returned value " << status << endl;
258  exit(1);
259  }
260  break;
261  case BES_INTERNAL_ERROR:
262  case BES_SYNTAX_USER_ERROR:
263  case BES_FORBIDDEN_ERROR:
264  case BES_NOT_FOUND_ERROR:
265 
266  default:
267  break;
268  }
269  }
270 
271  delete interface;
272  interface = 0;
273 
274  if (show_stream) {
275  *(_strm) << show_stream->str() << endl;
276  delete show_stream;
277  show_stream = 0;
278  }
279 
280  _strm->flush();
281  }
282  }
283 }
284 
301 void StandAloneClient::executeCommands(const string &cmd_list, int repeat)
302 {
303  _isInteractive = true;
304  if (repeat < 1) repeat = 1;
305 
306  CmdTranslation::set_show(false);
307  try {
308  string doc = CmdTranslation::translate(cmd_list);
309  if (!doc.empty()) {
310  executeCommand(doc, repeat);
311  }
312  }
313  catch (BESError &e) {
314  CmdTranslation::set_show(false);
315  _isInteractive = false;
316  throw e;
317  }
318  CmdTranslation::set_show(false);
319  _isInteractive = false;
320 }
321 
340 void StandAloneClient::executeCommands(ifstream & istrm, int repeat)
341 {
342  _isInteractive = false;
343  if (repeat < 1) repeat = 1;
344  for (int i = 0; i < repeat; i++) {
345  istrm.clear();
346  istrm.seekg(0, ios::beg);
347  string cmd;
348  string line;
349  while (getline(istrm, line)) {
350  cmd += line;
351  }
352  this->executeCommand(cmd, 1);
353  }
354 }
355 
372 {
373  _isInteractive = true;
374 
375  cout << endl << endl << "Type 'exit' to exit the command line client and 'help' or '?' "
376  << "to display the help screen" << endl << endl;
377 
378  bool done = false;
379  while (!done) {
380  string message = "";
381  size_t len = this->readLine(message);
382  if ( /*len == -1 || */message == "exit" || message == "exit;") {
383  done = true;
384  }
385  else if (message == "help" || message == "help;" || message == "?") {
386  this->displayHelp();
387  }
388  else if (message.length() > 6 && message.substr(0, 6) == "client") {
389  this->executeCommand(message, 1);
390  }
391  else if (len != 0 && message != "") {
392  CmdTranslation::set_show(false);
393  try {
394  string doc = CmdTranslation::translate(message);
395  if (!doc.empty()) {
396  this->executeCommand(doc, 1);
397  }
398  }
399  catch (BESError &e) {
400  CmdTranslation::set_show(false);
401  _isInteractive = false;
402  throw e;
403  }
404  CmdTranslation::set_show(false);
405  }
406  }
407  _isInteractive = false;
408 }
409 
415 size_t StandAloneClient::readLine(string & msg)
416 {
417  size_t len = 0;
418  char *buf = (char *) NULL;
419  buf = ::readline("BESClient> ");
420  if (buf && *buf) {
421  len = strlen(buf);
422 #ifdef HAVE_READLINE_HISTORY
423  add_history(buf);
424 #endif
425  if (len > SIZE_COMMUNICATION_BUFFER) {
426  cerr << __FILE__ << __LINE__ <<
427  ": incoming data buffer exceeds maximum capacity with lenght " << len << endl;
428  exit(1);
429  }
430  else {
431  msg = buf;
432  }
433  }
434  else {
435  if (!buf) {
436  // If a null buffer is returned then this means that EOF is
437  // returned. This is different from the user just hitting enter,
438  // which means a character buffer is returned, but is empty.
439 
440  // Problem: len is unsigned.
441  len = -1;
442  }
443  }
444  if (buf) {
445  free(buf);
446  buf = (char *) NULL;
447  }
448  return len;
449 }
450 
453 void StandAloneClient::displayHelp()
454 {
455  cout << endl;
456  cout << endl;
457  cout << "BES Command Line Client Help" << endl;
458  cout << endl;
459  cout << "Client commands available:" << endl;
460  cout << " exit - exit the command line interface" << endl;
461  cout << " help - display this help screen" << endl;
462  cout << " client suppress; - suppress output from the server" << endl;
463  cout << " client output to screen; - display server output to the screen" << endl;
464  cout << " client output to <file>; - display server output to specified file" << endl;
465  cout << endl;
466  cout << "Any commands beginning with 'client' must end with a semicolon" << endl;
467  cout << endl;
468  cout << "To display the list of commands available from the server " << "please type the command 'show help;'"
469  << endl;
470  cout << endl;
471  cout << endl;
472 }
473 
480 void StandAloneClient::dump(ostream & strm) const
481 {
482  strm << BESIndent::LMarg << "StandAloneClient::dump - (" << (void *) this << ")" << endl;
483  BESIndent::Indent();
484  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
485  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
486  BESIndent::UnIndent();
487 }
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:160
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
virtual int execute_request(const std::string &from)
The entry point for command execution; called by BESServerHandler::execute()
virtual bool start(std::string name)
Definition: BESStopWatch.cc:67
Entry point into BES using xml document requests.
void executeCommands(const std::string &cmd_list, int repeat)
Send the command(s) specified to the BES server after wrapping in request document.
void interact()
An interactive BES client that takes BES requests on the command line.
void executeClientCommand(const std::string &cmd)
Executes a client side command.
virtual void dump(std::ostream &strm) const
dumps information about this object
void setOutput(std::ostream *strm, bool created)
Set the output stream for responses from the BES server.