ホーム > デベロッパ > J2ME / MIDP プログラミング > 第 3 回

第 3 回 : 仕様・設計と実装( IM "improve" の設計・実装とエミュレーター動作)

はじめに

IM "improve" のサーバー側の機能仕様を決定し、システムを設計、実装します。 ezplus/J-PHONE それぞれのエミュレーターで動作させます。


improve サーバーの機能仕様

追加機能としてデバッグを容易にするために、

を搭載します。

※ 画面イメージ:図9,図10

improve の設計

全体構成

図1 improve の基本構造
improveシステム基本構造

参考情報

IM を携帯電話からだけでなく、PC からも使えるようにするときは 図 2 のような構造が考えられます。 これは携帯電話用の「ポーリング型クライアント」と PC 用の「コネクション型クライアント」の違いを吸収するために、「仮想コネクション型クライアント」を設けてメインのサーバーには最終的につながっているクライアントを意識させないようにしたものです。この場合、データベースだけでなく、仮想クライアントサーブレットと本サーバーは別の物理サーバーで動かすことも可能です。

図2 携帯電話と PC をクライアントに持つ IM のシステム構成例
システム構成の例

データモデルとプロトコルの設計

ポーリング型システムで実装するときに注意すべきことをまとめます。

データモデル仕様

図3 データベース improve のテーブル構造
データベースimproveのテーブル構造

アカウントを主キーとし、他のテーブルでもアカウントをそのまま用いることにします。

プロトコル仕様

表1にプロトコル仕様を示します。以下、プロトコル全体を「プロトコル」、プロトコルの構成要素を「オペレーション」と呼びます。

クライアントからの情報の送信はコード単純化のためすべてパスとパラメーターで渡すことにし、HTTP の GET メソッドのみ用います。

返値は 4 バイト ( signed int ) とします。ただしポーリングの時のみ、前半 ( 下位 2 バイト ) を友達の数、後半 ( 上位 2 バイト ) をメッセージの数とします。友達リストの先頭にはユーザー本人が入っていて、クライアントは各行を、

readUTF : account (アカウント)

readUTF : nickname (表示名)

readUTF : phone (電話番号)

readInt : status (状態:チャット許容度)

readUTF : description (状態:自由文)

のフォーマットで読み取ることにします。 メッセージリストの各行は、

readUTF : account (送り主)

readInt : type(種類)

readUTF : content (内容)

のフォーマットで読み取ることにします。

送受信に DataOutputStream と DataInputStream を使い、文字列は writeUTF、readUTF で送受信することにします。

表1 improve プロトコル
用途 パス パラメータ 返値:成功
返値:失敗
その他データ in
アカウント関連
アカウント作成 /create account=(アカウント) 0以上
0未満
パスワード
アカウント抹消 /delete account=(アカウント)
password=(パスワード)
0以上
0未満
N/A
友達リスト関連
友達追加 /add account=(アカウント)
password=(パスワード)
target=(対象アカウント)
0以上
0未満
N/A
友達削除 /remove account=(アカウント)
password=(パスワード)
target=(対象アカウント)
0以上
0未満
N/A
情報関連
自分の情報設定 /set account=(アカウント)
password=(パスワード)
item=(0〜n)
content=(内容)
0以上
0未満
N/A
メッセージ関連
メッセージ送信 /send account=(アカウント)
password=(パスワード)
target=(対象アカウント)
type=(タイプ)
content=(内容)
0以上
0未満
N/A
その他
ポーリング /polling account=(アカウント)
password=(パスワード)
本文参照
0未満
友達リストとメッセージリスト
プロトコルテスト /test path=(テストパス)
テストパラメーター郡
N/A HTML ページ:図10 参照
サーバー監視 /check N/A N/A HTML ページ:図9 参照

プロトコルを使ったフローを簡単に説明しますと:

となります。

サーバーの設計

HttpServlet クラスを継承した ImproveServlet クラスと、プロトコルの各オペレーションごとのクラスを作成します。ImproveServlet は Operation クラスに HTTP リクエストを判断させ、各 Operation インスタンスを取得します。ImproveServlet は以降の処理を各 Operation インスタンスに委譲します。各 Operation はデータベースにアクセスしてデータを返します。

図 4 サーバー側クラス図
サーバー側クラス図

クライアントの設計

図5 画面遷移図
画面遷移図

Display.callSerially と Timer.schedule

MIDP の UI のイベントループとタイマーに注意して、通信と UI を設計します。

という事情から、別スレッドで通信を行うわけですが、単にスレッドだけですと、同時に 2 本開いたり、UI 側スレッドがデータを読んでんでいる最中に、通信側スレッドがデータを変更をしてしまう危険があります。synchronized で排他制御しますが、効率よく synchronized を使うのは簡単ではありません。

次の 2 つのメソッドを使います。

これらを利用すると synchronized をかけなくてもスレッドセーフなコードを書けます。

まとめると次のようになります。

図5 schedule と callSerially のシーケンス図
scheduleとcallSeriallyのシーケンス図

ダウンロードと描画を例にとると以下のような動きとなります。

この方法のデメリットは

となります。Timer#schedule は周期呼び出しのスケジュールも可能ですので、ポーリングにもってこいです。improve のクライアントでは全面的にこの手法を用い、synchronized は一箇所も使用していません。

図6 にクライアントのクラス図を示します。

図6 クライアント側クラス図
クライアント側クラス図

上で説明した機構を利用するために、TimerTask を実装し、private で Timer を持っている Task クラスを作成します。このクラスを継承して、種々の通信前&後処理を定義します。

improve の実装

概要とともにクラス一覧を 表 2 に示すにとどめます。詳細はソースコードをご覧ください。

都合により Ticker と MessageBox のソースコードは公開していません。

なお、ソースコード等をまとめたアーカイブをこちらに用意しました。

表2 improve のクラス一覧
クラス名 機能の概要
com.s_cradle.improve
ImproveServlet improve サーバーのメインとなるクラスです。
com.s_cradle.improve.server.protocol
Operation 各オペレーションのための抽象クラスです。
GetOpertaion HTTP の GET メソッドを使うオペレーションのための抽象クラスです。
PostOperation HTTP の POST メソッドを使うオペレーションのための抽象クラスです。(未使用)
ErrorOperation パスが異常でオペレーションが見つからない場合に処理をするクラスです。
Create オペレーション create を処理するクラスです。
Delete オペレーション delete を処理するクラスです。
Add オペレーション add を処理するクラスです。
Remove オペレーション remove を処理するクラスです。
Send オペレーション send を処理するクラスです。
Set オペレーション set を処理するクラスです。
Polling オペレーション polling を処理するクラスです。
Test オペレーション test を処理するクラスです。
Check オペレーション check を処理するクラスです。
com.s_cradle.improve.client
ImproveMIDlet MIDlet を継承するメインのクラスです。
ImproveAbstractCanvas Ticker を貼り付けられる Improve 用の Canvas です。
(非公開) Ticker 独自の Ticker です。MIDP 標準のものに比べかなり高機能となっています。
BuddyListCanvas メイン画面の友達リストを描画する Canvas です。
Menu Improve で使うメニューの一般的な機能を提供する抽象クラスです。
BuddyListMenu 友達リストを表現する Menu です。
MainMenu 本人フォーカス時の Menu です。
FriendMenu 友達フォーカス時の Menu です。
ChangeStatusMenu 自分のステータスを変えるための Menu です。
TwoChoiceMenu 2択の Menu です。
MessagingCanvas 会話画面を描画する Canvas です。
(非公開) MessageBox メッセージを表示するスクロール&色付きテキストボックスです。
Buddy 友達(本人も含む)を表現するクラスです。
Message メッセージを表現するクラスです。
Task Timer を持ち、TimerTask を継承するクラスです。
CreateTask オペレーション create を使ったタスクを行うクラスです。
DeleteTask オペレーション delete を使ったタスクを行うクラスです。
FollowedByPollingTask ポーリングが後に続くタスクを行うクラスです。
PollingTask オペレーション polling を使ったタスクを行うクラスです。
ResourceManager RecordStrore や Image を管理するクラスです。

未実装&制限事項

上記ソースには次のような未実装&制限事項があります。

サーバー

エミュレーターで動かそう

サーバーのコンパイル&配備

tomcat の webapps に improve フォルダをつくって、そこに Servlet を配備します。定義した web.xml を示します。

<?xml version="1.0" encoding="ISO-8859-1"?>



<!DOCTYPE web-app

PUBLIC " -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN "

" http://java.sun.com/dtd/web-app_2_3.dtd ">



<web-app>

<servlet>

<servlet-name?>improve</servlet-name>

<servlet-class>com.s_cradle.improve.server.ImproveServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>improve</servlet-name>

<url-pattern>/ * </url-pattern>
</servlet-mapping>



</web-app>

また、データベース improve を createdb に EUC_JP を指定して作成し、psql に次のような init.sql を渡して初期化しました。

DROP TABLE messages; -- すでにある場合削除

DROP TABLE friends;-- すでにある場合削除

DROP TABLE users;-- すでにある場合削除



CREATE TABLE users (

account VARCHAR(10),-- アカウント

passwordVARCHAR(10),-- パスワード

nicknameVARCHAR(9), -- 表示名

phoneVARCHAR(11),-- 電話番号

statusINTEGER,-- 状態(0:オフライン 1:ダメ 2:すこしだけ 3:いつでもいいよ)

description VARCHAR(20),-- 状態文



PRIMARY KEY(account)-- 主キー

);



CREATE TABLE friends (

account VARCHAR(10) REFERENCES users ON DELETE CASCADE,
                                                   -- アカウント(誰が)。参照先削除時は削除

targetVARCHAR(10) REFERENCES users ON DELETE CASCADE,
                                                   -- アカウント(誰を)。参照先削除時は削除



PRIMARY KEY(account, target)-- 主キー

);





CREATE TABLE messages (

account VARCHAR(10), -- アカウント(誰から)

targetVARCHAR(10), -- アカウント(誰へ)

typeINTEGER,-- メッセージタイプ(1:通常 2:攻撃)

content VARCHAR(64), -- 内容

receiveTime Timestamp, -- 受信時刻



FOREIGN KEY(account, target)

 REFERENCES friends(account, target) ON DELETE CASCADE -- 外部キー指定。参照先削除時は削除

);

クライアントのコンパイル

ezplus の開発ツール付属の KJX 作成ツールを使用しました。

ezplus では jad ファイルの MIDlet-X-AllowURL-<n> で許可されていない URL にはアクセスできません。上でリンクしてあるコードは MIDlet-X-AllowURL-1 から つなぎにいくべき場所を取得しています。サーブレットの配備場所に応じて、適切に変更してください。なお J-PHONE Java では MIDlet-Network が Y に指定されている必要があります。

また、improve では RecordStore を使用していますので、MIDlet-Data-Size に1024 byte 程度の上限値を与えてください。

画像については以下のものを使用してください。

矢印 矢印アイコン上 矢印アイコン下 矢印アイコン左 矢印アイコン右
通常時アイコン 通常時アイコン1 通常時アイコン2 通常時アイコン3 通常時アイコン4
選択時アイコン 選択時アイコン1 選択時アイコン2 選択時アイコン3 選択時アイコン4

実行してみよう

無事アーカイブができたら実行してみてください。図7,8 にスクリーンショットを示します。

図7 improve のメイン画面
improveメイン画面1 improveメイン画面2
図8 メッセージング画面
メッセージ画面1 メッセージ画面2

※ ImproveServlet 配備先の /check にアクセスするとサーバーが現在保持している全データが HTML で一覧できます。

図9 サーバー状態確認ページ
サーバー状態確認ページ

参考までに、プロトコルをテストした時のスクリーンショットを 図10 に示します。

図10 プロトコルテストページ
プロトコルテストページ

まとめ