StandAloneClient.cc

Go to the documentation of this file.
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 #include "CmdPretty.h"
00087 
00088 StandAloneClient::~StandAloneClient()
00089 {
00090     if (_strmCreated && _strm) {
00091         _strm->flush();
00092         delete _strm;
00093         _strm = 0;
00094     } else if (_strm) {
00095         _strm->flush();
00096     }
00097 }
00098 
00115 void
00116 StandAloneClient::setOutput(ostream * strm, bool created)
00117 {
00118     if (_strmCreated && _strm) {
00119         _strm->flush();
00120         delete _strm;
00121     } else if (_strm) {
00122         _strm->flush();
00123     }
00124     _strm = strm;
00125     _strmCreated = created;
00126 }
00127 
00139 void
00140 StandAloneClient::executeClientCommand( const string &cmd )
00141 {
00142     string suppress = "suppress" ;
00143     if( cmd.compare( 0, suppress.length(), suppress ) == 0 )
00144     {
00145         setOutput( NULL, false ) ;
00146         return ;
00147     }
00148 
00149     string output = "output to" ;
00150     if( cmd.compare( 0, output.length(), output ) == 0 )
00151     {
00152         string subcmd = cmd.substr( output.length() + 1 ) ;
00153         string screen = "screen" ;
00154         if( subcmd.compare( 0, screen.length(), screen ) == 0 )
00155         {
00156             setOutput( &cout, false ) ;
00157         }
00158         else
00159         {
00160             // subcmd is the name of the file - then semicolon
00161             string file = subcmd.substr( 0, subcmd.length() - 1 ) ;
00162             ofstream *fstrm = new ofstream( file.c_str(), ios::app ) ;
00163             if( fstrm && !(*fstrm) )
00164             {
00165                         delete fstrm ;
00166                 cerr << "Unable to set client output to file " << file
00167                      << endl ;
00168             }
00169             else
00170             {
00171                 setOutput( fstrm, true ) ;
00172             }
00173         }
00174         return ;
00175     }
00176 
00177     // load commands from an input file and run them
00178     string load = "load" ;
00179     if( cmd.compare( 0, load.length(), load ) == 0 )
00180     {
00181         string file = cmd.substr( load.length() + 1,
00182                                   cmd.length() - load.length() - 2 ) ;
00183         ifstream fstrm( file.c_str() ) ;
00184         if( !fstrm )
00185         {
00186             cerr << "Unable to load commands from file " << file
00187                  << ": file does not exist or failed to open file" << endl ;
00188         }
00189         else
00190         {
00191             executeCommands( fstrm, 1 ) ;
00192         }
00193 
00194         return ;
00195     }
00196 
00197     cerr << "Improper client command " << cmd << endl ;
00198 }
00199 
00212 void
00213 StandAloneClient::executeCommand( const string & cmd, int repeat )
00214 {
00215     string client = "client" ;
00216     if( cmd.compare( 0, client.length(), client ) == 0 )
00217     {
00218         executeClientCommand( cmd.substr( client.length() + 1 ) ) ;
00219     }
00220     else
00221     {
00222         if( repeat < 1 ) repeat = 1 ;
00223         for( int i = 0; i < repeat; i++ )
00224         {
00225             ostringstream *show_stream = 0 ;
00226             if( CmdTranslation::is_show() )
00227             {
00228                 show_stream = new ostringstream ;
00229             }
00230             BESDEBUG( "standalone", "cmdclient sending " << cmd << endl ) ;
00231             BESXMLInterface *interface = 0 ;
00232             if( show_stream )
00233             {
00234                 interface = new BESXMLInterface( cmd, show_stream ) ;
00235             }
00236             else
00237             {
00238                 interface = new BESXMLInterface( cmd, _strm ) ;
00239             }
00240             int status = interface->execute_request( "standalone" ) ;
00241 
00242             if( status == 0 )
00243             {
00244                 BESDEBUG( "standalone", "BESServerHandler::execute - "
00245                                         << "executed successfully" << endl ) ;
00246             }
00247             else
00248             {
00249                 // an error has occurred.
00250                 BESDEBUG( "standalone", "BESServerHandler::execute - "
00251                                         "error occurred" << endl ) ;
00252 
00253                 // flush what we have in the stream to the client
00254                 *_strm << flush ;
00255 
00256                 // transmit the error message. finish_with_error will transmit
00257                 // the error
00258                 interface->finish_with_error( status ) ;
00259 
00260                 switch (status)
00261                 {
00262                     case BES_INTERNAL_FATAL_ERROR:
00263                         {
00264                             cerr << "BES server " << getpid()
00265                                  << ": Status not OK, dispatcher returned value "
00266                                  << status << endl ;
00267                             //string toSend = "FATAL ERROR: server must exit!" ;
00268                             //c->send( toSend ) ;
00269                             exit( 1 ) ;
00270                         }
00271                         break;
00272                     case BES_INTERNAL_ERROR:
00273                     case BES_SYNTAX_USER_ERROR:
00274                     case BES_FORBIDDEN_ERROR:
00275                     case BES_NOT_FOUND_ERROR:
00276                     default:
00277                         break;
00278                 }
00279             }
00280             delete interface ;
00281             interface = 0 ;
00282 
00283             if( show_stream )
00284             {
00285                 CmdPretty::make_pretty( show_stream->str(), *_strm ) ;
00286                 delete show_stream ;
00287                 show_stream = 0 ;
00288             }
00289 
00290             _strm->flush() ;
00291         }
00292     }
00293 }
00294 
00311 void
00312 StandAloneClient::executeCommands( const string &cmd_list, int repeat )
00313 {
00314     _isInteractive = true ;
00315     if( repeat < 1 ) repeat = 1 ;
00316 
00317     CmdTranslation::set_show( false ) ;
00318     try
00319     {
00320         string doc = CmdTranslation::translate( cmd_list ) ;
00321         if( !doc.empty() )
00322         {
00323             executeCommand( doc, repeat ) ;
00324         }
00325     }
00326     catch( BESError &e )
00327     {
00328         CmdTranslation::set_show( false ) ;
00329         _isInteractive = false ;
00330         throw e ;
00331     }
00332     CmdTranslation::set_show( false ) ;
00333     _isInteractive = false ;
00334 }
00335 
00354 void
00355 StandAloneClient::executeCommands(ifstream & istrm, int repeat)
00356 {
00357     _isInteractive = false ;
00358     if( repeat < 1 ) repeat = 1 ;
00359     for( int i = 0; i < repeat; i++ )
00360     {
00361         istrm.clear( ) ;
00362         istrm.seekg( 0, ios::beg ) ;
00363         string cmd ;
00364         while( !istrm.eof() )
00365         {
00366             char line[4096] ;
00367             line[0] = '\0' ;
00368             istrm.getline( line, 4096, '\n' ) ;
00369             cmd += line ;
00370         }
00371         this->executeCommand( cmd, 1 ) ;
00372     }
00373 }
00374 
00390 void
00391 StandAloneClient::interact()
00392 {
00393     _isInteractive = true ;
00394 
00395     cout << endl << endl
00396         << "Type 'exit' to exit the command line client and 'help' or '?' "
00397         << "to display the help screen" << endl << endl ;
00398 
00399     bool done = false ;
00400     while( !done )
00401     {
00402         string message = "" ;
00403         size_t len = this->readLine( message ) ;
00404         if( len == -1 || message == "exit" || message == "exit;" )
00405         {
00406             done = true ;
00407         }
00408         else if( message == "help" || message == "help;" || message == "?" )
00409         {
00410             this->displayHelp() ;
00411         }
00412         else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
00413         {
00414             this->executeCommand( message, 1 ) ;
00415         }
00416         else if( len != 0 && message != "" )
00417         {
00418             CmdTranslation::set_show( false ) ;
00419             try
00420             {
00421                 string doc = CmdTranslation::translate( message ) ;
00422                 if( !doc.empty() )
00423                 {
00424                     this->executeCommand( doc, 1 ) ;
00425                 }
00426             }
00427             catch( BESError &e )
00428             {
00429                 CmdTranslation::set_show( false ) ;
00430                 _isInteractive = false ;
00431                 throw e ;
00432             }
00433             CmdTranslation::set_show( false ) ;
00434         }
00435     }
00436     _isInteractive = false ;
00437 }
00438 
00444 size_t
00445 StandAloneClient::readLine(string & msg)
00446 {
00447     size_t len = 0;
00448     char *buf = (char *) NULL;
00449     buf =::readline("BESClient> ");
00450     if (buf && *buf) {
00451         len = strlen(buf);
00452 #ifdef HAVE_READLINE_HISTORY
00453         add_history(buf);
00454 #endif
00455         if (len > SIZE_COMMUNICATION_BUFFER) {
00456             cerr << __FILE__ << __LINE__
00457                 <<
00458                 ": incoming data buffer exceeds maximum capacity with lenght "
00459                 << len << endl;
00460             exit(1);
00461         } else {
00462             msg = buf;
00463         }
00464     } else {
00465         if (!buf) {
00466             // If a null buffer is returned then this means that EOF is
00467             // returned. This is different from the user just hitting enter,
00468             // which means a character buffer is returned, but is empty.
00469 
00470             // Problem: len is unsigned.
00471             len = -1;
00472         }
00473     }
00474     if (buf) {
00475         free(buf);
00476         buf = (char *) NULL;
00477     }
00478     return len;
00479 }
00480 
00483 void
00484 StandAloneClient::displayHelp()
00485 {
00486     cout << endl;
00487     cout << endl;
00488     cout << "BES Command Line Client Help" << endl;
00489     cout << endl;
00490     cout << "Client commands available:" << endl;
00491     cout <<
00492         "    exit                     - exit the command line interface" <<
00493         endl;
00494     cout << "    help                     - display this help screen" <<
00495         endl;
00496     cout <<
00497         "    client suppress;         - suppress output from the server" <<
00498         endl;
00499     cout <<
00500         "    client output to screen; - display server output to the screen"
00501         << endl;
00502     cout <<
00503         "    client output to <file>; - display server output to specified file"
00504         << endl;
00505     cout << endl;
00506     cout <<
00507         "Any commands beginning with 'client' must end with a semicolon" <<
00508         endl;
00509     cout << endl;
00510     cout << "To display the list of commands available from the server "
00511         << "please type the command 'show help;'" << endl;
00512     cout << endl;
00513     cout << endl;
00514 }
00515 
00522 void
00523 StandAloneClient::dump(ostream & strm) const
00524 {
00525     strm << BESIndent::LMarg << "StandAloneClient::dump - ("
00526         << (void *) this << ")" << endl;
00527     BESIndent::Indent();
00528     strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
00529     strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
00530     BESIndent::UnIndent();
00531 }

Generated on Wed May 12 09:53:08 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7