ハンズオン概要
本ハンズオンで参照するコードは以下の GitHub 上にアップされたコー ドです。(git tag: beforehandson)
https://github.com/nobuhikosekiya/jaxrs21handson/tree/beforehand son
ハンズオンを完了したときの状態のコードは以下の URL にありますの で、必要に応じて参考にしてください。(git tag: afterhandson) https://github.com/nobuhikosekiya/jaxrs21handson/tree/afterhands on
これらのハンズオンのコードは、下記 URL にある JAX-RS のリファレン ス実装である Jersey の GitHub リポジトリ上のサンプルコードをベース にしており、本ハンズオン向けに一部コードを省略しています。
https://github.com/jersey/jersey/tree/2.26-b02/examples/rx-client-webapp
(今回の GlassFish に含まれている Jersey と同じバージョンのタグ番 号 2.26-b02 のサンプルを使います)
アプリケーション構成について
35
ハンズオンプロジェクトの作成新たにこれ以降のハンズオン用の新規の NetBeans プロジェクトを作成します。
メニューから「ファイル (F)」→「新規プロジェクト(W)...」を選択してくだ さい。
表示される下記ウィンドウのカテゴリから「Java Web」を選択し、さらにプロ ジェクトから「Web アプリケーション」を選択し、「次 >」を押してくださ い。
次に表示される下記ウィンドウの「プロジェクト名」をここでは
「JavaEE8-JaxRS」として設定します。前回のプロジェクトと同様に、
ライブラリ・フォルダを今回インストールした GlassFish 5 内の lib
フォルダを指定し、「次 > 」を押してください。
次に表示される下記ウィンドウの「サーバー」は前回のプロジェクト で作成した「GlassFish 5 EA」が設定されていることを確認します。
コンテキスト・パスは、URL パスを簡単にするために今回は
「/jaxrs21」とし、「次 > 」を押してください。
37
プロジェクトへのライブラリの追加この章のハンズオンで利用するライブラリは以下の通りです。
RxJava … 今回のハンズオンで利用するリアクティブプログラミ ングのフレームワーク
Jersey Reactive Client- RXJava provider … JAX-RS の Reactive Client で RxJava を利用するための拡張
jersey-server.jar と jersey-guava.jar …今回のプロジェクトの REST サーバー側の実装に使用しているライブラリです。 JAX-RS Reactive Client とは直接は関係ありません。
今回のハンズオンで利用する RxJava(バージョン 1)のライブラリ JAR ファイルを以下のサイトよりダウンロードして、自身の PC の任意 のフォルダに保存してください。
https://mvnrepository.com/artifact/io.reactivex/rxjava/1.2.5
さらに、JAX-RS の Reactive REST クライアントから RxJava を組み込 むための JAX-RS の拡張実装のライブラリ(Jersey Reactive Client- RXJava provider)もダウンロードしてください。
https://mvnrepository.com/artifact/org.glassfish.jersey.ext.rx/jersey-rx-client-rxjava/2.26-b02
※RxJava と拡張ライブラリのバージョンの組み合わせ( rxjava 1.25 と jersey-rx-client-rxjava 2.26-b02)は、必ずここで指定したもの を本ハンズオンでは使用してください。組み合わせバージョンが異な ると、プロジェクトのコンパイルでエラーとなる場合があります。
以降の手順で、ダウンロードしたライブラリをプロジェクトで利用で
きるように設定します。
39 ->
表示される下記ウィンドウのカテゴリの「ソース」では、ソースバイ ナリ形式が「JDK8」に設定されていることをまず確認してください。
次に、カテゴリから「ライブラリ」を選択し、「ライブラリの追加」
ボタンを押してください。
次に表示されるウィンドウで「作成」ボタンを押し、ライブラリ名と
して「rxjava」と入力して「OK」を押してください。
「JAR/フォルダの追加」を押してください。
さきほどダウンロードした「rxjava-1.2.5.jar」を選択して「JAR/フ
ォルダの追加」ボタンを押してください。
41
以下のようなダイアログが表示されますので「はい」を押してくださ い。
その後、もう一つの jar ファイル「jersey-rx-client-rxjava-2.26-b02.jar」を選択して同様に追加してください。
その後、戻った下記ウィンドウの「OK」ボタンを押してください。
OK ボタン後に下記のウィンドウに戻るので、先ほど追加したライブラ
リを選択した状態で「ライブラリの追加」を押してください。
43
「作成」ボタンを押し、ライブラリ名を「jersey-libs」とし、「OK」
を押してください。
「JAR/ライブラリの追加」ボタンを押してください。
今回は glassfish/modules フォルダ(lib フォルダと同階層のフォル ダです)にある jersey-guava.jar と jersey-server.jar を追加してく ださい。
以下のように、2つの jar を設定したら、「OK」ボタンを押してくだ
さい。
45
OK 押し後に戻ったウィンドウでは、さきほど作成した「jersey-libs」を選択した上で「ライブラリの追加」ボタンを押してくださ い。
以下のように2つのライブラリ(中には計 4 つの jar ファイル)が登
録されたら「OK」を押して、ライブラリの登録は終了となります。
REST
サーバーの作成以下の GitHub の URL より今回のハンズオンのサンプルコードをダウンロードし てください。
https://github.com/nobuhikosekiya/jaxrs21handson/archive/beforehandson.zip ダウンロードした zip ファイルを任意の場所に解凍し、中に含まれる src\java のディレクトリ配下の org フォルダをプロジェクトのソース・パッケージへコ ピーペーストしてください。
->
その後、プロジェクトを右クリックし、「デプロイ」を実行してください。
47
デプロイが成功したのち、以下の URL をブラウザのアドレスバーに入力し、
JSON 形式のデータが返ってくることを確認してください。
※実際のブラウザ画面での JSON 文字列は整形されていません。以降も本ドキュ メント内では見やすいように結果は整形している場合があります。
http://localhost:8080/jaxrs21/rx/remote/destination/visited
[ {
"destination": "Zambia"
}, {
"destination": "Kiribati"
}, {
"destination": "Japan"
}, {
"destination": "Saudi Arabia"
}, {
"destination": "Palau"
} ]
http://localhost:8080/jaxrs21/rx/remote/destination/recommended
[ {
"destination": "Greece"
}, {
"destination": "Malta"
}, {
"destination": "Benin"
}, {
"destination": "Sweden"
}, {
"destination": "Uganda"
} ]
http://localhost:8080/jaxrs21/rx/remote/forecast/Tokyo
<forecast>
<destination>
Tokyo </destination>
</forecast>
<forecast>
Partly Sunny
</forecast>
http://localhost:8080/jaxrs21/rx/remote/calculation/from/Moon/to/Tokyo
<calculation>
<from>
Moon </from>
<price>
1680 </price>
<to>
Tokyo </to>
</calculation>
JAX-RS sync client
の作成リアクティブな JAX-RS クライアントとの対比のために最初にベーシックな同期 型の JAX-RS クライアントを作成します。
プロジェクトを右クリックし、新規の Java パッケージを作成してください。パ ッケージ名は「org.glassfish.jersey.examples.rx.agent」とします。
次に、作成したパッケージ「org.glassfish.jersey.examples.rx.agent」を右
クリックし、新規の Java クラスを作成してください。
49
クラス名に「SyncAgentResource」と入力し、「終了」ボタンを押してくださ い。
クラス作成後、以下の赤字の部分のコードを追加してください。
package org.glassfish.jersey.examples.rx.agent;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.glassfish.jersey.examples.rx.domain.AgentResponse;
@Path("agent/sync")
@Produces("application/json") public class SyncAgentResource { @GET
public AgentResponse sync() {
final long time = System.nanoTime();
final AgentResponse response = new AgentResponse();
response.setProcessingTime((System.nanoTime() - time) / 1000000);
return response;
} }
コード変更を保存すると、自動的に変更がデプロイされます。以下の URL にブ ラウザからアクセスし、現段階の実行結果を確認してください。ここでは単に 空の AgentResponse のオブジェクトを JSON として返却しているだけです。
http://localhost:8080/jaxrs21/rx/agent/sync 実行結果の例
{"processingTime":0,"visited":[]}
次に、以下の赤字のコードを先ほどの SyncAgentResource クラスのソースに追 加で挿入してください。
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.glassfish.jersey.examples.rx.domain.AgentResponse;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import org.glassfish.jersey.examples.rx.domain.Destination;
(省略)
public class SyncAgentResource {
final private Client client = ClientBuilder.newClient();
final private WebTarget destination =
client.target("http://localhost:8080/jaxrs21/rx").path("remote/destination");
@GET
public AgentResponse sync() {
final long time = System.nanoTime();
final AgentResponse response = new AgentResponse();
final List<Destination> visited = destination.path("visited").request() // Identify the user.
.header("Rx-User", "Sync") // Return a list of destinations
.get(new GenericType<List<Destination>>() {});
response.setVisited(visited);
(省略)
コードの保存により変更がデプロイされるので、以下の URL の実行結果を確認 してください。REST サーバーから Destination の情報を取得できるようになり ました。
http://localhost:8080/jaxrs21/rx/agent/sync 実行結果の例
{"processingTime":548,"visited":[{"destination":"Botswana"},{"destina tion":"Spain"},{"destination":"Lesotho"},{"destination":"Iceland"},{"
destination":"Venezuela"}]}
次に、以下の赤字のコードを同じクラスに追加してください。Recommend のデ ータを REST サーバーより取得するコードです。
(省略)
response.setVisited(visited);
51
response.setProcessingTime((System.nanoTime() - time) / 1000000);
(省略)
そのまま次に、以下の赤字のコードを挿入してください。Recommend の
destintion データ毎に forecast データを REST サーバーに繰り返し問い合わせ ています。
import org.glassfish.jersey.examples.rx.domain.Forecast;
import java.util.ArrayList;
final private WebTarget destination =
client.target("http://localhost:8080/jaxrs21/rx").path("remote/destination");
final private WebTarget forecast = client.
target("http://localhost:8080/jaxrs21/rx").path ("remote/forecast/{destination}");
(省略)
final List<Destination> recommended = (省略)
// Forecasts. (depend on recommended destinations)
final List<Forecast> forecasts = new ArrayList<>(recommended.size());
for (final Destination dest : recommended) {
forecasts.add(forecast.resolveTemplate("destination", dest.getDestination()).request().get(Forecast.class));
}
response.setProcessingTime((System.nanoTime() - time) / 1000000);
http://localhost:8080/jaxrs21/rx/remote/calculation/from/Moon/to/Morroc o
<calculation><from>Moon</from><price>6482</price><to>Morroco</to></ca lculation>
http://localhost:8080/jaxrs21/rx/remote/calculation/from/Moon/to/Cyprus
<calculation><from>Moon</from><price>8239</price><to>Cyprus</to></cal culation>
そのまま次に、以下の赤字のコードを挿入してください。Recommend の
destintion データ毎に Moon からその destination までのコストを REST サーバ ーに繰り返し問い合わせています。
import org.glassfish.jersey.examples.rx.domain.Calculation;
final private WebTarget destination =
client.target("http://localhost:8080/jaxrs21/rx").path("remote/destination");
final private WebTarget forecast = client.
target("http://localhost:8080/jaxrs21/rx").path ("remote/forecast/{destination}");
final private WebTarget calculation = client.
target("http://localhost:8080/jaxrs21/rx").path ("remote/calculation/from/{from}/to/{to}");
(省略)
final List<Forecast> forecasts = new ArrayList<>(recommended.size());
for (final Destination dest : recommended) {
forecasts.add(forecast.resolveTemplate("destination", dest.getDestination()).request().get(Forecast.class));
}
// Calculations. (depend on recommended destinations)
final List<Calculation> calculations = new ArrayList<>(recommended.size());
for (final Destination dest : recommended) {
calculations.add(calculation.resolveTemplate("from",
"Moon").resolveTemplate("to", dest.getDestination()) .request().get(Calculation.class));
}
response.setProcessingTime((System.nanoTime() - time) / 1000000);
最後に以下のコードを追加し、レスポンスとしてセットしてます。
import org.glassfish.jersey.examples.rx.domain.Recommendation;
(省略)
final List<Calculation> calculations = new ArrayList<>(recommended.size());
for (final Destination dest : recommended) {
calculations.add(calculation.resolveTemplate("from",
"Moon").resolveTemplate("to", dest.getDestination()) .request().get(Calculation.class));
}
// Recommendations.
final List<Recommendation> recommendations = new ArrayList<>(recommended.size());
for (int i = 0; i < recommended.size(); i++) { recommendations.add(new
Recommendation(recommended.get(i).getDestination(), forecasts.get(i).getForecast(),
calculations.get(i).getPrice()));
}
response.setRecommended(recommendations);
response.setProcessingTime((System.nanoTime() - time) / 1000000);
変更をデプロイし、以下の URL の実行結果を確認してください。REST サーバー から Destination の情報を取得できるようになりました。REST サーバーへのリ クエスト回数が何回も行われていることにより、レスポンスが返るまでに時間 がかかっていることがわかります。
http://localhost:8080/jaxrs21/rx/agent/sync 実行結果の例
{
"processingTime": 4700, "recommended": [
{
"destination": "Sao Tome & Principe", "forecast": "Overcast",
"price": 785 },
{
"destination": "China",
"forecast": "Chance of TStorm", "price": 3647
}, {
"destination": "Malta",