2011年7月3日日曜日

19.Generate postservice module from the server

サーバー(ゲストブックアプリケーション)で作成したpostserviceモジュールのコードは、
クライアントに対しては秘密であり、クライアントがその中身を知る必要はないはずです。
また、サーバーのコードはクライアントには必要のないライブラリに依存している場合もあります。
(つまり、クライアントアプリケーションを書く人が、サーバーのpostserviceモジュールを入手し、利用することは通常、ありえません。また、その必要もありません。)

サーバーは、RegistryServiceを公開していますので、
クライアントプログラムを書く際に必要になるモジュールを自動生成することができます。

これを行うために、ProtoRPCでは、「get_protorpc.py」というコマンドラインツールを用意しています。
コマンドシェルで、クライアントアプリケーションのディレクトリに移動し、
サーバーを指定してこのコマンドを実行することで、モジュールのコードを自動生成できます。
以下のコマンドを実行してみてください。

gen_protorpc.py registry localhost:8080 /postservice

クライアントアプリケーションのディレクトリを覗いてみると、
postservice.pyという名前のファイルがあるはずです。

そのファイルの中身は、サーバーで書いたpostservice.pyとよく似ていると思います。
しかし、クライアント側はPostServiceのメソッドは空で、何も書かれていないはずです。


Service stubs

サーバーとの通信は、クライアント側の持つスタブクラスによって行います。
個々のサービスは、スタブサブクラスを持ち、スタブはすべてのメソッドを含んでいます。

from protorpc import transport
import postservice

service = postservice.PostService.Stub(
    transport.HttpTransport(
        'http://localhost:8080/postservice'))


Invoke remote method

スタブを用いて、サーバーのget_notesメソッドを呼び出すリクエストハンドラを書いてみましょう。
(6行目に出てくる「service」は、さきほど定義したスタブです。
ですので、実行する際には、class MainHandlerの宣言の前に、上のservice=のコードを書いてください。)

from google.appengine.ext import webapp
from google.appengine.ext.webapp import util

class MainHandler(webapp.RequestHandler):
    def get(self):
        notes = service.get_notes().notes
        if notes is None:
            notes = []

        note_count = len(notes)
        note_lengths = [len(note.text) for note in notes]
        total_characters = sum(note_lengths)
        if note_count == 0:
            average_characters = 0
        else:
            average_characters = total_characters / note_count
        self.response.out.write('<br>Notes retrieved: %d\n' %
                                note_count)
        self.response.out.write('<br>Total characters: %d\n' %
                                total_characters)
        self.response.out.write('<br>Average characters: %d\n' %
                                average_characters)


def main():
    application = webapp.WSGIApplication([('/', MainHandler)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()


dev_appserverで、ゲストブックアプリケーションとは異なるポート番号を指定して、
クライアントアプリケーションを立ち上げてください。
クライアントアプリケーションにアクセスすると、
ゲストブックアプリケーションの投稿に関する統計情報が表示されるはずです。


Sending Parameters

上記では、クライアントアプリケーションは、get_notesを引数無しで呼び出しました。
しかし、サーバーはリクエストとしてGetNotesRequest型を受け取ることを知っていますよね
当然、クライアント側では、GetNotesRequest型のフィールドで指定されたパラメータをサーバーに送信することができます。
例えば、max_notesパラメータを送信することで、サーバーが返すノートの件数の上限を指定できます。

実は、スタブメソッドは内部でGetNotesRequestのインスタンスを生成し、それをサーバーに送っています。
get_notesメソッドのキーワード引数を指定することで、
サーバーに送信するGetNotesRequestインスタンスのフィールドを設定することができます。
以下のように、get_notesの呼び出し部分を変更します。

max_notes = int(self.request.params.get('max_notes', '10'))
notes = service.get_notes(limit=max_notes).notes


また、キーワード引数ではなく、GetNotesRequestのインスタンスそのものを渡すこともできます。

request = postservice.GetNotesRequest(limit=max_notes)
notes = service.get_notes(request).notes

0 件のコメント:

コメントを投稿