bes  Updated for version 3.20.5
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", "StandAloneClient::executeCommand 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  *_strm << flush;
240 
241  // Put the call to finish() here beacuse we're not sending chunked responses back
242  // to a client over PPT. In the BESServerHandler.cc code, we must do that and hence,
243  // break up the call to finish() for the error and no-error cases.
244  status = interface->finish(status);
245 
246  if (status == 0) {
247  BESDEBUG("standalone", "StandAloneClient::executeCommand - executed successfully" << endl);
248  }
249  else {
250  // an error has occurred.
251  BESDEBUG("standalone", "StandAloneClient::executeCommand - error occurred" << endl);
252  switch (status) {
253  case BES_INTERNAL_FATAL_ERROR: {
254  cerr << "Status not OK, dispatcher returned value " << status << endl;
255  exit(1);
256  }
257  break;
258  case BES_INTERNAL_ERROR:
259  case BES_SYNTAX_USER_ERROR:
260  case BES_FORBIDDEN_ERROR:
261  case BES_NOT_FOUND_ERROR:
262 
263  default:
264  break;
265  }
266  }
267 
268  delete interface;
269  interface = 0;
270 
271  if (show_stream) {
272  *(_strm) << show_stream->str() << endl;
273  delete show_stream;
274  show_stream = 0;
275  }
276 
277  _strm->flush();
278  }
279  }
280 }
281 
298 void StandAloneClient::executeCommands(const string &cmd_list, int repeat)
299 {
300  _isInteractive = true;
301  if (repeat < 1) repeat = 1;
302 
303  CmdTranslation::set_show(false);
304  try {
305  string doc = CmdTranslation::translate(cmd_list);
306  if (!doc.empty()) {
307  executeCommand(doc, repeat);
308  }
309  }
310  catch (BESError &e) {
311  CmdTranslation::set_show(false);
312  _isInteractive = false;
313  throw e;
314  }
315  CmdTranslation::set_show(false);
316  _isInteractive = false;
317 }
318 
337 void StandAloneClient::executeCommands(ifstream & istrm, int repeat)
338 {
339  _isInteractive = false;
340  if (repeat < 1) repeat = 1;
341  for (int i = 0; i < repeat; i++) {
342  istrm.clear();
343  istrm.seekg(0, ios::beg);
344  string cmd;
345  string line;
346  while (getline(istrm, line)) {
347  cmd += line;
348  }
349  this->executeCommand(cmd, 1);
350  }
351 }
352 
369 {
370  _isInteractive = true;
371 
372  cout << endl << endl << "Type 'exit' to exit the command line client and 'help' or '?' "
373  << "to display the help screen" << endl << endl;
374 
375  bool done = false;
376  while (!done) {
377  string message = "";
378  size_t len = this->readLine(message);
379  if ( /*len == -1 || */message == "exit" || message == "exit;") {
380  done = true;
381  }
382  else if (message == "help" || message == "help;" || message == "?") {
383  this->displayHelp();
384  }
385  else if (message.length() > 6 && message.substr(0, 6) == "client") {
386  this->executeCommand(message, 1);
387  }
388  else if (len != 0 && message != "") {
389  CmdTranslation::set_show(false);
390  try {
391  string doc = CmdTranslation::translate(message);
392  if (!doc.empty()) {
393  this->executeCommand(doc, 1);
394  }
395  }
396  catch (BESError &e) {
397  CmdTranslation::set_show(false);
398  _isInteractive = false;
399  throw e;
400  }
401  CmdTranslation::set_show(false);
402  }
403  }
404  _isInteractive = false;
405 }
406 
412 size_t StandAloneClient::readLine(string & msg)
413 {
414  size_t len = 0;
415  char *buf = (char *) NULL;
416  buf = ::readline("BESClient> ");
417  if (buf && *buf) {
418  len = strlen(buf);
419 #ifdef HAVE_READLINE_HISTORY
420  add_history(buf);
421 #endif
422  if (len > SIZE_COMMUNICATION_BUFFER) {
423  cerr << __FILE__ << __LINE__ <<
424  ": incoming data buffer exceeds maximum capacity with lenght " << len << endl;
425  exit(1);
426  }
427  else {
428  msg = buf;
429  }
430  }
431  else {
432  if (!buf) {
433  // If a null buffer is returned then this means that EOF is
434  // returned. This is different from the user just hitting enter,
435  // which means a character buffer is returned, but is empty.
436 
437  // Problem: len is unsigned.
438  len = -1;
439  }
440  }
441  if (buf) {
442  free(buf);
443  buf = (char *) NULL;
444  }
445  return len;
446 }
447 
450 void StandAloneClient::displayHelp()
451 {
452  cout << endl;
453  cout << endl;
454  cout << "BES Command Line Client Help" << endl;
455  cout << endl;
456  cout << "Client commands available:" << endl;
457  cout << " exit - exit the command line interface" << endl;
458  cout << " help - display this help screen" << endl;
459  cout << " client suppress; - suppress output from the server" << endl;
460  cout << " client output to screen; - display server output to the screen" << endl;
461  cout << " client output to <file>; - display server output to specified file" << endl;
462  cout << endl;
463  cout << "Any commands beginning with 'client' must end with a semicolon" << endl;
464  cout << endl;
465  cout << "To display the list of commands available from the server " << "please type the command 'show help;'"
466  << endl;
467  cout << endl;
468  cout << endl;
469 }
470 
477 void StandAloneClient::dump(ostream & strm) const
478 {
479  strm << BESIndent::LMarg << "StandAloneClient::dump - (" << (void *) this << ")" << endl;
480  BESIndent::Indent();
481  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
482  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
483  BESIndent::UnIndent();
484 }
StandAloneClient::setOutput
void setOutput(ostream *strm, bool created)
Set the output stream for responses from the BES server.
Definition: StandAloneClient.cc:125
StandAloneClient::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: StandAloneClient.cc:477
StandAloneClient::interact
void interact()
An interactive BES client that takes BES requests on the command line.
Definition: StandAloneClient.cc:368
BESStopWatch::start
virtual bool start(string name)
Definition: BESStopWatch.cc:57
BESXMLInterface
Entry point into BES using xml document requests.
Definition: BESXMLInterface.h:47
BESStopWatch
Definition: BESStopWatch.h:55
StandAloneClient::executeClientCommand
void executeClientCommand(const string &cmd)
Executes a client side command.
Definition: StandAloneClient.cc:149
StandAloneClient::executeCommands
void executeCommands(const string &cmd_list, int repeat)
Send the command(s) specified to the BES server after wrapping in request document.
Definition: StandAloneClient.cc:298
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:446