USGS

Isis 3.0 Object Programmers' Reference

Home

Application.cpp

Go to the documentation of this file.
00001 #include "IsisDebug.h"
00002 
00003 #include <cstdio>
00004 #include <sstream>
00005 #include <unistd.h>
00006 #include <sys/wait.h>
00007 #include <errno.h>
00008 extern int errno;
00009 #include <QString>
00010 #include <iostream>
00011 #include <sstream>
00012 #include <QCoreApplication>
00013 
00014 #include "Application.h"
00015 #include "UserInterface.h"
00016 #include "Gui.h"
00017 #include "Constants.h"
00018 #include "Message.h"
00019 #include "SessionLog.h"
00020 #include "System.h"
00021 #include "Preference.h"
00022 #include "iException.h"
00023 #include "CubeManager.h"
00024 
00048 namespace Isis {
00049   Application *iApp = NULL;
00050 
00060   Application::Application (int argc, char *argv[]) {
00061     // Init socket communications
00062     p_socket = -1;
00063     p_childSocket = -1;
00064     p_socketFile = "";
00065     p_ui = NULL;
00066 
00067     // Save the application name
00068     p_appName = argv[0];
00069 
00070     // Get the starting wall clock time
00071     p_datetime = DateTime(&p_startTime);
00072 
00073     // Init
00074     p_startClock = 0;
00075     p_startDirectIO = 0;
00076     p_startPageFaults = 0;
00077     p_startProcessSwaps = 0;
00078     p_BatchlistPass = 0;
00079 
00080     // Get the starting cpu time, direct I/Os, page faults, and swaps
00081     p_startClock = clock();
00082     p_startDirectIO = DirectIO();
00083     p_startPageFaults = PageFaults();
00084     p_startProcessSwaps = ProcessSwaps();
00085 
00086     // Create user interface and log
00087     try {
00088       Isis::Filename f = std::string(argv[0]) + ".xml";
00089 
00090       // Create preferences
00091       Isis::Preference::Preferences(f.Name() == "unitTest.xml");
00092 
00093       if (!f.Exists()) {
00094         f = "$ISISROOT/bin/xml/" + f.Name();
00095         if (!f.Exists()) {
00096           std::string message = Isis::Message::FileOpen(f.Expanded());
00097           throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_);
00098         }
00099       }
00100       std::string xmlfile = f.Expanded();
00101 
00102       p_ui = new Isis::UserInterface(xmlfile,argc,argv);
00103       if (!p_ui->IsInteractive()) {
00104         new QCoreApplication(argc,argv);
00105       }
00106       
00107     } catch (Isis::iException &e) {
00108       exit(e.Report());
00109     }
00110 
00111     iApp = this;
00112   }
00113 
00115   Application::~Application () {
00116     if (HasParent()) {
00117       SendParentData("DONE","");
00118       close(p_childSocket);
00119     }
00120 
00121     if (p_socket >= 0) {
00122       close(p_socket);
00123       remove(p_socketFile.c_str());
00124     }
00125 
00126     if(p_ui) {
00127       delete p_ui;
00128     }
00129   }
00130 
00138   int Application::Exec(void (*funct)()) {
00139     int status = 0;
00140     try {
00141       if (p_ui->IsInteractive()) {
00142         p_ui->TheGui()->Exec(funct);
00143       } else {
00144         if (p_ui->BatchListSize() > 0) {
00145           for (int i=0; i<p_ui->BatchListSize(); i++) {
00146             try {
00147               p_ui->SetBatchList(i);
00148 
00149               if (i != 0) {
00150                 p_datetime = DateTime(&p_startTime);
00151                 p_startClock = clock();
00152                 p_startDirectIO = DirectIO();
00153                 p_startPageFaults = PageFaults();
00154                 p_startProcessSwaps = ProcessSwaps();
00155                 SessionLog::TheLog(true);
00156               }
00157 
00158               funct();
00159               Application::FunctionCleanup();
00160               p_BatchlistPass++;
00161             } catch (Isis::iException &e) {
00162               p_ui->SetErrorList(i);
00163               status = Application::FunctionError(e);
00164               if (p_ui->AbortOnError()) {
00165                 for (int j=(i+1); j<p_ui->BatchListSize(); j++) {
00166                   p_ui->SetErrorList(j);
00167                   p_BatchlistPass++;
00168                 }
00169                 break;
00170               }
00171             }
00172           }
00173         } else {
00174           p_ui->SaveHistory();
00175           // The gui checks everything but not the command line mode so
00176           // verify if necessary. Batchlist verifies on SetBatchList
00177           p_ui->VerifyAll();
00178           funct();
00179           Application::FunctionCleanup();
00180         }
00181       }
00182     } catch (Isis::iException &e) {
00183       status = Application::FunctionError(e);
00184     }
00185 
00186 #if 0
00187     catch (std::exception &e) {
00188       std::string message = e.what ();
00189       Isis::iExceptionSystem i(message,_FILEINFO_);
00190       status = i.Report();
00191     } catch (...) {
00192       std::string message = "Unknown error expection";
00193       Isis::iExceptionSystem i(message,_FILEINFO_);
00194       status = i.Report();
00195     }
00196 #endif
00197 
00198     return status;
00199   }
00200 
00206   PvlObject Application::History() {
00207     PvlObject history(p_ui->ProgramName());
00208     history += Isis::PvlKeyword("IsisVersion",Isis::version);
00209     history += Isis::PvlKeyword("ProgramVersion",p_ui->Version());
00210     QString path = QCoreApplication::applicationDirPath();
00211     history += Isis::PvlKeyword("ProgramPath", path);
00212     history += Isis::PvlKeyword("ExecutionDateTime",p_datetime);
00213     history += Isis::PvlKeyword("HostName",HostName());
00214     history += Isis::PvlKeyword("UserName",UserName());
00215     history += Isis::PvlKeyword("Description",p_ui->Brief());
00216 
00217     // Add the user parameters
00218     Isis::Pvl pvl;
00219     p_ui->CommandLine(pvl);
00220     history.AddGroup(pvl.FindGroup("UserParameters"));
00221 
00222     return history;
00223   }
00224 
00230   PvlGroup Application::Accounting () {
00231     // Grab the ending time to compute connect time
00232     time_t endTime = time(NULL);
00233     double seconds = difftime (endTime,p_startTime);
00234     int minutes = (int) (seconds / 60.0);
00235     seconds = seconds - minutes * 60.0;
00236     int hours = minutes / 60;
00237     minutes = minutes - hours * 60;
00238     char temp[80];
00239     sprintf(temp,"%02d:%02d:%04.1f",hours,minutes,seconds);
00240     std::string conTime = temp;
00241 
00242     // Grab the ending cpu time to compute total cpu time
00243     clock_t endClock = clock();
00244     seconds = (double(endClock) - (double)p_startClock) / CLOCKS_PER_SEC;
00245     minutes = (int) (seconds / 60.0);
00246     seconds = seconds - minutes * 60.0;
00247     hours = minutes / 60;
00248     minutes = minutes - hours * 60;
00249     sprintf(temp,"%02d:%02d:%04.1f",hours,minutes,seconds);
00250     std::string cpuTime = temp;
00251 
00252     // Add this information to the log
00253     PvlGroup acct("Accounting");
00254     acct += Isis::PvlKeyword("ConnectTime",conTime);
00255     acct += Isis::PvlKeyword("CpuTime",cpuTime);
00256 
00257     // Not sure if these are really valuable.  If deemed so then
00258     // uncomment and complete private methods (DirectIO, Pagefaults, and
00259     // ProcessSwaps).
00260     //int directIO = DirectIO();
00261     //int pageFaults = PageFaults();
00262     //int processSwaps = ProcessSwaps();
00263     //acct += Isis::PvlKeyword("DirectIo",directIO);
00264     //acct += Isis::PvlKeyword("PageFaults",pageFaults);
00265     //acct += Isis::PvlKeyword("ProcessSwaps",processSwaps);
00266 
00267     return acct;
00268   }
00269 
00275   int Application::DirectIO() {
00276     return 0 - p_startDirectIO;
00277   }
00278 
00284   int Application::PageFaults() {
00285     return 0 - p_startPageFaults;
00286   }
00287 
00293   int Application::ProcessSwaps() {
00294     return 0 - p_startProcessSwaps;
00295   }
00296 
00302   void Application::Log(PvlGroup &results) {
00303     // Add it to the log file
00304     static bool blankLine = false;
00305     SessionLog::TheLog().AddResults(results);
00306 
00307     // See if the log file will be written to the terminal/gui
00308     if (SessionLog::TheLog().TerminalOutput()) return;
00309 
00310     // See if we should write the info to our parents gui
00311     if (HasParent()) {
00312       std::ostringstream ostr;
00313       if (blankLine) ostr << std::endl;
00314       ostr << results << std::endl;
00315       std::string data = ostr.str();
00316       SendParentData (std::string("LOG"),data);
00317     }
00318 
00319     // Otherwise see if we need to write to our gui
00320     else if (iApp->GetUserInterface().IsInteractive()) {
00321       std::ostringstream ostr;
00322       if (blankLine) ostr << std::endl;
00323       ostr << results << std::endl;
00324       iApp->GetUserInterface().TheGui()->Log(ostr.str());
00325       iApp->GetUserInterface().TheGui()->ShowLog();
00326     }
00327 
00328     // Otherwise its command line mode
00329     else {
00330       if (blankLine) std::cout << std::endl;
00331       std::cout << results << std::endl;
00332     }
00333     blankLine = true;
00334   }
00335 
00341   void Application::GuiLog(Pvl &results) {
00342     // See if we should write the info to our parents gui
00343     if (HasParent()) {
00344       std::ostringstream ostr;
00345       ostr << results << std::endl;
00346       std::string data = ostr.str();
00347       SendParentData (std::string("LOG"),data);
00348     }
00349 
00350     // Otherwise see if we need to write to our gui
00351     else if (iApp->GetUserInterface().IsInteractive()) {
00352       std::ostringstream ostr;
00353       ostr << results << std::endl;
00354       iApp->GetUserInterface().TheGui()->Log(ostr.str());
00355       iApp->GetUserInterface().TheGui()->ShowLog();
00356     }
00357   }
00358 
00364   void Application::GuiLog(PvlGroup &results) {
00365     // See if we should write the info to our parents gui
00366     if (HasParent()) {
00367       std::ostringstream ostr;
00368       ostr << results << std::endl;
00369       std::string data = ostr.str();
00370       SendParentData (std::string("LOG"),data);
00371     }
00372 
00373     // Otherwise see if we need to write to our gui
00374     else if (iApp->GetUserInterface().IsInteractive()) {
00375       std::ostringstream ostr;
00376       ostr << results << std::endl;
00377       iApp->GetUserInterface().TheGui()->Log(ostr.str());
00378       iApp->GetUserInterface().TheGui()->ShowLog();
00379     }
00380   }
00381 
00387   void Application::GuiLog(std::string &results) {
00388     // See if we should write the info to our parents gui
00389     if (HasParent()) {
00390       SendParentData (std::string("LOG"),results);
00391     }
00392 
00393     // Otherwise see if we need to write to our gui
00394     else if (iApp->GetUserInterface().IsInteractive()) {
00395       iApp->GetUserInterface().TheGui()->Log(results);
00396       iApp->GetUserInterface().TheGui()->ShowLog();
00397     }
00398   }
00399 
00405   Isis::UserInterface &Application::GetUserInterface() {
00406     return *iApp->p_ui;
00407   }
00408 
00414   bool Application::HasParent () {
00415     if (iApp == NULL) return false;
00416     if (iApp->p_ui == NULL) return false;
00417     if (iApp->p_ui->ParentId() == 0) return false;
00418     return true;
00419   }
00420 
00426   void Application::SendParentErrors (Isis::PvlObject &errors) {
00427     for (int i=0; i<errors.Groups(); i++) {
00428       std::ostringstream ostr;
00429       ostr << errors.Group(i) << std::endl;
00430       std::string data = ostr.str();
00431       SendParentData (std::string("ERROR"),data);
00432     }
00433   }
00434 
00445   int Application::p_childSocket = -1;
00446   void Application::SendParentData(const std::string code, const std::string &message) {
00447     // See if we need to connect to the parent
00448     if (p_childSocket < 0) {
00449       std::string socketFile = "/tmp/isis_" + Isis::iString(iApp->GetUserInterface().ParentId());
00450       sockaddr_un socketName;
00451       socketName.sun_family = AF_UNIX;
00452       strcpy(socketName.sun_path,socketFile.c_str());
00453       p_childSocket = socket(PF_UNIX,SOCK_STREAM,0);
00454       if (p_childSocket == -1) {
00455         std::string msg = "Unable to create child-to-parent socket [" +
00456                           socketFile + "]";
00457         std::cout << msg << std::endl;
00458         throw Isis::iException::Message(Isis::iException::System,
00459                                         msg,_FILEINFO_);
00460       }
00461 
00462       errno = 0;
00463       int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family);
00464       int status = connect(p_childSocket,(struct sockaddr *)&socketName,len);
00465       if (status == -1) {
00466         std::string msg = "Unable to connect to parent [" +
00467                           Isis::iString(iApp->GetUserInterface().ParentId()) + "] errno = " +
00468                           iString(errno);
00469         std::cout << msg << std::endl;
00470         throw Isis::iException::Message(Isis::iException::System,
00471                                         msg,_FILEINFO_);
00472       }
00473     }
00474 
00475     // Have connection so build data string and send it
00476     std::string data = code;
00477     data += char(27);
00478     if (message != "") {
00479       data += message;
00480       data += char(27);
00481     }
00482 
00483     if (send (p_childSocket,data.c_str(),data.size(),0) < 0) {
00484       std::string msg = "Unable to send to parent [" +
00485                         Isis::iString(iApp->GetUserInterface().ParentId()) + "]";
00486       std::cout << msg << std::endl;
00487       throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00488     }
00489   }
00490 
00496   void Application::FunctionCleanup() {
00497     CubeManager::CleanUp();
00498 
00499     SessionLog::TheLog().Write();
00500 
00501     if (SessionLog::TheLog().TerminalOutput()) {
00502       if (HasParent()) {
00503         std::ostringstream ostr;
00504         ostr << SessionLog::TheLog() << std::endl;
00505         std::string data = ostr.str();
00506         SendParentData (std::string("LOG"),data);
00507       } else if (p_ui->IsInteractive()) {
00508         std::ostringstream ostr;
00509         ostr << SessionLog::TheLog() << std::endl;
00510         p_ui->TheGui()->Log(ostr.str());
00511         p_ui->TheGui()->ShowLog();
00512       } else {
00513         std::cout << SessionLog::TheLog() << std::endl;
00514       }
00515     }
00516 
00517     // If debugging flag on write debugging log
00518     if (p_ui->GetInfoFlag()) {
00519       std::string filename = p_ui->GetInfoFileName();
00520       Pvl log;
00521       iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName;
00522       if (p_BatchlistPass == 0) {
00523         std::stringstream ss ;
00524         ss << SessionLog::TheLog();
00525         ss.clear();
00526         ss >> log;
00527         PvlGroup uname = Isis::GetUnameInfo();
00528         PvlGroup env = Isis::GetEnviromentInfo();
00529         log.AddGroup(uname);
00530         log.AddGroup(env);     
00531       }
00532 
00533       // Write to file
00534       if (filename.compare("") != 0) {
00535 
00536         if (p_BatchlistPass == 0) {
00537           std::ofstream debugingLog (filename.c_str());
00538           if (!debugingLog.good()) {
00539             std::string msg = "Error opening debugging log file [" + filename + "]";
00540             throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00541           }
00542           debugingLog << log << std::endl;
00543           debugingLog << "\n############### User Preferences ################\n" << std::endl;
00544           debugingLog << Preference::Preferences();
00545           debugingLog << "\n############## System Disk Space ################\n" << std::endl;
00546           debugingLog << SystemDiskSpace() << std::endl;
00547           debugingLog << "\n############ Executable Information #############\n" << std::endl;
00548           debugingLog << GetLibraryDependencies(app) << std::endl;
00549           debugingLog.close();
00550         } else {
00551           std::ofstream debugingLog (filename.c_str(),std::ios_base::app);
00552           debugingLog << SessionLog::TheLog() << std::endl;
00553           debugingLog.close();
00554         }        
00555       } else { // Write to std out
00556         if (p_BatchlistPass == 0) {
00557           std::cout << log << std::endl;
00558           std::cout << "\n############### User Preferences ################\n" << std::endl;
00559           std::cout << Preference::Preferences();
00560           std::cout << "\n############## System Disk Space ################\n" << std::endl;
00561           std::cout << SystemDiskSpace() << std::endl;
00562           std::cout << "\n############ Executable Information #############\n" << std::endl;
00563           std::cout << GetLibraryDependencies(app) << std::endl;
00564         } else {
00565           std::cout << SessionLog::TheLog() << std::endl;
00566         }
00567       }
00568     }
00569 
00570 
00571   }
00572 
00582   int Application::FunctionError(Isis::iException &e) {
00583     Pvl errors = e.PvlErrors();
00584     SessionLog::TheLog().AddError(errors);
00585     SessionLog::TheLog().Write();
00586 
00587     if (HasParent()) {
00588       SendParentErrors(errors);
00589     } else if (p_ui->IsInteractive()) {
00590       if (e.IsPvlFormat()) {
00591         std::ostringstream ostr;
00592         ostr << errors << std::endl;
00593         p_ui->TheGui()->LoadMessage(ostr.str());
00594       } else {
00595         p_ui->TheGui()->LoadMessage(e.Errors());
00596       }
00597     } else if (SessionLog::TheLog().TerminalOutput()) {
00598       std::cerr << SessionLog::TheLog() << std::endl;
00599     } else if (e.IsPvlFormat()) {
00600       std::cerr << errors << std::endl;
00601     } else {
00602       std::cerr << e.Errors() << std::endl;
00603     }
00604 
00605     // If debugging flag on write debugging log
00606     if (p_ui->GetInfoFlag()) {
00607       std::string filename = p_ui->GetInfoFileName();
00608       Pvl log;
00609       iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName;
00610       if (p_BatchlistPass == 0) {
00611         std::stringstream ss ;
00612         ss << SessionLog::TheLog();
00613         ss.clear();
00614         ss >> log;
00615         PvlGroup uname = Isis::GetUnameInfo();
00616         PvlGroup env = Isis::GetEnviromentInfo();
00617         log.AddGroup(uname);
00618         log.AddGroup(env);     
00619       }
00620 
00621       // Write to file
00622       if (filename.compare("") != 0) {
00623         if (p_BatchlistPass == 0) {
00624           std::ofstream debugingLog (filename.c_str());
00625           if (!debugingLog.good()) {
00626             std::string msg = "Error opening debugging log file [" + filename + "]";
00627             throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00628           }
00629           debugingLog << log << std::endl;
00630           debugingLog << "\n############### User Preferences ################\n" << std::endl;
00631           debugingLog << Preference::Preferences();
00632           debugingLog << "\n############ System Disk Space #############\n" << std::endl;
00633           debugingLog << SystemDiskSpace() << std::endl;
00634           debugingLog << "\n############ Executable Information #############\n" << std::endl;
00635           debugingLog << GetLibraryDependencies(app) << std::endl;
00636           debugingLog.close();
00637         } else {
00638           std::ofstream debugingLog (filename.c_str(),std::ios_base::app);
00639           debugingLog << SessionLog::TheLog() << std::endl;
00640           debugingLog.close();
00641         }        
00642       } else { // Write to std out
00643         if (p_BatchlistPass == 0) {
00644           std::cout << log << std::endl;
00645           std::cout << "\n############### User Preferences ################\n" << std::endl;
00646           std::cout << Preference::Preferences();
00647           std::cout << "\n############ System Disk Space #############\n" << std::endl;
00648           std::cout << SystemDiskSpace() << std::endl;
00649           std::cout << "\n############ Executable Information #############\n" << std::endl;
00650           std::cout << GetLibraryDependencies(app) << std::endl;
00651         } else {
00652           std::cout << SessionLog::TheLog() << std::endl;
00653         }
00654       }
00655     }
00656 
00657     int errorType = (int)e.Type();
00658     e.Clear();
00659     return errorType;
00660   }
00661 
00668   void Application::GuiReportError(Isis::iException &e) {
00669     Pvl errors = e.PvlErrors();
00670     if (e.Type() == Isis::iException::Cancel) {
00671       e.Clear ();
00672       p_ui->TheGui()->ProgressText ("Stopped");
00673     }
00674     if (e.IsPvlFormat()) {
00675       std::ostringstream ostr;
00676       ostr << errors << std::endl;
00677       p_ui->TheGui()->LoadMessage(ostr.str());
00678     } else {
00679       p_ui->TheGui()->LoadMessage(e.Errors());
00680     }
00681 
00682     if (p_ui->TheGui()->ShowWarning ()) exit (0);
00683     p_ui->TheGui()->ProgressText ("Error");
00684     e.Clear();
00685   }
00686 
00693   QString Application::p_appName("Unknown");
00694   std::string Application::Name() {
00695     return p_appName.toStdString();
00696   }
00697 
00705   void Application::UpdateProgress(const std::string &text, bool print) {
00706     if (HasParent()) {
00707       std::string msg = p_ui->ProgramName() + ": " + text;
00708       SendParentData(std::string("PROGRESSTEXT"),msg);
00709     } else if (p_ui->IsInteractive()) {
00710       p_ui->TheGui()->ProgressText(text);
00711     } else if (print) {
00712       std::string msg = p_ui->ProgramName() + ": " + text;
00713       std::cout << msg << std::endl;
00714     }
00715   }
00716 
00724   void Application::UpdateProgress(int percent, bool print) {
00725     if (HasParent()) {
00726       std::string data = Isis::iString(percent);
00727       SendParentData(std::string("PROGRESS"),data);
00728     } else if (p_ui->IsInteractive()) {
00729       p_ui->TheGui()->Progress(percent);
00730     } else if (print) {
00731       if (percent < 100) {
00732         std::cout << percent << "% Processed\r" << std::flush;
00733       } else {
00734         std::cout << percent << "% Processed" << std::endl;
00735       }
00736     }
00737   }
00738 
00745   void Application::ProcessGuiEvents() {
00746     if (p_ui->IsInteractive()) {
00747       bool cancel = p_ui->TheGui()->ProcessEvents();
00748       if (cancel) {
00749         throw Isis::iException::Message(Isis::iException::Cancel,"",_FILEINFO_);
00750       }
00751     }
00752   }
00753 
00764   void Application::Exec(const std::string &program, const std::string &parameters) {
00765     // Setup the command line
00766     Isis::Filename bin(program);
00767     if (!bin.Exists()) {
00768       bin = "$ISISROOT/bin/" + program;
00769     }
00770     //Isis::Filename bin("$ISISROOT/bin/"+program);
00771     std::string command = bin.Expanded() + " " + parameters;
00772 
00773     // If we are interactive we must do an asychronous execute
00774     // so we can watch our socket
00775     if (p_ui->IsInteractive()) {
00776       p_pid = getpid();
00777       pid_t childPid;
00778       if ((childPid = fork()) == -1) {
00779         std::string msg = "Unable to execute command [" + command + "]";
00780         throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00781       }
00782 
00783       if (childPid != 0) {
00784         EstablishConnections();
00785         ParentFork(command,program);
00786         ProcessGuiEvents();
00787       } else {
00788         ChildFork(command);
00789       }
00790     }
00791     // Handle command line programs invoked by GUI programs
00792     else if (HasParent()) {
00793       SendParentData("DISCONNECT","");
00794       close(p_childSocket);
00795       p_childSocket = -1;
00796       command += " -pid=" + Isis::iString((int)p_ui->ParentId());
00797       Isis::System(command);
00798       SendParentData("RECONNECT","");
00799     }
00800     // Otherwise just execute the command and wait for it to finish
00801     else {
00802       Isis::System(command);
00803     }
00804   }
00805 
00815   void Application::EstablishConnections() {
00816     if (p_socket != -1) return;
00817 
00818     // Create a socket
00819     if ((p_socket = socket(PF_UNIX,SOCK_STREAM,0)) == -1) {
00820       std::string msg = "Unable to create socket";
00821       throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00822     }
00823 
00824     // Get the process id and create a unique filename
00825     p_socketFile = "/tmp/isis_" + Isis::iString((int)p_pid);
00826 
00827     // Bind the file to the socket
00828     p_socketName.sun_family = AF_UNIX;
00829     strcpy(p_socketName.sun_path,p_socketFile.c_str());
00830     int len = strlen(p_socketName.sun_path) + sizeof(p_socketName.sun_family);
00831     if (bind(p_socket,(struct sockaddr *)&p_socketName,len) == -1) {
00832       std::string msg = "Unable to bind to socket [" + p_socketFile + "]";
00833       throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00834     }
00835 
00836     // Set up to listen to the socket
00837     if (listen(p_socket,5) == -1) {
00838       std::string msg = "Unable to listen to socket [" + p_socketFile + "]";
00839       throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00840     }
00841   }
00842 
00848   void Application::ChildFork(const std::string &commandLine) {
00849     // The child fork doesn't have the socket
00850     p_socket = -1;
00851 
00852     // Append the pid as an argument
00853     std::string command = commandLine + " -pid=" + Isis::iString((int)p_pid);
00854 
00855     // Run the command
00856     int status = system (command.c_str());
00857 
00858     int childSocket = socket(PF_UNIX,SOCK_STREAM,0);
00859     if (childSocket == -1) {
00860       std::cout << "couldn't create socket to parent fork" << std::endl << std::flush;
00861       // What should we dooo???? How do we stop the parent?
00862       exit(255);
00863     }
00864 
00865     sockaddr_un socketName;
00866     socketName.sun_family = AF_UNIX;
00867     iString socketFile = "/tmp/isis_" + Isis::iString((int)p_pid);
00868     strcpy(socketName.sun_path,socketFile.c_str());
00869 
00870     int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family);
00871     if (connect(childSocket,(struct sockaddr *)&socketName,len) == -1) {
00872       std::cout << "couldn't connect to parent fork" << std::endl << std::flush;
00873       // What should we dooo???? How do we stop the parent?
00874       exit(255);
00875     }
00876 
00877     if (status != 0) {
00878       char terminate[10] = "TERMINATE";
00879       terminate[9] = 27; // escape character
00880       if (send (childSocket,terminate,sizeof(terminate),0) < 0) {
00881         std::cout << "couldn't send terminate to parent fork" << std::endl << std::flush;
00882         // What should we dooo????  How do we stop the parent?
00883         exit(255);
00884       }
00885     } else {
00886       char success[8] = "SUCCESS";
00887       success[7] = 27; // escape character
00888       if (send (childSocket,success,sizeof(success),0) < 0) {
00889         std::cout << "couldn't send success to parent fork" << std::endl << std::flush;
00890         // What should we dooo???? How do we stop the parent?
00891         exit(255);
00892       }
00893     }
00894 
00895     close(childSocket);
00896     exit(0);
00897   }
00898 
00909   void Application::ParentFork(const std::string &command, const std::string &program) {
00910     // Try to accept a connection from the program our child fork executed.  If
00911     // the program we ran failed to start then we are waiting for the connection
00912     // in the child fork
00913     p_buffer = "";
00914     p_queue.clear();
00915 
00916     int childForkDone = false;
00917     while (!childForkDone) {
00918       int childSocket = -1;
00919       while (childSocket == -1) {
00920         errno = 0;
00921         socklen_t len = sizeof(p_socketName);
00922         childSocket = accept(p_socket, (struct sockaddr *)&p_socketName, &len);
00923         if (childSocket == -1) {
00924           if (errno != EINTR) {
00925             std::cout << "accept errno = " << errno << std::endl << std::flush;
00926             std::string msg = "Unable to accept socket connection [" +
00927                               p_socketFile + "] from child process";
00928             throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00929           }
00930         }
00931       }
00932 
00933       // Looks like we are the parent so we must wait for input to come from
00934       // the child.
00935       bool done = false;
00936       while (!done) {
00937         WaitForCommand(childSocket);
00938 
00939         while (p_queue.size() > 0) {
00940           if (p_queue[0] == "DONE") {
00941             p_queue.erase(p_queue.begin());
00942             done = true;
00943           } else if (p_queue[0] == "DISCONNECT") {
00944             p_queue.erase(p_queue.begin());
00945             done = true;
00946           } else if (p_queue[0] == "RECONNECT") {
00947             p_queue.erase(p_queue.begin());
00948           } else if (p_queue[0] == "SUCCESS") {
00949             p_queue.erase(p_queue.begin());
00950             done = true;
00951             childForkDone = true;
00952           } else if (p_queue[0] == "TERMINATE") {
00953             // Should only happen if child fork could not fire off the process
00954             p_queue.erase(p_queue.begin());
00955             std::string msg = "Unable to execute command [" + command + "]";
00956             throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
00957           } else if (p_queue[0] == "ERROR") {
00958             p_queue.erase(p_queue.begin());
00959             while (p_queue.size() == 0) WaitForCommand(childSocket);
00960             std::stringstream str;
00961             str << p_queue[0];
00962             p_queue.erase(p_queue.begin());
00963 
00964             Isis::Pvl error;
00965             str >> error;
00966 
00967             for (int i=0; i<error.Groups(); i++) {
00968               Isis::PvlGroup &g = error.Group(i);
00969               std::string eclass = g["Class"];
00970               std::string emsg = g["Message"];
00971               int ecode = g["Code"];
00972               std::string efile = g["File"];
00973               int eline = g["Line"];
00974 
00975               Isis::iException::Message((Isis::iException::errType)ecode,
00976                                         emsg,(char *)efile.c_str(),eline);
00977             }
00978           } else if (p_queue[0] == "PROGRESSTEXT") {
00979             p_queue.erase(p_queue.begin());
00980             while (p_queue.size() == 0) WaitForCommand(childSocket);
00981             p_ui->TheGui()->ProgressText(p_queue[0]);
00982             p_ui->TheGui()->Progress(0);
00983             p_queue.erase(p_queue.begin());
00984           } else if (p_queue[0] == "PROGRESS") {
00985             p_queue.erase(p_queue.begin());
00986             while (p_queue.size() == 0) WaitForCommand(childSocket);
00987             p_ui->TheGui()->Progress(Isis::iString(p_queue[0]).ToInteger());
00988             p_queue.erase(p_queue.begin());
00989           } else if (p_queue[0] == "LOG") {
00990             p_queue.erase(p_queue.begin());
00991             while (p_queue.size() == 0) WaitForCommand(childSocket);
00992 
00993             std::stringstream str;
00994             str << p_queue[0];
00995             p_queue.erase(p_queue.begin());
00996 
00997             p_ui->TheGui()->Log(str.str());
00998           } else {
00999             std::string msg = "Unknown command [" + p_queue[0];
01000             msg += "] on socket [" + p_socketFile + "]";
01001             throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
01002           }
01003           ProcessGuiEvents();
01004         }
01005       }
01006       close(childSocket);
01007     }
01008   }
01009 
01019   void Application::WaitForCommand (int childSocket) {
01020 
01021     // Now we are ready to receive commands from our child (like in real
01022     // life) so receive the command
01023     int bytes;
01024     char buf[1024*1024];
01025     if ((bytes = recv(childSocket,&buf,1024*1024,0)) < 0) {
01026       std::string msg = "Unable to read from socket [" + p_socketFile + "]";
01027       throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_);
01028     }
01029 
01030     // Push everything onto our string buffer
01031     for (int i=0; i<bytes; i++) p_buffer += buf[i];
01032 
01033     // Move esc delimited strings to our command queue
01034     std::string::size_type pos;
01035     while ((pos = p_buffer.find(27)) != std::string::npos) {
01036       p_queue.push_back(p_buffer.substr(0,pos));
01037       p_buffer.erase(0,pos+1);
01038     }
01039   }
01040 
01048   std::string Application::DateTime (time_t *curtime) {
01049     time_t startTime = time(NULL);
01050     if (curtime != 0) *curtime = startTime;
01051     struct tm *tmbuf = localtime(&startTime);
01052     char timestr[80];
01053     strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf);
01054     return(std::string) timestr;
01055   }
01056 
01062   std::string Application::UserName () {
01063     std::string user = "Unknown";
01064     char *userPtr = getenv("USER");
01065     if (userPtr != NULL) user = userPtr;
01066     return user;
01067   }
01068 
01074   std::string Application::HostName () {
01075     std::string host = "Unknown";
01076     char *hostPtr = getenv("HOST");
01077     if (hostPtr == NULL) hostPtr = getenv ("HOSTNAME");
01078     if (hostPtr != NULL) host = hostPtr;
01079     return host;
01080   }
01081 
01082 }  //end namespace isis
01083