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 - executed successfully" << endl )
00245             }
00246             else
00247             {
00248                 // an error has occurred.
00249                 BESDEBUG( "standalone", "BESServerHandler::execute - error occurred" << endl )
00250 
00251                 // flush what we have in the stream to the client
00252                 *_strm << flush ;
00253 
00254                 // transmit the error message. finish_with_error will transmit
00255                 // the error
00256                 interface->finish_with_error( status ) ;
00257 
00258                 switch (status)
00259                 {
00260                     case BES_INTERNAL_FATAL_ERROR:
00261                         {
00262                             cerr << "BES server " << getpid()
00263                                  << ": Status not OK, dispatcher returned value "
00264                                  << status << endl ;
00265                             //string toSend = "FATAL ERROR: server must exit!" ;
00266                             //c->send( toSend ) ;
00267                             exit( 1 ) ;
00268                         }
00269                         break;
00270                     case BES_INTERNAL_ERROR:
00271                     case BES_SYNTAX_USER_ERROR:
00272                     case BES_FORBIDDEN_ERROR:
00273                     case BES_NOT_FOUND_ERROR:
00274                     default:
00275                         break;
00276                 }
00277             }
00278             delete interface ;
00279             interface = 0 ;
00280 
00281             if( show_stream )
00282             {
00283                 CmdPretty::make_pretty( show_stream->str(), *_strm ) ;
00284                 delete show_stream ;
00285                 show_stream = 0 ;
00286             }
00287 
00288             _strm->flush() ;
00289         }
00290     }
00291 }
00292 
00309 void
00310 StandAloneClient::executeCommands( const string &cmd_list, int repeat )
00311 {
00312     _isInteractive = true ;
00313     if( repeat < 1 ) repeat = 1 ;
00314 
00315     CmdTranslation::set_show( false ) ;
00316     try
00317     {
00318         string doc = CmdTranslation::translate( cmd_list ) ;
00319         if( !doc.empty() )
00320         {
00321             executeCommand( doc, repeat ) ;
00322         }
00323     }
00324     catch( BESError &e )
00325     {
00326         CmdTranslation::set_show( false ) ;
00327         _isInteractive = false ;
00328         throw e ;
00329     }
00330     CmdTranslation::set_show( false ) ;
00331     _isInteractive = false ;
00332 }
00333 
00352 void
00353 StandAloneClient::executeCommands(ifstream & istrm, int repeat)
00354 {
00355     _isInteractive = false ;
00356     if( repeat < 1 ) repeat = 1 ;
00357     for( int i = 0; i < repeat; i++ )
00358     {
00359         istrm.clear( ) ;
00360         istrm.seekg( 0, ios::beg ) ;
00361         string cmd ;
00362         while( !istrm.eof() )
00363         {
00364             char line[4096] ;
00365             line[0] = '\0' ;
00366             istrm.getline( line, 4096, '\n' ) ;
00367             cmd += line ;
00368         }
00369         this->executeCommand( cmd, 1 ) ;
00370     }
00371 }
00372 
00388 void
00389 StandAloneClient::interact()
00390 {
00391     _isInteractive = true ;
00392 
00393     cout << endl << endl
00394         << "Type 'exit' to exit the command line client and 'help' or '?' "
00395         << "to display the help screen" << endl << endl ;
00396 
00397     bool done = false ;
00398     while( !done )
00399     {
00400         string message = "" ;
00401         size_t len = this->readLine( message ) ;
00402         if( len == -1 || message == "exit" || message == "exit;" )
00403         {
00404             done = true ;
00405         }
00406         else if( message == "help" || message == "help;" || message == "?" )
00407         {
00408             this->displayHelp() ;
00409         }
00410         else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
00411         {
00412             this->executeCommand( message, 1 ) ;
00413         }
00414         else if( len != 0 && message != "" )
00415         {
00416             CmdTranslation::set_show( false ) ;
00417             try
00418             {
00419                 string doc = CmdTranslation::translate( message ) ;
00420                 if( !doc.empty() )
00421                 {
00422                     this->executeCommand( doc, 1 ) ;
00423                 }
00424             }
00425             catch( BESError &e )
00426             {
00427                 CmdTranslation::set_show( false ) ;
00428                 _isInteractive = false ;
00429                 throw e ;
00430             }
00431             CmdTranslation::set_show( false ) ;
00432         }
00433     }
00434     _isInteractive = false ;
00435 }
00436 
00442 size_t
00443 StandAloneClient::readLine(string & msg)
00444 {
00445     size_t len = 0;
00446     char *buf = (char *) NULL;
00447     buf =::readline("BESClient> ");
00448     if (buf && *buf) {
00449         len = strlen(buf);
00450 #ifdef HAVE_READLINE_HISTORY
00451         add_history(buf);
00452 #endif
00453         if (len > SIZE_COMMUNICATION_BUFFER) {
00454             cerr << __FILE__ << __LINE__
00455                 <<
00456                 ": incoming data buffer exceeds maximum capacity with lenght "
00457                 << len << endl;
00458             exit(1);
00459         } else {
00460             msg = buf;
00461         }
00462     } else {
00463         if (!buf) {
00464             // If a null buffer is returned then this means that EOF is
00465             // returned. This is different from the user just hitting enter,
00466             // which means a character buffer is returned, but is empty.
00467 
00468             // Problem: len is unsigned.
00469             len = -1;
00470         }
00471     }
00472     if (buf) {
00473         free(buf);
00474         buf = (char *) NULL;
00475     }
00476     return len;
00477 }
00478 
00481 void
00482 StandAloneClient::displayHelp()
00483 {
00484     cout << endl;
00485     cout << endl;
00486     cout << "BES Command Line Client Help" << endl;
00487     cout << endl;
00488     cout << "Client commands available:" << endl;
00489     cout <<
00490         "    exit                     - exit the command line interface" <<
00491         endl;
00492     cout << "    help                     - display this help screen" <<
00493         endl;
00494     cout <<
00495         "    client suppress;         - suppress output from the server" <<
00496         endl;
00497     cout <<
00498         "    client output to screen; - display server output to the screen"
00499         << endl;
00500     cout <<
00501         "    client output to <file>; - display server output to specified file"
00502         << endl;
00503     cout << endl;
00504     cout <<
00505         "Any commands beginning with 'client' must end with a semicolon" <<
00506         endl;
00507     cout << endl;
00508     cout << "To display the list of commands available from the server "
00509         << "please type the command 'show help;'" << endl;
00510     cout << endl;
00511     cout << endl;
00512 }
00513 
00520 void
00521 StandAloneClient::dump(ostream & strm) const
00522 {
00523     strm << BESIndent::LMarg << "StandAloneClient::dump - ("
00524         << (void *) this << ")" << endl;
00525     BESIndent::Indent();
00526     strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
00527     strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
00528     BESIndent::UnIndent();
00529 }

Generated on Sat Aug 22 06:04:34 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0