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

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

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

    gembin

    OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

    HBase, Hadoop, ZooKeeper, Cassandra

    Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

    There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

    About Me

     

    Restlet創(chuàng)建面向資源的服務(wù)

    Restlet項(xiàng)目(http://www.restlet.org)為“建立REST概念與Java類(lèi)之間的映射”提供了一個(gè)輕量級(jí)而全面的框架。它可用于實(shí)現(xiàn)任何種類(lèi)的REST式系統(tǒng),而不僅僅是REST式Web服務(wù);而且,事實(shí)證明它自從2005年誕生之時(shí)起,就是一個(gè)可靠的軟件。
    estlet項(xiàng)目受到Servlet API、JSP(Java Server Pages)、HttpURLConnection及Struts等Web開(kāi)發(fā)技術(shù)的影響。該項(xiàng)目的主要目標(biāo)是:在提供同等功能的同時(shí),盡量遵守Roy Fielding博士論文中所闡述的REST的目標(biāo)。它的另一個(gè)主要目標(biāo)是:提出一個(gè)既適于客戶(hù)端應(yīng)用又適于服務(wù)端的應(yīng)用的、統(tǒng)一的Web視圖。

    Restlet的思想是:HTTP客戶(hù)端與HTTP服務(wù)器之間的差別,對(duì)架構(gòu)來(lái)說(shuō)無(wú)所謂。一個(gè)軟件應(yīng)可以既充當(dāng)Web客戶(hù)端又充當(dāng)Web服務(wù)器,而無(wú)須采用兩套完全不同的APIs。

    Restlet包括Restlet API和Noelios Restlet Engine(NRE)兩部分,NRE是對(duì)Restlet API的一種參考實(shí)現(xiàn)。這種劃分,使得不同實(shí)現(xiàn)可以具有同樣的API。NRE包括若干HTTP服務(wù)器連接器(HTTP server connector),它們都是基于Mortbay的Jetty、Codehaus的AsyncWeb,以及Simple框架這些流行的HTTP Java開(kāi)源項(xiàng)目的。它甚至提供一個(gè)適配器(adapter),使你可以在標(biāo)準(zhǔn)Servlet容器(如Apache Tomcat)內(nèi)部署一個(gè)Restlet應(yīng)用。

    Restlet還提供兩個(gè)HTTP客戶(hù)端連接器(HTTP client connector)。它們一個(gè)是基于官方的HttpURLConnection類(lèi),一個(gè)是基于A(yíng)pache的HTTP客戶(hù)端庫(kù)。還有一個(gè)連接器允許你容 易地按REST風(fēng)格通過(guò)XML文檔來(lái)處理JDBC源(source);此外,一個(gè)基于JavaMail API的SMTP連接器允許你發(fā)送內(nèi)容為XML的Email。

    Restlet API包括一些能夠創(chuàng)建基于字符串、文件、流(stream)、通道(channel)及XML文檔的表示(representation),它支持 SAX、DOM及XSLT。使用FreeMaker或Apache Velocity模板引擎,你可以很容易地創(chuàng)建基于JSP式模板的表示(representations)。你甚至可以像普通Web服務(wù)器那樣,用一個(gè)支 持內(nèi)容協(xié)商(content negotiation)的Directory類(lèi)來(lái)返回靜態(tài)文件與目錄。

    簡(jiǎn)單性(simplicity)和靈活性(flexibility)是貫穿整個(gè)框架的設(shè)計(jì)原則。Restlet API旨在把HTTP、URI及REST的概念抽象成一系列類(lèi)(classes),同時(shí)又不把低層信息(如原始HTTP報(bào)頭)完全隱藏起來(lái)。

    基本概念

    Restlet在術(shù)語(yǔ)上參照了Roy Fielding博士論文在講解REST時(shí)采用的術(shù)語(yǔ),如:資源(resource)、表示(representation)、連接器 (connector)、組件(component)、媒體類(lèi)型(media type)、語(yǔ)言(language),等等。這些術(shù)語(yǔ)你應(yīng)該不會(huì)陌生。Restlet增加了一些專(zhuān)門(mén)的類(lèi)(如Application、Filter、 Finder、Router和Route),用以簡(jiǎn)化restlets的彼此結(jié)合,以及簡(jiǎn)化把收到的請(qǐng)求(incoming requests)映射為處理它們的資源。

    圖12-1:Restlet的類(lèi)層次結(jié)構(gòu)

    抽象類(lèi)Uniform及其具體子類(lèi)Restlet,是Restlet的核心概念。正如其名稱(chēng)所暗示的,Uniform暴露一個(gè)符合REST規(guī)定的統(tǒng) 一接口(uniform interface)。雖然該接口是按HTTP統(tǒng)一接口定義的,但它也可用于其他協(xié)議(如FTP和SMTP)。

    handle是一個(gè)重要的方法,它接受兩個(gè)參數(shù):Request和Response。正如你可以從圖12-1中看到的,每個(gè)暴露于網(wǎng)上的調(diào)用處理者 (call handler)(無(wú)論作為客戶(hù)端還是服務(wù)端)都是Restlet的一個(gè)子類(lèi)——也就是說(shuō),它是一個(gè)restlets——并遵守這個(gè)統(tǒng)一接口。由于有統(tǒng)一 接口,restlets可以非常復(fù)雜的方式組合在一起。

    Restlet支持的每一個(gè)協(xié)議都是通過(guò)handle方法暴露的。這就是說(shuō),HTTP(服務(wù)器和客戶(hù)端)、HTTPS、SMTP,以及JDBC、文 件系統(tǒng),甚至類(lèi)加載器(class loaders)都是通過(guò)調(diào)用handle方法來(lái)操作的。這減少了開(kāi)發(fā)者需掌握的APIs的數(shù)量。

    過(guò)濾、安全、數(shù)據(jù)轉(zhuǎn)換及路由是“通過(guò)把Restlet的子類(lèi)鏈起來(lái)”進(jìn)行處理的。Filters可以在處理下個(gè)restlet調(diào)用之前或之后進(jìn)行處 理。Filters實(shí)例的工作方式與Rails過(guò)濾器差不多,只不過(guò)Filters實(shí)例跟其他Restlet類(lèi)一樣響應(yīng)handle方法,而不是具有一個(gè) 專(zhuān)門(mén)的API。

    一個(gè)Router restlet有許多附屬的Restlet對(duì)象,它把每個(gè)收到的協(xié)議調(diào)用(incoming protocol call)路由給適當(dāng)?shù)腞estlet處理器。路由(routing)通常是根據(jù)目標(biāo)URI進(jìn)行的。跟Rails不同的是,Restlet沒(méi)有對(duì)資源層次 結(jié)構(gòu)(resource hierarchy)作URI規(guī)則限定,所以可以隨意設(shè)置想要的URI,只要對(duì)Routers作相應(yīng)編程就行了。

    除了這一常見(jiàn)用途,Router還可用于其他用途。你可以用一個(gè)Router在多臺(tái)遠(yuǎn)程機(jī)器之間以動(dòng)態(tài)負(fù)載均衡的方式來(lái)轉(zhuǎn)發(fā)調(diào)用。即使在這種復(fù)雜的 情況下,它也一樣響應(yīng)Restlet的統(tǒng)一接口,并且可成為一個(gè)更大路由系統(tǒng)中的一個(gè)組件。VirtualHost類(lèi)(Router的一個(gè)子類(lèi))使我們可 以在同一臺(tái)物理主機(jī)上運(yùn)行多個(gè)具有不同域名的應(yīng)用。在過(guò)去,你要引入一個(gè)前端Web服務(wù)器(如Apache的httpd)才能實(shí)現(xiàn)此功能;而用 Restlet的話(huà),它只是另一個(gè)響應(yīng)統(tǒng)一接口的Router實(shí)現(xiàn)。

    一個(gè)Application對(duì)象能夠管理一組restlets,并提供常見(jiàn)的服務(wù),比方說(shuō)對(duì)壓縮的請(qǐng)求進(jìn)行透明解碼,或者利用method查詢(xún)參數(shù) 在重載的POST(overloaded POST)之上實(shí)現(xiàn)PUT和DELETE請(qǐng)求。最后,Component對(duì)象可以包含并編配(orchestrate)一組Connectors、 VirtualHosts及Applications(作為獨(dú)立Java應(yīng)用運(yùn)行的,或者嵌入在一個(gè)更大系統(tǒng)(如J2EE環(huán)境)中的)。

    在第6章,我向你介紹了“把一個(gè)問(wèn)題劃分為一組響應(yīng)HTTP統(tǒng)一接口的資源”的步驟。在第7章,為了處理Ruby on Rails的簡(jiǎn)單化假設(shè)(simplifying assumptions),我對(duì)該步驟作了相應(yīng)的調(diào)整。因?yàn)镽estlet沒(méi)有做簡(jiǎn)單化假設(shè)(simplifying assumptions),所以我們無(wú)須對(duì)此步驟進(jìn)行修改。它可以實(shí)現(xiàn)任何REST式系統(tǒng)。如果你剛好想實(shí)現(xiàn)一個(gè)REST式面向資源的Web服務(wù),可以按 愿意的方式來(lái)組織和實(shí)現(xiàn)這些資源。Restlet確實(shí)提供了一些便于創(chuàng)建面向資源的應(yīng)用的類(lèi)。其中特別值得一提的是Resource類(lèi),它可作為你所有應(yīng) 用資源的基礎(chǔ)。

    我在本書(shū)中一直用URI模板作為一組URIs的簡(jiǎn)化表達(dá)(見(jiàn)第9章)。Restlet用URI模板來(lái)進(jìn)行URI與資源的映射。假如用Restlet來(lái)實(shí)現(xiàn)第7章那個(gè)社會(huì)性書(shū)簽服務(wù)的話(huà),它也許要指定一個(gè)代表特定書(shū)簽的URI:

    /users/{username}/bookmarks/{URI}

    你可以在把Resource子類(lèi)附加到Router上時(shí)使用這種語(yǔ)法。假如你不相信真會(huì)這么好的話(huà),可以等到下一節(jié),那時(shí)我會(huì)實(shí)際實(shí)現(xiàn)部分書(shū)簽服務(wù)。

    編寫(xiě)Restlet客戶(hù)端

    在示例2-1中,你看到的是一個(gè)從Yahoo!搜索服務(wù)獲取XML搜索結(jié)果的Ruby客戶(hù)端。示例12-3是一個(gè)用Java參照Restlet 1.0實(shí)現(xiàn)的具有同樣功能的客戶(hù)端。要確保把以下JAR包寫(xiě)在你的classpath中,才能成功編譯并運(yùn)行接下來(lái)的例子:

    • org.restlet.jar(Restlet API)
    • com.noelios.restlet.jar (Noelios Restlet Engine核心)
    • com.noelios.restlet.ext.net.jar (基于JDK的HttpURLConnection的HTTP客戶(hù)端連接器)

    這些JAR包可以在Restlet發(fā)布包中的lib目錄里找到。要確保你的Java環(huán)境支持Java SE 5.0(或更高)版本。如果你確實(shí)需要的話(huà),可以用Retrotranslator(http://retrotranslator. sourceforge.net/)輕易地把Restlet代碼反移植(backport)到J2SE 4.0版上去。

    示例12-3:Yahoo!搜索服務(wù)的一個(gè)Restlet客戶(hù)端

    // YahooSearch.java
    import org.restlet.Client;
    import org.restlet.data.Protocol;
    import org.restlet.data.Reference;
    import org.restlet.data.Response;
    import org.restlet.resource.DomRepresentation;
    import org.w3c.dom.Node;

    /**
      * 用返回XML的Yahoo!搜索服務(wù)來(lái)搜索Web
     */
    public class YahooSearch {
        static final String BASE_URI =
        "http://api.search.yahoo.com/WebSearchService/V1/webSearch";

        public static void main(String[] args) throws Exception {
            if (args.length != 1) {
                System.err.println("You need to pass a term to search");
            } else {
                // 獲取一個(gè)資源,即一個(gè)包含搜索結(jié)果的XML文檔
                String term = Reference.encode(args[0]);
                String uri = BASE_URI + "?appid=restbook&query=" + term;
                Response response = new Client(Protocol.HTTP).get(uri);
                DomRepresentation document = response.getEntityAsDom();

                // 用XPath找出數(shù)據(jù)結(jié)構(gòu)中重要部分
                String expr = "/ResultSet/Result/Title";
                for (Node node : document.getNodes(expr)) {
                      System.out.println(node.getTextContent());
                }
            }
        }
    }

    跟示例2-1一樣,你可以在執(zhí)行這個(gè)類(lèi)時(shí)把一個(gè)搜索關(guān)鍵字作為命令行參數(shù)傳給它。比如像下面這樣:

    $ java YahooSearch xslt
         XSL Transformations (XSLT)
         The Extensible Stylesheet Language Family (XSL)
         XSLT Tutorial
              ...

    該示例證明了“用Restlet從Web服務(wù)獲取XML數(shù)據(jù),并用標(biāo)準(zhǔn)工具處理它”是極其簡(jiǎn)單的事。Yahoo!資源的URI是用一個(gè)常量和用戶(hù)提 供的搜索關(guān)鍵字構(gòu)造而成的。客戶(hù)端連接器(client connector)是用HTTP協(xié)議來(lái)初始化的。XML文檔是通過(guò)get方法獲得的,該方法對(duì)應(yīng)于HTTP統(tǒng)一接口的GET方法。當(dāng)調(diào)用返回時(shí),程序?qū)? 得到一個(gè)DOM表示。跟前面的Ruby例子一樣,XPath是對(duì)XML進(jìn)行查詢(xún)的最簡(jiǎn)單方式。

    跟前面的Ruby例子一樣,這個(gè)程序也忽略了XML文檔里的XML名稱(chēng)空間(namespaces)。Yahoo!為整個(gè)文檔采用名稱(chēng)空間urn: yahoo:srch,但我是直接引用標(biāo)簽的,比方說(shuō),我用ResultSet,而不是urn:yahoo:srch:ResultSet。前面的 Ruby例子忽略名稱(chēng)空間,是因?yàn)镽uby的默認(rèn)XML解析器不支持名稱(chēng)空間。Java的XML解析器支持名稱(chēng)空間,而且Restlet API令正確處理名稱(chēng)空間變得更加容易。雖然對(duì)上面那個(gè)簡(jiǎn)單例子來(lái)說(shuō),它們區(qū)別不大,但支持名稱(chēng)空間可以避免一些因名稱(chēng)空間而導(dǎo)致的微妙的問(wèn)題。

    當(dāng)然,若一直用urn:yahoo:srch:ResultSet,是比較煩人的。Restlet API可以容易地把一個(gè)簡(jiǎn)短前綴跟一個(gè)名稱(chēng)空間進(jìn)行關(guān)聯(lián),然后就可以在XPath表達(dá)式中使用這個(gè)簡(jiǎn)短前綴而不是整個(gè)名稱(chēng)空間了。示例12-4對(duì)示例12 -3后半部分代碼作了改動(dòng),它使用了帶名稱(chēng)空間的Xpath,這樣就不會(huì)把來(lái)自Yahoo!的ResultSet標(biāo)簽與來(lái)自其他名稱(chēng)空間的標(biāo)簽搞混了。

    示例12-4:支持名稱(chēng)空間的文檔處理代碼

                DomRepresentation document = response.getEntityAsDom();

                // 把該名稱(chēng)空間與前綴‘y’關(guān)聯(lián)起來(lái)
                document.setNamespaceAware(true);
                document.putNamespace("y", "urn:yahoo:srch");

                // 用XPath找出數(shù)據(jù)結(jié)構(gòu)中重要部分
                String expr = "/y:ResultSet/y:Result/y:Title/text()";
                for (Node node : document.getNodes(expr)) {
                      System.out.println(node.getTextContent());
                }

    示例2-15是Yahoo!搜索服務(wù)的另一個(gè)Ruby客戶(hù)端。它請(qǐng)求的是JSON格式(而不是XML格式)的搜索數(shù)據(jù)。示例12-5是一個(gè)與之功能等價(jià)的Restlet客戶(hù)端。它通過(guò)Restlet里的另兩個(gè)JAR文件獲取JSON支持:

    • org.restlet.ext.json_2.0.jar(用于JSON的Restlet擴(kuò)展)
    • org.json_2.0/org.json.jar(JSON官方程序庫(kù))

    示例12-5:Yahoo!的JSON搜索服務(wù)的一個(gè)Restlet客戶(hù)端

    // YahooSearchJSON.java
    import org.json.JSONArray;
    import org.json.JSONObject;
    import org.restlet.Client;
    import org.restlet.data.Protocol;
    import org.restlet.data.Reference;
    import org.restlet.data.Response;
    import org.restlet.ext.json.JsonRepresentation;

    /**
      * 用返回JSON的Yahoo!搜索服務(wù)來(lái)搜索Web
     */
    public class YahooSearchJSON {
        static final String BASE_URI =
        "http://api.search.yahoo.com/WebSearchService/V1/webSearch";

        public static void main(String[] args) throws Exception {
            if (args.length != 1) {
                System.err.println("You need to pass a term to search");
            } else {

                // 獲取一個(gè)資源,即一個(gè)包含搜索結(jié)果的JSON文檔
                String term = Reference.encode(args[0]);
                String uri = BASE_URI + "?appid=restbook&output=json&query=" + term;
                Response response = new Client(Protocol.HTTP).get(uri);
                JSONObject json = new JsonRepresentation(response.getEntity())
                         .toJsonObject();

                // 在JSON文檔中尋找并顯示標(biāo)題
                JSONObject resultSet = json.getJSONObject("ResultSet");
                JSONArray results = resultSet.getJSONArray("Result");
                for (int i = 0; i < results.length(); i++) {
                     System.out.println(results.getJSONObject(i).getString("Title"));
                }
            }
        }
    }

    當(dāng)你為Yahoo!的Web服務(wù)編寫(xiě)客戶(hù)端時(shí),可以選擇表示格式(representation format)。Restlet核心API支持XML,另外還可以通過(guò)擴(kuò)展支持JSON。正如你所預(yù)料的那樣,這兩個(gè)例子的區(qū)別僅僅在于對(duì)響應(yīng)的處理上。 JsonRepresentation類(lèi)可以把響應(yīng)實(shí)體主體(response entity-body)轉(zhuǎn)換成一個(gè)JSONObject實(shí)例(而Ruby的JSON庫(kù)是把JSON數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成一個(gè)本地?cái)?shù)據(jù)結(jié)構(gòu))。該數(shù)據(jù)結(jié)構(gòu)只能進(jìn) 行人工遍歷,因?yàn)槟壳癑SON中還沒(méi)有類(lèi)似XPath的查詢(xún)語(yǔ)言。

    編寫(xiě)Restlet服務(wù)

    接下來(lái)的例子會(huì)稍微復(fù)雜一些。我將向你展示如何設(shè)計(jì)并實(shí)現(xiàn)一個(gè)服務(wù)端應(yīng)用。在第7章,我用Ruby on Rails實(shí)現(xiàn)了一個(gè)書(shū)簽管理應(yīng)用,現(xiàn)在我用Restlet來(lái)重新實(shí)現(xiàn)其部分功能。為了簡(jiǎn)單起見(jiàn),該應(yīng)用只支持對(duì)用戶(hù)及其書(shū)簽進(jìn)行安全的(safe)操作。

    Java包結(jié)構(gòu)是這樣的:

    org restlet
     example
         book
       rest
        ch7
           -Application
           -ApplicationTest
           -Bookmark
           -BookmarkResource
           -BookmarksResource
           -User
           -UserResource

    也就是說(shuō),Bookmark等類(lèi)都在org.restlet.example.book.rest.ch7包里。

    我不打算在此展示完整的代碼。如果需要,你可以去本書(shū)的官方網(wǎng)站(http://www.oreilly. com/catalog/9780596529260),那里提供了本書(shū)的所有示例程序代碼。你也可以在restlet.org(http: //www.restlet.org)上找到本例的完整代碼。如果你已經(jīng)下載了Restlet的話(huà),那么也可以在 src/org/restlet.example/org/restlet/example/book/rest目錄里找到本節(jié)的示例代碼。

    我將從一些簡(jiǎn)單的代碼開(kāi)始。示例12-6是Application.main方法,它用來(lái)建立Web服務(wù)器,并開(kāi)始處理請(qǐng)求。

    示例12-6:Application.main方法:建立Web服務(wù)器

    public static void main(String... args) throws Exception {
        // 用HTTP服務(wù)器連接器創(chuàng)建一個(gè)組件
        Component comp = new Component();
        comp.getServers().add(Protocol.HTTP, 3000);

        // 把應(yīng)用附加到默認(rèn)主機(jī)上,并啟動(dòng)
        comp.getDefaultHost().attach("/v1", new Application());
        comp.start();
    }

    資源與URI設(shè)計(jì)

    由于Restlet未對(duì)資源設(shè)計(jì)作特別的限制,所以你完全可以根據(jù)ROA的設(shè)計(jì)原則來(lái)進(jìn)行資源類(lèi)(resource classes)及URIs的設(shè)計(jì)。在第7章,我要圍繞“Rails的基于控制器的架構(gòu)”來(lái)進(jìn)行設(shè)計(jì);而這里,我不需要圍繞Restlet架構(gòu)來(lái)進(jìn)行設(shè) 計(jì)。圖12-2 展示了URI是如何經(jīng)由Router映射到資源,再映射到下層restlet類(lèi)的。

    圖12-2:社會(huì)性書(shū)簽應(yīng)用的Restlet架構(gòu)

    為了理解如何用Java代碼實(shí)現(xiàn)這些映射,我們來(lái)看一下Application類(lèi)及它的createRoot 方法(見(jiàn)示例12-7)。它跟示例7-3所示的Rails routes.rb文件在功能上是等價(jià)的。

    示例12-7:Application.createRoot方法:實(shí)現(xiàn)URI模板到restlet的映射

    public Restlet createRoot() {
        Router router = new Router(getContext());

        // 為用戶(hù)資源增加路由
        router.attach("/users/{username}", UserResource.class);

        // 為用戶(hù)的書(shū)簽資源增加路由
        router.attach("/users/{username}/bookmarks", BookmarksResource.class);

        // 為書(shū)簽資源增加路由
        Route uriRoute = router.attach("/users/{username}/bookmarks/{URI}",
                                           BookmarkResource.class);
        uriRoute.getTemplate().getVariables()
          .put("URI", new Variable(Variable.TYPE_URI_ALL));
    }

    在我創(chuàng)建一個(gè)Application對(duì)象(比如像示例12-6中的那樣)時(shí),這段代碼便會(huì)運(yùn)行。它會(huì)在資源類(lèi)UserResource與URI模板 “/users/(username)”之間建立起清晰而直觀(guān)的映射關(guān)系。Router先拿請(qǐng)求的目標(biāo)URI跟URI模板(URI templates)進(jìn)行比較,然后把請(qǐng)求轉(zhuǎn)發(fā)給一個(gè)新建的相應(yīng)的資源類(lèi)實(shí)例。模板變量的值被存放在請(qǐng)求的屬性地圖(attributes map)里(跟Rails例子中的params地圖類(lèi)似),以便于在Resource代碼中使用。這既有效,又易于理解;當(dāng)你事隔很久再回顧代碼時(shí),這很 有幫助。

    請(qǐng)求處理和表示

    假定一個(gè)客戶(hù)端向URI http://localhost:3000/v1/users/jerome發(fā)出GET請(qǐng)求。我有一個(gè)監(jiān)聽(tīng)本地主機(jī)3000端口的Component對(duì) 象,和一個(gè)隸屬于 /v1 的Application對(duì)象。該Application有一個(gè)Router和一組Route對(duì)象,這些Route對(duì)象正等待著跟各個(gè)URI模板匹配的請(qǐng) 求。 URI路徑片段“/users/jerome”跟模板“/users/{username}”相匹配,而該模板的Route是與UserResource 類(lèi)(大致等價(jià)于Rails UsersController類(lèi))相關(guān)聯(lián)的。

    Restlet通過(guò)初始化一個(gè)新的UserResource對(duì)象,并調(diào)用它的handleGet方法來(lái)處理該請(qǐng)求。示例12-8是UserResource類(lèi)的構(gòu)造方法。

    示例12-8:UserResource類(lèi)的構(gòu)造方法

    /**
     * 構(gòu)造方法
     *
     * @param context
     *           上級(jí)上下文
     * @param request
     *           要處理的請(qǐng)求
     * @param response
     *           要返回的響應(yīng)
     */
     public UserResource(Context context, Request request, Response response) {
        super(context, request, response);
        this.userName = (String) request.getAttributes().get("username");
        ChallengeResponse cr = request.getChallengeResponse();
        this.login = (cr != null) ? cr.getIdentifier() : null;
        this.password = (cr != null) ? cr.getSecret() : null;
        this.user = findUser();

        if (user != null) {
            getVariants().add(new Variant(MediaType.TEXT_PLAIN));
        }
    }

    至此,這個(gè)架構(gòu)已經(jīng)建立了一個(gè)Request對(duì)象,它包含了我所需要的關(guān)于請(qǐng)求的所有信息。username屬性來(lái)自URI,認(rèn)證證書(shū)來(lái)自請(qǐng)求的 Authorization報(bào)頭。我還調(diào)用findUser方法來(lái)根據(jù)認(rèn)證證書(shū)在數(shù)據(jù)庫(kù)中查找用戶(hù)(為節(jié)省篇幅,我就不在此展示findUser方法的代 碼了)。這些工作在第7章都是由Rails過(guò)濾器完成的。

    在框架把一個(gè)UserResource實(shí)例化后,它會(huì)對(duì)資源對(duì)象調(diào)用適當(dāng)?shù)膆andle方法。HTTP統(tǒng)一接口中的每一個(gè)方法,都有一個(gè)對(duì)應(yīng)handle方法。 在這個(gè)例子中,Restlet架構(gòu)最后的任務(wù)是調(diào)用UserResource.handleGet。

    由于我沒(méi)有定義UserResource.handleGet這個(gè)方法,所以它將具有繼承Resource. handleGet方法的行為。HandleGet的默認(rèn)行為是找到最符合客戶(hù)端要求的資源的表示。客戶(hù)端通過(guò)內(nèi)容協(xié)商(content- negotiation)來(lái)表達(dá)它的要求。Restlet通過(guò)Accept報(bào)頭的值來(lái)決定返回哪個(gè)表示。由于這里只有一個(gè)表示格式,所以客戶(hù)端的要求不起 作用。這是由getVariants和getRepresentation方法處理的。由于在上述構(gòu)造方法中把text/ plain定義為唯一支持的表示格式,所以我的getRepresentation方法的實(shí)現(xiàn)是很簡(jiǎn)單的(見(jiàn)示例12-9)。

    示例12-9:UserResoure.getRepresentation:構(gòu)造一個(gè)用戶(hù)的表示

    @Override
    public Representation getRepresentation(Variant variant) {
        Representation result = null;

        if (variant.getMediaType().equals(MediaType.TEXT_PLAIN)) {
            // 創(chuàng)建一個(gè)文本表示
            StingBuilder sb=new StringBuilder();
            sb.append("------------\n");
            sb.append("User details\n");
            sb.append("------------\n\n");
            sb.append("Name:  ").append(this.user.getFullName()).append('\n');
            sb.append("Email: ").append(this.user.getEmail()).append('\n');
            result = new StringRepresentation(sb);
        }

        return result;
    }

    雖然這只是一個(gè)資源的一個(gè)方法,但其他資源,以及UserResource的其他HTTP方法的工作原理都差不多,比如:對(duì)用戶(hù)的PUT請(qǐng)求將被路 由給UserResource.handlePut,等等。正如我前面所提到的,這里的代碼只是社會(huì)性書(shū)簽應(yīng)用所有代碼的一部分;所以,如果你有興趣進(jìn)一 步學(xué)習(xí)的話(huà),可以去下載一個(gè)完整的示例代碼來(lái)閱讀。

    現(xiàn)在,你應(yīng)該了解Restlet架構(gòu)是如何把收到的(incoming)HTTP請(qǐng)求路由給特定的Resource類(lèi),然后再路由給該類(lèi)的特定方法 了。你也應(yīng)該知道如何由資源狀態(tài)來(lái)構(gòu)造表示(representations)了。一般,只要關(guān)注Application和Router代碼一次就行,因 為一個(gè)Router可用于你的所有資源。

    編譯、運(yùn)行與測(cè)試

    Application類(lèi)實(shí)現(xiàn)了運(yùn)行社會(huì)性書(shū)簽服務(wù)的HTTP服務(wù)器。你需要在classpath中加入以下JAR文件:

    • org.restlet.jar
    • com.noelios.restlet.jar
    • com.noelios.restlet.ext.net.jar
    • org.simpleframework_3.1/org.simpleframework.jar
    • com.noelios.restlet.ext.simple_3.1.jar
    • com.db4o_6.1/com.db4o.jar

    這些JAR包可以在Restlet發(fā)布包中的lib目錄里找到。有兩點(diǎn)需要注意:第一,Web服務(wù)器的實(shí)際工作是由一個(gè)非常緊湊的、基于 Simple框架的HTTP服務(wù)器連接器來(lái)處理的;第二,我們是用強(qiáng)大的db4o對(duì)象數(shù)據(jù)庫(kù)(而不是關(guān)系數(shù)據(jù)庫(kù))來(lái)存儲(chǔ)領(lǐng)域?qū)ο螅ㄓ脩?hù)和書(shū)簽)的。在編譯 好所有示例文件后,運(yùn)行org.restlet.example.book.rest.ch7. Application,它將作為服務(wù)器的端點(diǎn)(endpoint)。

    ApplicationTest類(lèi)為服務(wù)提供了一個(gè)客戶(hù)端接口。它采用上節(jié)描述的Restlet客戶(hù)端類(lèi)來(lái)添加和刪除用戶(hù)和書(shū)簽。它是通過(guò)HTTP統(tǒng)一接口進(jìn)行工作的:用PUT請(qǐng)求創(chuàng)建用戶(hù)和書(shū)簽,用DELETE請(qǐng)求刪除用戶(hù)和書(shū)簽。

    在命令行下運(yùn)行ApplicationTest類(lèi),你將得到以下消息:

       Usage  depends  on  the  number  of  arguments:
    -  Deletes  a  user                  :  userName,  password
    -  Deletes  a  bookmark         :  userName,  password,  URI
    -  Adds  a  new  user             :  userName,  password,  "full  name",  email
    -  Adds  a  new  bookmark   :  userName,  password,  URI,  shortDescription,
                                                     longDescription,  restrict[true  /  false]

    你可以用這個(gè)程序來(lái)添加一些用戶(hù),并增加一些書(shū)簽。然后,你就可以在Web瀏覽器中通過(guò)訪(fǎng)問(wèn)適當(dāng)?shù)腢RI(如http://localhost:3000/v1/users/jerome等)來(lái)瀏覽用戶(hù)書(shū)簽的HTML表示了。

    小結(jié)

    Restlet項(xiàng)目在2007年初發(fā)布了1.0正式版。它只用了12個(gè)多月的開(kāi)發(fā)時(shí)間。目前,該項(xiàng)目具有一個(gè)繁榮的開(kāi)發(fā)與用戶(hù)群體。Restlet 郵件列表很友好,不論是新手,還是有經(jīng)驗(yàn)的開(kāi)發(fā)者,它都?xì)g迎。作為該項(xiàng)目的創(chuàng)建者,Noelios咨詢(xún)公司是主要的開(kāi)發(fā)力量,他們也提供專(zhuān)業(yè)的支持計(jì)劃與 培訓(xùn)。

    在本書(shū)編寫(xiě)之時(shí),1.0版處于維護(hù)中,新的1.1版已經(jīng)開(kāi)始開(kāi)發(fā)了。該項(xiàng)目計(jì)劃將來(lái)把Restlet API提交給JCP(Java Community Process)。還有一個(gè)用于REST式Web服務(wù)的高層API,它已由Sun公司提交給JCP(JSR311)。這個(gè)高層API使得“把Java領(lǐng)域 對(duì)象暴露為REST式資源”更加容易。這將是對(duì)Restlet API(尤其是其Resource類(lèi))的一個(gè)很好的補(bǔ)充。Noelios咨詢(xún)公司是最初的專(zhuān)家組成員,他們將根據(jù)標(biāo)準(zhǔn)的進(jìn)展來(lái)對(duì)Restlet引擎作相應(yīng) 的更新。


    posted on 2008-07-24 11:53 gembin 閱讀(1531) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): SOA

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(6)

    隨筆分類(lèi)(440)

    隨筆檔案(378)

    文章檔案(6)

    新聞檔案(1)

    相冊(cè)

    收藏夾(9)

    Adobe

    Android

    AS3

    Blog-Links

    Build

    Design Pattern

    Eclipse

    Favorite Links

    Flickr

    Game Dev

    HBase

    Identity Management

    IT resources

    JEE

    Language

    OpenID

    OSGi

    SOA

    Version Control

    最新隨筆

    搜索

    積分與排名

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    free counters
    主站蜘蛛池模板: 啦啦啦中文在线观看电视剧免费版| 亚洲国产精品嫩草影院在线观看 | 国产成A人亚洲精V品无码性色| 亚洲av无码成人精品国产| 91香蕉成人免费网站| 亚洲国产精品自在在线观看| 99re6在线精品免费观看| 亚洲美日韩Av中文字幕无码久久久妻妇| 亚洲欧洲无卡二区视頻| 国产精品美女午夜爽爽爽免费| 亚洲成a人片毛片在线| 无码久久精品国产亚洲Av影片| 亚洲一区二区三区亚瑟| 精品一区二区三区无码免费视频 | 香蕉免费一区二区三区| 亚洲欧洲日产国码无码网站| 九九免费精品视频在这里| 免费在线观看视频a| 久久精品国产亚洲av天美18| 永久免费观看的毛片的网站| 亚洲精品乱码久久久久久V| 久久久久国产免费| 亚洲大尺度无码专区尤物| 久久精品成人免费观看97| 久久激情亚洲精品无码?V| 在线观看日本亚洲一区| 四虎永久在线精品免费网址| 亚洲最大中文字幕无码网站 | 亚洲美女自拍视频| 最近最新高清免费中文字幕 | 国产亚洲精品成人AA片新蒲金 | 99在线视频免费| 亚洲成年人电影在线观看| 四虎在线免费视频| 亚洲AV无码一区二区三区人| 毛片免费vip会员在线看| 亚洲日韩av无码中文| 国产又大又长又粗又硬的免费视频| 亚洲理论片在线观看| 99在线视频免费观看视频| 伊人久久亚洲综合影院首页|