KHTML
kjavaprocess.cpp
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kjavaprocess.h" 00023 00024 #include <kdebug.h> 00025 #include <kshell.h> 00026 #include <kio/kprotocolmanager.h> 00027 00028 #include <QtCore/QTextStream> 00029 #include <QtCore/QMap> 00030 00031 #include <config.h> 00032 00033 class KJavaProcessPrivate 00034 { 00035 friend class KJavaProcess; 00036 private: 00037 QString jvmPath; 00038 QString classPath; 00039 QString mainClass; 00040 QString extraArgs; 00041 QString classArgs; 00042 QMap<QString, QString> systemProps; 00043 }; 00044 00045 KJavaProcess::KJavaProcess( QObject* parent ) 00046 : KProcess( parent ), 00047 d(new KJavaProcessPrivate) 00048 00049 { 00050 connect( this, SIGNAL( readyReadStandardOutput() ), 00051 this, SLOT( slotReceivedData() ) ); 00052 connect( this, SIGNAL( finished( int, QProcess::ExitStatus ) ), 00053 this, SLOT( slotExited() ) ); 00054 connect( this, SIGNAL( error( QProcess::ProcessError ) ), 00055 this, SLOT( slotExited() ) ); 00056 00057 d->jvmPath = "java"; 00058 d->mainClass = "-help"; 00059 } 00060 00061 KJavaProcess::~KJavaProcess() 00062 { 00063 if ( state() != NotRunning ) 00064 { 00065 kDebug(6100) << "stopping java process"; 00066 stopJava(); 00067 } 00068 delete d; 00069 } 00070 00071 bool KJavaProcess::isRunning() 00072 { 00073 return state() != NotRunning; 00074 } 00075 00076 bool KJavaProcess::startJava() 00077 { 00078 return invokeJVM(); 00079 } 00080 00081 void KJavaProcess::stopJava() 00082 { 00083 killJVM(); 00084 } 00085 00086 void KJavaProcess::setJVMPath( const QString& path ) 00087 { 00088 d->jvmPath = path; 00089 } 00090 00091 void KJavaProcess::setClasspath( const QString& classpath ) 00092 { 00093 d->classPath = classpath; 00094 } 00095 00096 void KJavaProcess::setSystemProperty( const QString& name, 00097 const QString& value ) 00098 { 00099 d->systemProps.insert( name, value ); 00100 } 00101 00102 void KJavaProcess::setMainClass( const QString& className ) 00103 { 00104 d->mainClass = className; 00105 } 00106 00107 void KJavaProcess::setExtraArgs( const QString& args ) 00108 { 00109 d->extraArgs = args; 00110 } 00111 00112 void KJavaProcess::setClassArgs( const QString& args ) 00113 { 00114 d->classArgs = args; 00115 } 00116 00117 //Private Utility Functions used by the two send() methods 00118 QByteArray KJavaProcess::addArgs( char cmd_code, const QStringList& args ) 00119 { 00120 //the buffer to store stuff, etc. 00121 QByteArray buff; 00122 QTextStream output( &buff, QIODevice::ReadWrite ); 00123 const char sep = 0; 00124 00125 //make space for the command size: 8 characters... 00126 const QByteArray space( " " ); 00127 output << space; 00128 00129 //write command code 00130 output << cmd_code; 00131 00132 //store the arguments... 00133 if( args.isEmpty() ) 00134 { 00135 output << sep; 00136 } 00137 else 00138 { 00139 QStringList::ConstIterator it = args.begin(); 00140 const QStringList::ConstIterator itEnd = args.end(); 00141 for( ; it != itEnd; ++it ) 00142 { 00143 if( !(*it).isEmpty() ) 00144 { 00145 output << (*it).toLocal8Bit(); 00146 } 00147 output << sep; 00148 } 00149 } 00150 00151 return buff; 00152 } 00153 00154 void KJavaProcess::storeSize( QByteArray* buff ) 00155 { 00156 const int size = buff->size() - 8; //subtract out the length of the size_str 00157 const QString size_str = QString("%1").arg( size, 8 ); 00158 kDebug(6100) << "KJavaProcess::storeSize, size = " << size_str; 00159 00160 for( int i = 0; i < 8; ++i ) 00161 buff->data()[ i ] = size_str[i].toLatin1(); 00162 } 00163 00164 void KJavaProcess::send( char cmd_code, const QStringList& args ) 00165 { 00166 if( isRunning() ) 00167 { 00168 QByteArray buff = addArgs( cmd_code, args ); 00169 storeSize( &buff ); 00170 kDebug(6100) << "<KJavaProcess::send " << (int)cmd_code; 00171 write( buff ); 00172 } 00173 } 00174 00175 void KJavaProcess::send( char cmd_code, const QStringList& args, 00176 const QByteArray& data ) 00177 { 00178 if( isRunning() ) 00179 { 00180 kDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size(); 00181 00182 QByteArray buff = addArgs( cmd_code, args ); 00183 buff += data; 00184 00185 storeSize( &buff ); 00186 write( buff ); 00187 } 00188 } 00189 00190 bool KJavaProcess::invokeJVM() 00191 { 00192 QStringList args; 00193 00194 if( !d->classPath.isEmpty() ) 00195 { 00196 args << "-classpath"; 00197 args << d->classPath; 00198 } 00199 00200 //set the system properties, iterate through the qmap of system properties 00201 QMap<QString,QString>::ConstIterator it = d->systemProps.constBegin(); 00202 const QMap<QString,QString>::ConstIterator itEnd = d->systemProps.constEnd(); 00203 00204 for( ; it != itEnd; ++it ) 00205 { 00206 if( !it.key().isEmpty() ) 00207 { 00208 QString currarg = "-D" + it.key(); 00209 if( !it.value().isEmpty() ) 00210 currarg += '=' + it.value(); 00211 args << currarg; 00212 } 00213 } 00214 00215 //load the extra user-defined arguments 00216 if( !d->extraArgs.isEmpty() ) 00217 { 00218 KShell::Errors err; 00219 args += KShell::splitArgs( d->extraArgs, KShell::AbortOnMeta, &err ); 00220 if( err != KShell::NoError ) 00221 kWarning(6100) << "Extra args for JVM cannot be parsed, arguments = " << d->extraArgs; 00222 00223 } 00224 00225 args << d->mainClass; 00226 00227 if ( !d->classArgs.isNull() ) 00228 args << d->classArgs; 00229 00230 kDebug(6100) << "Invoking JVM" << d->jvmPath << "now...with arguments = " << KShell::joinArgs(args); 00231 00232 setOutputChannelMode(KProcess::SeparateChannels); 00233 setProgram( d->jvmPath, args ); 00234 start(); 00235 00236 return waitForStarted(); 00237 } 00238 00239 void KJavaProcess::killJVM() 00240 { 00241 closeReadChannel( StandardOutput ); 00242 terminate(); 00243 } 00244 00245 /* In this method, read one command and send it to the d->appletServer 00246 * then return, so we don't block the event handling 00247 */ 00248 void KJavaProcess::slotReceivedData() 00249 { 00250 //read out the length of the message, 00251 //read the message and send it to the applet server 00252 char length[9] = { 0 }; 00253 const int num_bytes = read( length, 8 ); 00254 if( num_bytes == -1 ) 00255 { 00256 kError(6100) << "could not read 8 characters for the message length!!!!" << endl; 00257 return; 00258 } 00259 00260 const QString lengthstr( length ); 00261 bool ok; 00262 const int num_len = lengthstr.toInt( &ok ); 00263 if( !ok ) 00264 { 00265 kError(6100) << "could not parse length out of: " << lengthstr << endl; 00266 return; 00267 } 00268 00269 //now parse out the rest of the message. 00270 char* const msg = new char[num_len]; 00271 const int num_bytes_msg = read( msg, num_len ); 00272 if( num_bytes_msg == -1 || num_bytes_msg != num_len ) 00273 { 00274 kError(6100) << "could not read the msg, num_bytes_msg = " << num_bytes_msg << endl; 00275 delete[] msg; 00276 return; 00277 } 00278 00279 emit received( QByteArray( msg, num_len ) ); 00280 delete[] msg; 00281 } 00282 00283 void KJavaProcess::slotExited() 00284 { 00285 int status = -1; 00286 if ( exitStatus() == NormalExit ) { 00287 status = exitCode(); 00288 } 00289 kDebug(6100) << "jvm exited with status " << status; 00290 emit exited(status); 00291 } 00292 00293 #include "kjavaprocess.moc"
KDE 4.6 API Reference