OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
StandAloneClient.cc
Go to the documentation of this file.
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 
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  {
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:
255  case BES_FORBIDDEN_ERROR:
256  case BES_NOT_FOUND_ERROR:
257  default:
258  break;
259  }
260  }
261  delete interface;
262  interface = 0;
263 
264  if (show_stream) {
265  *(_strm) << show_stream->str() << endl;
266  delete show_stream;
267  show_stream = 0;
268  }
269 
270  _strm->flush();
271  }
272  }
273 }
274 
291 void StandAloneClient::executeCommands(const string &cmd_list, int repeat)
292 {
293  _isInteractive = true;
294  if (repeat < 1) repeat = 1;
295 
297  try {
298  string doc = CmdTranslation::translate(cmd_list);
299  if (!doc.empty()) {
300  executeCommand(doc, repeat);
301  }
302  }
303  catch (BESError &e) {
305  _isInteractive = false;
306  throw e;
307  }
309  _isInteractive = false;
310 }
311 
330 void StandAloneClient::executeCommands(ifstream & istrm, int repeat)
331 {
332  _isInteractive = false;
333  if (repeat < 1) repeat = 1;
334  for (int i = 0; i < repeat; i++) {
335  istrm.clear();
336  istrm.seekg(0, ios::beg);
337  string cmd;
338  string line;
339  while (getline(istrm, line)) {
340  cmd += line;
341  }
342  this->executeCommand(cmd, 1);
343  }
344 }
345 
362 {
363  _isInteractive = true;
364 
365  cout << endl << endl << "Type 'exit' to exit the command line client and 'help' or '?' "
366  << "to display the help screen" << endl << endl;
367 
368  bool done = false;
369  while (!done) {
370  string message = "";
371  size_t len = this->readLine(message);
372  if ( /*len == -1 || */message == "exit" || message == "exit;") {
373  done = true;
374  }
375  else if (message == "help" || message == "help;" || message == "?") {
376  this->displayHelp();
377  }
378  else if (message.length() > 6 && message.substr(0, 6) == "client") {
379  this->executeCommand(message, 1);
380  }
381  else if (len != 0 && message != "") {
383  try {
384  string doc = CmdTranslation::translate(message);
385  if (!doc.empty()) {
386  this->executeCommand(doc, 1);
387  }
388  }
389  catch (BESError &e) {
391  _isInteractive = false;
392  throw e;
393  }
395  }
396  }
397  _isInteractive = false;
398 }
399 
405 size_t StandAloneClient::readLine(string & msg)
406 {
407  size_t len = 0;
408  char *buf = (char *) NULL;
409  buf = ::readline("BESClient> ");
410  if (buf && *buf) {
411  len = strlen(buf);
412 #ifdef HAVE_READLINE_HISTORY
413  add_history(buf);
414 #endif
415  if (len > SIZE_COMMUNICATION_BUFFER) {
416  cerr << __FILE__ << __LINE__ <<
417  ": incoming data buffer exceeds maximum capacity with lenght " << len << endl;
418  exit(1);
419  }
420  else {
421  msg = buf;
422  }
423  }
424  else {
425  if (!buf) {
426  // If a null buffer is returned then this means that EOF is
427  // returned. This is different from the user just hitting enter,
428  // which means a character buffer is returned, but is empty.
429 
430  // Problem: len is unsigned.
431  len = -1;
432  }
433  }
434  if (buf) {
435  free(buf);
436  buf = (char *) NULL;
437  }
438  return len;
439 }
440 
443 void StandAloneClient::displayHelp()
444 {
445  cout << endl;
446  cout << endl;
447  cout << "BES Command Line Client Help" << endl;
448  cout << endl;
449  cout << "Client commands available:" << endl;
450  cout << " exit - exit the command line interface" << endl;
451  cout << " help - display this help screen" << endl;
452  cout << " client suppress; - suppress output from the server" << endl;
453  cout << " client output to screen; - display server output to the screen" << endl;
454  cout << " client output to <file>; - display server output to specified file" << endl;
455  cout << endl;
456  cout << "Any commands beginning with 'client' must end with a semicolon" << endl;
457  cout << endl;
458  cout << "To display the list of commands available from the server " << "please type the command 'show help;'"
459  << endl;
460  cout << endl;
461  cout << endl;
462 }
463 
470 void StandAloneClient::dump(ostream & strm) const
471 {
472  strm << BESIndent::LMarg << "StandAloneClient::dump - (" << (void *) this << ")" << endl;
474  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
475  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
477 }
#define BES_SYNTAX_USER_ERROR
Definition: BESError.h:44
void free(void *)
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.
static bool is_show()
#define BES_INTERNAL_ERROR
Definition: BESError.h:42
virtual void dump(ostream &strm) const
dumps information about this object
#define BES_FORBIDDEN_ERROR
Definition: BESError.h:45
static void set_show(bool val)
static void Indent()
Definition: BESIndent.cc:38
static string translate(const string &commands)
Abstract exception class for the BES with basic string message.
Definition: BESError.h:51
void interact()
An interactive BES client that takes BES requests on the command line.
#define NULL
Definition: wcsUtil.h:65
static ostream & LMarg(ostream &strm)
Definition: BESIndent.cc:73
#define SIZE_COMMUNICATION_BUFFER
#define BES_INTERNAL_FATAL_ERROR
Definition: BESError.h:43
Entry point into BES using xml document requests.
#define BES_NOT_FOUND_ERROR
Definition: BESError.h:46
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static void UnIndent()
Definition: BESIndent.cc:44
void executeClientCommand(const string &cmd)
Executes a client side command.