# khtml Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | 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
    00035 class KJavaProcessPrivate
    00036 {
    00037 friend class KJavaProcess;
    00038 private:
    00039     QString jvmPath;
    00040     QString classPath;
    00041     QString mainClass;
    00042     QString extraArgs;
    00043     QString classArgs;
    00044     QPtrList<QByteArray> BufferList;
    00045     QMap<QString, QString> systemProps;
    00046     bool processKilled;
    00047 };
    00048
    00049 KJavaProcess::KJavaProcess() : KProcess()
    00050 {
    00051     d = new KJavaProcessPrivate;
    00052     d->BufferList.setAutoDelete( true );
    00053     d->processKilled = false;
    00054
    00055     javaProcess = this; //new KProcess();
    00056
    00057     connect( javaProcess, SIGNAL( wroteStdin( KProcess * ) ),
    00058              this, SLOT( slotWroteData() ) );
    00059     connect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
    00060              this, SLOT( slotReceivedData(int, int&) ) );
    00061     connect( javaProcess, SIGNAL( processExited (KProcess *) ),
    00062              this, SLOT( slotExited (KProcess *) ) );
    00063
    00064     d->jvmPath = "java";
    00065     d->mainClass = "-help";
    00066 }
    00067
    00068 KJavaProcess::~KJavaProcess()
    00069 {
    00070     if ( isRunning() )
    00071     {
    00072         kdDebug(6100) << "stopping java process" << endl;
    00073         stopJava();
    00074     }
    00075
    00076     //delete javaProcess;
    00077     delete d;
    00078 }
    00079
    00080 bool KJavaProcess::isRunning()
    00081 {
    00082    return javaProcess->isRunning();
    00083 }
    00084
    00085 bool KJavaProcess::startJava()
    00086 {
    00087    return invokeJVM();
    00088 }
    00089
    00090 void KJavaProcess::stopJava()
    00091 {
    00092    killJVM();
    00093 }
    00094
    00095 void KJavaProcess::setJVMPath( const QString& path )
    00096 {
    00097    d->jvmPath = path;
    00098 }
    00099
    00100 void KJavaProcess::setClasspath( const QString& classpath )
    00101 {
    00102     d->classPath = classpath;
    00103 }
    00104
    00105 void KJavaProcess::setSystemProperty( const QString& name,
    00106                                       const QString& value )
    00107 {
    00108    d->systemProps.insert( name, value );
    00109 }
    00110
    00111 void KJavaProcess::setMainClass( const QString& className )
    00112 {
    00113    d->mainClass = className;
    00114 }
    00115
    00116 void KJavaProcess::setExtraArgs( const QString& args )
    00117 {
    00118    d->extraArgs = args;
    00119 }
    00120
    00121 void KJavaProcess::setClassArgs( const QString& args )
    00122 {
    00123    d->classArgs = args;
    00124 }
    00125
    00126 //Private Utility Functions used by the two send() methods
    00127 QByteArray* KJavaProcess::addArgs( char cmd_code, const QStringList& args )
    00128 {
    00129     //the buffer to store stuff, etc.
    00130     QByteArray* const buff = new QByteArray();
    00131     QTextOStream output( *buff );
    00132     const char sep = 0;
    00133
    00134     //make space for the command size: 8 characters...
    00135     const QCString space( "        " );
    00136     output << space;
    00137
    00138     //write command code
    00139     output << cmd_code;
    00140
    00141     //store the arguments...
    00142     if( args.isEmpty() )
    00143     {
    00144         output << sep;
    00145     }
    00146     else
    00147     {
    00148         QStringList::ConstIterator it = args.begin();
    00149         const QStringList::ConstIterator itEnd = args.end();
    00150         for( ; it != itEnd; ++it )
    00151         {
    00152             if( !(*it).isEmpty() )
    00153             {
    00154                 output << (*it).local8Bit();
    00155             }
    00156             output << sep;
    00157         }
    00158     }
    00159
    00160     return buff;
    00161 }
    00162
    00163 void KJavaProcess::storeSize( QByteArray* buff )
    00164 {
    00165     const int size = buff->size() - 8;  //subtract out the length of the size_str
    00166     const QString size_str = QString("%1").arg( size, 8 );
    00167     kdDebug(6100) << "KJavaProcess::storeSize, size = " << size_str << endl;
    00168
    00169     const char* size_ptr = size_str.latin1();
    00170     for( int i = 0; i < 8; ++i )
    00171         buff->at(i) = size_ptr[i];
    00172 }
    00173
    00174 void KJavaProcess::sendBuffer( QByteArray* buff )
    00175 {
    00176     d->BufferList.append( buff );
    00177     if( d->BufferList.count() == 1)
    00178     {
    00179         popBuffer();
    00180     }
    00181 }
    00182
    00183 void KJavaProcess::send( char cmd_code, const QStringList& args )
    00184 {
    00185     if( isRunning() )
    00186     {
    00187         QByteArray* const buff = addArgs( cmd_code, args );
    00188         storeSize( buff );
    00189         kdDebug(6100) << "<KJavaProcess::send " << (int)cmd_code << endl;
    00190         sendBuffer( buff );
    00191     }
    00192 }
    00193
    00194 void KJavaProcess::send( char cmd_code, const QStringList& args,
    00195                          const QByteArray& data )
    00196 {
    00197     if( isRunning() )
    00198     {
    00199         kdDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size() << endl;
    00200
    00201         QByteArray* const buff = addArgs( cmd_code, args );
    00202         const int cur_size = buff->size();
    00203         const int data_size = data.size();
    00204         buff->resize( cur_size + data_size );
    00205         memcpy( buff->data() + cur_size, data.data(), data_size );
    00206
    00207         storeSize( buff );
    00208         sendBuffer( buff );
    00209     }
    00210 }
    00211
    00212 void KJavaProcess::popBuffer()
    00213 {
    00214     QByteArray* const buf = d->BufferList.first();
    00215     if( buf )
    00216     {
    00217 //        DEBUG stuff...
    00218 //  kdDebug(6100) << "Sending buffer to java, buffer = >>";
    00219 //        for( unsigned int i = 0; i < buf->size(); i++ )
    00220 //        {
    00221 //            if( buf->at(i) == (char)0 )
    00222 //                kdDebug(6100) << "<SEP>";
    00223 //            else if( buf->at(i) > 0 && buf->at(i) < 10 )
    00224 //                kdDebug(6100) << "<CMD " << (int) buf->at(i) << ">";
    00225 //            else
    00226 //                kdDebug(6100) << buf->at(i);
    00227 //        }
    00228 //        kdDebug(6100) << "<<" << endl;
    00229
    00230         //write the data
    00231         if ( !javaProcess->writeStdin( buf->data(),
    00232                                        buf->size() ) )
    00233         {
    00234             kdError(6100) << "Could not write command" << endl;
    00235         }
    00236     }
    00237 }
    00238
    00239 void KJavaProcess::slotWroteData( )
    00240 {
    00241     //do this here- we can't free the data until we know it went through
    00242     d->BufferList.removeFirst();  //this should delete it since we setAutoDelete(true)
    00243     kdDebug(6100) << "slotWroteData " << d->BufferList.count() << endl;
    00244
    00245     if ( !d->BufferList.isEmpty() )
    00246     {
    00247         popBuffer();
    00248     }
    00249 }
    00250
    00251
    00252 bool KJavaProcess::invokeJVM()
    00253 {
    00254
    00255     *javaProcess << d->jvmPath;
    00256
    00257     if( !d->classPath.isEmpty() )
    00258     {
    00259         *javaProcess << "-classpath";
    00260         *javaProcess << d->classPath;
    00261     }
    00262
    00263     //set the system properties, iterate through the qmap of system properties
    00264     QMap<QString,QString>::ConstIterator it = d->systemProps.begin();
    00265     const QMap<QString,QString>::ConstIterator itEnd = d->systemProps.end();
    00266
    00267     for( ; it != itEnd; ++it )
    00268     {
    00269         QString currarg;
    00270
    00271         if( !it.key().isEmpty() )
    00272         {
    00273             currarg = "-D" + it.key();
    00274             if( !it.data().isEmpty() )
    00275                 currarg += "=" + it.data();
    00276         }
    00277
    00278         if( !currarg.isEmpty() )
    00279             *javaProcess << currarg;
    00280     }
    00281
    00282     //load the extra user-defined arguments
    00283     if( !d->extraArgs.isEmpty() )
    00284     {
    00285         // BUG HERE: if an argument contains space (-Dname="My name")
    00286         // this parsing will fail. Need more sophisticated parsing -- use KShell?
    00287         const QStringList args = QStringList::split( " ", d->extraArgs );
    00288         QStringList::ConstIterator it = args.begin();
    00289         const QStringList::ConstIterator itEnd = args.end();
    00290         for ( ; it != itEnd; ++it )
    00291             *javaProcess << *it;
    00292     }
    00293
    00294     *javaProcess << d->mainClass;
    00295
    00296     if ( !d->classArgs.isNull() )
    00297         *javaProcess << d->classArgs;
    00298
    00299     kdDebug(6100) << "Invoking JVM now...with arguments = " << endl;
    00300     QString argStr;
    00301     QTextOStream stream( &argStr );
    00302     const QValueList<QCString> args = javaProcess->args();
    00303     qCopy( args.begin(), args.end(), QTextOStreamIterator<QCString>( stream, " " ) );
    00304     kdDebug(6100) << argStr << endl;
    00305
    00306     KProcess::Communication flags =  (KProcess::Communication)
    00307                                      (KProcess::Stdin | KProcess::Stdout |
    00308                                       KProcess::NoRead);
    00309
    00310     const bool rval = javaProcess->start( KProcess::NotifyOnExit, flags );
    00311     if( rval )
    00312         javaProcess->resume(); //start processing stdout on the java process
    00313     else
    00314         killJVM();
    00315
    00316     return rval;
    00317 }
    00318
    00319 void KJavaProcess::killJVM()
    00320 {
    00321    d->processKilled = true;
    00322    disconnect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
    00323                this, SLOT( slotReceivedData(int, int&) ) );
    00324    javaProcess->kill();
    00325 }
    00326
    00327 void KJavaProcess::flushBuffers()
    00328 {
    00329     while ( !d->BufferList.isEmpty() ) {
    00330         if (innot)
    00331             slotSendData(0);
    00332         else
    00333             d->BufferList.removeFirst();  //note: AutoDelete is true
    00334     }
    00335 }
    00336
    00337 /*  In this method, read one command and send it to the d->appletServer
    00338  *  then return, so we don't block the event handling
    00339  */
    00340 void KJavaProcess::slotReceivedData( int fd, int& len )
    00341 {
    00342     //read out the length of the message,
    00343     //read the message and send it to the applet server
    00344     char length[9] = { 0 };
    00345     const int num_bytes = ::read( fd, length, 8 );
    00346     if( !num_bytes )
    00347     {
    00348         len = 0;
    00349         return;
    00350     }
    00351     if( num_bytes == -1 )
    00352     {
    00353         kdError(6100) << "could not read 8 characters for the message length!!!!" << endl;
    00354         len = 0;
    00355         return;
    00356     }
    00357
    00358     const QString lengthstr( length );
    00359     bool ok;
    00360     const int num_len = lengthstr.toInt( &ok );
    00361     if( !ok )
    00362     {
    00363         kdError(6100) << "could not parse length out of: " << lengthstr << endl;
    00364         len = num_bytes;
    00365         return;
    00366     }
    00367
    00368     //now parse out the rest of the message.
    00369     char* const msg = new char[num_len];
    00370     const int num_bytes_msg = ::read( fd, msg, num_len );
    00371     if( num_bytes_msg == -1 || num_bytes_msg != num_len )
    00372     {
    00373         kdError(6100) << "could not read the msg, num_bytes_msg = " << num_bytes_msg << endl;
    00374         delete[] msg;
    00375         len = num_bytes;
    00376         return;
    00377     }
    00378
    00379     QByteArray qb;
    00380     emit received( qb.duplicate( msg, num_len ) );
    00381     delete[] msg;
    00382     len = num_bytes + num_bytes_msg;
    00383 }
    00384
    00385 void KJavaProcess::slotExited( KProcess *process )
    00386 {
    00387   if (process == javaProcess) {
    00388     int status = -1;
    00389     if (!d->processKilled) {
    00390      status = javaProcess->exitStatus();
    00391     }
    00392     kdDebug(6100) << "jvm exited with status " << status << endl;
    00393     emit exited(status);
    00394   }
    00395 }
    00396
    00397 #include "kjavaprocess.moc"

This file is part of the documentation for khtml Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:33:16 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003