00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 #include <assert.h>
00044
00045 #define KJAS_CREATE_CONTEXT (char)1
00046 #define KJAS_DESTROY_CONTEXT (char)2
00047 #define KJAS_CREATE_APPLET (char)3
00048 #define KJAS_DESTROY_APPLET (char)4
00049 #define KJAS_START_APPLET (char)5
00050 #define KJAS_STOP_APPLET (char)6
00051 #define KJAS_INIT_APPLET (char)7
00052 #define KJAS_SHOW_DOCUMENT (char)8
00053 #define KJAS_SHOW_URLINFRAME (char)9
00054 #define KJAS_SHOW_STATUS (char)10
00055 #define KJAS_RESIZE_APPLET (char)11
00056 #define KJAS_GET_URLDATA (char)12
00057 #define KJAS_URLDATA (char)13
00058 #define KJAS_SHUTDOWN_SERVER (char)14
00059 #define KJAS_JAVASCRIPT_EVENT (char)15
00060 #define KJAS_GET_MEMBER (char)16
00061 #define KJAS_CALL_MEMBER (char)17
00062 #define KJAS_PUT_MEMBER (char)18
00063 #define KJAS_DEREF_OBJECT (char)19
00064 #define KJAS_AUDIOCLIP_PLAY (char)20
00065 #define KJAS_AUDIOCLIP_LOOP (char)21
00066 #define KJAS_AUDIOCLIP_STOP (char)22
00067 #define KJAS_APPLET_STATE (char)23
00068 #define KJAS_APPLET_FAILED (char)24
00069
00070
00071 class JSStackNode {
00072 public:
00073 JSStackNode() : ready(false) {}
00074 bool ready;
00075 QStringList args;
00076 int size;
00077 };
00078
00079
00080 class KJavaAppletServerPrivate
00081 {
00082 friend class KJavaAppletServer;
00083 private:
00084 int counter;
00085 int ticketcounter;
00086 QMap< int, QGuardedPtr<KJavaAppletContext> > contexts;
00087 QString appletLabel;
00088 QMap< int, JSStackNode* > jsstack;
00089 bool javaProcessFailed;
00090 };
00091
00092 static KJavaAppletServer* self = 0;
00093
00094 KJavaAppletServer::KJavaAppletServer()
00095 {
00096 d = new KJavaAppletServerPrivate;
00097 d->ticketcounter = 0;
00098 process = new KJavaProcess();
00099
00100 connect( process, SIGNAL(received(const QByteArray&)),
00101 this, SLOT(slotJavaRequest(const QByteArray&)) );
00102
00103 setupJava( process );
00104
00105 if( process->startJava() ) {
00106 d->appletLabel = i18n( "Loading Applet" );
00107 d->javaProcessFailed = false;
00108 }
00109 else {
00110 d->appletLabel = i18n( "Error: java executable not found" );
00111 d->javaProcessFailed = true;
00112 }
00113 }
00114
00115 KJavaAppletServer::~KJavaAppletServer()
00116 {
00117 quit();
00118
00119 delete process;
00120 delete d;
00121 }
00122
00123 QString KJavaAppletServer::getAppletLabel()
00124 {
00125 if( self )
00126 return self->appletLabel();
00127 else
00128 return QString::null;
00129 }
00130
00131 QString KJavaAppletServer::appletLabel()
00132 {
00133 return d->appletLabel;
00134 }
00135
00136 KJavaAppletServer* KJavaAppletServer::allocateJavaServer()
00137 {
00138 if( self == 0 )
00139 {
00140 self = new KJavaAppletServer();
00141 self->d->counter = 0;
00142 }
00143
00144 self->d->counter++;
00145 return self;
00146 }
00147
00148 void KJavaAppletServer::freeJavaServer()
00149 {
00150 self->d->counter--;
00151
00152 if( self->d->counter == 0 )
00153 {
00154
00155
00156
00157 KConfig config( "konquerorrc", true );
00158 config.setGroup( "Java/JavaScript Settings" );
00159 if( config.readBoolEntry( "ShutdownAppletServer", true ) )
00160 {
00161 int value = config.readNumEntry( "AppletServerTimeout", 60 );
00162 QTimer::singleShot( value*1000, self, SLOT( checkShutdown() ) );
00163 }
00164 }
00165 }
00166
00167 void KJavaAppletServer::checkShutdown()
00168 {
00169 if( self->d->counter == 0 )
00170 {
00171 delete self;
00172 self = 0;
00173 }
00174 }
00175
00176 void KJavaAppletServer::setupJava( KJavaProcess *p )
00177 {
00178 KConfig config ( "konquerorrc", true );
00179 config.setGroup( "Java/JavaScript Settings" );
00180
00181 QString jvm_path = "java";
00182
00183 QString jPath = config.readPathEntry( "JavaPath" );
00184 if ( !jPath.isEmpty() && jPath != "java" )
00185 {
00186
00187 if( jPath[jPath.length()-1] == '/' )
00188 jPath.remove(jPath.length()-1, 1);
00189
00190 QDir dir( jPath );
00191 if( dir.exists( "bin/java" ) )
00192 {
00193 jvm_path = jPath + "/bin/java";
00194 }
00195 else if (dir.exists( "/jre/bin/java" ) )
00196 {
00197 jvm_path = jPath + "/jre/bin/java";
00198 }
00199 else if( QFile::exists(jPath) )
00200 {
00201
00202 jvm_path = jPath;
00203 }
00204 }
00205
00206
00207 p->setJVMPath( jvm_path );
00208
00209
00210 QString kjava_class = locate("data", "kjava/kjava.jar");
00211 kdDebug(6100) << "kjava_class = " << kjava_class << endl;
00212 if( kjava_class.isNull() )
00213 return;
00214
00215 QDir dir( kjava_class );
00216 dir.cdUp();
00217 kdDebug(6100) << "dir = " << dir.absPath() << endl;
00218
00219 QStringList entries = dir.entryList( "*.jar" );
00220 kdDebug(6100) << "entries = " << entries.join( ":" ) << endl;
00221
00222 QString classes;
00223 for( QStringList::Iterator it = entries.begin();
00224 it != entries.end(); it++ )
00225 {
00226 if( !classes.isEmpty() )
00227 classes += ":";
00228 classes += dir.absFilePath( *it );
00229 }
00230 p->setClasspath( classes );
00231
00232
00233 QString extraArgs = config.readEntry( "JavaArgs" );
00234 p->setExtraArgs( extraArgs );
00235
00236 if( config.readBoolEntry( "ShowJavaConsole", false) )
00237 {
00238 p->setSystemProperty( "kjas.showConsole", QString::null );
00239 }
00240
00241 if( config.readBoolEntry( "UseSecurityManager", true ) )
00242 {
00243 QString class_file = locate( "data", "kjava/kjava.policy" );
00244 p->setSystemProperty( "java.security.policy", class_file );
00245
00246 p->setSystemProperty( "java.security.manager",
00247 "org.kde.kjas.server.KJASSecurityManager" );
00248 }
00249
00250
00251 if( KProtocolManager::useProxy() )
00252 {
00253
00254
00255
00256
00257 KURL dummyURL( "http://www.kde.org/" );
00258 QString httpProxy = KProtocolManager::proxyForURL(dummyURL);
00259 kdDebug(6100) << "httpProxy is " << httpProxy << endl;
00260
00261 KURL url( httpProxy );
00262 p->setSystemProperty( "http.proxyHost", url.host() );
00263 p->setSystemProperty( "http.proxyPort", QString::number( url.port() ) );
00264 }
00265
00266
00267 p->setMainClass( "org.kde.kjas.server.Main" );
00268 }
00269
00270 void KJavaAppletServer::createContext( int contextId, KJavaAppletContext* context )
00271 {
00272
00273 if ( d->javaProcessFailed ) return;
00274
00275 d->contexts.insert( contextId, context );
00276
00277 QStringList args;
00278 args.append( QString::number( contextId ) );
00279 process->send( KJAS_CREATE_CONTEXT, args );
00280 }
00281
00282 void KJavaAppletServer::destroyContext( int contextId )
00283 {
00284
00285 if ( d->javaProcessFailed ) return;
00286 d->contexts.remove( contextId );
00287
00288 QStringList args;
00289 args.append( QString::number( contextId ) );
00290 process->send( KJAS_DESTROY_CONTEXT, args );
00291 }
00292
00293 bool KJavaAppletServer::createApplet( int contextId, int appletId,
00294 const QString & name, const QString & clazzName,
00295 const QString & baseURL, const QString & user,
00296 const QString & password, const QString & authname,
00297 const QString & codeBase, const QString & jarFile,
00298 QSize size, const QMap<QString,QString>& params,
00299 const QString & windowTitle )
00300 {
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 if ( d->javaProcessFailed ) return false;
00312
00313 QStringList args;
00314 args.append( QString::number( contextId ) );
00315 args.append( QString::number( appletId ) );
00316
00317
00318 args.append( name );
00319 args.append( clazzName );
00320 args.append( baseURL );
00321 args.append( user );
00322 args.append( password );
00323 args.append( authname );
00324 args.append( codeBase );
00325 args.append( jarFile );
00326
00327 args.append( QString::number( size.width() ) );
00328 args.append( QString::number( size.height() ) );
00329
00330 args.append( windowTitle );
00331
00332
00333 int num = params.count();
00334 QString num_params = QString("%1").arg( num, 8 );
00335 args.append( num_params );
00336
00337 QMap< QString, QString >::ConstIterator it;
00338
00339 for( it = params.begin(); it != params.end(); ++it )
00340 {
00341 args.append( it.key() );
00342 args.append( it.data() );
00343 }
00344
00345 process->send( KJAS_CREATE_APPLET, args );
00346
00347 return true;
00348 }
00349
00350 void KJavaAppletServer::initApplet( int contextId, int appletId )
00351 {
00352 if ( d->javaProcessFailed ) return;
00353 QStringList args;
00354 args.append( QString::number( contextId ) );
00355 args.append( QString::number( appletId ) );
00356
00357 process->send( KJAS_INIT_APPLET, args );
00358 }
00359
00360 void KJavaAppletServer::destroyApplet( int contextId, int appletId )
00361 {
00362 if ( d->javaProcessFailed ) return;
00363 QStringList args;
00364 args.append( QString::number(contextId) );
00365 args.append( QString::number(appletId) );
00366
00367 process->send( KJAS_DESTROY_APPLET, args );
00368 }
00369
00370 void KJavaAppletServer::startApplet( int contextId, int appletId )
00371 {
00372 if ( d->javaProcessFailed ) return;
00373 QStringList args;
00374 args.append( QString::number(contextId) );
00375 args.append( QString::number(appletId) );
00376
00377 process->send( KJAS_START_APPLET, args );
00378 }
00379
00380 void KJavaAppletServer::stopApplet( int contextId, int appletId )
00381 {
00382 if ( d->javaProcessFailed ) return;
00383 QStringList args;
00384 args.append( QString::number(contextId) );
00385 args.append( QString::number(appletId) );
00386
00387 process->send( KJAS_STOP_APPLET, args );
00388 }
00389
00390 void KJavaAppletServer::sendURLData( const QString& loaderID,
00391 const QString& url,
00392 const QByteArray& data )
00393 {
00394 QStringList args;
00395 args.append( loaderID );
00396 args.append( url );
00397
00398 process->send( KJAS_URLDATA, args, data );
00399
00400 }
00401
00402 void KJavaAppletServer::quit()
00403 {
00404 QStringList args;
00405
00406 process->send( KJAS_SHUTDOWN_SERVER, args );
00407 }
00408
00409 void KJavaAppletServer::slotJavaRequest( const QByteArray& qb )
00410 {
00411
00412
00413 QString cmd;
00414 QStringList args;
00415 int index = 0;
00416 int qb_size = qb.size();
00417
00418
00419 char cmd_code = qb[ index++ ];
00420 ++index;
00421
00422
00423 QString contextID;
00424 while( qb[index] != 0 && index < qb_size )
00425 {
00426 contextID += qb[ index++ ];
00427 }
00428 ++index;
00429
00430
00431 while( index < qb_size )
00432 {
00433 QString tmp;
00434 while( qb[index] != 0 )
00435 tmp += qb[ index++ ];
00436
00437 kdDebug(6100) << "KJavaAppletServer::slotJavaRequest: "<< tmp << endl;
00438 args.append( tmp );
00439
00440 ++index;
00441 }
00442
00443
00444 switch( cmd_code )
00445 {
00446 case KJAS_SHOW_DOCUMENT:
00447 cmd = QString::fromLatin1( "showdocument" );
00448 break;
00449
00450 case KJAS_SHOW_URLINFRAME:
00451 cmd = QString::fromLatin1( "showurlinframe" );
00452 break;
00453
00454 case KJAS_SHOW_STATUS:
00455 cmd = QString::fromLatin1( "showstatus" );
00456 break;
00457
00458 case KJAS_RESIZE_APPLET:
00459 cmd = QString::fromLatin1( "resizeapplet" );
00460 break;
00461
00462 case KJAS_GET_URLDATA:
00463
00464 kdDebug(6100) << "GetURLData from classloader: "<< contextID
00465 << " for url: " << args[0] << endl;
00466 break;
00467 case KJAS_JAVASCRIPT_EVENT:
00468 cmd = QString::fromLatin1( "JS_Event" );
00469 kdDebug(6100) << "Javascript request: "<< contextID
00470 << " code: " << args[0] << endl;
00471 break;
00472 case KJAS_GET_MEMBER:
00473 case KJAS_PUT_MEMBER:
00474 case KJAS_CALL_MEMBER: {
00475 int ticket = args[0].toInt();
00476 QMap<int, JSStackNode*>::iterator it = d->jsstack.find(ticket);
00477 if (it != d->jsstack.end()) {
00478 kdDebug(6100) << "slotJavaRequest: " << ticket << endl;
00479 args.pop_front();
00480 it.data()->args = args;
00481 it.data()->ready = true;
00482 process->syncCommandReceived(ticket);
00483 } else
00484 kdDebug(6100) << "Error: Missed return member data" << endl;
00485 return;
00486 }
00487 case KJAS_AUDIOCLIP_PLAY:
00488 cmd = QString::fromLatin1( "audioclip_play" );
00489 kdDebug(6100) << "Audio Play: url=" << args[0] << endl;
00490 break;
00491 case KJAS_AUDIOCLIP_LOOP:
00492 cmd = QString::fromLatin1( "audioclip_loop" );
00493 kdDebug(6100) << "Audio Loop: url=" << args[0] << endl;
00494 break;
00495 case KJAS_AUDIOCLIP_STOP:
00496 cmd = QString::fromLatin1( "audioclip_stop" );
00497 kdDebug(6100) << "Audio Stop: url=" << args[0] << endl;
00498 break;
00499 case KJAS_APPLET_STATE:
00500 kdDebug(6100) << "Applet State Notification for Applet " << args[0] << ". New state=" << args[1] << endl;
00501 cmd = QString::fromLatin1( "AppletStateNotification" );
00502 break;
00503 case KJAS_APPLET_FAILED:
00504 kdDebug(6100) << "Applet " << args[0] << " Failed: " << args[1] << endl;
00505 cmd = QString::fromLatin1( "AppletFailed" );
00506 break;
00507 default:
00508 return;
00509 break;
00510 }
00511
00512 if( cmd_code == KJAS_GET_URLDATA )
00513 {
00514 new KJavaDownloader( contextID, args[0] );
00515 }
00516 else
00517 {
00518 bool ok;
00519 int contextID_num = contextID.toInt( &ok );
00520
00521 if( !ok )
00522 {
00523 kdError(6100) << "could not parse out contextID to call command on" << endl;
00524 return;
00525 }
00526
00527 KJavaAppletContext* context = d->contexts[ contextID_num ];
00528 if( context )
00529 context->processCmd( cmd, args );
00530 else if (cmd != "AppletStateNotification")
00531 kdError(6100) << "no context object for this id" << endl;
00532 }
00533 }
00534
00535 bool KJavaAppletServer::getMember(int contextId, int appletId, const unsigned long objid, const QString & name, int & type, unsigned long & rid, QString & value) {
00536 QStringList args;
00537 int ticket = d->ticketcounter++;
00538 args.append( QString::number(contextId) );
00539 args.append( QString::number(appletId) );
00540 args.append( QString::number(ticket) );
00541 args.append( QString::number(objid) );
00542 args.append( name );
00543
00544 JSStackNode * frame = new JSStackNode;
00545 d->jsstack.insert(ticket, frame);
00546 kdDebug(6100) << "KJavaAppletServer::getMember " << name << " " << ticket << endl;
00547 process->sendSync( ticket, KJAS_GET_MEMBER, args );
00548
00549 bool retval = frame->ready;
00550 if (retval && frame->args.count() == 3) {
00551 type = frame->args[0].toInt(&retval);
00552 if (retval && type >= 0) {
00553 rid = frame->args[1].toInt(&retval);
00554 value = frame->args[2];
00555 } else
00556 retval = false;
00557 } else {
00558 kdError(6100) << "getMember: " << (retval ? "args ":"timeout ") << ticket << endl;
00559 }
00560
00561 d->jsstack.erase(ticket);
00562 delete frame;
00563
00564 return retval;
00565 }
00566
00567 bool KJavaAppletServer::putMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QString & value) {
00568 QStringList args;
00569 int ticket = d->ticketcounter++;
00570 args.append( QString::number(contextId) );
00571 args.append( QString::number(appletId) );
00572 args.append( QString::number(ticket) );
00573 args.append( QString::number(objid) );
00574 args.append( name );
00575 args.append( value );
00576
00577 JSStackNode * frame = new JSStackNode;
00578 d->jsstack.insert(ticket, frame);
00579 kdDebug(6100) << "KJavaAppletServer::putMember " << name << " " << ticket << endl;
00580
00581 process->sendSync( ticket, KJAS_PUT_MEMBER, args );
00582
00583 bool retval = frame->ready;
00584 if (retval) {
00585 retval = frame->args[0].toInt(&retval);
00586 } else {
00587 kdError(6100) << "putMember: timeout" << endl;
00588 }
00589
00590 d->jsstack.erase(ticket);
00591 delete frame;
00592
00593 return retval;
00594 }
00595
00596 bool KJavaAppletServer::callMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QStringList & fargs, int & type, unsigned long & rid, QString & value) {
00597 QStringList args;
00598 int ticket = d->ticketcounter++;
00599 args.append( QString::number(contextId) );
00600 args.append( QString::number(appletId) );
00601 args.append( QString::number(ticket) );
00602 args.append( QString::number(objid) );
00603 args.append( name );
00604 for (QStringList::const_iterator it = fargs.begin(); it != fargs.end(); it++)
00605 args.append(*it);
00606
00607 JSStackNode * frame = new JSStackNode;
00608 d->jsstack.insert(ticket, frame);
00609
00610 kdDebug(6100) << "KJavaAppletServer::callMember " << name << " " << ticket << endl;
00611 process->sendSync( ticket, KJAS_CALL_MEMBER, args );
00612
00613 bool retval = frame->ready;
00614 if (retval) {
00615 type = frame->args[0].toInt(&retval);
00616 if (retval && type > -1) {
00617 rid = frame->args[1].toInt(&retval);
00618 if (retval)
00619 value = frame->args[2];
00620 } else
00621 retval = false;
00622 } else {
00623 kdError(6100) << "callMember: timeout return data" << endl;
00624 }
00625
00626 d->jsstack.erase(ticket);
00627 delete frame;
00628
00629 return retval;
00630 }
00631
00632 void KJavaAppletServer::derefObject(int contextId, int appletId, const unsigned long objid) {
00633 QStringList args;
00634 args.append( QString::number(contextId) );
00635 args.append( QString::number(appletId) );
00636 args.append( QString::number(objid) );
00637
00638 process->send( KJAS_DEREF_OBJECT, args );
00639 }
00640 #include "kjavaappletserver.moc"