<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    內(nèi)蒙古java團隊

    j2se,j2ee開發(fā)組
    posts - 139, comments - 212, trackbacks - 0, articles - 65
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    MapGuide Web API

    Posted on 2011-04-15 00:18 帥子 閱讀(731) 評論(0)  編輯  收藏 所屬分類: MapGuide

    許多人都知道MapGuide提供了.NET、PHP和Java三種類型的Web API,但是不知道MapGuide是如何創(chuàng)建這三種類型的API的。試想一下,如果分別去創(chuàng)建這三種API,這將是一個很難維護的工作。每次增加或修改一些功能,就需要對三種類型的API都進行修改。所以,MapGuide使用了SWIG來自動生成這三種類型的API。我想這個時候許多人會問,什么是SWIG呢?我怎么從來沒有聽說過這個東東呢!其實,我也是在做MapGuide開發(fā)的時候才開始了解SWIG的。所以,首先讓我們來認識一下SWIG,然后再來看MapGuide是如何使用SWIG來生成API的。

    1. SWIG簡介

    ??? SWIG是Simple Wrapper and Interface Generator的縮寫,是一個幫助使用C或者C++編寫的軟件創(chuàng)建其他編語言的API的工具。例如,我想要為一個C++編寫的程序創(chuàng)建.NET API,一般情況下我必須使用托管C++(Managed C++)去編寫大量的代碼才能生成它的.NET API。有了SWIG,這個機械的工作將變得非常簡單。你只須要使用一個接口文件告訴SWIG要為那些類創(chuàng)建.NET API,SWIG就會自動幫你生成它的.NET API。是不是非常的酷啊?

    ??? 當然,SWIG不僅僅支持創(chuàng)建.NET API。最新版本的SWIG支持常用腳本語言Perl、PHP、Python、Tcl、Ruby和非腳本語言C#, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), Java, Modula-3, OCAML以及R,甚至是編譯器或者匯編的計劃應用(Guile, MzScheme, Chicken)。

    ??? 下面我們通過一個例子來看看SWIG是如何幫我們創(chuàng)建API的。假設我打算為如下的C++類創(chuàng)建C#和Java的API。

    ??? /* SwigTest.h */

    ??? class CSwigTest {
    ??? public:
    ??????? CSwigTest();
    ??? ??? virtual ~CSwigTest();
    ??????? int Add(int a, int b) { return a + b; }
    ??? ??? int Substract(int a, int b) { return a - b; }

    ??? ??? int Multiple(int a, int b) { return a * b; }
    ??????? float Divide(int a, int b) { return (float)a / (float)b; }
    ??? };

    1.1 接口文件

    ??? 首先,你需要寫一個接口文件(Interface File),告訴SWIG要為那些類的那些方法創(chuàng)建API。如下的接口文件只為類CSwigTest的方法Add(...)和Subtract(...)生成API,因為在接口文件的接口聲明部分只聲明了兩個方法。

    ??? /* SwigTest.i */
    ??? %module SwigTest
    ??? %{
    ??? #include "SwigTest.h"
    ??? %}

    ? ? /*?--- 接口聲明部分 ---*/
    ??? class CSwigTest {
    ??? public:
    ??????? int Add(int a, int b);

    ??????? int Substract(int a, int b);

    ??? };

    ??? 注解:%module標記用于定義SWIG生成的模塊的名稱,%{%}標記中的內(nèi)容會被一字不差地插入SWIG自動生成的文件xxx_wrapper.c中,其中xxx代表用%module指定的模塊名稱。這個文件會在下面介紹,不必著急去理解它究竟有什么作用。

    ??? 如果打算為類中所有方法創(chuàng)建API,那么有一個非常簡單的辦法,在接口文件的類聲明部分使用%include標記。SWIG將對%include所指定的文件進行語法分析,類中所有公有方法(Public Method)都將在API中暴露。

    ??? /* SwigTest.i */
    ??? %module SwigTest
    ??? %{
    ??? #include "SwigTest.h"
    ??? %}
    ??? #include “SwigTest.h”?

    1.2 編譯模塊

    ??? 有了接口文件之后,剩下的事就是執(zhí)行幾條命令。下面我們以Windows平臺上生成.NET API為例介紹這些命令。

    ??? (a) 調(diào)用SWIG自動生成代碼

    ??? swig -csharp? SwigTest.i

    ??? 執(zhí)行上面的命令會產(chǎn)生一個C語言文件SwigTest_wrapper.c和多個C#文件。在文件SwigTest_wrapper.c中,SWIG為接口文件中接口聲明部分指定的每個方法產(chǎn)生一個全局方法,以便C#使用Pinvoke調(diào)用這些函數(shù)。而那些C#文件就是用來生成.NET API的。

    ????(b) 為C++代碼生成DLL(動態(tài)鏈接庫)

    ??? cl SwigTest_wrapper.c *.cpp

    ??? link *.obj /out:SwigTest.dll

    ??? 執(zhí)行上面的命令,會為我們編寫C++代碼生成DLL。在編譯C++文件時,一定要包括SWIG為我們生成的C++文件SwigTest_wrapper.cpp。

    ??? 注意:為了讓大家便于理解上述命令,這些命令并沒有列出完整的編譯和鏈接選項。

    ????(C) 生成.NET模塊

    ??? csc /out:SwigTestNotNetAPI.dll /target:library *.cs

    ??? 執(zhí)行上面的命令就生成了.NET API模塊SwigTestNotNetAPI.dll。如果用戶想使用這些API,只需要添加對SwigTestNotNetAPI.dll的引用(Reference)就可以了。

    ??? 生成其它語言類型API的命令基本類似,下面我們再以Java在Unix平臺下的命令為例結束對SWIG的介紹。事實上,SWIG也是一個開源項目。如果想了解更多關于SWIG的信息,大家可以登陸SWIG的官方網(wǎng)站www.swig.org,那里有SWIG最詳細的資料。
    ????$ swig -java SwigTest_wrapper.i
    ?? ?$ gcc -c *.cpp SwigTest_wrapper.c -I/c/jdk1.3.1/include -I/c/jdk1.3.1/include/win32
    ?? ?$ gcc -shared *.o -mno-cygwin -Wl,--add-stdcall-alias? -o SwigTest.dll

    2. SWIG在MapGuide中的應用

    ??? 我們在前面已經(jīng)提到過,MapGuide使用了SWIG來自動生成.NET、Java和PHP這三種類型的API。但是,SWIG也有不少限制和缺陷,所以MapGuide對SWIG源代碼進行了大量的修改,以滿足自己的要求。下面,我們看看這些改進。

    2.1 IMake工具

    ??? SWIG要求開發(fā)人員編寫一個接口文件,那么能否讓接口文件自動生成呢?借用一句中國移動的廣告詞,我能!雖然SWIG沒有提供這方面的工具,但是我們可以自己開發(fā)嗎!IMake(Interface Maker)就是為了滿足這樣的要求而開發(fā)一個工具,給定一個XML文件,它能幫你自動生成SWIG接口文件。登錄MapGuide開源版的代碼瀏覽頁面(http://trac.osgeo.org/mapguide/browser),在root/trunk/MgDev/BuildTools/WebTools/IMake文件夾下可以找到IMake的源代碼。

    ???? 下面我們以MapGuide中使用的XML文件/trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml為例,介紹一下IMake的用法。為了便于理解,在此我刪掉了文件中的部分內(nèi)容。

    ??? <?xml version="1.0" encoding="UTF-8"?>
    ??? <Parameters>
    ????? <!-- 對應于%Module標記. -->
    ????? <Module name="MapGuideApi" />

    ????? <!-- 生成的接口文件的名稱. -->
    ????? <Target path="./MapGuideApi.i" />

    ????? <!-- 對應于%{%}標記 -->
    ????? <CppInline>
    ??????? #include &lt;string&gt;
    ??????? #include &lt;map&gt;
    ??????? #include "MapGuideCommon.h"
    ??????? #include "WebApp.h"
    ??????? ......
    ????? </CppInline>

    ????? <!-- 用于替換接口中使用的部分類型 -->
    ????? <TypeReplacements>
    ??????? <TypeReplacement oldtype="CREFSTRING" newtype="STRINGPARAM" />
    ??????? <TypeReplacement oldtype="INT64" newtype="long long" />
    ????? </TypeReplacements>

    ????? <!-- 此部分的內(nèi)容添加在%{%}之后,接口聲明部分之前 -->
    ????? <SwigInline>
    ??????? %include "language.i"?? //typemaps specific for each language
    ??????? ......
    ????? </SwigInline>
    ??????
    ????? <!-- 為指定的C++文件生成接口聲明 -->
    ????? <Headers>
    ??????? <Header path="../../../Common/Foundation/Data/Property.h" />
    ??????? ......
    ????? </Headers>
    ??? </Parameters>

    ??? 執(zhí)行命令“IMake MapGuideApiGen.xml”,IMake就幫我們自動生成了如下SWIG接口文件MapGuideApi.i。

    ??? /* MapGuideApi.i */
    ??? %module MapGuideApi?
    ??? %{
    ??????? #include <string>;
    ??????? #include <map>;
    ??????? #include "MapGuideCommon.h"
    ??????? #include "WebApp.h"
    ??????? ......
    ??? %}
    ?
    ??? %include "language.i"?? //typemaps specific for each language
    ??? ......

    ??? class MgProperty: public MgNamedSerializable
    ??? {
    ??? public:
    ??????? virtual INT16 GetPropertyType();
    ??????? STRING GetName();
    ??????? void SetName(CREFSTRING name);
    ??? };

    ??? ......

    ??? 如果打開文件Proper.h,我們可以看到MgProperty有更多的方法,例如CanSetName(...)。為什么只有三個方法添加到了SWIG接口文件中?IMake在生成接口文件時,它會查找C++頭文件中的宏PUBLISHED_API。只有被PUBLISHED_API修飾的方法,才會添加到接口文件中。

    ??? 注:宏PUBLISHED_API和INTERNAL_API的定義如下。

    ??? #define PUBLISHED_API public

    ??? #define INTERNAL_API public

    ??? class MG_FOUNDATION_API MgProperty : public MgNamedSerializable?
    ??? {?
    ??? PUBLISHED_API:

    ??????? virtual INT16 GetPropertyType() = 0;? /// __get???
    ??????? STRING GetName();? /// __get, __set?
    ??????? void SetName(CREFSTRING name);?
    ??
    ??? INTERNAL_API:?
    ??????? virtual bool CanSetName();?
    ??
    ??? protected:??
    ??????? INT32 GetClassId();?
    ??????? MgProperty();?
    ??????? virtual ~MgProperty();?
    ??????? virtual void Dispose();???
    ??????? virtual void ToXml(string &str, bool includeType = true, string rootElmName = "Property") = 0;?
    ??
    ??? private:?
    ??????? friend class MgPropertyCollection;?
    ??????? STRING m_propertyName;?
    ?
    ??? CLASS_ID:?
    ??????? static const INT32 m_cls_id = Foundation_Property_Property;?
    ??? };?????
    ??? 給定一個C++常量定義文件,IMake還可以自動生成對應的其他語言的常量定義文件。MapGuide .NET Web API中的所有常量都是使用IMake來生成的,例如MgMineType、MgPropertyType等。下面我們以MapGuide中使用的XML文件/trunk/MgDev/Web/src/MapGuideApi/Constants.xml為例,介紹如何自動生成各種語言的常量定義文件。同樣,為了便于理解,在此我刪掉了文件中的部分內(nèi)容。與MapGuideApiGen.xml不同,Constants.xml包含一個新的元素Classes用來指出需要在目標語言中產(chǎn)生對應的常量類的C++類。
    ??? <?xml version="1.0" encoding="UTF-8"?>

    ??? <Parameters>

    ??? <!-- 用于替換類型 -->

    ??? <PHPTypeReplacements>?
    ??????? <TypeReplacement oldtype="STRING" newtype="" />
    ??????? <TypeReplacement oldtype="INT16" newtype="" />
    ??????? ......
    ??? </PHPTypeReplacements>
    ??? <CSharpTypeReplacements>
    ??????? <TypeReplacement oldtype="STRING" newtype="string" />
    ??????? <TypeReplacement oldtype="INT16" newtype="short" />
    ??????? ......
    ??? </CSharpTypeReplacements>
    ??? <JavaTypeReplacements>
    ??????? <TypeReplacement oldtype="STRING" newtype="String" />
    ??????? <TypeReplacement oldtype="INT16" newtype="short" />
    ??????? ......
    ??? </JavaTypeReplacements>

    ??? <Namespace>OSGeo.MapGuide</Namespace>
    ??? <Package>org.osgeo.mapguide</Package>

    ??? <!--?用于指出需要在目標語言中產(chǎn)生對應的常量類的C++類 -->

    ??? <Classes>
    ??????? <Class name="MgMineType" />
    ??????? <Class name="MgPropertyType" />
    ??????? ......
    ??? </Classes>

    ??? <Headers>
    ??????? <Header path="../../../Common/Foundation/Data/MimeType.h" />
    ??????? <Header path="../../../Common/Foundation/Data/PropertyType.h" />
    ??????? ......
    ??? </Headers>

    ??? </Parameters>

    ??? 執(zhí)行命令“IMake.exe Constants.xml C# Constants.cs”,IMake就幫我們自動生成了一個C#常量文件Constants.cs。對于文件/trunk/MgDev/Common/Foundation/Data/PropertyType.h中定義了如下常量,

    ??? class MgPropertyType?
    ??? {?
    ??? PUBLISHED_API:??
    ?????? static const int Null???? =? 0;
    ?????? static const int Boolean? =? 1;?
    ?????? static const int Byte???? =? 2;?
    ?????? static const int DateTime =? 3;
    ?????? static const int Single?? =? 4;?
    ?????? ......
    ??? };

    ??? 在生成的Constants.cs文件中,有如下的類定義。
    ??? class MgPropertyType?
    ??? {?
    ?????? static const int Null???? =? 0;
    ?????? static const int Boolean? =? 1;?
    ?????? static const int Byte???? =? 2;?
    ?????? static const int DateTime =? 3;
    ?????? static const int Single?? =? 4;?
    ?????? ......
    ??? };

    ??? 這個文件可以被C#的編譯器直接編譯,所以MapGuide沒有使用SWIG生成常量的API,而是直接使用IMake。?如果想生成PHP或Java的常量定義文件,只需要將IMake命令的參數(shù)"C#"替換為"PHP"或"Jave"就可以了。

    2.2 MapGuide對SWIG的修改
    ??? 在MapGuide開始使用SWIG的時候,可用的SWIG的最高版本是1.3.21,從那以后MapGuide在沒有升級過SWIG。所以,到現(xiàn)在為止,MapGuide的SWIG版本仍然是1.3.21。這個版本的SWIG有不少限制和缺陷,

    • 無法創(chuàng)建基于自定義根異常類MgException的異常處理機制。
    • 無法創(chuàng)建屬性(Property)。
    • 對某些方法無法產(chǎn)生正確的API。例如,如果方法GetA(...)返回的是類A的子類B的實例,SWIG創(chuàng)建的API返回的仍然是A類的實例。此時如果你把返回值轉換為類B,那么轉換會失敗。
      ??? A* GetA();
    • ......

    ??? 事實上最新的SWIG版本也沒有全部解決這些問題,所以MapGuide對SWIG源代碼進行了大量的修改,以滿足自己的要求。看看MapGuide在使用SWIG命令是傳入的參數(shù),我們可以發(fā)現(xiàn)有許多參數(shù)不是SWIG標準的參數(shù),例如proxydir、clsidcode、clsiddata、catchallcode等。


    swig -c++ -csharp -dllname MapGuideUnmanagedApid -namespace OSGeo.MapGuide -proxydir .\custom -baseexception MgException -clsidcode getclassid.code -clsiddata m_cls_id -catchallcode catchall.code -dispose &quot;((MgDisposable*)arg1)-&gt;Release()&quot; -rethrow &quot;e-&gt;Raise();&quot; -nodefault -noconstants -module MapGuideApi -o MgApi_wrap.cpp -lib ..\..\..\Oem\SWIGEx\Lib MapGuideApi.i


    ??? 在此,我們不打算一一介紹這些參數(shù),因為在多數(shù)情況下你沒有必要對了解參數(shù)的含義。我們只介紹MapGuide是如何來解決上述SWIG的第二和第三個問題的,因為在擴展MapGuide Web API的時候你可能會用得著。


    2.2.1 創(chuàng)建屬性
    ??? 如果你看過MapGuide源代碼的話,你會發(fā)現(xiàn)有許多方法聲明之后有“__get”、“__set”或“__get, __set”這樣的注釋,如類MgProperty中的方法。
    ??? class MgProperty : public MgNamedSerializable?
    ??? {?
    ??? PUBLISHED_API:?
    ??????? virtual INT16 GetPropertyType() = 0;? /// __get???
    ??????? STRING GetName();? /// __get, __set?
    ??????? void SetName(CREFSTRING name);?
    ??????? ......
    };
    ??? 這些注釋是有特殊含義的,它們就是用來解決上述SWIG的第二個問題的。當IMake工具掃描C++頭文件時發(fā)現(xiàn)這注釋后,會在目錄“.\custom”下為每個類產(chǎn)生一個幫助創(chuàng)建屬性的代碼文件。例如,如果要類MgProperty生成.NET API,IMake會在“.\custom”生成一個文件名為MgProperty的C#代碼文件,它的內(nèi)容如下:
    ??? public int PropertyType {
    ??????? get {return GetPropertyType(); }
    ??? }
    ??? public int Name {
    ??????? get { return GetPropertyType(); }
    ??????? set { setName(value);}
    ??? }
    ??? 如果在SWIG的命令行中使用了參數(shù)proxydir,那么SWIG在為每個類生成代碼的時候,會在proxydir所指定的目錄下查找和類名相同的文件,并且將這個文件中的代碼插入類的目標代碼中。通過這種辦法,就解決了上述SWIG的第二個問題。

    2.2.2 ClassId
    ??? MapGuide Web API中的所有類都是從MgObject繼承而來的,在類MgObject中有一個方法GetClassId()用來返回每個類唯一的ID值。MapGuide就是用這個方法來解決上述SWIG的第三個問題的,所以如果要在MapGuide Web API中增加一個新類,一定要覆蓋(override)這個方法,并且提供一個唯一的ID值。
    ??? class MgObject
    ??? {
    ??? EXTERNAL_API:
    ??????? virtual INT32 GetClassId();
    ??????? virtual STRING GetClassName();
    ??? INTERNAL_API:
    ??????? virtual ~MgObject();
    ??????? bool IsOfClass(INT32 classId);
    ??? };

    3. 擴展MapGudie Web API

    ????如果你發(fā)現(xiàn)現(xiàn)有的MapGuide Web API無法滿足你的要求,沒有關系,你可以去嘗試擴展它,因為MapGuide是開源的。

    ??? 如果要新添類,基本步驟如下:
    ??? (a) 修改C++代碼,添加新的類。對于需要暴露于API的方法,使用宏PUBLISHED_API修飾。
    ??? (b) 修改XML文件/trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml的Headers部分,為每個新添加類所在的C++頭文件增加一個Header元素。下面的示例中,"path"代表C++頭文件的路徑,"filename.h"代表文件的名稱。
    ??? <Headers>
    ??????? <Header path="path/filename.h" />
    ??????? ......
    ??? </Headers>
    ??? (c) 重新編譯MapGuide的Web模塊(/trunk/MgDev/Web/src/)。
    ?
    ??? 如果要增加一些新的方法到現(xiàn)有的類中,基本步驟如下:
    ??? (a) 修改C++代碼,添加新的方法,并且使用宏PUBLISHED_API修飾這些方法。
    ??? (b) 重新編譯MapGuide的Web模塊(/trunk/MgDev/Web/src/)。

    ??? 如果要新增常量類,基本步驟如下:
    ??? (a) 修改C++代碼,添加新的常量類。
    ??? (b) 修改XML文件/trunk/MgDev/Web/src/MapGuideApi/Constants.xml,在Classes部分為每個新添加常量類增加一個Class元素,在Headers部分為每個新添加常量類所在的C++頭文件增加一個Header元素。下面的示例中,"ClassName"代表新添加的C++常量類的名稱。

    ??? <Classes>
    ??????? <Class name="ClassName" />
    ??????? ......
    ??? </Classes>
    ??? <Headers>
    ??????? <Header path="path/filename.h" />
    ??????? ......
    ??? </Headers>????
    ??? (c) 重新編譯MapGuide的Web模塊(/trunk/MgDev/Web/src/)。

    主站蜘蛛池模板: 激情综合亚洲色婷婷五月| 88av免费观看| 亚洲中文无码永久免| 亚洲VA中文字幕无码毛片| 国产乱弄免费视频| 我的小后妈韩剧在线看免费高清版 | 亚洲熟妇AV一区二区三区浪潮| 久久精品国产精品亚洲艾草网| 亚洲国产精品碰碰| 国产一级理论免费版| 毛片免费vip会员在线看| 最近2019年免费中文字幕高清| 最近免费中文字幕中文高清| 三级片免费观看久久| 99亚洲精品卡2卡三卡4卡2卡| 亚洲精品123区在线观看| 亚洲妓女综合网99| 色噜噜综合亚洲av中文无码| 亚洲av无码乱码国产精品| 亚洲中文字幕无码一区二区三区| 免费国产在线观看不卡| 国产小视频免费观看| 精品无码国产污污污免费| 成年人在线免费看视频| 免费无码A片一区二三区| 成年人视频免费在线观看| 精品福利一区二区三区免费视频 | 亚洲午夜无码AV毛片久久| 亚洲成av人在片观看| 亚洲国产精品综合久久一线| 亚洲毛片av日韩av无码| 免费a级毛片无码av| 亚洲国产aⅴ综合网| 国内精品久久久久久久亚洲| 浮力影院亚洲国产第一页| 亚洲熟女一区二区三区| 亚洲av无码乱码国产精品fc2| 亚洲丝袜美腿视频| 亚洲精品伊人久久久久| 亚洲啪AV永久无码精品放毛片| 亚洲国产精品无码久久久秋霞1|