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
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;
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
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
00127 QByteArray* KJavaProcess::addArgs( char cmd_code, const QStringList& args )
00128 {
00129
00130 QByteArray* const buff = new QByteArray();
00131 QTextOStream output( *buff );
00132 const char sep = 0;
00133
00134
00135 const QCString space( " " );
00136 output << space;
00137
00138
00139 output << cmd_code;
00140
00141
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;
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
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
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
00242 d->BufferList.removeFirst();
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
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
00283 if( !d->extraArgs.isEmpty() )
00284 {
00285
00286
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();
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();
00334 }
00335 }
00336
00337
00338
00339
00340 void KJavaProcess::slotReceivedData( int fd, int& len )
00341 {
00342
00343
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
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"