geoserver 源码介绍

上一章我们通过实现一个服务对如何扩展GeoServer有了一定的了解,但是,对于为何要这样做并没有说明,本章我们重点来说说GeoServer的结构,下图来自GeoServer官网(希望没有侵权),它很好的揭示了GeoServer处理请求的全过程。

我们说GeoServer使用Spring框架来构建,这里就可以看到Spring的使用,虚线框中的Restlet就是用Spring引入系统的,每个服务包的“applicationContext.xml”文件里都包含了描述Route映射的信息,例如WMS就有如下片段:

    <bean id="wmsURLMapping"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="alwaysUseFullPath" value="true"/>
        <property name="mappings">
            <props>
                <prop key="/wms">dispatcher</prop>
                <!-- prop key="/wms/putstyles">putStylesWrapper</prop-->
                <prop key="/wms/*">dispatcher</prop>
            </props>
        </property>
    </bean>

它将形如“/wms/”的请求映射到“dispatcher”对象,而这个对象就是上一章调试的重点“org.geoserver.ows.Dispatcher”。所以,如果我们希望我们的服务也和WMS有相似的处理方式,我们就需要在自己的配置文件里加上类似的一段。

本章我准备先两个方面入手讲解GeoServer是如何处理OWS请求的。首先介绍GeoServer的运行时环境,包括对象是如何创建并且引用的,以及SpringFramework的配置体系。然后以Dispatcher类的处理算法入手,重点介绍扩展点,熟悉了扩展点,我们就可以对GeoServer的OWS处理进行扩展,开发符合我们要求的应用。

搞清楚处理机制后,我会谈谈GeoServer的资源API。这个部分主要罗列了GeoServer的一些接口,以及它们代表的概念。

一 OWS请求处理

我们知道applicationContext.xml文件是SpringFramework的配置文件,许多对象都在这个文件中定义,但是为什么是这个文件呢,它们之间有没有关系呢。

让我们先来看看“web-app”的“web.xml”文件,中间有这样一段

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/applicationContext.xml classpath*:/applicationSecurityContext.xml</param-value>
    </context-param>

可以看到,这里定义了classpath下面的applicationContext.xml文件和applicationSecurityContext.xml作为配置文件,系统运行起来后SpringFramework会扫描classpath下面所有的applicationContext.xml文件和applicationSecurityContext.xml文件,创建里面定义的对象。所以只要我们提供的包里面包含这两个文件中的任意一个,就可以把自定义的对象装载到系统运行时中,同时还可以引用已经创建的对象。

main包中的applicationContext.xml文件定义了许多基础对象,很重要的有:catalog,geoServer和dispatcher,这几个对象将是我们后面讲解的重点。

上面这幅图描述了GeoServer处理OWS请求的步骤,右边的红色方框是每个步骤的扩展点,每个扩展点都对应一个抽象类或者接口。可以通过实现这些类和接口来扩展GeoServer的功能。下面我们来介绍Dispatcher类处理OWS请求的步骤,每一步都有具体的函数相对应。

第一步 解析HTTP请求参数(见org.geoserver.ows.Dispatcher.init(Request))

程序并不会直接采用HTTP的参数,它们是字符串键值对(KVP)或者是XML字符串,程序会先把它们转换成相应的对象。类型org.geoserver.ows.Request是代表请求参数的类型,它包含转换后的KVP Map就已经将原来的字符串变成了对象。

转换参数的工作由Parser来完成。举例说明:参数“BBOX=-180,-90,180,90”的值是字符串“-180,-90,180,90”,经过org.geoserver.wfs.kvp.BBoxKvpParser的处理,就变成了org.geotools.geometry.jts.ReferencedEnvelope的对象,显然它更容易使用。

设想,如果我们有一个参数需要传递数据表,我们可以这样构造参数格式:TABLE=cell11,cell12,cell13|cell21,cell22,cell23|cell31,cell32,cell33。当程序遇到这个参数的时候我们就可以使用我们开发的Parser对象来将它转换成一个表对象,供后续代码使用。我们只需要将这个Parser对象放到applicationContext.xml文件立即可,就像下面这样

     <bean id="tableKvpParser" class="examples.TableKvpParser"/>

所有Parser都必须从org.geoserver.ows.KvpParser继承。

第二步 匹配服务对象(见org.geoserver.ows.Dispatcher.service(Request))

程序根据参数SERVICE和VERSION的值来选择合适的服务,例如:http://www.dummy.com/geoserver/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities,这个URL是在请求1.1.1版本的WMS服务。所以注册服务时需要指明服务ID和版本号,下面是wms服务的注册代码

     <bean id="wmsService2" class="org.geoserver.wms.DefaultWebMapService">
       <constructor-arg ref="wms"/>
     </bean>
     <alias name="wmsService2" alias="webMapService"/>

     <bean id="wmsServiceDescriptor" class="org.geoserver.platform.Service">
        <constructor-arg index="0" value="wms"/>
        <constructor-arg index="1" ref="wmsService2"/>
        <constructor-arg index="2" value="1.1.1"/>
        <constructor-arg index="3">
          <list>
            <value>Capabilities</value>
            <value>GetCapabilities</value>
            <value>DescribeLayer</value>
            <value>GetFeatureInfo</value>
            <value>GetLegendGraphic</value>
            <value>GetMap</value>
            <value>Map</value>
            <value>reflect</value>
            <value>kml</value>
            <value>GetStyles</value>
          </list>
        </constructor-arg>
     </bean>

来看Service类的构造函数

public Service(String id, Object service, Version version, List<String> operations)

不难看出上面的配置信息其实定义的是构造函数的参数,其中id,version,operations的含义都不难猜出,然我们来看看service这个参数。它是一个Object,也就说对service这个对象并没有强类型要求。但是并非任何对象都可以作为service参数传进来,关于这个问题,我们会在后面加以说明,在这个例子里,service是类org.geoserver.wms.DefaultWebMapService的对象。

上面的配置信息将一个ID是“wms”版本是“1.1.1”的OWS服务注册到系统运行时中,当一个OWS请求到来时,系统就会遍历所有注册的服务,寻找符合要求的服务。

第三步 执行操作(见org.geoserver.ows.Dispatcher.dispatch(Request, Service))

这一步主要的操作就是创建执行对象org.geoserver.platform.Operation,这个对象采用了Java的反射原理来实现函数调用,所以需要创建函数参数数组。前面提到过OWS参数的格式有KVP和XML两种,因此对参数的处理也分为两种,具体到类就是org.geoserver.ows.KvpRequestReader和org.geoserver.ows.XmlRequestReader。这两个类将参数字符串转换成相应的对象,在这点上与前面的Parser类似,不同的是这里的转换对应的是一个服务调用,而不是具体一个参数。例如org.geoserver.wms.kvp.GetMapKvpRequestReader就负责将GetMap的参数转换成org.vfny.geoserver.wms.requests.GetMapRequest对象。

这一步的扩展点就是以上两个Reader,来看WMS中GetMap Reader的定义

    <bean id="getMapKvpReader"
        class="org.geoserver.wms.kvp.GetMapKvpRequestReader">
        <constructor-arg ref="wms"/>
    </bean> 
    <bean id="getMapXmlReader"
       class="org.geoserver.wms.xml.WMSXmlRequestReaderAdapter">
       <constructor-arg index="0" value="http://www.opengis.net/ows"/>
        <constructor-arg index="1" value="GetMap"/>
       <constructor-arg index="2" ref="wms"/>
       <constructor-arg index="3" value="org.vfny.geoserver.wms.requests.GetMapXmlReader"/>
   </bean> 

与前面的扩展一样,我们只需要把我们设计的相关Reader注册到系统中,程序就会自己找到它。下面说说匹配Reader的算法。

第二步提到了一个service对象,除了知道它是一个Object之外,我们并没有过多说明。实际上,Operation类会持有这个对象,并且从里面查找与注册的操作同名的公共成员函数,这个函数将通过反射来调用。显然,我们提供给这个函数的参数必须符合它声明的参数类型。所以,匹配KVP Reader的算法就是匹配参数类型的过程。DefaultWebMapService的getMap函数的签名如下:

public GetMapResponse getMap(GetMapRequest request)

程序会遍历所有注册的GetMapKvpRequestReader,将注册函数的参数类型与org.geoserver.ows.KvpRequestReader.getRequestBean()的返回值比较,如果两者可以交换(Assignable)则匹配成功。

XML Reader的匹配与KVP Reader完全不同,这一点很奇怪,它是根据注册的操作名称,服务ID和服务版本来匹配的。

至于执行操作,实在没什么需要特殊说明的,就是调用方法而已,唯一值得注意的是它的返回值,因为我们要把它写到返回流(Response Stream)中。而这是下一步的事情了。

第四步 返回结果(见org.geoserver.ows.Dispatcher.response(Object, Request, Operation))

现在需要把结果返回给客户端了,这个步骤叫做Response。这一步的扩展点是一个叫org.geoserver.ows.Response的类,程序会遍历所有注册的Response类(与前面的那些匹配完全一样),比较返回值的类型与org.geoserver.ows.Response.getBinding()的值,如果两者可以交换(Assignable)则匹配成功。匹配成功后就调用org.geoserver.ows.Response.write(Object, OutputStream, Operation)函数回写结果。下面是WMS GetMap的Response配置信息

    <bean id="getMapResponse"
        class="org.geoserver.ows.adapters.ResponseAdapter">
        <constructor-arg value="org.vfny.geoserver.wms.responses.GetMapResponse"/>
        <constructor-arg ref="geoServer"/>
    </bean>

这里用到了一个叫ResponseAdapter的类主要是为了适配接口。

到此OWS的处理就介绍完了,下面来看看GeoServer的资源API。

二 资源对象模型

这是我起的名称,实际上是一套接口。在包“main”的命名空间org.geoserver.catalog下面有许多接口描述了GeoServer中许多基本概念,搞清楚这些是学习GeoServer的关键之一。

特别需要说明一下,GeoServer所有的资源都派生自接口org.geoserver.catalog.Info,它唯一的方法是org.geoserver.catalog.Info.getId()。这说明,GeoServer里面所有的资源都有一个全局唯一的ID。我们会在后面的文章中详细介绍,包括它的产生和保存。

1 Catalog

这里有一段摘录自main配置文件的脚本

    <bean id="rawCatalog" class="org.geoserver.catalog.impl.CatalogImpl">
         <property name="resourceLoader" ref="resourceLoader"/>
    </bean>
    <bean id="secureCatalog" class="org.geoserver.security.SecureCatalogImpl">
        <constructor-arg ref="rawCatalog" />
    </bean>
    <!-- Switch this when you want to enable the secure catalog by default -->
    <alias name="secureCatalog" alias="catalog"/> 

里面定义了一个叫“catalog”的变量,下面是一个引用它的例子

    <bean id="geoServer" class="org.geoserver.config.impl.GeoServerImpl">
      <property name="catalog" ref="catalog"/>
    </bean>

这就是我们要说的Catalog。查看Catalog接口的代码,会看到它定义了许多函数(代码太长就不贴出了),这些函数基本涵盖了“增删改查”所有的方法,而每一套“增删改查”都对应了我们将要介绍一个概念,例如这一段:

    void add(LayerInfo layer);
    void remove(LayerInfo layer);
    void save(LayerInfo layer);
    LayerInfo getLayer(String id);

后面还有很多getLayer方法就不赘述了。

我们可以这样定义:Catalog是一个抽象概念,它提供了一套访问GeoServer资源的方法,通过这些方法程序可以对GeoServer的资源进行“增删改查”的操作,而无需知道资源的具体保存形式。当然,目前唯一的实现就是CatalogImpl,但是我们完全可以用我们自己的Catalog来替换它,只需要修改一下上面的配置信息就可以了。

需要说明的是,很多时候我们都是通过GeoServer这个对象来获得Catalog的,下面我们就来说说GeoServer。

2 GeoServer

它的完整名称是org.geoserver.config.GeoServer,根据注释的解释,它是用来访问GeoServer服务器的配置信息的接口,而它的名称也反映出这个特点。我们可以通过它来获得与具体服务无关的数据,例如服务的字符集,服务的联系人,发布了哪些OWS服务等。当然还有服务的资源接口Catalog。在自定义的配置文件里,可以用“geoServer”来引用它。

3 Layer

Layer是空间数据源与表现样式的组合,WMS GetMap中我们指定的参数LAYERS指的就是它。org.geoserver.catalog.LayerInfo是它的代码形式。通过这个接口,我们可以访问与Layer相关联的资源,主要有空间数据源(Resource),样式(Style),图例(Legend)等。Layer可以相互嵌套形成LayerGroup,LayerGroup在行为上与Layer完全一样,这是一个组合模式的应用。

4 Resource

这里的Resource并非泛指的资源,而是与空间相关联的资源,所以org.geoserver.catalog.ResourceInfo中有访问空间参考(SRS或CRS)的方法。另外,通过这个接口我们可以访问资源的Store(又是一个概念,我们姑且就使用原文),也就是资源的存储器。GeoServer中有两个概念是从Resource派生来的,Coverage和FeatureType,并且它们有各自的Store。

5 Store

Store表示Resource的存储。org.geoserver.catalog.StoreInfo是它的代码形式,最重要的函数是org.geoserver.catalog.StoreInfo.getConnectionParameters(),返回连接参数,参数的具体含义由具体的存储介质来决定。Coverage和FeatureType都有各自的Store,org.geoserver.catalog.CoverageStoreInfo和org.geoserver.catalog.DataStoreInfo。

6 Coverage

Coverage一直是让我迷惑的概念,我把wiki的解释原文抄录在这里:In geographic information systems, a coverage is a mapping of one aspect of data in space.大意是:在GIS领域,一个Coverage就是一附地图,它反应了空间数据的一个方面。(很笼统是吧,如果你有准确的解释,希望你能发给我,我将不胜感激)。org.geoserver.catalog.CoverageInfo是这个概念的代码形式。

7 FeatureType

要解释FeatureType就必须先解释Feature。Feature,即要素,是一个具有空间意义的实体,并且拥有附加的属性。例如:某个城市,它的位置是东经116.46度 北纬 39.92 度,它的名字是“北京”,它的常住人口是1972万。我们就可以用一个要素来表示它,这个要素是一个点,点的坐标是[116.46 39.92],它的属性表示为


属性名称


属性值

Name 北京
Popu 1972

如果我们有许多城市数据,都具有相似的特征,我们就可以定义一个叫“CITIES”的FeatureType,它的几何类型是Point(点),它的属性Scehma是


属性名称


值类型

Name 字符串
Popu 数值

可以把FeatureType与Feature的关系想象为类与类实例的关系。也可以把它们的关系想象为数据表与数据记录的关系。后者其实更实用,因为许多时候Feature数据就是以表的形式组织和访问的。

org.geoserver.catalog.FeatureTypeInfo是它的代码形式。它最重要的方法就是org.geoserver.catalog.FeatureTypeInfo.getFeatureSource(ProgressListener, Hints),这个方法会返回数据源,我们可以用这个数据源来查询Feature。

8 Style

Style,可以翻译成渲染样式,提供了一套方法用来描述如何渲染Feature。WMS GetMap中我们指定的参数STYLES指的就是它。OGC的标准SLD提供了一种语言用来描述Style。GeoServer采用了这个语言,其他很多GIS平台也支持这个语言。推荐我的一篇文章《OGC之路(2) 之 Style之谜》说得比较详细,还附有代码。

org.geoserver.catalog.StyleInfo是它的代码形式。它最重要的方法就是org.geoserver.catalog.StyleInfo.getStyle(),返回样式对象org.geotools.styling.Style。我们可以通过它来获得SLD里面定义的元素。

至此,我把GeoServer的结构做了一个简单的介绍,从OWS处理请求的方式到GeoServer资源访问的API。其实GeoServer的结构远不止这么简单,它还提供了一套完整的管理服务以及相关GUI,这个部分不是我们介绍的内容,所以在此略过,但是作为用户接触最频繁的部分,它的结构还是很值得研究的。此外,GeoServer保存资源的方式也很重要,GeoServer采用文件目录结构来分类保存各种资源,并且设置了访问权限,我们将在下一章对此做详细说明。

转自:http://www.cnblogs.com/sillyemperor/archive/2011/01/26/1933248.html

时间: 2024-11-05 04:57:37

geoserver 源码介绍的相关文章

Eclipse下建立geoserver源码工程

1.http://geoserver.org/download/下载源码 例子:http://sourceforge.net/projects/geoserver/files/GeoServer/2.5.2/geoserver-2.5.2-src.zip 2.下载Maven( http://maven.apache.org/download.cgi )选择apache-maven-3.21-bin.zip,maven是命令行程序,将下载得到的压缩包解压,在使用时临时指定PATH变量即可. 3.打

geoserver源码导出war包

题外语:踏破铁鞋无觅处,得来全部费工夫.从网上找了下将Geoserver源码导出为war文件的方法,少之甚少,没办法,百度靠不住,还得靠自己,上Geoserver官网上看了下,又在官方论坛上找了找,说是什么jetty,说实话,不懂哎,就瞎翻的看了看,擦,山重水复疑无路,柳暗花明又一村,竟然就在那,在此note下来,以便后用. 如何在eclipse中构建Geoserver的源码工程,可参考博文http://blog.csdn.net/gisshixisheng/article/details/43

eclipse中建geoserver源码

概述:本文讲述的是在eclipse中如何构建geoserver源码工程,其中涉及到了jdk,github,marven等. 1.安装git 从(http://git-scm.com/download/win),获得Git-1.9.0-preview2014021 7.exe文件,直接安装即可.安装成功后,在任何处所右击鼠标,出现如下图所示: 百度网盘下载 2.从git中签出geoserver源码 点击"Git GUI"将呈现如下界面,选择"克隆已有版本",进入源码克

关于导入geoserver 源码到Eclipse编译运行

参考http://blog.csdn.net/gisshixisheng/article/details/43016443 和  http://blog.sina.com.cn/s/blog_6e3765300102vvh8.html 两篇文章 一.安装JDK环境 1.到到官网下载JDK 最好是1.8.0以上版本,这里jdk jdk-8u101-windows-x64(我的机器是64位,如果是32位,需要32位) 2.安装JDK 一路next,其中jdk安装位置和jre安装位置默认是放在c盘,如

1-开发共享版APP(源码介绍)-BUG修复

这一系列文章将介绍APP的源码,这一节作为所有BUG问题修复! https://www.cnblogs.com/yangfengwu/category/1512162.html    //开发共享版APP(接入指南) https://www.cnblogs.com/yangfengwu/category/1515825.html    //开发共享版APP(搭建指南) https://www.cnblogs.com/yangfengwu/category/1529078.html    //开发

Weka开发[9]—KMeans源码介绍

以前介绍的都是分类的内容,这一次介绍聚类,以最简单的SimpleKMeans源码为例. 分类中训练一个分类器是用buildClassifier(),在聚类中学习一个Clusterer是用buildCluster().分类中分类一个样本是用classifyInstance,而在聚类中是用clusterInstance.那我怎么知道这些的呢?(或者说:你怎么知道我是不是在骗你呢?)以ID3为例,你可以看出它继承自Classifier类,进入Classifier类,它有三个比较重要的函数,buildC

HoverTree系统源码介绍

HoverTree是一个开源asp.net系统.系统的效果请到:http://h.keleyi.com体验. 源码描述:一.源码特点采用典型的三层架构进行开发,实现了留言板的功能,后台管理,留言审核.回复功能和文章发布功能.二.功能介绍本源码是一个文章与留言板系统源码,前台用户留言,后台管理员审核通过即可显示,完全开源,欢迎下载三.菜单功能前台1.显示所有留言内容,点击我要留言,即可进入用户留言界面2.提交留言后,点击查看留言即可跳回查看页面(注:留言需要管理员后台审核后用户才能看到)管理员1.

【krpano】高德地图导航插件(源码+介绍+预览)

简介 krpano可以利用js调用第三方网页版地图,因此可以实现导航效果,用来帮助用户导航到我们全景所在的位置. 效果截图如下,在手机端点击左侧按钮,便会对用户进行定位,跳转至高德地图进行导航      使用说明 插件共有3个文件,如下图所示: nv.js为js代码,主要作用为浏览器定位,生成地图调用uri等. nv.xml为样式文件,定义了krpano中按钮的位置 navigation.png为图标 使用时,把上述3个文件复制到项目目录,修改xml文件中的目的地参数即可. desloc对应于目

【krpano技术】浏览点赞插件(源码+介绍+预览)

简介 最近几天研究了如何在krpano全景的基础上实现记录浏览量和点赞次数,写了一个插件,方便大家使用. 效果截图如下: 每当有用户打开该全景页面时,浏览量会自动加1: 用户可以主动点击点赞按钮,点击后,赞的数量加1,第二次点赞会取消点赞. 使用说明 使用说明,插件文件共有以下5个文件: 前三个文件为图片,可以自行修改定义不同的样式 va.min.js 为js代码,用于控制点赞,与后台交互等操作 va.xml为xml文件,用于配置样式 使用时,把上述5个文件复制到项目目录,在你的xml文件里添加