WildFly 運用のための覚え書き

もうあまり使うことはないかもしれないが、Java のアプリケーションサーバ WildFly の運用のための覚え書き。

同一物理マシンに複数の WildFly を設置するのは可能か?

レガシーなプロジェクトで、JavaEE ウェブアプリと JakartaEE ウェブアプリが混在するような場合、少なくとも2台のWildFly が必要になる。27 以降の WildFly と 27 より前のバージョンがそれぞれ少なくとも一つは必要。

結論から言うとできる。

ただ、ポートがかち合わないように設定ファイルを変える。
ワイの場合は、各ポート番号に 10000 を足す。

standalone-full.xml
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="ajp" port="${jboss.ajp.port:18009}"/>
        <socket-binding name="http" port="${jboss.http.port:18080}"/>
        <socket-binding name="https" port="${jboss.https.port:18443}"/>
        <socket-binding name="iiop" interface="unsecure" port="13528"/>
        <socket-binding name="iiop-ssl" interface="unsecure" port="13529"/>
        <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:19990}"/>
        <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:19993}"/>
        <socket-binding name="txn-recovery-environment" port="14712"/>
        <socket-binding name="txn-status-manager" port="14713"/>
        <outbound-socket-binding name="mail-smtp">
           <remote-destination host="${jboss.mail.server.host:localhost}" port="${jboss.mail.server.port:10025}"/>
        </outbound-socket-binding>
        <outbound-socket-binding name="messaging-activemq">
            <remote-destination host="${jboss.messaging.connector.host:localhost}" port="${jboss.messaging.connector.port:51616}"/>
        </outbound-socket-binding>
    </socket-binding-group>

ただし、このやり方だと activemq は 71616 となり

A maximum value of 65535 is required

と WildFly に怒られるので、10000 を引く。

こうしておくと以下のように管理画面も同時に表示できる。

めでたしめでたし。

WildFly をサービス化する

JBOSS_HOME の docs 以下のフォルダに各種サンプルファイルがあるので、これをうまく活用する。
Ubuntu の場合は、以下のようにそのまま使える。

sudo mkdir /etc/wildfly
sudo cp /opt/wildfly/docs/contrib/scripts/systemd/wildfly.conf /etc/wildfly
sudo cp /opt/wildfly/docs/contrib/scripts/systemd/wildfly.service /etc/systemd/system/wildfly.service
sudo cp /opt/wildfly/docs/contrib/scripts/systemd/launch.sh /opt/wildfly/bin/launch.sh

この作業が終わった後、初回起動は

sudo systemctl enable --now wildfly

というコマンドで。

jboss-cli.sh による deploy

なお、サービスが走っている場合のデプロイは jboss-cli.sh を走らせ、そこから

deploy PathTo/hoge.war

で投入できる。

バックグランドで起動させる

Java の慣習でしょうか & を付ける。

standalone.sh -c stanalone-full.xml &

Ctrl+C でメッセージを終了させてもプロセスは終わってない模様。

コマンドラインから停止

バックグランドで走らせた状態では Ctrl+C では停止できないので以下のコマンドを使う。

jboss-cli.sh --connect command=shutdown

 

(適宜修正予定)

WildFly の導入時にすること

X などで「わかっているのだが、覚えるには至っておらず、何度も調べてしまうこと」が度々話題になる。

vi の操作方法とかさ。

ワイの場合は WildFly の初期設定もそのうちの一つ。

一体、何度、調べただろう?

いい加減、あちこち調べるのが嫌になってきたので、忘備録的なまとめ。

管理ユーザーの設定

まずは、管理ユーザーを作成するのがいいだろう。
管理ユーザーなしでも WildFly 自体は起動できるのだが、コンソール画面に入れないので、まず、これをやる。

Linux/Mac などでは bin フォルダ内の add-user.sh を実行。Windows では add-user.bat 。

ほとんどの場合、既存プロジェクトの WildFly のバージョンアップデートに伴う移行だと思うので、管理ユーザー名も同一にしておくと迷わなくてすむ。

ただし、この手の作業が面倒に感じる理由の一つとして、「パスワードの設定方法が変わってしまう」というのもあるだろう。
今回、作業した WildFly27 では、以下のように non-alphanumeric symbol が必要とされた。

The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)

以前のように「12345678」ではダメである。英数字以外の記号を一つ含める必要がある。

他は、y と答えておいて困ることはない。

モジュールのインストール

デバイスドライバなどをインストールする。

PostgreSQL のドライバをインストールする場合には、以下のようにする。
(ドライバはここから取ってくる)

WildFly 自体を起動した状態で jboss-cli.sh を実行

You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /]

というメッセージが現れるので、connect と打ち込む。

その後

module add --name=org.postgresql --resources=(パス)\postgresql-(バージョン).jar --dependencies=javax.api,jakarta.transaction.api
/subsystem=datasources/jdbc-driver=postgresql:add(driver-name="postgresql",driver-module-name="org.postgresql",driver-class-name="org.postgresql.Driver")

とタイプ。

上のように success が返ってくればOKです。

なお dependencies=javax.api, jakarta.transaction.api となっている点に注意。
いわゆる JavaEE -> JakartaEE 移行に伴う名前空間の変更の影響を受けています。

その他

思いつくままに。

コマンドラインでの終了のさせ方

これも何度検索かけただろう?

jboss-cli.sh --connect --command=":shutdown"

だそうです。

 

(適宜情報追加予定)

ものぐさ RESTEasy -画像データなどを REST っぽく返したい-

『ものぐさ Jersey』的なやつが好評のようなので、その RESTEasy 編。

いきなりで恐縮だが、REST なウェブサービスを作っている際に画像も REST 的に取り扱いたいときがある。
要するに適当なエンドポイントを叩くと画像ファイルが返ってくる、みたいなやつだ。

サーブレットで実現するのが一番簡単なようなんだが、サーブレットを使わない方向でチャレンジする。

リンクした記事は jsp で書いてあるが、ちなみにサーブレットで書き直すとこんな感じ↓になる。

あっさり成功。

 

で、RESTEasy 。
まずは公式ドキュメントのチェック。

レスポンスを適当に加工すれば、なんとかなるだろうくらいに思って調べてみた。

なんだが…

なんでしょう、この突き放された感じ(笑)。

jakarta.ws.rs.core.StreamingOutput を使って自分で実装しろ的なことが書かれている。

いや、そんなことをするくらいならば、サーブレットのやつそのまま使いたいかなあ(困惑)。

アウトプットストリーム系を使って、とりあえずバイト列を返す

他の人がどうやっているかよくわからないのだが、まずはシンプルに攻める。

(公式ドキュメントのサジェスチョンを尊重して)バイト列を生成して、そいつを ByteArrayOutputStream にセットし、さらにそれを Response の中(Entity とかいうみたいだ)に入れ込んで REST っぽく返す、と以下のような感じになる。


@Path("/octet")
public class OctetServer {

 @GET
 @Produces(MediaType.APPLICATION_OCTET_STREAM)
 public Response sendOctet() throws IOException{

  byte[] byteData = "123456789ABCDE".getBytes();

  ByteArrayOutputStream output = new ByteArrayOutputStream();
  output.write(byteData);

  return Response.ok(output.toByteArray(), MediaType.APPLICATION_OCTET_STREAM).build();

 }

}

これで curl で (コンテクスト)/octet を叩くと、もちろん 123456789ABCDE がバイナリで返ってくる。
ブラウザからアクセスすると octet というファイルを落としてくれるが、中身は当然 123456789ABCDE だ。

これで、第一段階はクリア…

と思っていたが、コード見直すと、バイト列をストリームにセットした後、さらにバイト列に戻す、というバカっぽいことをやっている(苦笑)。

バイト列をエンティティとしても同じ

だから、上のサンプルはもうちょっと簡単になる。

具体的には、

return Response.ok(output.toByteArray(), MediaType.APPLICATION_OCTET_STREAM).build();

は、

return Response.ok(byteData, MediaType.APPLICATION_OCTET_STREAM).build();

としても変わらない。

もちろん、その上の2行は全く不要。

とりあえず、バイナリのデータを返すだけであれば、アウトプットストリーム系は不要で返したいデータのバイト列を response のエンティティにセットすればいいだけのようだ。

指定した画像などを返したければ、path parameter を設定してデータベースから検索して云々とやれば、実現できそう。

 

 

JakartaEE 各仕様まとめ

JakartaEE 関係の記事が増えてきたような気がするので、ここら辺でまとめ。

JakartaEE 各仕様

各仕様毎に軽めの記事を書いてきたつもりだったが、読み返したら微妙にオーバーラップしてる。

JAX-RS

ものぐさ Jersey』WildFly は RestEasy だが、GlassFish, Payara は Jersey なので取り上げた。が、最後の方で Jackson 成分も混じっている。

JAX-RS と JSON と List と hibernate』これも、REST の話から始まって、JPA(hibernate) につながっている。

JPA

実は JPA の仕様は資料にあたったことはない。実務的には hibernate でデータベース操作ができればいいでしょう、というわけで書いたのが

最も簡単な hibernate のサンプル

ここら辺から、「読みやすい」と言われるようになってきた。

CDI

初学者泣かせの CDI 。

CDI と weld の関係

で取り上げたが、なくてもなんとかなるので、無理して @Inject とかしなくていいかも。

つか、参考書の類で CDI の説明でわかりやすいのがないと思う。初学者にいきなり「依存性を注入して…」とか言ってもなんのことかさっぱりわからないと思う。

JAXB

Java と XML -JAXB の話-』理解があやふやだったので、自分の勉強のために書いた記事。実際、勉強になった。


他にもあるが、代表的なのはこんなところでしょうか。

 

 

Java と XML -JAXB の話-

これまで、Java ⇄ JSON みたいな話はしてきた。

このご時世、JSON 大流行りなので、大抵はこれで方が付くんだが、もちろん情報交換のフォーマットとして今でも XML フォーマットは使われている。

ここら辺は「さすが Java」という感じなのだが、Java ネイティブ型 ⇄ XML の変換を取り決めている仕様が存在する。

それが Java Architecture for XML Binding というやつで、JAXB などと呼称されている。
読み方は「ジャックスビー」と思い込んいたが、正式には「ジェイエックスビー」らしいです。

必要性は低くなってきているが、無視はできない

ところで、正直言わせてもらえれば、JAXB の話をするのはあまり気乗りがしていない。

というのは、これまで、この仕様を使わなくてもなんとかなってきたから。

XML を解析するだけであれば、

・jdom(2) を使って解析→コレクション(list や map)を用いて手動で適宜後処理

という手法でも実務上あまり困らないと思う。

これはワイに限ったことではなく、JAXB が Java の正式仕様から外されたり復活したりしている理由は背景にこういった状況があるからだろう。

時代は良くも悪くも JSON 形式なのだ。

ただ、少々汚い形式の XML 文書を Java のオブジェクトとしてプログラム内に取り込んで自由自在に扱うというのは「映え」はする。

なんか釈然としないが、気を取り直して・・・。

準備

マッピングすべきクラスのフィールド変数が基本データ型だけで構成されていればそんなに難しいことはないんだが、配列や list が含まれていると難易度が上がる。
印象としては xml では、要素のまとまりなどは配列的に使われていることが多いと思うが、Java などではこれを list として取り扱いたいということが多いと思う。

配列⇄List の相互変換

Java では、配列と List を相互変換できる。

・配列(Array)→ List のときは Arrays.asLIST

・List → 配列(Array)のときは toArray

を使うのが原則。

List<String> items (= [item1, item2, item3]) があったとき、これを配列 String[] array にしたければ

String[] array = items.toArray(new String[items.size()]);

とする。

逆に array を items に戻したければ

List<String> items = Arrays.asList(array);

とする。

ただし、以下のサンプルコードが示すようにこの小技はあまり使う必要がないかも。

サンプルコード

えいやっと書いてしまった。

Parent.java
public class Parent {

private int id;
private String name;
private List<Child> children;
(以下、セッターゲッター)

せっかく配列や List の話もしたので、Child.java も設定。


public class Child {

private String name;
(以下、セッターゲッター)

この状態でオブジェクトに適当な値を設定。

JAXB.marshal(parent, System.out);

などとすると標準出力に以下のような xml 文書を吐き出してくれる。


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<parent>
<id>1</id>
<name>アグネスタキオン</name>
<children>
<name>ダイワスカーレット</name>
</children>
<children>
<name>ディープスカイ</name>
</children>
</parent>

逆に XML→ Java オブジェクトにしたければ、

JAXB.unmarshal(new StringReader(xml), Parent.class);

などとすればいい。

食わず嫌いでした

実際に手を動かすと意外に使いやすい。

ジャクソンの場合、手を入れる必要がある箇所でも marshal/unmarshal で済んでしまう。

これは食わず嫌いだったかな。

 

参考記事

https://qiita.com/opengl-8080/items/f7112240c72d61d4cdf4