summaryrefslogtreecommitdiffstats
path: root/khtml/java/kjavaprocess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/java/kjavaprocess.cpp')
-rw-r--r--khtml/java/kjavaprocess.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/khtml/java/kjavaprocess.cpp b/khtml/java/kjavaprocess.cpp
new file mode 100644
index 000000000..cdc69bcc0
--- /dev/null
+++ b/khtml/java/kjavaprocess.cpp
@@ -0,0 +1,397 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 Richard Moore <rich@kde.org>
+ * 2000 Wynn Wilkes <wynnw@caldera.com>
+ *
+ * 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 <kdebug.h>
+#include <kio/kprotocolmanager.h>
+
+#include <qtextstream.h>
+#include <qmap.h>
+
+#include <config.h>
+
+#include <unistd.h>
+#include <qptrlist.h>
+
+class KJavaProcessPrivate
+{
+friend class KJavaProcess;
+private:
+ QString jvmPath;
+ QString classPath;
+ QString mainClass;
+ QString extraArgs;
+ QString classArgs;
+ QPtrList<QByteArray> BufferList;
+ QMap<QString, QString> systemProps;
+ bool processKilled;
+};
+
+KJavaProcess::KJavaProcess() : KProcess()
+{
+ d = new KJavaProcessPrivate;
+ d->BufferList.setAutoDelete( true );
+ d->processKilled = false;
+
+ javaProcess = this; //new KProcess();
+
+ connect( javaProcess, SIGNAL( wroteStdin( KProcess * ) ),
+ this, SLOT( slotWroteData() ) );
+ connect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
+ this, SLOT( slotReceivedData(int, int&) ) );
+ connect( javaProcess, SIGNAL( processExited (KProcess *) ),
+ this, SLOT( slotExited (KProcess *) ) );
+
+ d->jvmPath = "java";
+ d->mainClass = "-help";
+}
+
+KJavaProcess::~KJavaProcess()
+{
+ if ( isRunning() )
+ {
+ kdDebug(6100) << "stopping java process" << endl;
+ stopJava();
+ }
+
+ //delete javaProcess;
+ delete d;
+}
+
+bool KJavaProcess::isRunning()
+{
+ return javaProcess->isRunning();
+}
+
+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* const buff = new QByteArray();
+ QTextOStream output( *buff );
+ const char sep = 0;
+
+ //make space for the command size: 8 characters...
+ const QCString 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).local8Bit();
+ }
+ 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 );
+ kdDebug(6100) << "KJavaProcess::storeSize, size = " << size_str << endl;
+
+ const char* size_ptr = size_str.latin1();
+ for( int i = 0; i < 8; ++i )
+ buff->at(i) = size_ptr[i];
+}
+
+void KJavaProcess::sendBuffer( QByteArray* buff )
+{
+ d->BufferList.append( buff );
+ if( d->BufferList.count() == 1)
+ {
+ popBuffer();
+ }
+}
+
+void KJavaProcess::send( char cmd_code, const QStringList& args )
+{
+ if( isRunning() )
+ {
+ QByteArray* const buff = addArgs( cmd_code, args );
+ storeSize( buff );
+ kdDebug(6100) << "<KJavaProcess::send " << (int)cmd_code << endl;
+ sendBuffer( buff );
+ }
+}
+
+void KJavaProcess::send( char cmd_code, const QStringList& args,
+ const QByteArray& data )
+{
+ if( isRunning() )
+ {
+ kdDebug(6100) << "KJavaProcess::send, qbytearray is size = " << data.size() << endl;
+
+ QByteArray* const buff = addArgs( cmd_code, args );
+ const int cur_size = buff->size();
+ const int data_size = data.size();
+ buff->resize( cur_size + data_size );
+ memcpy( buff->data() + cur_size, data.data(), data_size );
+
+ storeSize( buff );
+ sendBuffer( buff );
+ }
+}
+
+void KJavaProcess::popBuffer()
+{
+ QByteArray* const buf = d->BufferList.first();
+ if( buf )
+ {
+// DEBUG stuff...
+// kdDebug(6100) << "Sending buffer to java, buffer = >>";
+// for( unsigned int i = 0; i < buf->size(); i++ )
+// {
+// if( buf->at(i) == (char)0 )
+// kdDebug(6100) << "<SEP>";
+// else if( buf->at(i) > 0 && buf->at(i) < 10 )
+// kdDebug(6100) << "<CMD " << (int) buf->at(i) << ">";
+// else
+// kdDebug(6100) << buf->at(i);
+// }
+// kdDebug(6100) << "<<" << endl;
+
+ //write the data
+ if ( !javaProcess->writeStdin( buf->data(),
+ buf->size() ) )
+ {
+ kdError(6100) << "Could not write command" << endl;
+ }
+ }
+}
+
+void KJavaProcess::slotWroteData( )
+{
+ //do this here- we can't free the data until we know it went through
+ d->BufferList.removeFirst(); //this should delete it since we setAutoDelete(true)
+ kdDebug(6100) << "slotWroteData " << d->BufferList.count() << endl;
+
+ if ( !d->BufferList.isEmpty() )
+ {
+ popBuffer();
+ }
+}
+
+
+bool KJavaProcess::invokeJVM()
+{
+
+ *javaProcess << d->jvmPath;
+
+ if( !d->classPath.isEmpty() )
+ {
+ *javaProcess << "-classpath";
+ *javaProcess << d->classPath;
+ }
+
+ //set the system properties, iterate through the qmap of system properties
+ QMap<QString,QString>::ConstIterator it = d->systemProps.begin();
+ const QMap<QString,QString>::ConstIterator itEnd = d->systemProps.end();
+
+ for( ; it != itEnd; ++it )
+ {
+ QString currarg;
+
+ if( !it.key().isEmpty() )
+ {
+ currarg = "-D" + it.key();
+ if( !it.data().isEmpty() )
+ currarg += "=" + it.data();
+ }
+
+ if( !currarg.isEmpty() )
+ *javaProcess << currarg;
+ }
+
+ //load the extra user-defined arguments
+ if( !d->extraArgs.isEmpty() )
+ {
+ // BUG HERE: if an argument contains space (-Dname="My name")
+ // this parsing will fail. Need more sophisticated parsing -- use KShell?
+ const QStringList args = QStringList::split( " ", d->extraArgs );
+ QStringList::ConstIterator it = args.begin();
+ const QStringList::ConstIterator itEnd = args.end();
+ for ( ; it != itEnd; ++it )
+ *javaProcess << *it;
+ }
+
+ *javaProcess << d->mainClass;
+
+ if ( !d->classArgs.isNull() )
+ *javaProcess << d->classArgs;
+
+ kdDebug(6100) << "Invoking JVM now...with arguments = " << endl;
+ QString argStr;
+ QTextOStream stream( &argStr );
+ const QValueList<QCString> args = javaProcess->args();
+ qCopy( args.begin(), args.end(), QTextOStreamIterator<QCString>( stream, " " ) );
+ kdDebug(6100) << argStr << endl;
+
+ KProcess::Communication flags = (KProcess::Communication)
+ (KProcess::Stdin | KProcess::Stdout |
+ KProcess::NoRead);
+
+ const bool rval = javaProcess->start( KProcess::NotifyOnExit, flags );
+ if( rval )
+ javaProcess->resume(); //start processing stdout on the java process
+ else
+ killJVM();
+
+ return rval;
+}
+
+void KJavaProcess::killJVM()
+{
+ d->processKilled = true;
+ disconnect( javaProcess, SIGNAL( receivedStdout( int, int& ) ),
+ this, SLOT( slotReceivedData(int, int&) ) );
+ javaProcess->kill();
+}
+
+void KJavaProcess::flushBuffers()
+{
+ while ( !d->BufferList.isEmpty() ) {
+ if (innot)
+ slotSendData(0);
+ else
+ d->BufferList.removeFirst(); //note: AutoDelete is true
+ }
+}
+
+/* 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( int fd, int& len )
+{
+ //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( fd, length, 8 );
+ if( !num_bytes )
+ {
+ len = 0;
+ return;
+ }
+ if( num_bytes == -1 )
+ {
+ kdError(6100) << "could not read 8 characters for the message length!!!!" << endl;
+ len = 0;
+ return;
+ }
+
+ const QString lengthstr( length );
+ bool ok;
+ const int num_len = lengthstr.toInt( &ok );
+ if( !ok )
+ {
+ kdError(6100) << "could not parse length out of: " << lengthstr << endl;
+ len = num_bytes;
+ return;
+ }
+
+ //now parse out the rest of the message.
+ char* const msg = new char[num_len];
+ const int num_bytes_msg = ::read( fd, msg, num_len );
+ if( num_bytes_msg == -1 || num_bytes_msg != num_len )
+ {
+ kdError(6100) << "could not read the msg, num_bytes_msg = " << num_bytes_msg << endl;
+ delete[] msg;
+ len = num_bytes;
+ return;
+ }
+
+ QByteArray qb;
+ emit received( qb.duplicate( msg, num_len ) );
+ delete[] msg;
+ len = num_bytes + num_bytes_msg;
+}
+
+void KJavaProcess::slotExited( KProcess *process )
+{
+ if (process == javaProcess) {
+ int status = -1;
+ if (!d->processKilled) {
+ status = javaProcess->exitStatus();
+ }
+ kdDebug(6100) << "jvm exited with status " << status << endl;
+ emit exited(status);
+ }
+}
+
+#include "kjavaprocess.moc"