同樣,在介紹MapGuide 服務(wù)器如何處理枚舉資源操作之前,讓我們首先來(lái)看看MapGuide 服務(wù)器用于處理服務(wù)請(qǐng)求和操作的類,圖19?9顯示服務(wù)請(qǐng)求處理器類的類圖,圖19?10顯示了操作處理器類的類圖。
圖?19?10 服務(wù)請(qǐng)求處理器類的類圖
圖?19?11 操作處理器類的類圖
MapGuide提供了資源服務(wù)、要素服務(wù)等多種服務(wù),每種服務(wù)包含了大量操作。MapGuide為每種服務(wù)提供了一個(gè)服務(wù)請(qǐng)求處理器類,用于處理這些服務(wù)所提供的操作,例如MgResourceServiceHandler、MgFeatureServiceHanlder等。這些類都繼承自IMgServiceHandler,并且實(shí)現(xiàn)了方法IMgServiceHandler::ProcessOperation(...)。MapGuide使用工廠類MgServiceHanlderFactory來(lái)創(chuàng)建一個(gè)服務(wù)請(qǐng)求處理器類的實(shí)例,給定一個(gè)服務(wù)ID,調(diào)用方法MgServiceHandlerFactory::GetHandler(...)可以創(chuàng)建對(duì)應(yīng)的服務(wù)請(qǐng)求處理器類的實(shí)例。
對(duì)于服務(wù)中的每種操作,MapGuide也提供了相應(yīng)的操作處理器類。從圖19?10可以看到,操作處理器類分為四個(gè)層次,最高一層是類IMgOperationHandler,它是所有操作處理類的基類,第二層是類MgServiceOperation,第三層是類MgXXXOperation,“XXX”代表服務(wù)名稱,在這一層每種類型的服務(wù)都有一個(gè)對(duì)應(yīng)的類,例如MgFeatureOperation、MgResourceOperation等,第四層為真正負(fù)責(zé)工作的操作處理器類,每種服務(wù)中的每個(gè)操作都有一個(gè)對(duì)應(yīng)的操作處理器類,某種服務(wù)中操作處理器類都繼承自同一個(gè)父類,例如MgEnumerateResource、MgSetResource都繼承自MgResourceOperation。
接下來(lái)讓我們看看MapGuide服務(wù)器如何處理枚舉資源操作,這個(gè)操作流程的時(shí)序圖如圖 19?11所示。
圖?19?12 MapGuide服務(wù)器處理枚舉資源操作的時(shí)序圖
1) 在線程池中找一個(gè)空閑的線程執(zhí)行操作
MapGuide服務(wù)器使用了多線程和線程池的技術(shù)來(lái)提高操作處理和響應(yīng)請(qǐng)求的性能。在MapGuide服務(wù)器啟動(dòng)時(shí),會(huì)創(chuàng)建一個(gè)操作請(qǐng)求隊(duì)列和一個(gè)用于處理操作請(qǐng)求的線程池。當(dāng)一個(gè)操作請(qǐng)求進(jìn)入操作隊(duì)列,MapGuide服務(wù)器會(huì)在線程池中找一個(gè)空閑的線程執(zhí)行操作。如果沒(méi)有空閑的線程,那么這個(gè)操作請(qǐng)求會(huì)處于等待狀態(tài),直到線程池中有了空閑的線程。
首先,讓我們查看一下服務(wù)器的入口函數(shù)的源代碼,看看服務(wù)器是如何啟動(dòng)的。MapGuide服務(wù)器可以像普通的應(yīng)用程序一樣運(yùn)行,還可以在Windows操作系統(tǒng)可以運(yùn)行為Windows服務(wù),在Linux操作系統(tǒng)運(yùn)行為守護(hù)進(jìn)程,下面的代碼中只保留了運(yùn)行為普通應(yīng)用程序部分的代碼。
typedef ACE_Singleton SERVER;
int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
int nResult = 0;
......
// 初始化ACE服務(wù)
ACE::init();
......
// 根據(jù)命令行參數(shù)執(zhí)行響應(yīng)的操作
if((ACE_OS::strcasecmp(parameter, ACE_TEXT("?")) == 0) ||
(ACE_OS::strcasecmp(parameter,
MG_WCHAR_TO_TCHAR(MgResources::ServerCmdHelp)) == 0))
{
// 顯示服務(wù)器命令行參數(shù)
ShowCommandlineHelp();
......
}
else if((ACE_OS::strcasecmp(parameter,
MG_WCHAR_TO_TCHAR(MgResources::ServerCmdRun)) == 0) ||
(ACE_OS::strcasecmp(parameter,
MG_WCHAR_TO_TCHAR(MgResources::ServerCmdInteractive)) == 0))
{
ACE_OS::printf(MG_WCHAR_TO_CHAR(MgResources::ServerCmdRunInfo));
......
// 以普通應(yīng)用程序的方式運(yùn)行服務(wù)器
nResult = SERVER::instance()->init(argc, argv);
if(0 == nResult)
{
// 啟動(dòng)服務(wù)
nResult = SERVER::instance()->open();
// 終止服務(wù)
SERVER::instance()->fini();
}
......
}
......
// 終止ACE服務(wù)
ACE::fini();
return nResult;
}
|
在上面的代碼中,我們可以看到大量以“ACE”為前綴的類,這些類是ACE自適配通信環(huán)境(Adaptive Communication Environment)工具包中的類。ACE是一個(gè)開源的工具包,它實(shí)現(xiàn)了許多用于并發(fā)通信軟件的核心模式。ACE的目標(biāo)用戶是在UNIX和Win32平臺(tái)上開發(fā)高性能通信服務(wù)和應(yīng)用的開發(fā)者。ACE簡(jiǎn)化了使用進(jìn)程間通信、事件多路分離、顯式動(dòng)態(tài)鏈接和并發(fā)的OO網(wǎng)絡(luò)應(yīng)用和服務(wù)的開發(fā)。ACE提供了一組豐富的可復(fù)用C++ Wrapper Facade(包裝外觀)和框架組件,可跨越多種平臺(tái)完成通用的通信軟件任務(wù),其中包括:事件多路分離和事件處理器分派、信號(hào)處理、服務(wù)初始化、進(jìn)程間通信、共享內(nèi)存管理、消息路由、分布式服務(wù)動(dòng)態(tài)(重)配置、并發(fā)執(zhí)行和同步等。
類MgServer繼承自AEC工具包中的類ACE_NT_Service或ACE_Service_Object,對(duì)應(yīng)于服務(wù)器的主線程,圖19?12顯示了服務(wù)器主線程類的類圖。MgServer::svc()是主線程的入口,調(diào)用方法MgServer::open()會(huì)啟動(dòng)主線程并且執(zhí)行方法MgServer::svc(),調(diào)用MgServer::fini()會(huì)終止主線程。MapGuide使用了Singleton模板ACE_Singleton將MgServer封裝為一個(gè)單實(shí)例類,為了方便使用MapGuide使用typedef為ACE_Singleton定義了一個(gè)別名SERVER,調(diào)用方法SERVER::instance()可以創(chuàng)建類MgServer的一個(gè)實(shí)例。
圖?19?13 服務(wù)器主線程類的類圖
MgServer::svc()是主線程的入口,該方法會(huì)創(chuàng)建一個(gè)操作請(qǐng)求隊(duì)列和一個(gè)用于處理操作請(qǐng)求的線程池,它的代碼如下所示。事實(shí)上,該方法還定義了其它類型的隊(duì)列和線程池,為了便于理解我們省略掉了這些代碼。
int MgServer::svc()
{
MgServerManager* pServerManager = MgServerManager::GetInstance();
// 創(chuàng)建線程管理器和操作線程
ACE_Thread_Manager threadManager;
MgOperationThread clientThreads(threadManager,
pServerManager->GetClientThreads());
pServerManager->SetClientMessageQueue(clientThreads.msg_queue_);
MgClientAcceptor clientAcceptor(clientAddr, ACE_Reactor::instance(),
clientThreads.msg_queue_);
nResult = clientAcceptor.Initialize();
if(nResult == 0)
{
// 啟動(dòng)線程池
nResult = clientThreads.Activate();
if(nResult == 0)
{
// 通知操作線程停止執(zhí)行
ACE_Message_Block* mb = new ACE_Message_Block(4);
if(mb)
{
mb->msg_type(ACE_Message_Block::MB_STOP);
clientThreads.putq(mb);
}
// 停止操作線程
clientThreads.close();
// 等待所有操作線程執(zhí)行完成
threadManager.wait();
threadManager.close();
}
}
return nResult;
}
|
上面的代碼中創(chuàng)建一個(gè)類MgOperationThread的實(shí)例,該對(duì)象創(chuàng)建了一個(gè)線程池,維護(hù)了一個(gè)操作請(qǐng)求隊(duì)列。類MgOperationThread 繼承自ACE工具包中的模板類AEC_Task,對(duì)應(yīng)于操作線程,圖19?13顯示了操作線程類的類圖。ACE_Task封裝了任務(wù),每個(gè)任務(wù)都含有一或多個(gè)線程,以及一個(gè)底層消息隊(duì)列。方法ACE_Task::svc()是線程的啟動(dòng)入口,調(diào)用方法ACE_Task::open()用于初始化任務(wù),調(diào)用方法ACE_Task::close()用于終止任務(wù),調(diào)用方法ACE_Task::activate()用于啟動(dòng)線程,調(diào)用方法ACE_Task::putq()放置消息到任務(wù)的消息隊(duì)列中,調(diào)用方法ACE_Task::getq()從任務(wù)的消息隊(duì)列中取出消息。
圖?19?14 操作線程類的類圖
方法MgOperationThread::svc()是操作線程的入口,它的代碼如下所示。
int MgOperationThread::svc()
{
INT32 nResult = 0;
while (m_bActive)
{
ACE_Message_Block* messageBlock = NULL;
// 從消息隊(duì)列中取出消息
while (getq(messageBlock) == -1)
{
......
}
if(messageBlock->msg_type() == ACE_Message_Block::MB_STOP)
{
m_bActive = false;
ACE_Message_Block* mb = new ACE_Message_Block(4);
if(mb)
{
mb->msg_type(ACE_Message_Block::MB_STOP);
putq(mb);
}
}
else if(messageBlock->msg_type() ==?ACE_Message_Block::MB_DATA)
{
MgServerStreamData* pData =
dynamic_cast(messageBlock->data_block());
IMgServiceHandler::MgProcessStatus stat =?ProcessMessage(messageBlock);
......
}
}
return nResult;
}
IMgServiceHandler::MgProcessStatus MgOperationThread::ProcessMessage(ACE_Message_Block* pMB)
{
IMgServiceHandler::MgProcessStatus stat = IMgServiceHandler::mpsError;
MgServerStreamData* pData = NULL;
pData = (MgServerStreamData*) pMB->data_block();
......
MgStreamParser::ParseStreamHeader(pData);
MgStreamParser::ParseDataHeader(pData);
MgPacketParser::MgPacketHeader pt = MgPacketParser::GetPacketHeader(pData);
switch ( pt )
{
case (MgPacketParser::mphOperation):
stat = ProcessOperation( pData );
break;
......
}
return stat;
}
|
從上面的代碼可以看到,方法MgOperationThread::svc()會(huì)調(diào)用方法getq(…)循環(huán)訪問(wèn)消息隊(duì)列,取出等待處理的消息。如果是數(shù)據(jù)類型的消息,那么調(diào)用方法MgOperationThread:: ProcessMessage(...)處理這個(gè)消息。方法MgOperationThread::ProcessMessage(...)會(huì)解析這個(gè)消息的頭和數(shù)據(jù),如果消息數(shù)據(jù)中包含了一個(gè)操作請(qǐng)求,那么調(diào)用方法MgOperationThread:: ProcessOperation(…)處理這個(gè)操作請(qǐng)求。
2) 處理服務(wù)請(qǐng)求
方法MgOperationThread::ProcessOperation(…) 首先會(huì)解析消息數(shù)據(jù)中的服務(wù)ID、操作ID、操作的版本號(hào)等信息,然后根據(jù)服務(wù)ID使用工廠類MgServiceHanlderFactory來(lái)創(chuàng)建一個(gè)服務(wù)請(qǐng)求處理器類的實(shí)例,最后調(diào)用這個(gè)服務(wù)請(qǐng)求處理器類的方法IMgServiceHandler:: ProcessOperation(...)處理這個(gè)服務(wù)請(qǐng)求。
本節(jié)的示例中客戶端發(fā)送的是一個(gè)枚舉資源的操作請(qǐng)求,所以工廠類會(huì)創(chuàng)建一個(gè)MgResourceServiceHandler的實(shí)例,調(diào)用方法MgResourceServiceHandler::ProcessOperation(...)處理這個(gè)服務(wù)請(qǐng)求。
IMgServiceHandler::MgProcessStatus
MgOperationThread::ProcessOperation(MgServerStreamData* pData)
{
IMgServiceHandler::MgProcessStatus stat = IMgServiceHandler::mpsError;
MgOperationPacket op;
MgStreamHelper* pHelper = NULL;
pHelper = pData->GetStreamHelper();
pHelper->GetUINT32(op.m_PacketHeader);
pHelper->GetUINT32(op.m_PacketVersion);
pHelper->GetUINT32(op.m_ServiceID);
pHelper->GetUINT32(op.m_OperationID);
pHelper->GetUINT32(op.m_OperationVersion);
IMgServiceHandler* pServiceHandler =
MgServiceHandlerFactory::Instance()->GetHandler(op.m_ServiceID, pData, op);
delete pServiceHandler;
pServiceHandler = NULL;
stat = pServiceHandler->ProcessOperation();
return stat;
}
|
3) 處理操作請(qǐng)求
首先,方法MgResourceServiceHandler::ProcessOperation(...)會(huì)根據(jù)操作請(qǐng)求的ID,調(diào)用資源操作工廠類的方法MgResourceOperationFactory::GetOperation(…)創(chuàng)建相應(yīng)的資源服務(wù)操作類MgOpEnumerateResources的實(shí)例。然后,調(diào)用MgOpEnumerateResources:: Initialize(...)初始化枚舉資源操作處理器,調(diào)用方法MgServiceManager::RequestService(…)創(chuàng)建服務(wù)器資源服務(wù)MgServerResourceService的實(shí)例。最后,調(diào)用方法MgOpEnumerateResources::Execute()處理操作請(qǐng)求,該方法會(huì)調(diào)用MgServerResourceService::EnumerateResources(…)實(shí)際執(zhí)行枚舉資源的功能。
IMgServiceHandler::MgProcessStatus MgResourceServiceHandler::ProcessOperation()
{
IMgServiceHandler::MgProcessStatus status = IMgServiceHandler::mpsError;
auto_ptr handler;
MG_TRY()
handler.reset(MgResourceOperationFactory::GetOperation(
m_packet.m_OperationID, m_packet.m_OperationVersion));
assert(NULL != handler.get());
handler->Initialize(m_data, m_packet);
handler->Execute();
status = IMgServiceHandler::mpsDone;
MG_CATCH(L"MgResourceServiceHandler.ProcessOperation")
if (mgException != NULL && NULL != handler.get())
{
status = (handler.get()->HandleException(mgException) ?
IMgServiceHandler::mpsDone : IMgServiceHandler::mpsError);
}
if (IMgServiceHandler::mpsDone != status)
{
MG_THROW();
}
return status;
}
void MgOpEnumerateResources::Execute()
{
......
BeginExecution();
......
Validate();
Ptr byteReader = m_service->EnumerateResources(resource, depth,
type, properties, fromDate, toDate, computeChildren);
EndExecution(byteReader);
......
}
|