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  } else if (_strm) {
97  _strm->flush();
98  }
99 }
100 
117 void
118 StandAloneClient::setOutput(ostream * strm, bool created)
119 {
120  if (_strmCreated && _strm) {
121  _strm->flush();
122  delete _strm;
123  } else if (_strm) {
124  _strm->flush();
125  }
126  _strm = strm;
127  _strmCreated = created;
128 }
129 
141 void
143 {
144  string suppress = "suppress" ;
145  if( cmd.compare( 0, suppress.length(), suppress ) == 0 )
146  {
147  setOutput( NULL, false ) ;
148  return ;
149  }
150 
151  string output = "output to" ;
152  if( cmd.compare( 0, output.length(), output ) == 0 )
153  {
154  string subcmd = cmd.substr( output.length() + 1 ) ;
155  string screen = "screen" ;
156  if( subcmd.compare( 0, screen.length(), screen ) == 0 )
157  {
158  setOutput( &cout, false ) ;
159  }
160  else
161  {
162  // subcmd is the name of the file - then semicolon
163  string file = subcmd.substr( 0, subcmd.length() - 1 ) ;
164  ofstream *fstrm = new ofstream( file.c_str(), ios::app ) ;
165  if( fstrm && !(*fstrm) )
166  {
167  delete fstrm ;
168  cerr << "Unable to set client output to file " << file
169  << endl ;
170  }
171  else
172  {
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  {
183  string file = cmd.substr( load.length() + 1,
184  cmd.length() - load.length() - 2 ) ;
185  ifstream fstrm( file.c_str() ) ;
186  if( !fstrm )
187  {
188  cerr << "Unable to load commands from file " << file
189  << ": file does not exist or failed to open file" << endl ;
190  }
191  else
192  {
193  executeCommands( fstrm, 1 ) ;
194  }
195 
196  return ;
197  }
198 
199  cerr << "Improper client command " << cmd << endl ;
200 }
201 
214 void
215 StandAloneClient::executeCommand( const string & cmd, int repeat )
216 {
217  string client = "client" ;
218  if( cmd.compare( 0, client.length(), client ) == 0 )
219  {
220  executeClientCommand( cmd.substr( client.length() + 1 ) ) ;
221  }
222  else
223  {
224  if( repeat < 1 ) repeat = 1 ;
225  for( int i = 0; i < repeat; i++ )
226  {
227  ostringstream *show_stream = 0 ;
229  {
230  show_stream = new ostringstream ;
231  }
232  BESDEBUG( "standalone", "cmdclient sending " << cmd << endl ) ;
233  BESXMLInterface *interface = 0 ;
234  if( show_stream )
235  {
236  interface = new BESXMLInterface( cmd, show_stream ) ;
237  }
238  else
239  {
240  interface = new BESXMLInterface( cmd, _strm ) ;
241  }
242  int status = interface->execute_request( "standalone" ) ;
243 
244  if( status == 0 )
245  {
246  BESDEBUG( "standalone", "BESServerHandler::execute - "
247  << "executed successfully" << endl ) ;
248  }
249  else
250  {
251  // an error has occurred.
252  BESDEBUG( "standalone", "BESServerHandler::execute - "
253  "error occurred" << endl ) ;
254 
255  // flush what we have in the stream to the client
256  *_strm << flush ;
257 
258  // transmit the error message. finish_with_error will transmit
259  // the error
260  interface->finish_with_error( status ) ;
261 
262  switch (status)
263  {
265  {
266  cerr << "BES server " << getpid()
267  << ": Status not OK, dispatcher returned value "
268  << status << endl ;
269  //string toSend = "FATAL ERROR: server must exit!" ;
270  //c->send( toSend ) ;
271  exit( 1 ) ;
272  }
273  break;
274  case BES_INTERNAL_ERROR:
276  case BES_FORBIDDEN_ERROR:
277  case BES_NOT_FOUND_ERROR:
278  default:
279  break;
280  }
281  }
282  delete interface ;
283  interface = 0 ;
284 
285  if( show_stream )
286  {
287  *(_strm) << show_stream->str() << endl ;
288  delete show_stream ;
289  show_stream = 0 ;
290  }
291 
292  _strm->flush() ;
293  }
294  }
295 }
296 
313 void
314 StandAloneClient::executeCommands( const string &cmd_list, int repeat )
315 {
316  _isInteractive = true ;
317  if( repeat < 1 ) repeat = 1 ;
318 
319  CmdTranslation::set_show( false ) ;
320  try
321  {
322  string doc = CmdTranslation::translate( cmd_list ) ;
323  if( !doc.empty() )
324  {
325  executeCommand( doc, repeat ) ;
326  }
327  }
328  catch( BESError &e )
329  {
330  CmdTranslation::set_show( false ) ;
331  _isInteractive = false ;
332  throw e ;
333  }
334  CmdTranslation::set_show( false ) ;
335  _isInteractive = false ;
336 }
337 
356 void
357 StandAloneClient::executeCommands(ifstream & istrm, int repeat)
358 {
359  _isInteractive = false ;
360  if( repeat < 1 ) repeat = 1 ;
361  for( int i = 0; i < repeat; i++ )
362  {
363  istrm.clear( ) ;
364  istrm.seekg( 0, ios::beg ) ;
365  string cmd ;
366  string line ;
367  while(getline(istrm, line))
368  {
369  cmd += line ;
370  }
371  this->executeCommand( cmd, 1 ) ;
372  }
373 }
374 
390 void
392 {
393  _isInteractive = true ;
394 
395  cout << endl << endl
396  << "Type 'exit' to exit the command line client and 'help' or '?' "
397  << "to display the help screen" << endl << endl ;
398 
399  bool done = false ;
400  while( !done )
401  {
402  string message = "" ;
403  size_t len = this->readLine( message ) ;
404  if( /*len == -1 || */ message == "exit" || message == "exit;" )
405  {
406  done = true ;
407  }
408  else if( message == "help" || message == "help;" || message == "?" )
409  {
410  this->displayHelp() ;
411  }
412  else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
413  {
414  this->executeCommand( message, 1 ) ;
415  }
416  else if( len != 0 && message != "" )
417  {
418  CmdTranslation::set_show( false ) ;
419  try
420  {
421  string doc = CmdTranslation::translate( message ) ;
422  if( !doc.empty() )
423  {
424  this->executeCommand( doc, 1 ) ;
425  }
426  }
427  catch( BESError &e )
428  {
429  CmdTranslation::set_show( false ) ;
430  _isInteractive = false ;
431  throw e ;
432  }
433  CmdTranslation::set_show( false ) ;
434  }
435  }
436  _isInteractive = false ;
437 }
438 
444 size_t
445 StandAloneClient::readLine(string & msg)
446 {
447  size_t len = 0;
448  char *buf = (char *) NULL;
449  buf =::readline("BESClient> ");
450  if (buf && *buf) {
451  len = strlen(buf);
452 #ifdef HAVE_READLINE_HISTORY
453  add_history(buf);
454 #endif
455  if (len > SIZE_COMMUNICATION_BUFFER) {
456  cerr << __FILE__ << __LINE__
457  <<
458  ": incoming data buffer exceeds maximum capacity with lenght "
459  << len << endl;
460  exit(1);
461  } else {
462  msg = buf;
463  }
464  } else {
465  if (!buf) {
466  // If a null buffer is returned then this means that EOF is
467  // returned. This is different from the user just hitting enter,
468  // which means a character buffer is returned, but is empty.
469 
470  // Problem: len is unsigned.
471  len = -1;
472  }
473  }
474  if (buf) {
475  free(buf);
476  buf = (char *) NULL;
477  }
478  return len;
479 }
480 
483 void
484 StandAloneClient::displayHelp()
485 {
486  cout << endl;
487  cout << endl;
488  cout << "BES Command Line Client Help" << endl;
489  cout << endl;
490  cout << "Client commands available:" << endl;
491  cout <<
492  " exit - exit the command line interface" <<
493  endl;
494  cout << " help - display this help screen" <<
495  endl;
496  cout <<
497  " client suppress; - suppress output from the server" <<
498  endl;
499  cout <<
500  " client output to screen; - display server output to the screen"
501  << endl;
502  cout <<
503  " client output to <file>; - display server output to specified file"
504  << endl;
505  cout << endl;
506  cout <<
507  "Any commands beginning with 'client' must end with a semicolon" <<
508  endl;
509  cout << endl;
510  cout << "To display the list of commands available from the server "
511  << "please type the command 'show help;'" << endl;
512  cout << endl;
513  cout << endl;
514 }
515 
522 void
523 StandAloneClient::dump(ostream & strm) const
524 {
525  strm << BESIndent::LMarg << "StandAloneClient::dump - ("
526  << (void *) this << ")" << endl;
528  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
529  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
531 }
#define BES_SYNTAX_USER_ERROR
Definition: BESError.h:44
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.
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.