bes  Updated for version 3.17.4
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 #include "config.h"
37 
38 #include <cstdlib>
39 #include <iostream>
40 #include <fstream>
41 #include <sstream>
42 
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 
47 using std::cout;
48 using std::endl;
49 using std::cerr;
50 using std::ofstream;
51 using std::ios;
52 using std::flush;
53 using std::ostringstream;
54 
55 #ifdef HAVE_LIBREADLINE
56 # if defined(HAVE_READLINE_READLINE_H)
57 # include <readline/readline.h>
58 # elif defined(HAVE_READLINE_H)
59 # include <readline.h>
60 # else /* !defined(HAVE_READLINE_H) */
61 extern "C" {
62  char *readline(const char *);
63 }
64 # endif /* !defined(HAVE_READLINE_H) */
65 char *cmdline = NULL;
66 #else /* !defined(HAVE_READLINE_READLINE_H) */
67 /* no readline */
68 #endif /* HAVE_LIBREADLINE */
69 
70 #ifdef HAVE_READLINE_HISTORY
71 # if defined(HAVE_READLINE_HISTORY_H)
72 # include <readline/history.h>
73 # elif defined(HAVE_HISTORY_H)
74 # include <history.h>
75 # else /* !defined(HAVE_HISTORY_H) */
76 extern "C" {
77  int add_history(const char *);
78  int write_history(const char *);
79  int read_history(const char *);
80 }
81 # endif /* defined(HAVE_READLINE_HISTORY_H) */
82 /* no history */
83 #endif /* HAVE_READLINE_HISTORY */
84 #define SIZE_COMMUNICATION_BUFFER 4096*4096
85 #include "StandAloneClient.h"
86 #include "BESDebug.h"
87 #include "BESXMLInterface.h"
88 #include "CmdTranslation.h"
89 
90 StandAloneClient::~StandAloneClient()
91 {
92  if (_strmCreated && _strm) {
93  _strm->flush();
94  delete _strm;
95  _strm = 0;
96  }
97  else if (_strm) {
98  _strm->flush();
99  }
100 }
101 
118 void StandAloneClient::setOutput(ostream * strm, bool created)
119 {
120  if (_strmCreated && _strm) {
121  _strm->flush();
122  delete _strm;
123  }
124  else if (_strm) {
125  _strm->flush();
126  }
127  _strm = strm;
128  _strmCreated = created;
129 }
130 
143 {
144  string suppress = "suppress";
145  if (cmd.compare(0, suppress.length(), suppress) == 0) {
146  setOutput( NULL, false);
147  return;
148  }
149 
150  string output = "output to";
151  if (cmd.compare(0, output.length(), output) == 0) {
152  string subcmd = cmd.substr(output.length() + 1);
153  string screen = "screen";
154  if (subcmd.compare(0, screen.length(), screen) == 0) {
155  setOutput(&cout, false);
156  }
157  else {
158  // subcmd is the name of the file - then semicolon
159  string file = subcmd.substr(0, subcmd.length() - 1);
160  ofstream *fstrm = new ofstream(file.c_str(), ios::app);
161  if (fstrm && !(*fstrm)) {
162  delete fstrm;
163  cerr << "Unable to set client output to file " << file << endl;
164  }
165  else {
166  setOutput(fstrm, true);
167  }
168  }
169  return;
170  }
171 
172  // load commands from an input file and run them
173  string load = "load";
174  if (cmd.compare(0, load.length(), load) == 0) {
175  string file = cmd.substr(load.length() + 1, cmd.length() - load.length() - 2);
176  ifstream fstrm(file.c_str());
177  if (!fstrm) {
178  cerr << "Unable to load commands from file " << file << ": file does not exist or failed to open file"
179  << endl;
180  }
181  else {
182  executeCommands(fstrm, 1);
183  }
184 
185  return;
186  }
187 
188  cerr << "Improper client command " << cmd << endl;
189 }
190 
203 void StandAloneClient::executeCommand(const string & cmd, int repeat)
204 {
205  string client = "client";
206  if (cmd.compare(0, client.length(), client) == 0) {
207  executeClientCommand(cmd.substr(client.length() + 1));
208  }
209  else {
210  if (repeat < 1) repeat = 1;
211  for (int i = 0; i < repeat; i++) {
212  ostringstream *show_stream = 0;
213  if (CmdTranslation::is_show()) {
214  show_stream = new ostringstream;
215  }
216  BESDEBUG( "standalone", "cmdclient sending " << cmd << endl );
217  BESXMLInterface *interface = 0;
218  if (show_stream) {
219  interface = new BESXMLInterface(cmd, show_stream);
220  }
221  else {
222  interface = new BESXMLInterface(cmd, _strm);
223  }
224  int status = interface->execute_request("standalone");
225 
226  if (status == 0) {
227  BESDEBUG( "standalone", "BESServerHandler::execute - "
228  << "executed successfully" << endl );
229  }
230  else
231  {
232  // an error has occurred.
233  BESDEBUG( "standalone", "BESServerHandler::execute - "
234  "error occurred" << endl );
235 
236  // flush what we have in the stream to the client
237  *_strm << flush;
238 
239  // transmit the error message. finish_with_error will transmit
240  // the error
241  interface->finish_with_error( status );
242 
243  switch (status)
244  {
245  case BES_INTERNAL_FATAL_ERROR:
246  {
247  cerr << "BES server " << getpid()
248  << ": Status not OK, dispatcher returned value "
249  << status << endl;
250  exit( 1 );
251  }
252  break;
253  case BES_INTERNAL_ERROR:
254  case BES_SYNTAX_USER_ERROR:
255  case BES_FORBIDDEN_ERROR:
256  case BES_NOT_FOUND_ERROR:
257 
258  default:
259  break;
260  }
261  }
262  delete interface;
263  interface = 0;
264 
265  if (show_stream) {
266  *(_strm) << show_stream->str() << endl;
267  delete show_stream;
268  show_stream = 0;
269  }
270 
271  _strm->flush();
272  }
273  }
274 }
275 
292 void StandAloneClient::executeCommands(const string &cmd_list, int repeat)
293 {
294  _isInteractive = true;
295  if (repeat < 1) repeat = 1;
296 
297  CmdTranslation::set_show(false);
298  try {
299  string doc = CmdTranslation::translate(cmd_list);
300  if (!doc.empty()) {
301  executeCommand(doc, repeat);
302  }
303  }
304  catch (BESError &e) {
305  CmdTranslation::set_show(false);
306  _isInteractive = false;
307  throw e;
308  }
309  CmdTranslation::set_show(false);
310  _isInteractive = false;
311 }
312 
331 void StandAloneClient::executeCommands(ifstream & istrm, int repeat)
332 {
333  _isInteractive = false;
334  if (repeat < 1) repeat = 1;
335  for (int i = 0; i < repeat; i++) {
336  istrm.clear();
337  istrm.seekg(0, ios::beg);
338  string cmd;
339  string line;
340  while (getline(istrm, line)) {
341  cmd += line;
342  }
343  this->executeCommand(cmd, 1);
344  }
345 }
346 
363 {
364  _isInteractive = true;
365 
366  cout << endl << endl << "Type 'exit' to exit the command line client and 'help' or '?' "
367  << "to display the help screen" << endl << endl;
368 
369  bool done = false;
370  while (!done) {
371  string message = "";
372  size_t len = this->readLine(message);
373  if ( /*len == -1 || */message == "exit" || message == "exit;") {
374  done = true;
375  }
376  else if (message == "help" || message == "help;" || message == "?") {
377  this->displayHelp();
378  }
379  else if (message.length() > 6 && message.substr(0, 6) == "client") {
380  this->executeCommand(message, 1);
381  }
382  else if (len != 0 && message != "") {
383  CmdTranslation::set_show(false);
384  try {
385  string doc = CmdTranslation::translate(message);
386  if (!doc.empty()) {
387  this->executeCommand(doc, 1);
388  }
389  }
390  catch (BESError &e) {
391  CmdTranslation::set_show(false);
392  _isInteractive = false;
393  throw e;
394  }
395  CmdTranslation::set_show(false);
396  }
397  }
398  _isInteractive = false;
399 }
400 
406 size_t StandAloneClient::readLine(string & msg)
407 {
408  size_t len = 0;
409  char *buf = (char *) NULL;
410  buf = ::readline("BESClient> ");
411  if (buf && *buf) {
412  len = strlen(buf);
413 #ifdef HAVE_READLINE_HISTORY
414  add_history(buf);
415 #endif
416  if (len > SIZE_COMMUNICATION_BUFFER) {
417  cerr << __FILE__ << __LINE__ <<
418  ": incoming data buffer exceeds maximum capacity with lenght " << len << endl;
419  exit(1);
420  }
421  else {
422  msg = buf;
423  }
424  }
425  else {
426  if (!buf) {
427  // If a null buffer is returned then this means that EOF is
428  // returned. This is different from the user just hitting enter,
429  // which means a character buffer is returned, but is empty.
430 
431  // Problem: len is unsigned.
432  len = -1;
433  }
434  }
435  if (buf) {
436  free(buf);
437  buf = (char *) NULL;
438  }
439  return len;
440 }
441 
444 void StandAloneClient::displayHelp()
445 {
446  cout << endl;
447  cout << endl;
448  cout << "BES Command Line Client Help" << endl;
449  cout << endl;
450  cout << "Client commands available:" << endl;
451  cout << " exit - exit the command line interface" << endl;
452  cout << " help - display this help screen" << endl;
453  cout << " client suppress; - suppress output from the server" << endl;
454  cout << " client output to screen; - display server output to the screen" << endl;
455  cout << " client output to <file>; - display server output to specified file" << endl;
456  cout << endl;
457  cout << "Any commands beginning with 'client' must end with a semicolon" << endl;
458  cout << endl;
459  cout << "To display the list of commands available from the server " << "please type the command 'show help;'"
460  << endl;
461  cout << endl;
462  cout << endl;
463 }
464 
471 void StandAloneClient::dump(ostream & strm) const
472 {
473  strm << BESIndent::LMarg << "StandAloneClient::dump - (" << (void *) this << ")" << endl;
474  BESIndent::Indent();
475  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
476  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
477  BESIndent::UnIndent();
478 }
void executeCommands(const string &cmd_list, int repeat)
Send the command(s) specified to the BES server after wrapping in request document.
virtual int execute_request(const string &from)
Override execute_request in order to register memory pool.
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
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.
void executeClientCommand(const string &cmd)
Executes a client side command.