OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // StandAloneClient.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include "config.h" 00034 00035 #include <cstdlib> 00036 #include <iostream> 00037 #include <fstream> 00038 #include <sstream> 00039 00040 #ifdef HAVE_UNISTD_H 00041 #include <unistd.h> 00042 #endif 00043 00044 using std::cout; 00045 using std::endl; 00046 using std::cerr; 00047 using std::ofstream; 00048 using std::ios; 00049 using std::flush; 00050 using std::ostringstream; 00051 00052 #ifdef HAVE_LIBREADLINE 00053 # if defined(HAVE_READLINE_READLINE_H) 00054 # include <readline/readline.h> 00055 # elif defined(HAVE_READLINE_H) 00056 # include <readline.h> 00057 # else /* !defined(HAVE_READLINE_H) */ 00058 extern "C" { 00059 char *readline(const char *); 00060 } 00061 # endif /* !defined(HAVE_READLINE_H) */ 00062 char *cmdline = NULL; 00063 #else /* !defined(HAVE_READLINE_READLINE_H) */ 00064 /* no readline */ 00065 #endif /* HAVE_LIBREADLINE */ 00066 00067 #ifdef HAVE_READLINE_HISTORY 00068 # if defined(HAVE_READLINE_HISTORY_H) 00069 # include <readline/history.h> 00070 # elif defined(HAVE_HISTORY_H) 00071 # include <history.h> 00072 # else /* !defined(HAVE_HISTORY_H) */ 00073 extern "C" { 00074 int add_history(const char *); 00075 int write_history(const char *); 00076 int read_history(const char *); 00077 } 00078 # endif /* defined(HAVE_READLINE_HISTORY_H) */ 00079 /* no history */ 00080 #endif /* HAVE_READLINE_HISTORY */ 00081 #define SIZE_COMMUNICATION_BUFFER 4096*4096 00082 #include "StandAloneClient.h" 00083 #include "BESDebug.h" 00084 #include "BESXMLInterface.h" 00085 #include "CmdTranslation.h" 00086 00087 StandAloneClient::~StandAloneClient() 00088 { 00089 if (_strmCreated && _strm) { 00090 _strm->flush(); 00091 delete _strm; 00092 _strm = 0; 00093 } else if (_strm) { 00094 _strm->flush(); 00095 } 00096 } 00097 00114 void 00115 StandAloneClient::setOutput(ostream * strm, bool created) 00116 { 00117 if (_strmCreated && _strm) { 00118 _strm->flush(); 00119 delete _strm; 00120 } else if (_strm) { 00121 _strm->flush(); 00122 } 00123 _strm = strm; 00124 _strmCreated = created; 00125 } 00126 00138 void 00139 StandAloneClient::executeClientCommand( const string &cmd ) 00140 { 00141 string suppress = "suppress" ; 00142 if( cmd.compare( 0, suppress.length(), suppress ) == 0 ) 00143 { 00144 setOutput( NULL, false ) ; 00145 return ; 00146 } 00147 00148 string output = "output to" ; 00149 if( cmd.compare( 0, output.length(), output ) == 0 ) 00150 { 00151 string subcmd = cmd.substr( output.length() + 1 ) ; 00152 string screen = "screen" ; 00153 if( subcmd.compare( 0, screen.length(), screen ) == 0 ) 00154 { 00155 setOutput( &cout, false ) ; 00156 } 00157 else 00158 { 00159 // subcmd is the name of the file - then semicolon 00160 string file = subcmd.substr( 0, subcmd.length() - 1 ) ; 00161 ofstream *fstrm = new ofstream( file.c_str(), ios::app ) ; 00162 if( fstrm && !(*fstrm) ) 00163 { 00164 delete fstrm ; 00165 cerr << "Unable to set client output to file " << file 00166 << endl ; 00167 } 00168 else 00169 { 00170 setOutput( fstrm, true ) ; 00171 } 00172 } 00173 return ; 00174 } 00175 00176 // load commands from an input file and run them 00177 string load = "load" ; 00178 if( cmd.compare( 0, load.length(), load ) == 0 ) 00179 { 00180 string file = cmd.substr( load.length() + 1, 00181 cmd.length() - load.length() - 2 ) ; 00182 ifstream fstrm( file.c_str() ) ; 00183 if( !fstrm ) 00184 { 00185 cerr << "Unable to load commands from file " << file 00186 << ": file does not exist or failed to open file" << endl ; 00187 } 00188 else 00189 { 00190 executeCommands( fstrm, 1 ) ; 00191 } 00192 00193 return ; 00194 } 00195 00196 cerr << "Improper client command " << cmd << endl ; 00197 } 00198 00211 void 00212 StandAloneClient::executeCommand( const string & cmd, int repeat ) 00213 { 00214 string client = "client" ; 00215 if( cmd.compare( 0, client.length(), client ) == 0 ) 00216 { 00217 executeClientCommand( cmd.substr( client.length() + 1 ) ) ; 00218 } 00219 else 00220 { 00221 if( repeat < 1 ) repeat = 1 ; 00222 for( int i = 0; i < repeat; i++ ) 00223 { 00224 ostringstream *show_stream = 0 ; 00225 if( CmdTranslation::is_show() ) 00226 { 00227 show_stream = new ostringstream ; 00228 } 00229 BESDEBUG( "standalone", "cmdclient sending " << cmd << endl ) ; 00230 BESXMLInterface *interface = 0 ; 00231 if( show_stream ) 00232 { 00233 interface = new BESXMLInterface( cmd, show_stream ) ; 00234 } 00235 else 00236 { 00237 interface = new BESXMLInterface( cmd, _strm ) ; 00238 } 00239 int status = interface->execute_request( "standalone" ) ; 00240 00241 if( status == 0 ) 00242 { 00243 BESDEBUG( "standalone", "BESServerHandler::execute - " 00244 << "executed successfully" << endl ) ; 00245 } 00246 else 00247 { 00248 // an error has occurred. 00249 BESDEBUG( "standalone", "BESServerHandler::execute - " 00250 "error occurred" << endl ) ; 00251 00252 // flush what we have in the stream to the client 00253 *_strm << flush ; 00254 00255 // transmit the error message. finish_with_error will transmit 00256 // the error 00257 interface->finish_with_error( status ) ; 00258 00259 switch (status) 00260 { 00261 case BES_INTERNAL_FATAL_ERROR: 00262 { 00263 cerr << "BES server " << getpid() 00264 << ": Status not OK, dispatcher returned value " 00265 << status << endl ; 00266 //string toSend = "FATAL ERROR: server must exit!" ; 00267 //c->send( toSend ) ; 00268 exit( 1 ) ; 00269 } 00270 break; 00271 case BES_INTERNAL_ERROR: 00272 case BES_SYNTAX_USER_ERROR: 00273 case BES_FORBIDDEN_ERROR: 00274 case BES_NOT_FOUND_ERROR: 00275 default: 00276 break; 00277 } 00278 } 00279 delete interface ; 00280 interface = 0 ; 00281 00282 if( show_stream ) 00283 { 00284 *(_strm) << show_stream->str() << endl ; 00285 delete show_stream ; 00286 show_stream = 0 ; 00287 } 00288 00289 _strm->flush() ; 00290 } 00291 } 00292 } 00293 00310 void 00311 StandAloneClient::executeCommands( const string &cmd_list, int repeat ) 00312 { 00313 _isInteractive = true ; 00314 if( repeat < 1 ) repeat = 1 ; 00315 00316 CmdTranslation::set_show( false ) ; 00317 try 00318 { 00319 string doc = CmdTranslation::translate( cmd_list ) ; 00320 if( !doc.empty() ) 00321 { 00322 executeCommand( doc, repeat ) ; 00323 } 00324 } 00325 catch( BESError &e ) 00326 { 00327 CmdTranslation::set_show( false ) ; 00328 _isInteractive = false ; 00329 throw e ; 00330 } 00331 CmdTranslation::set_show( false ) ; 00332 _isInteractive = false ; 00333 } 00334 00353 void 00354 StandAloneClient::executeCommands(ifstream & istrm, int repeat) 00355 { 00356 _isInteractive = false ; 00357 if( repeat < 1 ) repeat = 1 ; 00358 for( int i = 0; i < repeat; i++ ) 00359 { 00360 istrm.clear( ) ; 00361 istrm.seekg( 0, ios::beg ) ; 00362 string cmd ; 00363 while( !istrm.eof() ) 00364 { 00365 char line[4096] ; 00366 line[0] = '\0' ; 00367 istrm.getline( line, 4096, '\n' ) ; 00368 cmd += line ; 00369 } 00370 this->executeCommand( cmd, 1 ) ; 00371 } 00372 } 00373 00389 void 00390 StandAloneClient::interact() 00391 { 00392 _isInteractive = true ; 00393 00394 cout << endl << endl 00395 << "Type 'exit' to exit the command line client and 'help' or '?' " 00396 << "to display the help screen" << endl << endl ; 00397 00398 bool done = false ; 00399 while( !done ) 00400 { 00401 string message = "" ; 00402 size_t len = this->readLine( message ) ; 00403 if( len == -1 || message == "exit" || message == "exit;" ) 00404 { 00405 done = true ; 00406 } 00407 else if( message == "help" || message == "help;" || message == "?" ) 00408 { 00409 this->displayHelp() ; 00410 } 00411 else if( message.length() > 6 && message.substr( 0, 6 ) == "client" ) 00412 { 00413 this->executeCommand( message, 1 ) ; 00414 } 00415 else if( len != 0 && message != "" ) 00416 { 00417 CmdTranslation::set_show( false ) ; 00418 try 00419 { 00420 string doc = CmdTranslation::translate( message ) ; 00421 if( !doc.empty() ) 00422 { 00423 this->executeCommand( doc, 1 ) ; 00424 } 00425 } 00426 catch( BESError &e ) 00427 { 00428 CmdTranslation::set_show( false ) ; 00429 _isInteractive = false ; 00430 throw e ; 00431 } 00432 CmdTranslation::set_show( false ) ; 00433 } 00434 } 00435 _isInteractive = false ; 00436 } 00437 00443 size_t 00444 StandAloneClient::readLine(string & msg) 00445 { 00446 size_t len = 0; 00447 char *buf = (char *) NULL; 00448 buf =::readline("BESClient> "); 00449 if (buf && *buf) { 00450 len = strlen(buf); 00451 #ifdef HAVE_READLINE_HISTORY 00452 add_history(buf); 00453 #endif 00454 if (len > SIZE_COMMUNICATION_BUFFER) { 00455 cerr << __FILE__ << __LINE__ 00456 << 00457 ": incoming data buffer exceeds maximum capacity with lenght " 00458 << len << endl; 00459 exit(1); 00460 } else { 00461 msg = buf; 00462 } 00463 } else { 00464 if (!buf) { 00465 // If a null buffer is returned then this means that EOF is 00466 // returned. This is different from the user just hitting enter, 00467 // which means a character buffer is returned, but is empty. 00468 00469 // Problem: len is unsigned. 00470 len = -1; 00471 } 00472 } 00473 if (buf) { 00474 free(buf); 00475 buf = (char *) NULL; 00476 } 00477 return len; 00478 } 00479 00482 void 00483 StandAloneClient::displayHelp() 00484 { 00485 cout << endl; 00486 cout << endl; 00487 cout << "BES Command Line Client Help" << endl; 00488 cout << endl; 00489 cout << "Client commands available:" << endl; 00490 cout << 00491 " exit - exit the command line interface" << 00492 endl; 00493 cout << " help - display this help screen" << 00494 endl; 00495 cout << 00496 " client suppress; - suppress output from the server" << 00497 endl; 00498 cout << 00499 " client output to screen; - display server output to the screen" 00500 << endl; 00501 cout << 00502 " client output to <file>; - display server output to specified file" 00503 << endl; 00504 cout << endl; 00505 cout << 00506 "Any commands beginning with 'client' must end with a semicolon" << 00507 endl; 00508 cout << endl; 00509 cout << "To display the list of commands available from the server " 00510 << "please type the command 'show help;'" << endl; 00511 cout << endl; 00512 cout << endl; 00513 } 00514 00521 void 00522 StandAloneClient::dump(ostream & strm) const 00523 { 00524 strm << BESIndent::LMarg << "StandAloneClient::dump - (" 00525 << (void *) this << ")" << endl; 00526 BESIndent::Indent(); 00527 strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl; 00528 strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl; 00529 BESIndent::UnIndent(); 00530 }