00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 bool processKilled;
00051 int sync_count;
00052 };
00053
00054 KJavaProcess::KJavaProcess() : KProcess()
00055 {
00056 d = new KJavaProcessPrivate;
00057 d->BufferList.setAutoDelete( true );
00058 d->processKilled = false;
00059 d->sync_count = 0;
00060
00061 javaProcess = this;
00062
00063 connect( javaProcess, SIGNAL( wroteStdin( KProcess * ) ),
00064 this, SLOT( slotWroteData() ) );
00065 connect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
00066 this, SLOT( slotReceivedData(int, int&) ) );
00067 connect( javaProcess, SIGNAL( processExited (KProcess *) ),
00068 this, SLOT( slotExited (KProcess *) ) );
00069
00070 d->jvmPath = "java";
00071 d->mainClass = "-help";
00072 }
00073
00074 KJavaProcess::~KJavaProcess()
00075 {
00076 if ( isRunning() )
00077 {
00078 kdDebug(6100) << "stopping java process" << endl;
00079 stopJava();
00080 }
00081
00082
00083 delete d;
00084 }
00085
00086 bool KJavaProcess::isRunning()
00087 {
00088 return javaProcess->isRunning();
00089 }
00090
00091 bool KJavaProcess::startJava()
00092 {
00093 return invokeJVM();
00094 }
00095
00096 void KJavaProcess::stopJava()
00097 {
00098 killJVM();
00099 }
00100
00101 void KJavaProcess::setJVMPath( const QString& path )
00102 {
00103 d->jvmPath = path;
00104 }
00105
00106 void KJavaProcess::setClasspath( const QString& classpath )
00107 {
00108 d->classPath = classpath;
00109 }
00110
00111 void KJavaProcess::setSystemProperty( const QString& name,
00112 const QString& value )
00113 {
00114 d->systemProps.insert( name, value );
00115 }
00116
00117 void KJavaProcess::setMainClass( const QString& className )
00118 {
00119 d->mainClass = className;
00120 }
00121
00122 void KJavaProcess::setExtraArgs( const QString& args )
00123 {
00124 d->extraArgs = args;
00125 }
00126
00127 void KJavaProcess::setClassArgs( const QString& args )
00128 {
00129 d->classArgs = args;
00130 }
00131
00132
00133 QByteArray* KJavaProcess::addArgs( char cmd_code, const QStringList& args )
00134 {
00135
00136 QByteArray* buff = new QByteArray();
00137 QTextOStream output( *buff );
00138 char sep = 0;
00139
00140
00141 QCString space( " " );
00142 output << space;
00143
00144
00145 output << cmd_code;
00146
00147
00148 if( args.count() == 0 )
00149 {
00150 output << sep;
00151 }
00152 else
00153 {
00154 for( QStringList::ConstIterator it = args.begin();
00155 it != args.end(); ++it )
00156 {
00157 if( !(*it).isEmpty() )
00158 {
00159 output << (*it).latin1();
00160 }
00161 output << sep;
00162 }
00163 }
00164
00165 return buff;
00166 }
00167
00168 void KJavaProcess::storeSize( QByteArray* buff )
00169 {
00170 int size = buff->size() - 8;
00171 QString size_str = QString("%1").arg( size, 8 );
00172 kdDebug(6100) << "KJavaProcess::storeSize, size = " << size_str << endl;
00173
00174 const char* size_ptr = size_str.latin1();
00175 for( int i = 0; i < 8; i++ )
00176 buff->at(i) = size_ptr[i];
00177 }
00178
00179 void KJavaProcess::sendBuffer( QByteArray* buff )
00180 {
00181 d->BufferList.append( buff );
00182 if( d->BufferList.count() == 1 )
00183 {
00184 popBuffer();
00185 }
00186 }
00187
00188 void KJavaProcess::sendSync( char cmd_code, const QStringList& args ) {
00189 kdDebug(6100) << ">KJavaProcess::sendSync " << d->sync_count << endl;
00190 if (d->sync_count++ == 0)
00191 javaProcess->suspend();
00192 QByteArray* buff = addArgs( cmd_code, args );
00193 storeSize( buff );
00194 int dummy;
00195 int current_sync_count;
00196 int size = buff->size();
00197 char *data = buff->data();
00198 fd_set fds;
00199 timeval tv;
00200 do {
00201 FD_ZERO(&fds);
00202 FD_SET(in[1], &fds);
00203 tv.tv_sec = 5;
00204 tv.tv_usec = 0;
00205 int retval = select(in[1]+1, 0L, &fds, 0L, &tv);
00206 FD_CLR(in[1], &fds);
00207 if (retval < 0 && errno == EINTR) {
00208 continue;
00209 } else if (retval <= 0) {
00210 kdError(6100) << "KJavaProcess::sendSync " << retval << endl;
00211 goto bail_out;
00212 } else if (KProcess::input_data) {
00213 KProcess::slotSendData(dummy);
00214 } else {
00215 int nr = ::write(in[1], data, size);
00216 size -= nr;
00217 data += nr;
00218 }
00219 } while (size > 0);
00220 current_sync_count = d->sync_count;
00221 do {
00222 FD_ZERO(&fds);
00223 FD_SET(out[0], &fds);
00224 tv.tv_sec = 5;
00225 tv.tv_usec = 0;
00226 kdDebug(6100) << "KJavaProcess::sendSync bf read" << endl;
00227 int retval = select(out[0]+1, &fds, 0L, 0L, &tv);
00228 FD_CLR(out[0], &fds);
00229 if (retval < 0 && errno == EINTR) {
00230 continue;
00231 } else if (retval <= 0) {
00232 kdError(6100) << "KJavaProcess::sendSync timeout" <<endl;
00233 d->sync_count--;
00234 break;
00235 } else {
00236 slotReceivedData(out[0], dummy);
00237 }
00238 if (d->sync_count < current_sync_count)
00239 break;
00240 } while(true);
00241 bail_out:
00242 delete buff;
00243 if (d->sync_count == 0)
00244 javaProcess->resume();
00245 kdDebug(6100) << "<KJavaProcess::sendSync " << d->sync_count << endl;
00246 }
00247
00248 void KJavaProcess::syncCommandReceived() {
00249 if (--d->sync_count < 0) {
00250 kdError(6100) << "syncCommandReceived() sync_count below zero" << endl;
00251 d->sync_count = 0;
00252 }
00253 }
00254
00255 void KJavaProcess::send( char cmd_code, const QStringList& args )
00256 {
00257 if( isRunning() )
00258 {
00259 QByteArray* buff = addArgs( cmd_code, args );
00260 storeSize( buff );
00261 sendBuffer( buff );
00262 }
00263 }
00264
00265 void KJavaProcess::send( char cmd_code, const QStringList& args,
00266 const QByteArray& data )
00267 {
00268 if( isRunning() )
00269 {
00270 kdDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size() << endl;
00271
00272 QByteArray* buff = addArgs( cmd_code, args );
00273 int cur_size = buff->size();
00274 int data_size = data.size();
00275 buff->resize( cur_size + data_size );
00276 memcpy( buff->data() + cur_size, data.data(), data_size );
00277
00278 storeSize( buff );
00279 sendBuffer( buff );
00280 }
00281 }
00282
00283 void KJavaProcess::popBuffer()
00284 {
00285 QByteArray* buf = d->BufferList.first();
00286 if( buf )
00287 {
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if ( !javaProcess->writeStdin( buf->data(),
00303 buf->size() ) )
00304 {
00305 kdError(6100) << "Could not write command" << endl;
00306 }
00307 }
00308 }
00309
00310 void KJavaProcess::slotWroteData( )
00311 {
00312
00313 d->BufferList.removeFirst();
00314 kdDebug(6100) << "slotWroteData " << d->BufferList.count() << endl;
00315
00316 if ( d->BufferList.count() >= 1 )
00317 {
00318 popBuffer();
00319 }
00320 }
00321
00322
00323 bool KJavaProcess::invokeJVM()
00324 {
00325
00326 *javaProcess << d->jvmPath;
00327
00328 if( !d->classPath.isEmpty() )
00329 {
00330 *javaProcess << "-classpath";
00331 *javaProcess << d->classPath;
00332 }
00333
00334
00335 for( QMap<QString,QString>::Iterator it = d->systemProps.begin();
00336 it != d->systemProps.end(); ++it )
00337 {
00338 QString currarg;
00339
00340 if( !it.key().isEmpty() )
00341 {
00342 currarg = "-D" + it.key();
00343 if( !it.data().isEmpty() )
00344 currarg += "=" + it.data();
00345 }
00346
00347 if( !currarg.isEmpty() )
00348 *javaProcess << currarg;
00349 }
00350
00351
00352 if( !d->extraArgs.isEmpty() )
00353 {
00354
00355
00356 QStringList args = QStringList::split( " ", d->extraArgs );
00357 for ( QStringList::Iterator it = args.begin(); it != args.end(); ++it )
00358 *javaProcess << *it;
00359 }
00360
00361 *javaProcess << d->mainClass;
00362
00363 if ( d->classArgs != QString::null )
00364 *javaProcess << d->classArgs;
00365
00366 kdDebug(6100) << "Invoking JVM now...with arguments = " << endl;
00367 QString argStr;
00368 QTextOStream stream( &argStr );
00369 QValueList<QCString> args = javaProcess->args();
00370 qCopy( args.begin(), args.end(), QTextOStreamIterator<QCString>( stream, " " ) );
00371 kdDebug(6100) << argStr << endl;
00372
00373 KProcess::Communication flags = (KProcess::Communication)
00374 (KProcess::Stdin | KProcess::Stdout |
00375 KProcess::NoRead);
00376
00377 bool rval = javaProcess->start( KProcess::NotifyOnExit, flags );
00378 if( rval )
00379 javaProcess->resume();
00380
00381 return rval;
00382 }
00383
00384 void KJavaProcess::killJVM()
00385 {
00386 d->processKilled = true;
00387 javaProcess->kill();
00388 }
00389
00390
00391
00392
00393 void KJavaProcess::slotReceivedData( int fd, int& )
00394 {
00395
00396
00397 char length[9] = { 0 };
00398 int num_bytes = ::read( fd, length, 8 );
00399 if( num_bytes == -1 )
00400 {
00401 kdError(6100) << "could not read 8 characters for the message length!!!!" << endl;
00402 return;
00403 }
00404
00405 QString lengthstr( length );
00406 bool ok;
00407 int num_len = lengthstr.toInt( &ok );
00408 if( !ok )
00409 {
00410 kdError(6100) << "could not parse length out of: " << lengthstr << endl;
00411 return;
00412 }
00413
00414
00415 char* msg = new char[num_len];
00416 num_bytes = ::read( fd, msg, num_len );
00417 if( num_bytes == -1 || num_bytes != num_len )
00418 {
00419 kdError(6100) << "could not read the msg, num_bytes = " << num_bytes << endl;
00420 delete[] msg;
00421 return;
00422 }
00423
00424 QByteArray qb;
00425 emit received( qb.duplicate( msg, num_len ) );
00426 delete[] msg;
00427 }
00428
00429 void KJavaProcess::slotExited( KProcess *process )
00430 {
00431 if (process && process == javaProcess) {
00432 int status = -1;
00433 if (!d->processKilled) {
00434 status = javaProcess->exitStatus();
00435 }
00436 kdDebug(6100) << "jvm exited with status " << status << endl;
00437 emit exited(status);
00438 }
00439 }
00440
00441 #include "kjavaprocess.moc"