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 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;
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
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
00134 QByteArray* KJavaProcess::addArgs( char cmd_code, const QStringList& args )
00135 {
00136
00137 QByteArray* buff = new QByteArray();
00138 QTextOStream output( *buff );
00139 char sep = 0;
00140
00141
00142 QCString space( " " );
00143 output << space;
00144
00145
00146 output << cmd_code;
00147
00148
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;
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
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
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
00320 d->BufferList.removeFirst();
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
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
00359 if( !d->extraArgs.isEmpty() )
00360 {
00361
00362
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();
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
00400
00401
00402 void KJavaProcess::slotReceivedData( int fd, int& )
00403 {
00404
00405
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
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"