kjavaprocess.cpp Source File (khtml Library)

| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kjavaprocess.cpp

    00001 /* This file is part of the KDE project
    00002  *
    00003  * Copyright (C) 2000 Richard Moore <rich@kde.org>
    00004  *               2000 Wynn Wilkes <wynnw@caldera.com>
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the GNU Library General Public
    00008  * License as published by the Free Software Foundation; either
    00009  * version 2 of the License, or (at your option) any later version.
    00010  *
    00011  * This library is distributed in the hope that it will be useful,
    00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014  * Library General Public License for more details.
    00015  *
    00016  * You should have received a copy of the GNU Library General Public License
    00017  * along with this library; see the file COPYING.LIB.  If not, write to
    00018  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00019  * Boston, MA 02111-1307, USA.
    00020  */
    00021
    00022 #include "kjavaprocess.h"
    00023
    00024 #include <kdebug.h>
    00025 #include <kio/kprotocolmanager.h>
    00026
    00027 #include <qtextstream.h>
    00028 #include <qmap.h>
    00029
    00030 #include <config.h>
    00031
    00032 #include <unistd.h>
    00033 #include <qptrlist.h>
    00034 #include <sys/time.h>
    00035 #include <sys/types.h>
    00036 #include <unistd.h>
    00037 #include <errno.h>
    00038
    00039 class KJavaProcessPrivate
    00040 {
    00041 friend class KJavaProcess;
    00042 private:
    00043     QString jvmPath;
    00044     QString classPath;
    00045     QString mainClass;
    00046     QString extraArgs;
    00047     QString classArgs;
    00048     QPtrList<QByteArray> BufferList;
    00049     QMap<QString, QString> systemProps;
    00050     QValueList<int> tickets;
    00051     bool processKilled;
    00052     int sync_count;
    00053 };
    00054
    00055 KJavaProcess::KJavaProcess() : KProcess()
    00056 {
    00057     d = new KJavaProcessPrivate;
    00058     d->BufferList.setAutoDelete( true );
    00059     d->processKilled = false;
    00060     d->sync_count = 0;
    00061
    00062     javaProcess = this; //new KProcess();
    00063
    00064     connect( javaProcess, SIGNAL( wroteStdin( KProcess * ) ),
    00065              this, SLOT( slotWroteData() ) );
    00066     connect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
    00067              this, SLOT( slotReceivedData(int, int&) ) );
    00068     connect( javaProcess, SIGNAL( processExited (KProcess *) ),
    00069              this, SLOT( slotExited (KProcess *) ) );
    00070
    00071     d->jvmPath = "java";
    00072     d->mainClass = "-help";
    00073 }
    00074
    00075 KJavaProcess::~KJavaProcess()
    00076 {
    00077     if ( isRunning() )
    00078     {
    00079         kdDebug(6100) << "stopping java process" << endl;
    00080         stopJava();
    00081     }
    00082
    00083     //delete javaProcess;
    00084     delete d;
    00085 }
    00086
    00087 bool KJavaProcess::isRunning()
    00088 {
    00089    return javaProcess->isRunning();
    00090 }
    00091
    00092 bool KJavaProcess::startJava()
    00093 {
    00094    return invokeJVM();
    00095 }
    00096
    00097 void KJavaProcess::stopJava()
    00098 {
    00099    killJVM();
    00100 }
    00101
    00102 void KJavaProcess::setJVMPath( const QString& path )
    00103 {
    00104    d->jvmPath = path;
    00105 }
    00106
    00107 void KJavaProcess::setClasspath( const QString& classpath )
    00108 {
    00109     d->classPath = classpath;
    00110 }
    00111
    00112 void KJavaProcess::setSystemProperty( const QString& name,
    00113                                       const QString& value )
    00114 {
    00115    d->systemProps.insert( name, value );
    00116 }
    00117
    00118 void KJavaProcess::setMainClass( const QString& className )
    00119 {
    00120    d->mainClass = className;
    00121 }
    00122
    00123 void KJavaProcess::setExtraArgs( const QString& args )
    00124 {
    00125    d->extraArgs = args;
    00126 }
    00127
    00128 void KJavaProcess::setClassArgs( const QString& args )
    00129 {
    00130    d->classArgs = args;
    00131 }
    00132
    00133 //Private Utility Functions used by the two send() methods
    00134 QByteArray* KJavaProcess::addArgs( char cmd_code, const QStringList& args )
    00135 {
    00136     //the buffer to store stuff, etc.
    00137     QByteArray* buff = new QByteArray();
    00138     QTextOStream output( *buff );
    00139     char sep = 0;
    00140
    00141     //make space for the command size: 8 characters...
    00142     QCString space( "        " );
    00143     output << space;
    00144
    00145     //write command code
    00146     output << cmd_code;
    00147
    00148     //store the arguments...
    00149     if( args.count() == 0 )
    00150     {
    00151         output << sep;
    00152     }
    00153     else
    00154     {
    00155         for( QStringList::ConstIterator it = args.begin();
    00156              it != args.end(); ++it )
    00157         {
    00158             if( !(*it).isEmpty() )
    00159             {
    00160                 output << (*it).latin1();
    00161             }
    00162             output << sep;
    00163         }
    00164     }
    00165
    00166     return buff;
    00167 }
    00168
    00169 void KJavaProcess::storeSize( QByteArray* buff )
    00170 {
    00171     int size = buff->size() - 8;  //subtract out the length of the size_str
    00172     QString size_str = QString("%1").arg( size, 8 );
    00173     kdDebug(6100) << "KJavaProcess::storeSize, size = " << size_str << endl;
    00174
    00175     const char* size_ptr = size_str.latin1();
    00176     for( int i = 0; i < 8; i++ )
    00177         buff->at(i) = size_ptr[i];
    00178 }
    00179
    00180 void KJavaProcess::sendBuffer( QByteArray* buff )
    00181 {
    00182     d->BufferList.append( buff );
    00183     if( d->BufferList.count() == 1 && d->sync_count == 0)
    00184     {
    00185         popBuffer();
    00186     }
    00187 }
    00188
    00189 void KJavaProcess::sendSync( int ticket, char cmd_code, const QStringList& args ) {
    00190     kdDebug(6100) << ">KJavaProcess::sendSync " << d->sync_count << endl;
    00191     if (d->sync_count++ == 0)
    00192         javaProcess->suspend();
    00193     QByteArray* buff = addArgs( cmd_code, args );
    00194     storeSize( buff );
    00195     int dummy;
    00196     int current_sync_count;
    00197     int size = buff->size();
    00198     char *data = buff->data();
    00199
    00200     d->tickets.append( ticket );
    00201
    00202     fd_set fds;
    00203     timeval tv;
    00204     do {
    00205         FD_ZERO(&fds);
    00206         FD_SET(in[1], &fds);
    00207         tv.tv_sec = 5;
    00208         tv.tv_usec = 0;
    00209         int retval = select(in[1]+1, 0L, &fds, 0L, &tv);
    00210         FD_CLR(in[1], &fds);
    00211         if (retval < 0 && errno == EINTR) {
    00212             continue;
    00213         } else if (retval <= 0) {
    00214             kdError(6100) << "KJavaProcess::sendSync " << retval << endl;
    00215             goto bail_out;
    00216         } else if (KProcess::input_data) {
    00217             KProcess::slotSendData(dummy);
    00218         } else if( d->BufferList.count() > 0) {
    00219             popBuffer();
    00220         } else {
    00221             int nr = ::write(in[1], data, size);
    00222             size -= nr;
    00223             data += nr;
    00224         }
    00225     } while (size > 0);
    00226     current_sync_count = d->sync_count;
    00227     do {
    00228         FD_ZERO(&fds);
    00229         FD_SET(out[0], &fds);
    00230         tv.tv_sec = 15;
    00231         tv.tv_usec = 0;
    00232         kdDebug(6100) << "KJavaProcess::sendSync bf read" << endl;
    00233         int retval = select(out[0]+1, &fds, 0L, 0L, &tv);
    00234         FD_CLR(out[0], &fds);
    00235         if (retval < 0 && errno == EINTR) {
    00236             continue;
    00237         } else if (retval <= 0) {
    00238             kdError(6100) << "KJavaProcess::sendSync timeout " << retval<< endl;
    00239             break;
    00240         } else {
    00241             slotReceivedData(out[0], dummy);
    00242         }
    00243         QValueList<int>::iterator it = d->tickets.find(ticket);
    00244         if (it == d->tickets.end())
    00245             break;
    00246     } while(true);
    00247 bail_out:
    00248     delete buff;
    00249     if (--d->sync_count <= 0) {
    00250         javaProcess->resume();
    00251         if ( d->BufferList.count() > 0 )
    00252             popBuffer();
    00253     }
    00254     kdDebug(6100) << "<KJavaProcess::sendSync " << d->sync_count << endl;
    00255 }
    00256
    00257 void KJavaProcess::syncCommandReceived(int ticket) {
    00258     d->tickets.remove( ticket );
    00259 }
    00260
    00261 void KJavaProcess::send( char cmd_code, const QStringList& args )
    00262 {
    00263     if( isRunning() )
    00264     {
    00265         QByteArray* buff = addArgs( cmd_code, args );
    00266         storeSize( buff );
    00267         kdDebug(6100) << "<KJavaProcess::send " << (int)cmd_code << endl;
    00268         sendBuffer( buff );
    00269     }
    00270 }
    00271
    00272 void KJavaProcess::send( char cmd_code, const QStringList& args,
    00273                          const QByteArray& data )
    00274 {
    00275     if( isRunning() )
    00276     {
    00277         kdDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size() << endl;
    00278
    00279         QByteArray* buff = addArgs( cmd_code, args );
    00280         int cur_size = buff->size();
    00281         int data_size = data.size();
    00282         buff->resize( cur_size + data_size );
    00283         memcpy( buff->data() + cur_size, data.data(), data_size );
    00284
    00285         storeSize( buff );
    00286         sendBuffer( buff );
    00287     }
    00288 }
    00289
    00290 void KJavaProcess::popBuffer()
    00291 {
    00292     QByteArray* buf = d->BufferList.first();
    00293     if( buf )
    00294     {
    00295 //        DEBUG stuff...
    00296 //      kdDebug(6100) << "Sending buffer to java, buffer = >>";
    00297 //        for( unsigned int i = 0; i < buf->size(); i++ )
    00298 //        {
    00299 //            if( buf->at(i) == (char)0 )
    00300 //                kdDebug(6100) << "<SEP>";
    00301 //            else if( buf->at(i) > 0 && buf->at(i) < 10 )
    00302 //                kdDebug(6100) << "<CMD " << (int) buf->at(i) << ">";
    00303 //            else
    00304 //                kdDebug(6100) << buf->at(i);
    00305 //        }
    00306 //        kdDebug(6100) << "<<" << endl;
    00307
    00308         //write the data
    00309         if ( !javaProcess->writeStdin( buf->data(),
    00310                                        buf->size() ) )
    00311         {
    00312             kdError(6100) << "Could not write command" << endl;
    00313         }
    00314     }
    00315 }
    00316
    00317 void KJavaProcess::slotWroteData( )
    00318 {
    00319     //do this here- we can't free the data until we know it went through
    00320     d->BufferList.removeFirst();  //this should delete it since we setAutoDelete(true)
    00321     kdDebug(6100) << "slotWroteData " << d->BufferList.count() << endl;
    00322
    00323     if ( d->BufferList.count() >= 1 && d->sync_count == 0 )
    00324     {
    00325         popBuffer();
    00326     }
    00327 }
    00328
    00329
    00330 bool KJavaProcess::invokeJVM()
    00331 {
    00332
    00333     *javaProcess << d->jvmPath;
    00334
    00335     if( !d->classPath.isEmpty() )
    00336     {
    00337         *javaProcess << "-classpath";
    00338         *javaProcess << d->classPath;
    00339     }
    00340
    00341     //set the system properties, iterate through the qmap of system properties
    00342     for( QMap<QString,QString>::Iterator it = d->systemProps.begin();
    00343          it != d->systemProps.end(); ++it )
    00344     {
    00345         QString currarg;
    00346
    00347         if( !it.key().isEmpty() )
    00348         {
    00349             currarg = "-D" + it.key();
    00350             if( !it.data().isEmpty() )
    00351                 currarg += "=" + it.data();
    00352         }
    00353
    00354         if( !currarg.isEmpty() )
    00355             *javaProcess << currarg;
    00356     }
    00357
    00358     //load the extra user-defined arguments
    00359     if( !d->extraArgs.isEmpty() )
    00360     {
    00361         // BUG HERE: if an argument contains space (-Dname="My name")
    00362         // this parsing will fail. Need more sophisticated parsing
    00363         QStringList args = QStringList::split( " ", d->extraArgs );
    00364         for ( QStringList::Iterator it = args.begin(); it != args.end(); ++it )
    00365             *javaProcess << *it;
    00366     }
    00367
    00368     *javaProcess << d->mainClass;
    00369
    00370     if ( !d->classArgs.isNull() )
    00371         *javaProcess << d->classArgs;
    00372
    00373     kdDebug(6100) << "Invoking JVM now...with arguments = " << endl;
    00374     QString argStr;
    00375     QTextOStream stream( &argStr );
    00376     QValueList<QCString> args = javaProcess->args();
    00377     qCopy( args.begin(), args.end(), QTextOStreamIterator<QCString>( stream, " " ) );
    00378     kdDebug(6100) << argStr << endl;
    00379
    00380     KProcess::Communication flags =  (KProcess::Communication)
    00381                                      (KProcess::Stdin | KProcess::Stdout |
    00382                                       KProcess::NoRead);
    00383
    00384     bool rval = javaProcess->start( KProcess::NotifyOnExit, flags );
    00385     if( rval )
    00386         javaProcess->resume(); //start processing stdout on the java process
    00387     else
    00388         killJVM();
    00389
    00390     return rval;
    00391 }
    00392
    00393 void KJavaProcess::killJVM()
    00394 {
    00395    d->processKilled = true;
    00396    javaProcess->kill();
    00397 }
    00398
    00399 /*  In this method, read one command and send it to the d->appletServer
    00400  *  then return, so we don't block the event handling
    00401  */
    00402 void KJavaProcess::slotReceivedData( int fd, int& )
    00403 {
    00404     //read out the length of the message,
    00405     //read the message and send it to the applet server
    00406     char length[9] = { 0 };
    00407     int num_bytes = ::read( fd, length, 8 );
    00408     if( num_bytes == -1 )
    00409     {
    00410         kdError(6100) << "could not read 8 characters for the message length!!!!" << endl;
    00411         return;
    00412     }
    00413
    00414     QString lengthstr( length );
    00415     bool ok;
    00416     int num_len = lengthstr.toInt( &ok );
    00417     if( !ok )
    00418     {
    00419         kdError(6100) << "could not parse length out of: " << lengthstr << endl;
    00420         return;
    00421     }
    00422
    00423     //now parse out the rest of the message.
    00424     char* msg = new char[num_len];
    00425     num_bytes = ::read( fd, msg, num_len );
    00426     if( num_bytes == -1 ||  num_bytes != num_len )
    00427     {
    00428         kdError(6100) << "could not read the msg, num_bytes = " << num_bytes << endl;
    00429         delete[] msg;
    00430         return;
    00431     }
    00432
    00433     QByteArray qb;
    00434     emit received( qb.duplicate( msg, num_len ) );
    00435     delete[] msg;
    00436 }
    00437
    00438 void KJavaProcess::slotExited( KProcess *process )
    00439 {
    00440   if (process && process == javaProcess) {
    00441     int status = -1;
    00442     if (!d->processKilled) {
    00443      status = javaProcess->exitStatus();
    00444     }
    00445     kdDebug(6100) << "jvm exited with status " << status << endl;
    00446     emit exited(status);
    00447   }
    00448 }
    00449
    00450 #include "kjavaprocess.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:11 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001