diff -r f5050f1da672 -r 04becd199f91 javauis/javalegacyutils/src/eventserver/CJavaEventServer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/javalegacyutils/src/eventserver/CJavaEventServer.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,481 @@ +/* +* Copyright (c) 1999-2001 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include +#include +#include + +#include "JesServer.h" +#include "CJavaEventServer.h" + + + +const TInt KMaxUserName=64; +const TInt KMaxJesName=3+1+8+1+KMaxUserName+1+8; + + +class TJesName : public TBuf +{ +public: + TJesName(const TDesC& aUserName); + TJesName(const TDesC& aUserName,TInt aHandle); +private: + void Build(const TDesC& aUserName); +}; + +class TJesParam : public MEventServer +{ +public: + virtual void Started(TInt aError, RServer2 aServer) + { + iServerHandle = aServer; + iThread.RequestComplete(iStatus,aError); + } + virtual TAny* Arg() const + { + return iArg; + } +public: + RThread iThread; + RServer2 iServerHandle; + TRequestStatus* iStatus; + TAny* iArg; +}; + +class CJesSession : public CSession2 +{ + class TExecute + { + public: + inline TInt operator()() const; + private: + TInt(*iFunc)(TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*); + TAny* iParam[9]; + }; +private: + void ServiceL(const RMessage2& aMessage); + static TInt ExecuteTrap(const TExecute& aExecute); +}; + +class CJesScheduler : public CActiveScheduler, public MJesShutdown +{ +public: + static TInt Create(RServer2& serverHandle); + virtual void Shutdown(); +private: + CJesScheduler(); + static void CreateL(RServer2& serverHandle); +private: + CJesServer iServer; +}; + +// Class TJesName + +// The thread name is made up of the user name, the process Id and +// the address of this object. + +_LIT(KName,"jes-"); + +TJesName::TJesName(const TDesC& aUserName) +// +// Construct the base Java Event Server name +// +{ + Build(aUserName); +} + +TJesName::TJesName(const TDesC& aUserName,TInt aHandle) +// +// Construct the full Java Event Server name +// +{ + Build(aUserName); + AppendNum(aHandle,EHex); +} + +void TJesName::Build(const TDesC& aUserName) +// +// Create the base of the server name +// +{ + Copy(KName); + TProcessId id(RProcess().Id()); + AppendNum(*reinterpret_cast(&id),EHex); + Append('-'); + Append(aUserName); + Append('@'); +} + + +// class RJess + +TInt RJess::Connect(RServer2& aServer) +// +// Establish an IPC session with the event server and share it +// +{ + TInt r=CreateSession(aServer, TVersion(), CJavaEventBase::ELastPriority + 1); + if (r==KErrNone) + { + r=ShareAuto(); + if (r!=KErrNone) + Close(); + } + return r; +} + +// class TJavaEventServer + +inline TJavaEventServer::TJavaEventServer(CJavaEventServer* aServer) + :iServer(aServer) +{} + +EXPORT_C TJavaEventServer TJavaEventServer::NewL(const TDesC& aName, TThreadFunction aServerThread, TAny* aServerArg) +{ + return CJavaEventServer::NewL(aName, aServerThread, aServerArg, 0, 0); +} + +EXPORT_C TJavaEventServer TJavaEventServer::NewL(const TDesC& aName, TThreadFunction aServerThread, TAny* aServerArg, + TUint aStackSize, RAllocator* aHeap) +{ + return CJavaEventServer::NewL(aName, aServerThread, aServerArg, aStackSize, aHeap); +} + +EXPORT_C void TJavaEventServer::Shutdown() +{ + iServer->Shutdown(); +} + +// class CJesServer + +EXPORT_C CJesServer::CJesServer(MJesShutdown* aShutdown): +// +// The Java Event Server shares the session between all thread clients +// + CServer2(0,ESharableSessions) + , iShutdown(aShutdown) +{ +} + +CJesServer::~CJesServer() +{ +} + +CSession2* CJesServer::NewSessionL(const TVersion& /*version*/, const RMessage2& /*message*/) const +{ + return new(ELeave) CJesSession(); +} + +void CJesServer::Shutdown() +{ + iShutdown.Start(); +} + + +// class CJesScheduler +CJesScheduler::CJesScheduler() + : iServer(this) +{ +} + +void CJesScheduler::Shutdown() +{ + CActiveScheduler::Stop(); +} + +void CJesScheduler::CreateL(RServer2& serverHandle) +{ + CJesScheduler* s=new(ELeave) CJesScheduler; + CActiveScheduler::Install(s); + s->iServer.StartL(KNullDesC); + serverHandle = s->iServer.Server(); +} + +TInt CJesScheduler::Create(RServer2& serverHandle) +// +// Create the Java Event thread scheduler and server +// +{ + TRAPD(r,CreateL(serverHandle)); + return r; +} + +// java-side +void CJavaEventServer::AddRef() +{ + iMutex.Wait(); + ++iRef; + iMutex.Signal(); +} + +// java-side +void CJavaEventServer::RemoveRef() +{ + iMutex.Wait(); + if ((--iRef == 0) && iShutdown) + { + iSession.Shutdown(); + } + iMutex.Signal(); +} + +// java-side - consider purging event queue. +void CJavaEventServer::Shutdown() +{ + iMutex.Wait(); + iShutdown=ETrue; + if (0 == iRef) + { + iSession.Shutdown(); + } + iMutex.Signal(); +} + +TInt CJavaEventServer::ServerThread(TAny* aParam) +// +// The thread function for the Java event server thread +// This initialises the thread environment before reporting success +// and then starting its scheduler +// +{ + MEventServer* server = static_cast(aParam); + + TInt err = KErrNoMemory; + + RServer2 serverHandle; + + CTrapCleanup* cleanup = CTrapCleanup::New(); + if (cleanup) + { + err = CJesScheduler::Create(serverHandle); + } + + server->Started(err, serverHandle); // don't touch server again - its gone. + server = NULL; + if (err==KErrNone) + { + CActiveScheduler::Start(); + } + delete CActiveScheduler::Current(); // will delete all objects + delete cleanup; + return 0; +} + +#ifndef JAVA_STACKSIZE +#define JAVA_STACKSIZE 0x2000 +#endif + +void CJavaEventServer::ConstructL(const TDesC& aUserName, TThreadFunction aServerThread, TAny* aServerArg, + TUint aStackSize, RAllocator* aHeap) +// +// Main construction of the event server +// +{ + User::LeaveIfError(iMutex.CreateLocal()); + + if (NULL == aServerThread) + { + // default thread function. + aServerThread = &ServerThread; + } + + TJesParam param; + param.iArg = aServerArg; + User::LeaveIfError(param.iThread.Duplicate(param.iThread,EOwnerProcess)); // make the thread handle process relative + CleanupClosePushL(param.iThread); + TRequestStatus s(KRequestPending); + param.iStatus=&s; + RThread js; + if (aStackSize == 0) + { + aStackSize = JAVA_STACKSIZE; + } + + TJesName name(aUserName,TJavaEventServer::Handle(this)); + User::LeaveIfError(js.Create(name,aServerThread,aStackSize,aHeap,¶m,EOwnerProcess)); +// js.SetPriority(EPriorityMore); + js.Resume(); + js.Close(); + User::WaitForRequest(s); // wait for signal from server thread + User::LeaveIfError(s.Int()); + CleanupStack::PopAndDestroy(); // param.iThread + User::LeaveIfError(iSession.Connect(param.iServerHandle)); +} + +CJavaEventServer::CJavaEventServer() +{ +} + +CJavaEventServer::~CJavaEventServer() +{ + iSession.Close(); + iMutex.Close(); +} + +CJavaEventServer* CJavaEventServer::NewL(const TDesC& aUserName,TThreadFunction aServerThread, TAny* aServerArg, + TUint aStackSize, RAllocator* aHeap) +{ + CJavaEventServer* self=new(ELeave) CJavaEventServer; + CleanupStack::PushL(self); + self->ConstructL(aUserName, aServerThread, aServerArg, aStackSize, aHeap); + CleanupStack::Pop(); + return self; +} + +// class CJavaEventBase + +void CJavaEventBase::Run(JNIEnv& aJni) +// +// Dispatch this event and destroy the event object +// +{ + CJavaEventSourceBase& source = Object(); + + // check if the event type is disposable before calling java callback + // because if it's reusable it can be destroyed during servicing process + TBool isDisposable = IsDisposable(); + + if (!source.IsDisposed() && !aJni.IsSameObject(source.Peer(),0)) + { + if (aJni.PushLocalFrame(16)==0) + { + Dispatch(aJni); + if (aJni.ExceptionCheck()) + { // Report any exceptions that were generated and clear them from the JNI environment + aJni.ExceptionDescribe(); + aJni.ExceptionClear(); + } + aJni.PopLocalFrame(0); + } + } + if (isDisposable) + { + delete this; + } + // Close must be called last, because it may result in the destruction of this + // event object if the event is a reusable event + source.Close(aJni); +} + +// class CJesSession + +inline TInt CJesSession::TExecute::operator()() const +{ + return iFunc(iParam[0],iParam[1],iParam[2],iParam[3],iParam[4],iParam[5],iParam[6],iParam[7],iParam[8]); +} + +TInt CJesSession::ExecuteTrap(const TExecute& aExecute) +// +// Execute the client function inside a trap harness +// +{ + TRAPD(r,aExecute()); + return r; +} + + +void CJesSession::ServiceL(const RMessage2& m) +// +// Invoke the requested client function +// +{ + switch (m.Function()) + { + case EJessExecute: + { + const TExecute& e = *static_cast(m.Ptr0()); + TInt result = e(); + m.Complete(result != KRequestPending ? result : KErrNotSupported); + } + break; + + case EJessExecuteTrap: + m.Complete(ExecuteTrap(*static_cast(m.Ptr0()))); + break; + + case EJessShutdown: + ((CJesServer*)Server())->Shutdown(); + m.Complete(KErrNone); + break; + } +} + +CJesShutdown::CJesShutdown(MJesShutdown* aShutdown) + : CActive(CActive::EPriorityStandard) + , iShutdown(aShutdown) +{ +} + +void CJesShutdown::Start() +{ + CActiveScheduler::Add(this); + iStatus=KRequestPending; + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); +} + +void CJesShutdown::RunL() +{ + ASSERT(iShutdown); + iShutdown->Shutdown(); + iShutdown = NULL; +} + +TInt CJesShutdown::RunError(TInt aError) +{ + if (aError == KLeaveExit) + { + return aError; + } + return KErrNone; +} + +void CJesShutdown::DoCancel() +{ + // nop +} + +// Helper method to trace output (int) to Java side, eg. System.out +void CJavaEventServer::Trace(JNIEnv& aJni, TInt value) +{ + jclass clazz = aJni.FindClass("com/symbian/lcdjava/lang/SystemExtensions"); + jmethodID method = aJni.GetStaticMethodID(clazz, "trace" , "(I)V"); + aJni.CallStaticVoidMethod(clazz, method, value); +} + +// Notify Java thread of a new event +void CJavaEventServer::NotifyJavaCall(TInt aEvent, TInt aPriority) +{ + CEventQueue::NotifyServer(aEvent, aPriority); +} + + +void CJavaEventServer::Cleanup(RArray& aServerHandles) +{ + CEventQueue::Cleanup(); + + // Loop through event server instances and remove each + for (TInt i = aServerHandles.Count() - 1; i >= 0; --i) + { + TInt handle = aServerHandles[i]; + aServerHandles.Remove(i); + delete JavaUnhand(handle); + } +} +