/* This file is part of the KDE project * * Copyright (C) 2000 Richard Moore * 2000 Wynn Wilkes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kjavaprocess.h" #include #include #include #include #include #include class KJavaProcessPrivate { friend class KJavaProcess; private: QString jvmPath; QString classPath; QString mainClass; QString extraArgs; QString classArgs; QMap systemProps; }; KJavaProcess::KJavaProcess( QObject* parent ) : KProcess( parent ), d(new KJavaProcessPrivate) { connect( this, SIGNAL(readyReadStandardOutput()), this, SLOT(slotReceivedData()) ); connect( this, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotExited()) ); connect( this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(slotExited()) ); d->jvmPath = "java"; d->mainClass = "-help"; } KJavaProcess::~KJavaProcess() { if ( state() != NotRunning ) { kDebug(6100) << "stopping java process"; stopJava(); } delete d; } bool KJavaProcess::isRunning() { return state() != NotRunning; } bool KJavaProcess::startJava() { return invokeJVM(); } void KJavaProcess::stopJava() { killJVM(); } void KJavaProcess::setJVMPath( const QString& path ) { d->jvmPath = path; } void KJavaProcess::setClasspath( const QString& classpath ) { d->classPath = classpath; } void KJavaProcess::setSystemProperty( const QString& name, const QString& value ) { d->systemProps.insert( name, value ); } void KJavaProcess::setMainClass( const QString& className ) { d->mainClass = className; } void KJavaProcess::setExtraArgs( const QString& args ) { d->extraArgs = args; } void KJavaProcess::setClassArgs( const QString& args ) { d->classArgs = args; } //Private Utility Functions used by the two send() methods QByteArray KJavaProcess::addArgs( char cmd_code, const QStringList& args ) { //the buffer to store stuff, etc. QByteArray buff; QTextStream output( &buff, QIODevice::ReadWrite ); const char sep = 0; //make space for the command size: 8 characters... const QByteArray space( " " ); output << space; //write command code output << cmd_code; //store the arguments... if( args.isEmpty() ) { output << sep; } else { QStringList::ConstIterator it = args.begin(); const QStringList::ConstIterator itEnd = args.end(); for( ; it != itEnd; ++it ) { if( !(*it).isEmpty() ) { output << (*it).toLocal8Bit(); } output << sep; } } return buff; } void KJavaProcess::storeSize( QByteArray* buff ) { const int size = buff->size() - 8; //subtract out the length of the size_str const QString size_str = QString("%1").arg( size, 8 ); kDebug(6100) << "KJavaProcess::storeSize, size = " << size_str; for( int i = 0; i < 8; ++i ) buff->data()[ i ] = size_str[i].toLatin1(); } void KJavaProcess::send( char cmd_code, const QStringList& args ) { if( isRunning() ) { QByteArray buff = addArgs( cmd_code, args ); storeSize( &buff ); kDebug(6100) << "classPath; } //set the system properties, iterate through the qmap of system properties QMap::ConstIterator it = d->systemProps.constBegin(); const QMap::ConstIterator itEnd = d->systemProps.constEnd(); for( ; it != itEnd; ++it ) { if( !it.key().isEmpty() ) { QString currarg = "-D" + it.key(); if( !it.value().isEmpty() ) currarg += '=' + it.value(); args << currarg; } } //load the extra user-defined arguments if( !d->extraArgs.isEmpty() ) { KShell::Errors err; args += KShell::splitArgs( d->extraArgs, KShell::AbortOnMeta, &err ); if( err != KShell::NoError ) kWarning(6100) << "Extra args for JVM cannot be parsed, arguments = " << d->extraArgs; } args << d->mainClass; if ( !d->classArgs.isNull() ) args << d->classArgs; kDebug(6100) << "Invoking JVM" << d->jvmPath << "now...with arguments = " << KShell::joinArgs(args); setOutputChannelMode(KProcess::SeparateChannels); setProgram( d->jvmPath, args ); start(); return waitForStarted(); } void KJavaProcess::killJVM() { closeReadChannel( StandardOutput ); terminate(); } /* In this method, read one command and send it to the d->appletServer * then return, so we don't block the event handling */ void KJavaProcess::slotReceivedData() { //read out the length of the message, //read the message and send it to the applet server char length[9] = { 0 }; const int num_bytes = read( length, 8 ); if( num_bytes == -1 ) { kError(6100) << "could not read 8 characters for the message length!!!!" << endl; return; } const QString lengthstr( length ); bool ok; const int num_len = lengthstr.toInt( &ok ); if( !ok ) { kError(6100) << "could not parse length out of: " << lengthstr << endl; return; } //now parse out the rest of the message. char* const msg = new char[num_len]; const int num_bytes_msg = read( msg, num_len ); if( num_bytes_msg == -1 || num_bytes_msg != num_len ) { kError(6100) << "could not read the msg, num_bytes_msg = " << num_bytes_msg << endl; delete[] msg; return; } emit received( QByteArray( msg, num_len ) ); delete[] msg; } void KJavaProcess::slotExited() { int status = -1; if ( exitStatus() == NormalExit ) { status = exitCode(); } kDebug(6100) << "jvm exited with status " << status; emit exited(status); } #include "moc_kjavaprocess.cpp"