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.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:33:59 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003