はじめに
前回はCurlの簡単な説明とHelloWorldを実行するまでを説明しました。今回はJavaでサーバーサイドを作成し、クライアントサイドのCurlアプリケーションと通信を行います。
前回の記事
Curlアプリケーションのアーキテクチャ
クライアントサイドとサーバーサイド
Curlアプリケーションは、クライアントマシンにインストールされたCurl RTE上で実行されます。
業務アプリケーションでは、サーバーサイドのデータベースを利用するのが一般的ですが、Curlアプリケーションはデータベースサーバに対して直接アクセスすることはしません。通常、サーバーサイドにもCurl以外の言語でアプリケーションを構築する必要があります。
Curlアプリケーションからデータベースに対してCRUD操作を行うには、サーバーサイドのアプリケーションを経由します。Curlアプリケーションから必要なパラメータをサーバーサイドのアプリケーションに送信し、サーバーサイドアプリケーションが必要な処理を行い、それに対するレスポンスをCurlアプリケーションに返します。

JSPを用いたHTMLアプリケーションでは、サーバーサイドから返されるデータはレイアウト情報が含まれており、クライアントのブラウザはそれを表示するだけです。一方、Curlアプリケーションでは、サーバーサイドから返されたデータを元に、クライアントサイドでレイアウトを生成し、画面を表示します。
通信プロトコル
Curlアプリケーションとサーバとの通信には、次のプロトコルとデータ形式が利用できます。HTTPとXMLを用いたSOAP通信なども可能です。
プロトコル
- HTTP/HTTPS
- ソケット通信
データ形式
- テキスト
- バイナリ
- XML
- JSON
- CSV

アーキテクチャ
Javaを用いたWebアプリケーションの場合、表示に関するロジックとビジネスロジックは、プレゼンテーション層とそれ以外で分離するのが一般的です。
一方、Curlアプリケーションの場合は、サーバーサイドはデータを返すのみで複雑なロジックは持たず、クライアントサイド、つまりCurl言語を用いてビジネスロジックを作成するのが一般的です。
クライアントサイドにロジックを多く持てば、CPUやメモリといったリソースをクライアントサイドに分散できるというメリットがあります。クライアント数が多いようなシステムでは、Curlアプリケーションのようなアーキテクチャのメリットをより多く享受できると考えます。
また、サーバーサイドでビジネスロジックを作成し、クライアントサイドは表示のみに徹するということも可能です。
JSON
Curlは、バージョン6.0からJSONをサポートするようになりました。そこで今回は、サーバからデータをJSON形式でレスポンスを返し、クライアントサイドでデータの表示を行うプログラムの説明をします。
JSONとは
JSON(ジェイソン、JavaScript Object Notation)は軽量なデータ記述言語で、主にAjaxの分野で利用されています。
JSON形式で記述した例は次のようになり、
{
"name":"Foo",
"price":1980
}
という文字列は,nameが文字列"Foo",priceが数値1980を持つデータを表します。
JavaのJSONライブラリ
Javaはライブラリを使用することで、JSON形式のデータを簡単に扱うことができるようになります。JavaオブジェクトとJSONを相互変換するためのライブラリには次のようながあります。
JSONICにはWebServiceServletというサーブレットが付属しており、別途フレームワークなどを用意しなくてもJSONを利用したWebサービスを実現できます。今回はJSONICを利用してアプリケーションを作成します。
アプリケーションの作成 1
サーバーサイドの作成
JSONICには、SeasarやSpringと連携する機能があります。そこで今回は、Seasar、JSONICとTomcatを使用してサーバーサイドを作成します。
まず、JSONICからコールされるServiceやDaoを作成します。インターフェースやDaoについては省略しますが、Serviceの実装クラスのコードは次のようになります。
package sample.service.impl;
...中略...
public class EmpServiceImpl implements EmpService {
public List<Emp> find(EmpQuery query) {
return empDao.getDatas(query);
}
public void create(Emp emp) {
empDao.insert(emp);
}
public void update(Emp emp) {
empDao.update(emp);
}
public void delete(Emp emp) {
empDao.delete(emp);
}
...中略...
}
上記のコードは複雑なロジックを記述していないので、Webアプリケーションを作成した事のあるJava技術者であれば理解できると思います。
作成したServiceや、Daoをdiconファイルに記述します(注:今回は、理解しやすさを優先して、app.diconに直接記述しています)。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <include path="aop.dicon"/> <include path="dao.dicon"/> <component class="sample.service.impl.EmpServiceImpl" > <aspect>aop.traceThrowsInterceptor</aspect> <aspect>aop.traceInterceptor</aspect> <aspect>j2ee.requiredTx</aspect> </component> <component class="sample.dao.EmpDao" > <aspect>dao.interceptor</aspect> </component> </components>
そして、JSONICとSeasarを連携させるためには、web.xmlを次のように記述します。
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<filter>
<filter-name>s2filter</filter-name>
<filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>s2filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>s2servlet</servlet-name>
<servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<description>JSON-WebService</description>
<servlet-name>json-ws</servlet-name>
<servlet-class>net.arnx.jsonic.web.WebServiceServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>
container: 'net.arnx.jsonic.web.S2Container'
debug: true
mappings: {
'/[package]/[class]/[id].[ext]': 'sample.web.${package}.service.${class}Service'
'/[package]/[class].[ext]': 'sample.web.${package}.service.${class}Service'
'/[class].[ext]': 'sample.service.${class}Service'
}
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>s2servlet</servlet-name>
<url-pattern>/s2servlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>json-ws</servlet-name>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
</web-app>
JSON-WebServiceのinit-paramに注目してください。containerに、'net.arnx.jsonic.web.S2Container'と記述することで、Seasarとの連携が可能になります('net.arnx.jsonic.web.SpringContainer'と記述すればSpringと連携できます)。また、mappingsには、URLとDIコンテナに登録されたコンポーネントのマッピングを記述します。この記述の場合、例えば、/emp.jsonというURLでアクセスした場合、sample.service.EmpServiceがコールされます。
RESTスタイルの場合、コールされるメソッドは、次のようにHTTPのメソッドによって決定されます。
- GET
findメソッドが呼び出される。引数はURLのクエリ文字列で指定
- POST
createメソッドが呼び出される。メソッドの引数はリクエストボディにJSONとして指定
- PUT
updateメソッドが呼び出される。メソッドの引数はリクエストボディにJSONとして指定
- DELETE
deleteメソッドが呼び出される。メソッドの引数はリクエストボディにJSONとして指定
動作確認をするには、Tomcatを起動し、ブラウザに次のURLを入力しアクセスします(注:URLはTomcatの設定により変わります)。
- http://localhost:8080/curl_server/emp.json
すると、次のようなリクエストが返ってきます。
[
{
"deptno": 20,
"empno": 7369,
"ename": "SMITH",
"hiredate": 345826800000,
"job": "CLERK",
"mgr": 7902,
"sal": 800.0
},
{
"deptno": 30,
"empno": 7499,
"ename": "ALLEN",
"hiredate": 351442800000,
"job": "SALESMAN",
"mgr": 7698,
"sal": 1600.0
},
...中略...
]
Service、Daoを作成して、それをSeasarに登録し、web.xmlを記述するだけで、サーバーサイドの準備は完了です。
アプリケーションの作成 2
クライアントサイドの作成
まずは、実行結果を見てください。
JSONのAPIを利用するためには、CURL.IO.JSONパッケージのインポートが必要です。そして、JsonValue-parseプロシージャを使用してアクセス先のURLデータを受け取り、JsonValueオブジェクトへ変換します。
{import * from CURL.IO.JSON}
|| サーバからのJSONデータの受信
{let empJsonValue: JsonValue =
{JsonValue-parse
{url "http://localhost:8080/curl_server/emp.json"}
}
}
実行結果のようなグリッドテーブル表示を行うには、RecordGridを使用します。
RecordGridを使用するには、まず、各列に対する名前と型、それにcaptionで見出し(実行結果のヘッダー)を宣言します。
{let employees: RecordSet =
{RecordSet
{RecordFields
{RecordField "empno", caption = "empno", domain = int}
, {RecordField "ename", caption = "ename", domain = String}
, {RecordField "job", caption = "job", domain = String}
, {RecordField "mgr", caption = "mgr", domain = int}
, {RecordField "hiredate", caption = "hiredate", domain = double}
, {RecordField "sal", caption = "sal", domain = double}
, {RecordField "deptno", caption = "deptno", domain = int}
}
}
}
サーバから受信したJsonValueオブジェクトの値を、RecordSetにセットして最後に表示を行えば、先ほどの実行結果を表示できます。
|| Jsonデータをcustomersに追加する
{define-proc public {add-rec
empno:int
, ename: String
, job: String
, mgr: int
, hiredate: double
, sal: double
, deptno: int
}: void
let new-rec: Record = {employees.new-record}
{new-rec.set "empno", empno}
{new-rec.set "ename", ename}
{new-rec.set "job", job}
{new-rec.set "mgr", mgr}
{new-rec.set "hiredate", hiredate}
{new-rec.set "sal", sal}
{new-rec.set "deptno", deptno}
{employees.append new-rec}
}
{for emp: JsonObject in empJsonValue do
let found?: bool = false
let empno: int = 0
let ename: String = {String}
let job: String = {String}
let mgr: int = 0
let hiredate: double = 0
let sal: double = 0
let deptno: int = 0
set (empno, found?) = {emp.get-if-exists "empno"}
set (ename, found?) = {emp.get-if-exists "ename"}
set (job, found?) = {emp.get-if-exists "job"}
set (mgr, found?) = {emp.get-if-exists "mgr"}
set (hiredate, found?) = {emp.get-if-exists "hiredate"}
set (sal, found?) = {emp.get-if-exists "sal"}
set (deptno, found?) = {emp.get-if-exists "deptno"}
{if found? then
{add-rec empno, ename, job, mgr, hiredate, sal, deptno}
}
}
{value
{RecordGrid
width=700
, record-source = employees
}
}
以上で、DBのデータをそのまま表示するというシンプルなアプリケーションを作成しました。非常に簡単なコーディングでグリッドテーブルの表示ができています。また、クライアントサイドでヘッダーをクリックすれば、ソートをすることも可能です。
最後に、start.curlのコード全体を掲載します。
{curl 6.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{import * from CURL.IO.JSON}
|| サーバからのJSONデータの受信
{let empJsonValue: JsonValue =
{JsonValue-parse
{url "http://localhost:8080/curl_server/emp.json"}
}
}
{let employees: RecordSet =
{RecordSet
{RecordFields
{RecordField "empno", caption = "empno", domain = int}
, {RecordField "ename", caption = "ename", domain = String}
, {RecordField "job", caption = "job", domain = String}
, {RecordField "mgr", caption = "mgr", domain = int}
, {RecordField "hiredate", caption = "hiredate", domain = double}
, {RecordField "sal", caption = "sal", domain = double}
, {RecordField "deptno", caption = "deptno", domain = int}
}
}
}
|| Jsonデータをcustomersに追加する
{define-proc public {add-rec
empno:int
, ename: String
, job: String
, mgr: int
, hiredate: double
, sal: double
, deptno: int
}: void
let new-rec: Record = {employees.new-record}
{new-rec.set "empno", empno}
{new-rec.set "ename", ename}
{new-rec.set "job", job}
{new-rec.set "mgr", mgr}
{new-rec.set "hiredate", hiredate}
{new-rec.set "sal", sal}
{new-rec.set "deptno", deptno}
{employees.append new-rec}
}
{for emp: JsonObject in empJsonValue do
let found?: bool = false
let empno: int = 0
let ename: String = {String}
let job: String = {String}
let mgr: int = 0
let hiredate: double = 0
let sal: double = 0
let deptno: int = 0
set (empno, found?) = {emp.get-if-exists "empno"}
set (ename, found?) = {emp.get-if-exists "ename"}
set (job, found?) = {emp.get-if-exists "job"}
set (mgr, found?) = {emp.get-if-exists "mgr"}
set (hiredate, found?) = {emp.get-if-exists "hiredate"}
set (sal, found?) = {emp.get-if-exists "sal"}
set (deptno, found?) = {emp.get-if-exists "deptno"}
{if found? then
{add-rec empno, ename, job, mgr, hiredate, sal, deptno}
}
}
{value
{RecordGrid
width=700
, record-source = employees
}
}
まとめ
Curlはバージョン6.0から、JSONをサポートするようになりました。その紹介も兼ねて、今回はJavaで作成したサーバーサイドとJSON形式で通信を行うアプリケーションの作成を行いました。
次回はJSON形式ではなく、「Curl ORB for Java」というOSSのライブラリを使用して、CurlアプリケーションからPOJO(Plain Old Java Object)のメソッドをコールし、戻り値をCurlアプリケーションで受け取るアプリケーションを作成する手順を紹介する予定です。



