OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3

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 
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 }