内蒙古java团队

j2se,j2ee开发组
posts - 139, comments - 212, trackbacks - 0, articles - 65
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

MapGuide源码分析【

Posted on 2011-04-15 00:24 帅子 阅读(360) 评论(0)  编辑  收藏 所属分类: MapGuide

本节中,我们将通过介绍如何完成枚举资源功能来介绍MapGuide Web扩展的部分源代码。

在浏览器端的地址栏输入类似如下字符串,就会发送一个枚举资源的HTTP请求。

http://hostname/mapGuide/mapagent.fcig?OPERATION=EnumerateResources&VERSION=1.0.0& RESOURCEID=Library:// &TYPE=FeatureSource&DEPTH=3

下面我们来看看MapGuide Web扩展如何处理这个请求。

在介绍MapGuide Web扩展如何处理枚举资源HTTP请求之前,让我们首先来看看MapGuide Web扩展用于处理HTTP请求和响应的类,这些类的类图如图19‑4所示。

clip_image002

图 19‑5 HTTP请求和响应类的类图

类MgHttpRequest和类MgHttpResponse分别是对HTTP请求和响应结果的抽象,这两个类可以用于任何类型的Web应用服务器,也就是说它们的代码不依赖于任何Web应用服务器API。在文件夹“\MgDev\Web\src\HttpHandler”下可以找到所有前缀为“MgHttp”类的源代码。

类MgHttpRequest用于处理HTTP请求,它包含了一个HTTP请求头MgHttpHeader的实例、一个HTTP请求参数HttpRequestParam的实例和一个HTTP请求元数据HttpRequestMetadata的实例。调用方法MgHttpRequest::Execute()会将HTTP请求转发给MapGuide服务器,当MapGuide服务器处理完这个请求,将请求结果返回给Web扩展之后,这个方法会返回一个MgHttpResponse对象,它表示HTTP请求的响应结果。

接下来让我们看看MapGuide Web扩展如何处理枚举资源的HTTP请求。大多数MapGuide用户都是使用IIS作为Web应用服务器,并且使用Web扩展模块isapi_MapAgent.dll来处理HTTP请求,所以本节侧重于isapi_MapAgent.dll模块处理HTTP请求的流程,这个处理流程的时序图如图19‑5所示。

clip_image004

 19‑6 Web扩展处理枚举资源请求的时序图

1) 加载Web应用服务器扩展模块

如果使用的是IIS Web应用服务,那么在接收到后缀为“fcgi”的HTTP请求后,IIS会加载Web应用服务器扩展模块isapi_MapAgent.dll或MapAgent.exe。其中,isapi_MapAgent.dll基于IIS API,具有更好的性能;MapAgent.exe基于CGI技术,性能要稍微差一些。如果使用的是Apache Web应用服务器,那么在Windows平台上Apache会加载Web应用服务器扩展模块MapAgent.exe,在Linux平台上会加载模块mod_mgmapagent.so。

这三个Web服务器扩展模块实现了类似的功能,它们的源代码位置如表19‑2所示。

服务器扩展模块

源代码位置

isapi_MapAgent.dll

\Web\src\IsapiAgent

MapAgent.exe

\Web\src\CgiAgent

mod_mgmapagent.so

\Web\src\ApacheAgent

 19‑2 Web服务器扩展模块的源代码位置

从图19‑6中可以看到这三个Web服务器扩展模块提供了类似的类,这些类提供了相同的接口,类XXXPostParser用于解析HTTP请求中传入的参数及参数值,类XXXResponseHandler用于将HTTP请求的响应结果发送给客户端。其中,“XXX”表示“Cgi”、“Isapi”或“Apache”。

clip_image006

 19‑7 Web扩展的请求处理模块

对于模块isapi_MapAgent.dll,每个“fcgi”类型的HTTP请求会调用此模块中的方法HttpExtensionProc,这个方法的代码如下所示,为了便于理解我们只保留了一些核心代码。

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)

{

Initialize(pECB);

// 调用GetServerVariable读取诸如服务器名称、端口号等服务器变量信息

......

// 创建MgHttpRequest的实例,用于处理HTTP请求

Ptr request = new MgHttpRequest(wUrl);

// 解析HTTP请求中的参数,并且将这些参数置入MgHttpRequest对象中

Ptr params = request->GetRequestParam();

......

IsapiPostParser postParser(pECB);

postParser.Parse(params);

......

// 创建IsapiResponseHandler的实例,用于将响应请求返回给客户端

IsapiResponseHandler responseHandler(pECB);

......

// 将HTTP请求转发给MapGuide服务器,当MapGuide服务器处理完这个请求,

// 将请求结果返回给Web扩展之后,这个方法会返回一个MgHttpResponse对象,

// 它表示HTTP请求的响应结果。

Ptr response = request->Execute();

// 将响应结果返回给客户端

responseHandler.SendResponse(response);

......

}

2) 创建MgHttpRequest的实例,用于处理HTTP请求

在加载Web应用服务器扩展模块后,需要创建一个MgHttpRequest的实例用于处理HTTP请求。类MgHttpRequest并不关联与任何类型的Web应用服务器,所以Web应用服务器扩展模块会使用类XXXPostParser解析HTTP请求中传入的参数及参数值,将这些参数设置到MgHttpRequest对象中。

3) 调用方法MgHttpRequest::Execute()处理HTTP请求

方法MgHttpRequest::Execute()的源代码如下所示。为了便于理解,我们同样只保留了一些核心代码。

MgHttpResponse* MgHttpRequest::Execute()

{

Ptr hResponse;

Ptr result;

// 创建MgHttpResponse对象,用于返回HTTP请求响应结果

hResponse = new MgHttpResponse();

result = hResponse->GetResult();

// 获得HTTP请求中参数“OPERATION”的值

STRING sParamValue = m_requestParam->GetParameterValue(MgHttpResourceStrings::reqOperation);

......

// 根据参数“OPERATION”的值取得对应操作的请求响应处理器

Ptr rrHandler =

CreateRequestResponseHandler(sParamValue, result);

.......

// 处理HTTP请求

if(rrHandler != NULL) rrHandler->Execute(*hResponse);

......

// 返回响应结果

return SAFE_ADDREF((MgHttpResponse*)hResponse);

}

每个HTTP请求中包含一个参数“OPERATION”,它用于代表操作的类型。对于不同的操作,MapGuide定义了不同的请求响应处理器类,这个类会调用MapGuide服务中对应的方法处理这个操作,这些请求响应处理器类的类图如图19‑7所示。从图19‑7可以看到,所有请求响应处理器类都继承自类MgHttpRequestResponseHandler,每一种操作都有一个对应的子类,例如枚举资源操作使用了类MgHttpEnumerateResources,描述模式操作使用了类MgHttpDescribeSchema。

clip_image008

 19‑8 HTTP请求响应处理器的类图

MapGuide定义了一个全局map对象用于存放每种操作对应的请求响应处理器类对象,它的键是操作的名称,值是请求响应处理器类对象。

// 定义一个全局map对象,用于存放每种操作对应的请求响应处理器类对象

static map

httpClassCreators;

bool InitializeStaticData()

{

httpClassCreators[MgHttpResourceStrings::opGetMap] =

MgHttpGetMap::CreateObject;

httpClassCreators[MgHttpResourceStrings::opGetMapUpdate] =

MgHttpGetMapUpdate::CreateObject;

httpClassCreators[MgHttpResourceStrings::opGetDrawing] =

MgHttpGetDrawing::CreateObject;

......

httpClassCreators[MgHttpResourceStrings::opDescribeDrawing] = MgHttpDescribeDrawing::CreateObject;

httpClassCreators[MgHttpResourceStrings::opEnumerateResources] = MgHttpEnumerateResources::CreateObject;

......

}

调用方法MgHttpRequest::CreateRequestResponseHandler(...)可以根据操作的名称获得对应的请求响应处理器类对象。对于枚举资源操作,它会返回一个类MgHttpEnumerateResources的对象。

调用这些请求响应处理器类的Execute(…)方法,会创建一个代理服务类对象,然后调用代理服务中对应的方法。为什么说创建的是一个代理服务类对象呢?我想看完图19‑8之后大家会有所明白。从图19‑8中可以看到,所有的MapGuide服务有两个子类,一个是名称为MgProxyXXXService的代理服务类,它是MapGuide Web扩展端的一个类,另一个是名称为MgServerXXXService的服务器服务类,它是MapGuide服务器端的一个类。MgProxyXXXService最终会将服务请求转发给服务器端类MgServerXXXService,所以说真正处理服务请求的类是MgServerXXXService,MgProxyXXXService仅仅起到一个转发的作用,这也就是为什么称类MgProxyXXXService为代理服务类的原因。

clip_image010

 19‑9 代理服务和服务器服务类的类图

对于枚举资源操作,MgHttpEnumerateResources::Execute(...)的源代码如下所示。调用这个方法会创建一个代理资源服务类MgProxyResourceService的对象,然后调用MgProxyResourceService::EnumerateResources(...)枚举资源,最后将操作的执行结果放入MgHttpResponse对象中。

void MgHttpEnumerateResources::Execute(MgHttpResponse& hResponse)

{

Ptr hResult;

hResult = hResponse.GetResult();

// 检查HTTP请求中的参数

ValidateCommonParameters();

// 创建MgProxyResourceService实例

Ptr mgprService =

(MgResourceService*)(CreateService(MgServiceType::ResourceService));

......

// 执行枚举资源操作

Ptr byteReader = mgprService->

EnumerateResources(&mgrIdentifier, m_depth, m_type, m_computeChildren);

// 如果需要,转换响应请求的格式

ProcessFormatConversion(byteReader);

// 将操作结果放入响应请求中的MgHttpResult对象

hResult->SetResultObject(byteReader, byteReader->GetMimeType());

}

MgByteReader* MgProxyResourceService::EnumerateResources(

MgResourceIdentifier* resource, INT32 depth, CREFSTRING type,

INT32 properties, CREFSTRING fromDate, CREFSTRING toDate,

bool computeChildren)

{

MgCommand cmd;

cmd.ExecuteCommand(m_connProp,

MgCommand::knObject,

MgResourceService::opIdEnumerateResources,

7,

Resource_Service,

BUILD_VERSION(1,0,0),

MgCommand::knObject, resource,

MgCommand::knInt32, depth,

MgCommand::knString, &type,

MgCommand::knInt32, properties,

MgCommand::knString, &fromDate,

MgCommand::knString, &toDate,

MgCommand::knInt8, (int)computeChildren,

MgCommand::knNone);

SetWarning(cmd.GetWarningObject());

return (MgByteReader*)cmd.GetReturnValue().val.m_obj;

}

4) 将HTTP请求的响应结果返回给客户端

调用MgHttpRequest::Execute()会返回一个MgHttpResponse对象,这个对象包含了HTTP请求的响应结果。不过,还需要调用方法XXXResponseHandler::SendResponse(...),这样Web应用服务器才会将这个响应结果返回给客户端。


只有注册用户登录后才能发表评论。


网站导航: