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