CmdClient.cc

Go to the documentation of this file.
00001 // CmdClient.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,2005 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 <map>
00039 
00040 using std::cout;
00041 using std::endl;
00042 using std::cerr;
00043 using std::ofstream;
00044 using std::ios;
00045 using std::map;
00046 
00047 #ifdef HAVE_LIBREADLINE
00048 #  if defined(HAVE_READLINE_READLINE_H)
00049 #    include <readline/readline.h>
00050 #  elif defined(HAVE_READLINE_H)
00051 #    include <readline.h>
00052 #  else                         /* !defined(HAVE_READLINE_H) */
00053 extern "C" {
00054     char *readline(const char *);
00055 }
00056 #  endif                        /* !defined(HAVE_READLINE_H) */
00057 char *cmdline = NULL;
00058 #else                           /* !defined(HAVE_READLINE_READLINE_H) */
00059   /* no readline */
00060 #endif                          /* HAVE_LIBREADLINE */
00061 
00062 #ifdef HAVE_READLINE_HISTORY
00063 #  if defined(HAVE_READLINE_HISTORY_H)
00064 #    include <readline/history.h>
00065 #  elif defined(HAVE_HISTORY_H)
00066 #    include <history.h>
00067 #  else                         /* !defined(HAVE_HISTORY_H) */
00068 extern "C" {
00069     int add_history(const char *);
00070     int write_history(const char *);
00071     int read_history(const char *);
00072 }
00073 #  endif                        /* defined(HAVE_READLINE_HISTORY_H) */
00074   /* no history */
00075 #endif                          /* HAVE_READLINE_HISTORY */
00076 #define SIZE_COMMUNICATION_BUFFER 4096*4096
00077 #include "CmdClient.h"
00078 #include "PPTClient.h"
00079 #include "BESDebug.h"
00080 
00081 CmdClient::~CmdClient()
00082 {
00083     if (_strmCreated && _strm) {
00084         _strm->flush();
00085         delete _strm;
00086         _strm = 0;
00087     } else if (_strm) {
00088         _strm->flush();
00089     }
00090     if (_client) {
00091         delete _client;
00092         _client = 0;
00093     }
00094 }
00095 
00110 void
00111 CmdClient::startClient(const string & host, int portVal, int timeout)
00112 {
00113     _client = new PPTClient(host, portVal, timeout);
00114     _client->initConnection();
00115 }
00116 
00126 void
00127 CmdClient::startClient(const string & unixStr, int timeout)
00128 {
00129     _client = new PPTClient(unixStr, timeout);
00130     _client->initConnection();
00131 }
00132 
00141 void
00142 CmdClient::shutdownClient()
00143 {
00144     if( _client )
00145         _client->closeConnection();
00146 }
00147 
00164 void
00165 CmdClient::setOutput(ostream * strm, bool created)
00166 {
00167     if (_strmCreated && _strm) {
00168         _strm->flush();
00169         delete _strm;
00170     } else if (_strm) {
00171         _strm->flush();
00172     }
00173     _strm = strm;
00174     _strmCreated = created;
00175 }
00176 
00187 void
00188 CmdClient::executeClientCommand(const string & cmd)
00189 {
00190     string suppress = "suppress";
00191     if (cmd.compare(0, suppress.length(), suppress) == 0) {
00192         setOutput(NULL, false);
00193     } else {
00194         string output = "output to";
00195         if (cmd.compare(0, output.length(), output) == 0) {
00196             string subcmd = cmd.substr(output.length() + 1);
00197             string screen = "screen";
00198             if (subcmd.compare(0, screen.length(), screen) == 0) {
00199                 setOutput(&cout, false);
00200             } else {
00201                 // subcmd is the name of the file - the semicolon
00202                 string file = subcmd.substr(0, subcmd.length() - 1);
00203                 ofstream *fstrm = new ofstream(file.c_str(), ios::app);
00204                 if (!(*fstrm)) {
00205                     if( fstrm ) delete fstrm ;
00206                     cerr << "Unable to set client output to file " << file
00207                          << endl;
00208                 } else {
00209                     setOutput(fstrm, true);
00210                 }
00211             }
00212         } else {
00213             cerr << "Improper client command " << cmd << endl;
00214         }
00215     }
00216 }
00217 
00232 void
00233 CmdClient::executeCommand(const string & cmd, int repeat )
00234 {
00235     string client = "client";
00236     if (cmd.compare(0, client.length(), client) == 0) {
00237         executeClientCommand(cmd.substr(client.length() + 1));
00238     } else {
00239         if( repeat < 1 ) repeat = 1 ;
00240         for( int i = 0; i < repeat; i++ )
00241         {
00242             BESDEBUG( "cmdln", "cmdclient sending " << cmd << endl )
00243             map<string,string> extensions ;
00244             _client->send(cmd, extensions);
00245 
00246             BESDEBUG( "cmdln", "cmdclient receiving " << endl )
00247             // keep reading till we get the last chunk, send to _strm
00248             bool done = false ;
00249             while( !done )
00250             {
00251                 done = _client->receive( extensions, _strm ) ;
00252                 if( extensions["status"] == "error" )
00253                 {
00254                     // If there is an error, just flush what I have
00255                     // and continue on.
00256                     _strm->flush() ;
00257                 }
00258             }
00259             if( BESDebug::IsSet( "cmdln" ) )
00260             {
00261                 BESDEBUG( "cmdln", "extensions:" << endl )
00262                 map<string,string>::const_iterator i = extensions.begin() ;
00263                 map<string,string>::const_iterator e = extensions.end() ;
00264                 for( ; i != e; i++ )
00265                 {
00266                     BESDEBUG( "cmdln", "  " << (*i).first << " = " << (*i).second << endl )
00267                 }
00268                 BESDEBUG( "cmdln", "cmdclient done receiving " << endl )
00269             }
00270 
00271             _strm->flush();
00272         }
00273     }
00274 }
00275 
00290 void
00291 CmdClient::executeCommands(const string & cmd_list, int repeat)
00292 {
00293     if( repeat < 1 ) repeat = 1 ;
00294     for( int i = 0; i < repeat; i++ )
00295     {
00296         std::string::size_type start = 0;
00297         std::string::size_type end = 0;
00298         while ((end = cmd_list.find(';', start)) != string::npos) {
00299             string cmd = cmd_list.substr(start, end - start + 1);
00300             executeCommand(cmd, 1);
00301             start = end + 1;
00302         }
00303     }
00304 }
00305 
00327 void
00328 CmdClient::executeCommands(ifstream & istrm, int repeat)
00329 {
00330     if( repeat < 1 ) repeat = 1 ;
00331     for( int i = 0; i < repeat; i++ )
00332     {
00333         istrm.clear( ) ;
00334         istrm.seekg( 0, ios::beg ) ;
00335         string cmd;
00336         bool done = false;
00337         while (!done) {
00338             char line[4096];
00339             line[0] = '\0';
00340             istrm.getline(line, 4096, '\n');
00341             string nextLine = line;
00342             if (nextLine == "") {
00343                 if (cmd != "") {
00344                     this->executeCommands(cmd, 1);
00345                 }
00346                 done = true;
00347             } else {
00348                 std::string::size_type i = nextLine.find_last_of(';');
00349                 if (i == string::npos) {
00350                     if (cmd == "") {
00351                         cmd = nextLine;
00352                     } else {
00353                         cmd += " " + nextLine;
00354                     }
00355                 } else {
00356                     string sub = nextLine.substr(0, i + 1);
00357                     if (cmd == "") {
00358                         cmd = sub;
00359                     } else {
00360                         cmd += " " + sub;
00361                     }
00362                     this->executeCommands(cmd, 1);
00363                     if (i == nextLine.length() || i == nextLine.length() - 1) {
00364                         cmd = "";
00365                     } else {
00366                         cmd = nextLine.substr(i + 1, nextLine.length());
00367                     }
00368                 }
00369             }
00370         }
00371     }
00372 }
00373 
00389 void
00390 CmdClient::interact()
00391 {
00392     cout << endl << endl
00393         << "Type 'exit' to exit the command line client and 'help' or '?' "
00394         << "to display the help screen" << endl << endl;
00395 
00396     bool done = false;
00397     while (!done) {
00398         string message = "";
00399         size_t len = this->readLine(message);
00400         if (len == -1 || message == "exit" || message == "exit;") {
00401             done = true;
00402         } else if (message == "help" || message == "help;"
00403                    || message == "?") {
00404             this->displayHelp();
00405         } else if (len != 0 && message != "") {
00406             if (message[message.length() - 1] != ';') {
00407                 cerr << "Commands must end with a semicolon" << endl;
00408             } else {
00409                 this->executeCommands(message, 1);
00410             }
00411         }
00412     }
00413 }
00414 
00420 size_t
00421 CmdClient::readLine(string & msg)
00422 {
00423     size_t len = 0;
00424     char *buf = (char *) NULL;
00425     buf =::readline("BESClient> ");
00426     if (buf && *buf) {
00427         len = strlen(buf);
00428 #ifdef HAVE_READLINE_HISTORY
00429         add_history(buf);
00430 #endif
00431         if (len > SIZE_COMMUNICATION_BUFFER) {
00432             cerr << __FILE__ << __LINE__
00433                 <<
00434                 ": incoming data buffer exceeds maximum capacity with lenght "
00435                 << len << endl;
00436             exit(1);
00437         } else {
00438             msg = buf;
00439         }
00440     } else {
00441         if (!buf) {
00442             // If a null buffer is returned then this means that EOF is
00443             // returned. This is different from the user just hitting enter,
00444             // which means a character buffer is returned, but is empty.
00445             
00446             // Problem: len is unsigned.
00447             len = -1;
00448         }
00449     }
00450     if (buf) {
00451         free(buf);
00452         buf = (char *) NULL;
00453     }
00454     return len;
00455 }
00456 
00459 void
00460 CmdClient::displayHelp()
00461 {
00462     cout << endl;
00463     cout << endl;
00464     cout << "BES Command Line Client Help" << endl;
00465     cout << endl;
00466     cout << "Client commands available:" << endl;
00467     cout <<
00468         "    exit                     - exit the command line interface" <<
00469         endl;
00470     cout << "    help                     - display this help screen" <<
00471         endl;
00472     cout <<
00473         "    client suppress;         - suppress output from the server" <<
00474         endl;
00475     cout <<
00476         "    client output to screen; - display server output to the screen"
00477         << endl;
00478     cout <<
00479         "    client output to <file>; - display server output to specified file"
00480         << endl;
00481     cout << endl;
00482     cout <<
00483         "Any commands beginning with 'client' must end with a semicolon" <<
00484         endl;
00485     cout << endl;
00486     cout << "To display the list of commands available from the server "
00487         << "please type the command 'show help;'" << endl;
00488     cout << endl;
00489     cout << endl;
00490 }
00491 
00496 bool
00497 CmdClient::isConnected()
00498 {
00499     if (_client)
00500         return _client->isConnected();
00501     return false;
00502 }
00503 
00506 void
00507 CmdClient::brokenPipe()
00508 {
00509     if (_client)
00510         _client->brokenPipe();
00511 }
00512 
00519 void
00520 CmdClient::dump(ostream & strm) const
00521 {
00522     strm << BESIndent::LMarg << "CmdClient::dump - ("
00523         << (void *) this << ")" << endl;
00524     BESIndent::Indent();
00525     if (_client) {
00526         strm << BESIndent::LMarg << "client:" << endl;
00527         BESIndent::Indent();
00528         _client->dump(strm);
00529         BESIndent::UnIndent();
00530     } else {
00531         strm << BESIndent::LMarg << "client: null" << endl;
00532     }
00533     strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl;
00534     strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl;
00535     BESIndent::UnIndent();
00536 }

Generated on Tue Mar 4 23:13:36 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1