Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Agile Web Development With Rails, 1st Edition (2005).pdf
Скачиваний:
28
Добавлен:
17.08.2013
Размер:
7.99 Mб
Скачать

DISPATCHING MODES 417

:float

A floating-point number.

:time

A timestamp value, containing both date and time. Coerced into the Ruby Time type.

:datetime

A timestamp value, containing both date and time. Coerced into the Ruby DateTime type.

:date

A date value, containing just the date. Coerced into the Ruby Date type.

Structured Parameter Types

In addition to the base types, AWS lets us use the Class objects of ActionWebService::Struct or ActiveRecord::Base in signatures.

Using these lets external developers work with the native structured types for their platform when accessing our web services.

So what gets put into the structured type seen by remote callers? For

ActionWebService::Struct, all the members defined with member( ).

class Person < ActionWebService::Struct member :id, :int

member :name, :string end

An ActiveRecord::Base derivative exposes the columns defined in its corresponding database table.

20.3 Dispatching Modes

Remote callers send their invocation requests to endpoint URLs. (See Sec-

endpoint URLs

tion 20.6, External Client Applications (XML-RPC), on page 424, for the for-

 

mats of endpoint URLs.) Dispatching is the process by which AWS maps

 

these incoming requests to methods in objects that implement the ser-

 

vices.

 

The default dispatching mode is direct dispatching and requires no addi-

direct dispatching

tional configuration to set up. This is the mode we used for the example

 

on page 412.

 

Prepared exclusively for Rida Al Barazi

Report erratum

DISPATCHING MODES 418

NewPost(post)

Remote Caller

Controller

new_post(post)

Figure 20.2: Overview of Direct Dispatching

Direct Dispatching

With direct dispatching, the API definition is attached directly to the controller, and the API method implementations are placed in the controller as public instance methods.

The advantage of this approach is its simplicity. The drawback is that only one API definition can be attached to the controller; therefore, we can have only one API implementation for a unique endpoint URL. It also blurs the separation of model and controller code. It is shown in Figure 20.2 .

Layered Dispatching

Layered dispatching allows us to implement multiple APIs with one controller, with one unique endpoint URL for all the APIs. This works well for overlapping XML-RPC–based APIs (such as the various blogging APIs), which have desktop client applications supporting only one endpoint URL. This is shown in Figure 20.3, on the following page.

 

Delegated Dispatching

 

Delegated dispatching is identical to layered dispatching except that it

 

uses a unique endpoint URL per contained API. Instead of embedding API

 

identifiers in the method invocation messages, remote callers send the

 

messages for a specific API to its associated endpoint URI.

 

We use the web_service_dispatching_mode( ) method in a controller to select

 

that controller’s dispatching mode.

File 220

class RpcController < ActionController::Base

 

web_service_dispatching_mode :layered

 

end

 

The valid modes are :direct, :layered, and :delegated.

Prepared exclusively for Rida Al Barazi

Report erratum

DISPATCHING MODES 419

Remote Caller

FindProductById(id)

ProductService

find_product_by_id(id)

Controller

OrderService

is_order_shipped(id)

IsOrderShipped(id)

Remote Caller

Figure 20.3: Overview of Layered Dispatching

Layered Dispatching from a Remote Caller’s Perspective

Method invocation requests from remote callers differentiate between the APIs by sending an identifier indicating which API the method call should go to.

In the case of XML-RPC, remote callers use the standard XML-RPC serviceName.methodName convention, serviceName being the identifier. For example, an XML-RPC method with a name in the XML-RPC message of blogger.newPost would be sent to a newPost( ) method in whichever object is declared to implement the blogger service.

In the case of SOAP, this information is encoded in the SOAPAction HTTP header as declared by the generated WSDL. This has the implication that remote callers behind a proxy stripping off this HTTP header will not be able to call web services that use layered dispatching.

Prepared exclusively for Rida Al Barazi

Report erratum

USING ALTERNATE DISPATCHING

420

 

20.4 Using Alternate Dispatching

 

As we’ve already used direct dispatching in our first example web service,

 

let’s implement the same web service in one of the other modes.

 

Layered Dispatching Mode

 

Since layered dispatching implements multiple APIs with one controller, it

 

needs to create mappings for incoming method calls to the objects imple-

 

menting them. We do this mapping using the web_service( ) declaration in

 

the controller.

File 134

class LayeredBackendController < ApplicationController

 

web_service_dispatching_mode :layered

 

web_service_scaffold :invoke

 

web_service :product, ProductService.new

 

web_service(:order) { OrderService.new }

 

end

 

You’ll notice that we no longer attach the API definition to the controller, as

 

it no longer contains the API methods. Also notice the two different ways

 

we called web_service( ).

 

The first call to web_service( ) passed it a ProductService instance directly.

 

This is sufficient if our web service doesn’t need to have anything to do

 

with the controller. As the instance is created at class definition time,

 

though, it has no access to the instance variables of the controller, so it

 

effectively operates in isolation from it.

 

The second call to web_service( ) passes a block parameter. This has the

 

effect of deferring OrderService instantiation to request time. The block

 

we give it will be evaluated in controller instance context, so it will have

 

access to all the instance variables and methods of the controller. This

 

can be useful if we need to use helper methods such as url_for( ) in our web

 

service methods.

 

Here’s the rest of our code. First, here’s the implementation of our product

 

searching service.

File 130

class ProductService < ActionWebService::Base

 

web_service_api ProductApi

 

def find_all_products

 

Product.find(:all).map{ |product| product.id }

 

end

 

def find_product_by_id(id)

 

Product.find(id)

 

end

 

end

Prepared exclusively for Rida Al Barazi

Report erratum