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) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include "config.h"
34 
35 #include <cstdlib>
36 #include <iostream>
37 #include <fstream>
38 #include <sstream>
39 
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 using std::cout;
45 using std::endl;
46 using std::cerr;
47 using std::ofstream;
48 using std::ios;
49 using std::flush;
50 using std::ostringstream;
51 
52 #ifdef HAVE_LIBREADLINE
53 # if defined(HAVE_READLINE_READLINE_H)
54 # include <readline/readline.h>
55 # elif defined(HAVE_READLINE_H)
56 # include <readline.h>
57 # else /* !defined(HAVE_READLINE_H) */
58 extern "C" {
59  char *readline(const char *);
60 }
61 # endif /* !defined(HAVE_READLINE_H) */
62 char *cmdline = NULL;
63 #else /* !defined(HAVE_READLINE_READLINE_H) */
64  /* no readline */
65 #endif /* HAVE_LIBREADLINE */
66 
67 #ifdef HAVE_READLINE_HISTORY
68 # if defined(HAVE_READLINE_HISTORY_H)
69 # include <readline/history.h>
70 # elif defined(HAVE_HISTORY_H)
71 # include <history.h>
72 # else /* !defined(HAVE_HISTORY_H) */
73 extern "C" {
74  int add_history(const char *);
75  int write_history(const char *);
76  int read_history(const char *);
77 }
78 # endif /* defined(HAVE_READLINE_HISTORY_H) */
79  /* no history */
80 #endif /* HAVE_READLINE_HISTORY */
81 #define SIZE_COMMUNICATION_BUFFER 4096*4096
82 #include "StandAloneClient.h"
83 #include "BESDebug.h"
84 #include "BESXMLInterface.h"
85 #include "CmdTranslation.h"
86 
88 {
89  if (_strmCreated && _strm) {
90  _strm->flush();
91  delete _strm;
92  _strm = 0;
93  } else if (_strm) {
94  _strm->flush();
95  }
96 }
97 
114 void
115 StandAloneClient::setOutput(ostream * strm, bool created)
116 {
117  if (_strmCreated && _strm) {
118  _strm->flush();
119  delete _strm;
120  } else if (_strm) {
121  _strm->flush();
122  }
123  _strm = strm;
124  _strmCreated = created;
125 }
126 
138 void
140 {
141  string suppress = "suppress" ;
142  if( cmd.compare( 0, suppress.length(), suppress ) == 0 )
143  {
144  setOutput( NULL, false ) ;
145  return ;
146  }
147 
148  string output = "output to" ;
149  if( cmd.compare( 0, output.length(), output ) == 0 )
150  {
151  string subcmd = cmd.substr( output.length() + 1 ) ;
152  string screen = "screen" ;
153  if( subcmd.compare( 0, screen.length(), screen ) == 0 )
154  {
155  setOutput( &cout, false ) ;
156  }
157  else
158  {
159  // subcmd is the name of the file - then semicolon
160  string file = subcmd.substr( 0, subcmd.length() - 1 ) ;
161  ofstream *fstrm = new ofstream( file.c_str(), ios::app ) ;
162  if( fstrm && !(*fstrm) )
163  {
164  delete fstrm ;
165  cerr << "Unable to set client output to file " << file
166  << endl ;
167  }
168  else
169  {
170  setOutput( fstrm, true ) ;
171  }
172  }
173  return ;
174  }
175 
176  // load commands from an input file and run them
177  string load = "load" ;
178  if( cmd.compare( 0, load.length(), load ) == 0 )
179  {
180  string file = cmd.substr( load.length() + 1,
181  cmd.length() - load.length() - 2 ) ;
182  ifstream fstrm( file.c_str() ) ;
183  if( !fstrm )
184  {
185  cerr << "Unable to load commands from file " << file
186  << ": file does not exist or failed to open file" << endl ;
187  }
188  else
189  {
190  executeCommands( fstrm, 1 ) ;
191  }
192 
193  return ;
194  }
195 
196  cerr << "Improper client command " << cmd << endl ;
197 }
198 
211 void
212 StandAloneClient::executeCommand( const string & cmd, int repeat )
213 {
214  string client = "client" ;
215  if( cmd.compare( 0, client.length(), client ) == 0 )
216  {
217  executeClientCommand( cmd.substr( client.length() + 1 ) ) ;
218  }
219  else
220  {
221  if( repeat < 1 ) repeat = 1 ;
222  for( int i = 0; i < repeat; i++ )
223  {
224  ostringstream *show_stream = 0 ;
226  {
227  show_stream = new ostringstream ;
228  }
229  BESDEBUG( "standalone", "cmdclient sending " << cmd << endl ) ;
230  BESXMLInterface *interface = 0 ;
231  if( show_stream )
232  {
233  interface = new BESXMLInterface( cmd, show_stream ) ;
234  }
235  else
236  {
237  interface = new BESXMLInterface( cmd, _strm ) ;
238  }
239  int status = interface->execute_request( "standalone" ) ;
240 
241  if( status == 0 )
242  {
243  BESDEBUG( "standalone", "BESServerHandler::execute - "
244  << "executed successfully" << endl ) ;
245  }
246  else
247  {
248  // an error has occurred.
249  BESDEBUG( "standalone", "BESServerHandler::execute - "
250  "error occurred" << endl ) ;
251 
252  // flush what we have in the stream to the client
253  *_strm << flush ;
254 
255  // transmit the error message. finish_with_error will transmit
256  // the error
257  interface->finish_with_error( status ) ;
258 
259  switch (status)
260  {
262  {
263  cerr << "BES server " << getpid()
264  << ": Status not OK, dispatcher returned value "
265  << status << endl ;
266  //string toSend = "FATAL ERROR: server must exit!" ;
267  //c->send( toSend ) ;
268  exit( 1 ) ;
269  }
270  break;
271  case BES_INTERNAL_ERROR:
273  case BES_FORBIDDEN_ERROR:
274  case BES_NOT_FOUND_ERROR:
275  default:
276  break;
277  }
278  }
279  delete interface ;
280  interface = 0 ;
281 
282  if( show_stream )
283  {
284  *(_strm) << show_stream->str() << endl ;
285  delete show_stream ;
286  show_stream = 0 ;
287  }
288 
289  _strm->flush() ;
290  }
291  }
292 }
293 
310 void
311 StandAloneClient::executeCommands( const string &cmd_list, int repeat )
312 {
313  _isInteractive = true ;
314  if( repeat < 1 ) repeat = 1 ;
315 
316  CmdTranslation::set_show( false ) ;
317  try
318  {
319  string doc = CmdTranslation::translate( cmd_list ) ;
320  if( !doc.empty() )
321  {
322  executeCommand( doc, repeat ) ;
323  }
324  }
325  catch( BESError &e )
326  {
327  CmdTranslation::set_show( false ) ;
328  _isInteractive = false ;
329  throw e ;
330  }
331  CmdTranslation::set_show( false ) ;
332  _isInteractive = false ;
333 }
334 
353 void
354 StandAloneClient::executeCommands(ifstream & istrm, int repeat)
355 {
356  _isInteractive = false ;
357  if( repeat < 1 ) repeat = 1 ;
358  for( int i = 0; i < repeat; i++ )
359  {
360  istrm.clear( ) ;
361  istrm.seekg( 0, ios::beg ) ;
362  string cmd ;
363  while( !istrm.eof() )
364  {
365  char line[4096] ;
366  line[0] = '\0' ;
367  istrm.getline( line, 4096, '\n' ) ;
368  cmd += line ;
369  }
370  this->executeCommand( cmd, 1 ) ;
371  }
372 }
373 
389 void
391 {
392  _isInteractive = true ;
393 
394  cout << endl << endl
395  << "Type 'exit' to exit the command line client and 'help' or '?' "
396  << "to display the help screen" << endl << endl ;
397 
398  bool done = false ;
399  while( !done )
400  {
401  string message = "" ;
402  size_t len = this->readLine( message ) ;
403  if( len == -1 || message == "exit" || message == "exit;" )
404  {
405  done = true ;
406  }
407  else if( message == "help" || message == "help;" || message == "?" )
408  {
409  this->displayHelp() ;
410  }
411  else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
412  {
413  this->executeCommand( message, 1 ) ;
414  }
415  else if( len != 0 && message != "" )
416  {
417  CmdTranslation::set_show( false ) ;
418  try
419  {
420  string doc = CmdTranslation::translate( message ) ;
421  if( !doc.empty() )
422  {
423  this->executeCommand( doc, 1 ) ;
424  }
425  }
426  catch( BESError &e )
427  {
428  CmdTranslation::set_show( false ) ;
429  _isInteractive = false ;
430  throw e ;
431  }
432  CmdTranslation::set_show( false ) ;
433  }
434  }
435  _isInteractive = false ;
436 }
437 
443 size_t
444 StandAloneClient::readLine(string & msg)
445 {
446  size_t len = 0;
447  char *buf = (char *) NULL;
448  buf =::readline("BESClient> ");
449  if (buf && *buf) {
450  len = strlen(buf);
451 #ifdef HAVE_READLINE_HISTORY
452  add_history(buf);
453 #endif
454  if (len > SIZE_COMMUNICATION_BUFFER) {
455  cerr << __FILE__ << __LINE__
456  <<
457  ": incoming data buffer exceeds maximum capacity with lenght "
458  << len << endl;
459  exit(1);
460  } else {
461  msg = buf;
462  }
463  } else {
464  if (!buf) {
465  // If a null buffer is returned then this means that EOF is
466  // returned. This is different from the user just hitting enter,
467  // which means a character buffer is returned, but is empty.
468 
469  // Problem: len is unsigned.
470  len = -1;
471  }
472  }
473  if (buf) {
474  free(buf);
475  buf = (char *) NULL;
476  }
477  return len;
478 }
479 
482 void
483 StandAloneClient::displayHelp()
484 {
485  cout << endl;
486  cout << endl;
487  cout << "BES Command Line Client Help" << endl;
488  cout << endl;
489  cout << "Client commands available:" << endl;
490  cout <<
491  " exit - exit the command line interface" <<
492  endl;
493  cout << " help - display this help screen" <<
494  endl;
495  cout <<
496  " client suppress; - suppress output from the server" <<
497  endl;
498  cout <<
499  " client output to screen; - display server output to the screen"
500  << endl;
501  cout <<
502  " client output to <file>; - display server output to specified file"
503  << endl;
504  cout << endl;
505  cout <<
506  "Any commands beginning with 'client' must end with a semicolon" <<
507  endl;
508  cout << endl;
509  cout << "To display the list of commands available from the server "
510  << "please type the command 'show help;'" << endl;
511  cout << endl;
512  cout << endl;
513 }
514 
521 void
522 StandAloneClient::dump(ostream & strm) const
523 {
524  strm << BESIndent::LMarg << "StandAloneClient::dump - ("
525  << (void *) this << ")" << endl;
527  strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
528  strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
530 }
#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.