khtml Library API Documentation

kjavaappletserver.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 <config.h>
00023 #include "kjavaappletserver.h"
00024 #include "kjavaappletcontext.h"
00025 #include "kjavaprocess.h"
00026 #include "kjavadownloader.h"
00027 
00028 #include <kdebug.h>
00029 #include <kconfig.h>
00030 #include <klocale.h>
00031 #include <kparts/browserextension.h>
00032 #include <kapplication.h>
00033 #include <kstandarddirs.h>
00034 
00035 #include <kio/job.h>
00036 #include <kio/kprotocolmanager.h>
00037 
00038 #include <qtimer.h>
00039 #include <qguardedptr.h>
00040 #include <qdir.h>
00041 
00042 #include <stdlib.h>
00043 
00044 #define KJAS_CREATE_CONTEXT    (char)1
00045 #define KJAS_DESTROY_CONTEXT   (char)2
00046 #define KJAS_CREATE_APPLET     (char)3
00047 #define KJAS_DESTROY_APPLET    (char)4
00048 #define KJAS_START_APPLET      (char)5
00049 #define KJAS_STOP_APPLET       (char)6
00050 #define KJAS_INIT_APPLET       (char)7
00051 #define KJAS_SHOW_DOCUMENT     (char)8
00052 #define KJAS_SHOW_URLINFRAME   (char)9
00053 #define KJAS_SHOW_STATUS       (char)10
00054 #define KJAS_RESIZE_APPLET     (char)11
00055 #define KJAS_GET_URLDATA       (char)12
00056 #define KJAS_URLDATA           (char)13
00057 #define KJAS_SHUTDOWN_SERVER   (char)14
00058 #define KJAS_JAVASCRIPT_EVENT   (char)15
00059 #define KJAS_GET_MEMBER        (char)16
00060 #define KJAS_CALL_MEMBER       (char)17
00061 #define KJAS_PUT_MEMBER        (char)18
00062 #define KJAS_DEREF_OBJECT      (char)19
00063 #define KJAS_AUDIOCLIP_PLAY    (char)20
00064 #define KJAS_AUDIOCLIP_LOOP    (char)21
00065 #define KJAS_AUDIOCLIP_STOP    (char)22
00066 #define KJAS_APPLET_STATE      (char)23
00067 #define KJAS_APPLET_FAILED     (char)24
00068 
00069 
00070 class JSStackNode {
00071 public:
00072     JSStackNode(JSStackNode *u) : ready(false), size(u ? u->size+1: 1), up(u) {}
00073     bool ready;
00074     QStringList args;
00075     int size;
00076     JSStackNode *up;
00077 };
00078 
00079 // For future expansion
00080 class KJavaAppletServerPrivate
00081 {
00082 friend class KJavaAppletServer;
00083 private:
00084    int counter;
00085    QMap< int, QGuardedPtr<KJavaAppletContext> > contexts;
00086    QString appletLabel;
00087    JSStackNode *jsstack;
00088 };
00089 
00090 static KJavaAppletServer* self = 0;
00091 
00092 KJavaAppletServer::KJavaAppletServer()
00093 {
00094     d = new KJavaAppletServerPrivate;
00095     d->jsstack = 0L;
00096     process = new KJavaProcess();
00097 
00098     connect( process, SIGNAL(received(const QByteArray&)),
00099              this,    SLOT(slotJavaRequest(const QByteArray&)) );
00100 
00101     setupJava( process );
00102 
00103     if( process->startJava() )
00104         d->appletLabel = i18n( "Loading Applet" );
00105     else
00106         d->appletLabel = i18n( "Error: java executable not found" );
00107 
00108 }
00109 
00110 KJavaAppletServer::~KJavaAppletServer()
00111 {
00112     quit();
00113 
00114     delete process;
00115     delete d;
00116 }
00117 
00118 QString KJavaAppletServer::getAppletLabel()
00119 {
00120     if( self )
00121         return self->appletLabel();
00122     else
00123         return QString::null;
00124 }
00125 
00126 QString KJavaAppletServer::appletLabel()
00127 {
00128     return d->appletLabel;
00129 }
00130 
00131 KJavaAppletServer* KJavaAppletServer::allocateJavaServer()
00132 {
00133    if( self == 0 )
00134    {
00135       self = new KJavaAppletServer();
00136       self->d->counter = 0;
00137    }
00138 
00139    self->d->counter++;
00140    return self;
00141 }
00142 
00143 void KJavaAppletServer::freeJavaServer()
00144 {
00145     self->d->counter--;
00146 
00147     if( self->d->counter == 0 )
00148     {
00149         //instead of immediately quitting here, set a timer to kill us
00150         //if there are still no servers- give us one minute
00151         //this is to prevent repeated loading and unloading of the jvm
00152         KConfig config( "konquerorrc", true );
00153         config.setGroup( "Java/JavaScript Settings" );
00154         if( config.readBoolEntry( "ShutdownAppletServer", true )  )
00155         {
00156             int value = config.readNumEntry( "AppletServerTimeout", 60 );
00157             QTimer::singleShot( value*1000, self, SLOT( checkShutdown() ) );
00158         }
00159     }
00160 }
00161 
00162 void KJavaAppletServer::checkShutdown()
00163 {
00164     if( self->d->counter == 0 )
00165     {
00166         delete self;
00167         self = 0;
00168     }
00169 }
00170 
00171 void KJavaAppletServer::setupJava( KJavaProcess *p )
00172 {
00173     KConfig config ( "konquerorrc", true );
00174     config.setGroup( "Java/JavaScript Settings" );
00175 
00176     QString jvm_path = "java";
00177 
00178     QString jPath = config.readEntry( "JavaPath" );
00179     if ( !jPath.isEmpty() && jPath != "java" )
00180     {
00181         // Cut off trailing slash if any
00182         if( jPath[jPath.length()-1] == '/' )
00183             jPath.remove(jPath.length()-1, 1);
00184             
00185         QDir dir( jPath );
00186         if( dir.exists( "bin/java" ) )
00187         {
00188             jvm_path = jPath + "/bin/java";
00189         } 
00190         else if (dir.exists( "/jre/bin/java" ) )
00191         { 
00192             jvm_path = jPath + "/jre/bin/java";
00193         } 
00194         else if( QFile::exists(jPath) )
00195         {
00196             //check here to see if they entered the whole path the java exe
00197             jvm_path = jPath;
00198         }
00199     }
00200 
00201     //check to see if jvm_path is valid and set d->appletLabel accordingly
00202     p->setJVMPath( jvm_path );
00203 
00204     // Prepare classpath variable
00205     QString kjava_class = locate("data", "kjava/kjava.jar");
00206     kdDebug(6100) << "kjava_class = " << kjava_class << endl;
00207     if( kjava_class.isNull() ) // Should not happen
00208         return;
00209 
00210     QDir dir( kjava_class );
00211     dir.cdUp();
00212     kdDebug(6100) << "dir = " << dir.absPath() << endl;
00213 
00214     QStringList entries = dir.entryList( "*.jar" );
00215     kdDebug(6100) << "entries = " << entries.join( ":" ) << endl;
00216 
00217     QString classes;
00218     for( QStringList::Iterator it = entries.begin();
00219          it != entries.end(); it++ )
00220     {
00221         if( !classes.isEmpty() )
00222             classes += ":";
00223         classes += dir.absFilePath( *it );
00224     }
00225     p->setClasspath( classes );
00226 
00227     // Fix all the extra arguments
00228     QString extraArgs = config.readEntry( "JavaArgs", "" );
00229     p->setExtraArgs( extraArgs );
00230 
00231     if( config.readBoolEntry( "ShowJavaConsole", false) )
00232     {
00233         p->setSystemProperty( "kjas.showConsole", QString::null );
00234     }
00235 
00236     if( config.readBoolEntry( "UseSecurityManager", true ) )
00237     {
00238         QString class_file = locate( "data", "kjava/kjava.policy" );
00239         p->setSystemProperty( "java.security.policy", class_file );
00240 
00241         p->setSystemProperty( "java.security.manager",
00242                               "org.kde.kjas.server.KJASSecurityManager" );
00243     }
00244 
00245     //check for http proxies...
00246     if( KProtocolManager::useProxy() )
00247     {
00248         // only proxyForURL honours automatic proxy scripts
00249         // we do not know the applet url here so we just use a dummy url
00250         // this is a workaround for now
00251         // FIXME
00252         KURL dummyURL( "http://www.kde.org/" );
00253         QString httpProxy = KProtocolManager::proxyForURL(dummyURL);
00254         kdDebug(6100) << "httpProxy is " << httpProxy << endl;
00255 
00256         KURL url( httpProxy );
00257         p->setSystemProperty( "http.proxyHost", url.host() );
00258         p->setSystemProperty( "http.proxyPort", QString::number( url.port() ) );
00259     }
00260 
00261     //set the main class to run
00262     p->setMainClass( "org.kde.kjas.server.Main" );
00263 }
00264 
00265 void KJavaAppletServer::createContext( int contextId, KJavaAppletContext* context )
00266 {
00267 //    kdDebug(6100) << "createContext: " << contextId << endl;
00268     d->contexts.insert( contextId, context );
00269 
00270     QStringList args;
00271     args.append( QString::number( contextId ) );
00272     process->send( KJAS_CREATE_CONTEXT, args );
00273 }
00274 
00275 void KJavaAppletServer::destroyContext( int contextId )
00276 {
00277 //    kdDebug(6100) << "destroyContext: " << contextId << endl;
00278     d->contexts.remove( contextId );
00279 
00280     QStringList args;
00281     args.append( QString::number( contextId ) );
00282     process->send( KJAS_DESTROY_CONTEXT, args );
00283 }
00284 
00285 void KJavaAppletServer::createApplet( int contextId, int appletId,
00286                                       const QString name, const QString clazzName,
00287                                       const QString baseURL, const QString codeBase,
00288                                       const QString jarFile, QSize size,
00289                                       const QMap<QString,QString>& params,
00290                                       const QString windowTitle )
00291 {
00292 //    kdDebug(6100) << "createApplet: contextId = " << contextId     << endl
00293 //              << "              appletId  = " << appletId      << endl
00294 //              << "              name      = " << name          << endl
00295 //              << "              clazzName = " << clazzName     << endl
00296 //              << "              baseURL   = " << baseURL       << endl
00297 //              << "              codeBase  = " << codeBase      << endl
00298 //              << "              jarFile   = " << jarFile       << endl
00299 //              << "              width     = " << size.width()  << endl
00300 //              << "              height    = " << size.height() << endl;
00301 
00302     QStringList args;
00303     args.append( QString::number( contextId ) );
00304     args.append( QString::number( appletId ) );
00305 
00306     //it's ok if these are empty strings, I take care of it later...
00307     args.append( name );
00308     args.append( clazzName );
00309     args.append( baseURL );
00310     args.append( codeBase );
00311     args.append( jarFile );
00312 
00313     args.append( QString::number( size.width() ) );
00314     args.append( QString::number( size.height() ) );
00315 
00316     args.append( windowTitle );
00317 
00318     //add on the number of parameter pairs...
00319     int num = params.count();
00320     QString num_params = QString("%1").arg( num, 8 );
00321     args.append( num_params );
00322 
00323     QMap< QString, QString >::ConstIterator it;
00324 
00325     for( it = params.begin(); it != params.end(); ++it )
00326     {
00327         args.append( it.key() );
00328         args.append( it.data() );
00329     }
00330 
00331     process->send( KJAS_CREATE_APPLET, args );
00332 }
00333 
00334 void KJavaAppletServer::initApplet( int contextId, int appletId )
00335 {
00336     QStringList args;
00337     args.append( QString::number( contextId ) );
00338     args.append( QString::number( appletId ) );
00339 
00340     process->send( KJAS_INIT_APPLET, args );
00341 }
00342 
00343 void KJavaAppletServer::destroyApplet( int contextId, int appletId )
00344 {
00345     QStringList args;
00346     args.append( QString::number(contextId) );
00347     args.append( QString::number(appletId) );
00348 
00349     process->send( KJAS_DESTROY_APPLET, args );
00350 }
00351 
00352 void KJavaAppletServer::startApplet( int contextId, int appletId )
00353 {
00354     QStringList args;
00355     args.append( QString::number(contextId) );
00356     args.append( QString::number(appletId) );
00357 
00358     process->send( KJAS_START_APPLET, args );
00359 }
00360 
00361 void KJavaAppletServer::stopApplet( int contextId, int appletId )
00362 {
00363     QStringList args;
00364     args.append( QString::number(contextId) );
00365     args.append( QString::number(appletId) );
00366 
00367     process->send( KJAS_STOP_APPLET, args );
00368 }
00369 
00370 void KJavaAppletServer::sendURLData( const QString& loaderID,
00371                                      const QString& url,
00372                                      const QByteArray& data )
00373 {
00374     QStringList args;
00375     args.append( loaderID );
00376     args.append( url );
00377 
00378     process->send( KJAS_URLDATA, args, data );
00379 
00380 }
00381 
00382 void KJavaAppletServer::quit()
00383 {
00384     QStringList args;
00385 
00386     process->send( KJAS_SHUTDOWN_SERVER, args );
00387 }
00388 
00389 void KJavaAppletServer::slotJavaRequest( const QByteArray& qb )
00390 {
00391     // qb should be one command only without the length string,
00392     // we parse out the command and it's meaning here...
00393     QString cmd;
00394     QStringList args;
00395     int index = 0;
00396     int qb_size = qb.size();
00397 
00398     //get the command code
00399     char cmd_code = qb[ index++ ];
00400     ++index; //skip the next sep
00401 
00402     //get contextID
00403     QString contextID;
00404     while( qb[index] != 0 && index < qb_size )
00405     {
00406         contextID += qb[ index++ ];
00407     }
00408     ++index; //skip the sep
00409 
00410     //now parse out the arguments
00411     while( index < qb_size )
00412     {
00413         QString tmp;
00414         while( qb[index] != 0 )
00415             tmp += qb[ index++ ];
00416 
00417         kdDebug(6100) << "KJavaAppletServer::slotJavaRequest: "<< tmp << endl;
00418         args.append( tmp );
00419 
00420         ++index; //skip the sep
00421     }
00422     //here I should find the context and call the method directly
00423     //instead of emitting signals
00424     switch( cmd_code )
00425     {
00426         case KJAS_SHOW_DOCUMENT:
00427             cmd = QString::fromLatin1( "showdocument" );
00428             break;
00429 
00430         case KJAS_SHOW_URLINFRAME:
00431             cmd = QString::fromLatin1( "showurlinframe" );
00432             break;
00433 
00434         case KJAS_SHOW_STATUS:
00435             cmd = QString::fromLatin1( "showstatus" );
00436             break;
00437 
00438         case KJAS_RESIZE_APPLET:
00439             cmd = QString::fromLatin1( "resizeapplet" );
00440             break;
00441 
00442         case KJAS_GET_URLDATA:
00443             //here we need to get some data for a class loader and send it back...
00444             kdDebug(6100) << "GetURLData from classloader: "<< contextID
00445                           << " for url: " << args[0] << endl;
00446             break;
00447         case KJAS_JAVASCRIPT_EVENT:
00448             cmd = QString::fromLatin1( "JS_Event" );
00449             kdDebug(6100) << "Javascript request: "<< contextID
00450                           << " code: " << args[0] << endl;
00451             break;
00452         case KJAS_GET_MEMBER:
00453         case KJAS_PUT_MEMBER:
00454         case KJAS_CALL_MEMBER:
00455             if (d->jsstack) {
00456                 d->jsstack->args = args;
00457                 d->jsstack->ready = true;
00458                 d->jsstack = d->jsstack->up;
00459                 process->syncCommandReceived();
00460             } else
00461                 kdDebug(6100) << "Error: Missed return member data" << endl;
00462             return;
00463         case KJAS_AUDIOCLIP_PLAY:
00464             cmd = QString::fromLatin1( "audioclip_play" );
00465             kdDebug(6100) << "Audio Play: url=" << args[0] << endl;
00466             break;
00467         case KJAS_AUDIOCLIP_LOOP:
00468             cmd = QString::fromLatin1( "audioclip_loop" );
00469             kdDebug(6100) << "Audio Loop: url=" << args[0] << endl;
00470             break;
00471         case KJAS_AUDIOCLIP_STOP:
00472             cmd = QString::fromLatin1( "audioclip_stop" );
00473             kdDebug(6100) << "Audio Stop: url=" << args[0] << endl;
00474             break;
00475         case KJAS_APPLET_STATE:
00476             kdDebug(6100) << "Applet State Notification for Applet " << args[0] << ". New state=" << args[1] << endl;
00477             cmd = QString::fromLatin1( "AppletStateNotification" );
00478             break;
00479         case KJAS_APPLET_FAILED:
00480             kdDebug(6100) << "Applet " << args[0] << " Failed: " << args[1] << endl;
00481             cmd = QString::fromLatin1( "AppletFailed" );
00482             break;
00483         default:
00484             return;
00485             break;
00486     }
00487 
00488     if( cmd_code == KJAS_GET_URLDATA )
00489     {
00490         new KJavaDownloader( contextID, args[0] );
00491     }
00492     else
00493     {
00494         bool ok;
00495         int contextID_num = contextID.toInt( &ok );
00496 
00497         if( !ok )
00498         {
00499             kdError(6100) << "could not parse out contextID to call command on" << endl;
00500             return;
00501         }
00502 
00503         KJavaAppletContext* context = d->contexts[ contextID_num ];
00504         if( context )
00505             context->processCmd( cmd, args );
00506         else if (cmd != "AppletStateNotification") 
00507             kdError(6100) << "no context object for this id" << endl;
00508     }
00509 }
00510 
00511 bool KJavaAppletServer::getMember(int contextId, int appletId, const unsigned long objid, const QString & name, int & type, unsigned long & rid, QString & value) {
00512     QStringList args;
00513     args.append( QString::number(contextId) );
00514     args.append( QString::number(appletId) );
00515     args.append( QString::number(objid) );
00516     args.append( name );
00517 
00518     JSStackNode * frame = d->jsstack = new JSStackNode(d->jsstack);
00519 
00520     kdDebug(6100) << "KJavaAppletServer::getMember " << name << endl;
00521     process->sendSync( KJAS_GET_MEMBER, args );
00522 
00523     bool retval = frame->ready;
00524     if (retval) {
00525         type = frame->args[0].toInt(&retval);
00526         if (retval && type >= 0) {
00527             rid = frame->args[1].toInt(&retval);
00528             value = frame->args[2];
00529         } else
00530             retval = false;
00531     } else {
00532         kdError(6100) << "getMember: timeout" << endl;
00533         d->jsstack = frame->up; // FIXME: if(d->jsstack != frame)
00534     }
00535 
00536     delete frame;
00537 
00538     return retval;
00539 }
00540 
00541 bool KJavaAppletServer::putMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QString & value) {
00542     QStringList args;
00543     args.append( QString::number(contextId) );
00544     args.append( QString::number(appletId) );
00545     args.append( QString::number(objid) );
00546     args.append( name );
00547     args.append( value );
00548 
00549     kdDebug(6100) << "KJavaAppletServer::putMember " << name << endl;
00550     JSStackNode * frame = d->jsstack = new JSStackNode(d->jsstack);
00551 
00552     process->sendSync( KJAS_PUT_MEMBER, args );
00553 
00554     bool retval = frame->ready;
00555     if (retval) {
00556         retval = frame->args[0].toInt(&retval);
00557     } else {
00558         kdError(6100) << "putMember: timeout" << endl;
00559         d->jsstack = frame->up;
00560     }
00561 
00562     delete frame;
00563 
00564     return retval;
00565 }
00566 
00567 bool KJavaAppletServer::callMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QStringList & fargs, int & type, unsigned long & rid, QString & value) {
00568     QStringList args;
00569     args.append( QString::number(contextId) );
00570     args.append( QString::number(appletId) );
00571     args.append( QString::number(objid) );
00572     args.append( name );
00573     for (QStringList::const_iterator it = fargs.begin(); it != fargs.end(); it++)
00574         args.append(*it);
00575 
00576     JSStackNode * frame = d->jsstack = new JSStackNode(d->jsstack);
00577 
00578     kdDebug(6100) << "KJavaAppletServer::callMember " << name << endl;
00579     process->sendSync( KJAS_CALL_MEMBER, args );
00580 
00581     bool retval = frame->ready;
00582     if (retval) {
00583         type = frame->args[0].toInt(&retval);
00584         if (retval && type > -1) {
00585             rid = frame->args[1].toInt(&retval);
00586             if (retval)
00587                 value = frame->args[2];
00588         } else
00589             retval = false;
00590     } else {
00591         kdError(6100) << "callMember: timeout return data" << endl;
00592         d->jsstack = frame->up;
00593     }
00594 
00595     delete frame;
00596 
00597     return retval;
00598 }
00599 
00600 void KJavaAppletServer::derefObject(int contextId, int appletId, const unsigned long objid) {
00601     QStringList args;
00602     args.append( QString::number(contextId) );
00603     args.append( QString::number(appletId) );
00604     args.append( QString::number(objid) );
00605 
00606     process->send( KJAS_DEREF_OBJECT, args );
00607 }
00608 #include "kjavaappletserver.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:40 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001