khtml Library API Documentation

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* buff = new QByteArray();
00131     QTextOStream output( *buff );
00132     char sep = 0;
00133 
00134     //make space for the command size: 8 characters...
00135     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         for( QStringList::ConstIterator it = args.begin();
00149              it != args.end(); ++it )
00150         {
00151             if( !(*it).isEmpty() )
00152             {
00153                 output << (*it).local8Bit();
00154             }
00155             output << sep;
00156         }
00157     }
00158 
00159     return buff;
00160 }
00161 
00162 void KJavaProcess::storeSize( QByteArray* buff )
00163 {
00164     int size = buff->size() - 8;  //subtract out the length of the size_str
00165     QString size_str = QString("%1").arg( size, 8 );
00166     kdDebug(6100) << "KJavaProcess::storeSize, size = " << size_str << endl;
00167 
00168     const char* size_ptr = size_str.latin1();
00169     for( int i = 0; i < 8; i++ )
00170         buff->at(i) = size_ptr[i];
00171 }
00172 
00173 void KJavaProcess::sendBuffer( QByteArray* buff )
00174 {
00175     d->BufferList.append( buff );
00176     if( d->BufferList.count() == 1)
00177     {
00178         popBuffer();
00179     }
00180 }
00181 
00182 void KJavaProcess::send( char cmd_code, const QStringList& args )
00183 {
00184     if( isRunning() )
00185     {
00186         QByteArray* buff = addArgs( cmd_code, args );
00187         storeSize( buff );
00188         kdDebug(6100) << "<KJavaProcess::send " << (int)cmd_code << endl;
00189         sendBuffer( buff );
00190     }
00191 }
00192 
00193 void KJavaProcess::send( char cmd_code, const QStringList& args,
00194                          const QByteArray& data )
00195 {
00196     if( isRunning() )
00197     {
00198         kdDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size() << endl;
00199 
00200         QByteArray* buff = addArgs( cmd_code, args );
00201         int cur_size = buff->size();
00202         int data_size = data.size();
00203         buff->resize( cur_size + data_size );
00204         memcpy( buff->data() + cur_size, data.data(), data_size );
00205 
00206         storeSize( buff );
00207         sendBuffer( buff );
00208     }
00209 }
00210 
00211 void KJavaProcess::popBuffer()
00212 {
00213     QByteArray* buf = d->BufferList.first();
00214     if( buf )
00215     {
00216 //        DEBUG stuff...
00217 //  kdDebug(6100) << "Sending buffer to java, buffer = >>";
00218 //        for( unsigned int i = 0; i < buf->size(); i++ )
00219 //        {
00220 //            if( buf->at(i) == (char)0 )
00221 //                kdDebug(6100) << "<SEP>";
00222 //            else if( buf->at(i) > 0 && buf->at(i) < 10 )
00223 //                kdDebug(6100) << "<CMD " << (int) buf->at(i) << ">";
00224 //            else
00225 //                kdDebug(6100) << buf->at(i);
00226 //        }
00227 //        kdDebug(6100) << "<<" << endl;
00228 
00229         //write the data
00230         if ( !javaProcess->writeStdin( buf->data(),
00231                                        buf->size() ) )
00232         {
00233             kdError(6100) << "Could not write command" << endl;
00234         }
00235     }
00236 }
00237 
00238 void KJavaProcess::slotWroteData( )
00239 {
00240     //do this here- we can't free the data until we know it went through
00241     d->BufferList.removeFirst();  //this should delete it since we setAutoDelete(true)
00242     kdDebug(6100) << "slotWroteData " << d->BufferList.count() << endl;
00243 
00244     if ( !d->BufferList.isEmpty() )
00245     {
00246         popBuffer();
00247     }
00248 }
00249 
00250 
00251 bool KJavaProcess::invokeJVM()
00252 {
00253     
00254     *javaProcess << d->jvmPath;
00255 
00256     if( !d->classPath.isEmpty() )
00257     {
00258         *javaProcess << "-classpath";
00259         *javaProcess << d->classPath;
00260     }
00261 
00262     //set the system properties, iterate through the qmap of system properties
00263     for( QMap<QString,QString>::Iterator it = d->systemProps.begin();
00264          it != d->systemProps.end(); ++it )
00265     {
00266         QString currarg;
00267 
00268         if( !it.key().isEmpty() )
00269         {
00270             currarg = "-D" + it.key();
00271             if( !it.data().isEmpty() )
00272                 currarg += "=" + it.data();
00273         }
00274 
00275         if( !currarg.isEmpty() )
00276             *javaProcess << currarg;
00277     }
00278 
00279     //load the extra user-defined arguments
00280     if( !d->extraArgs.isEmpty() )
00281     {
00282         // BUG HERE: if an argument contains space (-Dname="My name")
00283         // this parsing will fail. Need more sophisticated parsing -- use KShell?
00284         QStringList args = QStringList::split( " ", d->extraArgs );
00285         for ( QStringList::Iterator it = args.begin(); it != args.end(); ++it )
00286             *javaProcess << *it;
00287     }
00288 
00289     *javaProcess << d->mainClass;
00290 
00291     if ( !d->classArgs.isNull() )
00292         *javaProcess << d->classArgs;
00293 
00294     kdDebug(6100) << "Invoking JVM now...with arguments = " << endl;
00295     QString argStr;
00296     QTextOStream stream( &argStr );
00297     QValueList<QCString> args = javaProcess->args();
00298     qCopy( args.begin(), args.end(), QTextOStreamIterator<QCString>( stream, " " ) );
00299     kdDebug(6100) << argStr << endl;
00300 
00301     KProcess::Communication flags =  (KProcess::Communication)
00302                                      (KProcess::Stdin | KProcess::Stdout |
00303                                       KProcess::NoRead);
00304 
00305     bool rval = javaProcess->start( KProcess::NotifyOnExit, flags );
00306     if( rval )
00307         javaProcess->resume(); //start processing stdout on the java process
00308     else
00309         killJVM();
00310 
00311     return rval;
00312 }
00313 
00314 void KJavaProcess::killJVM()
00315 {
00316    d->processKilled = true;
00317    disconnect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
00318                this, SLOT( slotReceivedData(int, int&) ) );
00319    javaProcess->kill();
00320 }
00321 
00322 void KJavaProcess::flushBuffers()
00323 {
00324     while ( !d->BufferList.isEmpty() )
00325         slotSendData(0);
00326 }
00327 
00328 /*  In this method, read one command and send it to the d->appletServer
00329  *  then return, so we don't block the event handling
00330  */
00331 void KJavaProcess::slotReceivedData( int fd, int& len )
00332 {
00333     //read out the length of the message,
00334     //read the message and send it to the applet server
00335     char length[9] = { 0 };
00336     int num_bytes = ::read( fd, length, 8 );
00337     if( !num_bytes )
00338     {
00339         len = 0;
00340         return;
00341     }
00342     if( num_bytes == -1 )
00343     {
00344         kdError(6100) << "could not read 8 characters for the message length!!!!" << endl;
00345         len = 0;
00346         return;
00347     }
00348 
00349     QString lengthstr( length );
00350     bool ok;
00351     int num_len = lengthstr.toInt( &ok );
00352     if( !ok )
00353     {
00354         kdError(6100) << "could not parse length out of: " << lengthstr << endl;
00355         len = num_bytes;
00356         return;
00357     }
00358 
00359     //now parse out the rest of the message.
00360     char* msg = new char[num_len];
00361     int num_bytes_msg = ::read( fd, msg, num_len );
00362     if( num_bytes_msg == -1 || num_bytes_msg != num_len )
00363     {
00364         kdError(6100) << "could not read the msg, num_bytes_msg = " << num_bytes_msg << endl;
00365         delete[] msg;
00366         len = num_bytes;
00367         return;
00368     }
00369 
00370     QByteArray qb;
00371     emit received( qb.duplicate( msg, num_len ) );
00372     delete[] msg;
00373     len = num_bytes + num_bytes_msg;
00374 }
00375 
00376 void KJavaProcess::slotExited( KProcess *process )
00377 {
00378   if (process == javaProcess) {
00379     int status = -1;
00380     if (!d->processKilled) {
00381      status = javaProcess->exitStatus();
00382     }
00383     kdDebug(6100) << "jvm exited with status " << status << endl; 
00384     emit exited(status);
00385   }
00386 }
00387 
00388 #include "kjavaprocess.moc"
KDE Logo
This file is part of the documentation for khtml Library Version 3.2.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Mar 4 22:45:43 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003