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* 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"
KDE Logo
This file is part of the documentation for khtml Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:31:31 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003