bes  Updated for version 3.20.6
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 (BESISDEBUG(TIMING_LOG)) 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 }
BESStopWatch::start
virtual bool start(std::string name)
Definition: BESStopWatch.cc:58
StandAloneClient::executeClientCommand
void executeClientCommand(const std::string &cmd)
Executes a client side command.
Definition: StandAloneClient.cc:152
StandAloneClient::executeCommands
void executeCommands(const std::string &cmd_list, int repeat)
Send the command(s) specified to the BES server after wrapping in request document.
Definition: StandAloneClient.cc:301
StandAloneClient::interact
void interact()
An interactive BES client that takes BES requests on the command line.
Definition: StandAloneClient.cc:371
BESXMLInterface
Entry point into BES using xml document requests.
Definition: BESXMLInterface.h:47
BESStopWatch
Definition: BESStopWatch.h:55
StandAloneClient::setOutput
void setOutput(std::ostream *strm, bool created)
Set the output stream for responses from the BES server.
Definition: StandAloneClient.cc:128
BESError
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
BESInterface::execute_request
virtual int execute_request(const std::string &from)
The entry point for command execution; called by BESServerHandler::execute()
Definition: BESInterface.cc:447
StandAloneClient::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: StandAloneClient.cc:480