非推奨となっていたJava.facesをCDIにリプレイスしてみた

 7年前くらいに作ったWebLogicで動かしているアプリがあるのですが、Java.faces系のDI実装がだいぶ前から非推奨となっていたので、どこかで対応しないとなあ~と思っていてから数年経ちましたが、時間が取れたのでCDI実装に置き換えてみました。

 まず、簡単なところでは、javax.faces.bean.RequestScoped 等のスコープ指定を CDIのjavax.enterprise.context.RequestScoped に、
javax.faces.bean.ManagedBean を javax.inject.Named に
この辺りは単純にimportするライブラリを変更するだけです。ただし、@ViewScopedと@SessionScopedについては、Serializableを実装する必要があるようです。

 次に、javax.faces.bean.ManagedProperty ですが、こちらは2パターンの対応が必要となり、@ManagedPropertyでDIしている箇所は、@Injectと@Namedに置き換えるだけです。

 ManagedPropertyの別パターンで、今回対象のアプリではxhtmlからのPOSTデータ授受に使用していたのですが、javax.faces.annotation.ManagedProperty に置き換えても動かなかったので、下記のようにFacesContext経由でデータを受け取るようにしました。

 最後に、アプリでは共有したいセッション情報等を保持する為に、@ApplicationScopedをeager指定してアプリ開始時に生成していたのですが、CDI-APIの方では存在せず、初回コール時のタイミングで生成されるようです。

 参照している箇所も見直しが必要で結果的に下記のように置き換えました。

 動作は一通り確認しましたが、何か機能が追加された訳でもなく、置き換え前でも動きは変わらないので、いつリリース出来るかなあ。。

いつのまにかojdbcがMaven Repositoryに公開されていた

 現在、数年前に作ったOracleDBを使うアプリの改修しているのですが、前まではOracleのリポジトリ(maven.oracle.com)からしかダウンロードできなかったojdbcが、いつのまにかMaven Repositoryからダウンロードできるようになってました。

 しかも、Oracleのリポジトリがどこかのタイミングで更新を止めているのか、Maven Repositoryから取得出来るライブラリの方が新しいバージョンを取得出来る状態になっているようです。自前のリポジトリ運用を諦めたのでしょうか?

 Oracleのリポジトリでは、groupIdがcom.oracle.jdbcとMavenと微妙に違っているので、気が付かないとOracleのリポジトリにあるライブラリが最新かと勘違いしてしまいます。

 Weblogic等、DB周りのライブラリ以外は従来のままっぽいです。

カテゴリー: Java

SpringBootを2.0.1.RELEASEから2.6.6にバージョンアップしてみた

数年前に他で作られたものを引き継いで担当しているSpringBootアプリがあるのですが、dependency-checkを実行するとライブラリに多数の脆弱性がある事が判明。

対応の時間が取れそうなので、spring-boot-starterを対応開始時点最新だった2.6.4へ一気に上げてみる事にしました。今回対象のアプリではごく一部だけコード変更が必要でしたが、それを書き直して実行してみると、、起動に失敗しているようです。

下記にも出てましたが、メッセージの図が示している通り循環参照をしているようです。

該当箇所のコードを読み、そのままで問題無い事を確認した上でメッセージの通りにapplication.ymlに設定を追加します。

稼働確認をしていくと数か所の動作に問題がありましたが、基本的にはライブラリ間のバージョン不一致によるものだったので、使用ライブラリの依存を整理してバージョンを調整。

対応が殆ど終わったと思ったら、Springの脆弱性「Spring4Shell」が見つかり、実行環境的にはJava1.8なので影響は無いのですが、最新の2.6.6にして再度稼働確認し一段落。

FileInputStreamでは日本語のファイル名が見つからない

emlファイルからメールをいろいろ加工するようなブツを作っているのですが、日本語が含まれるファイルの場合、問題になる事が判明。

開発環境のWindowsでは特に問題ありませんでしたが、Linux環境で実行するとファイルが見つかりませんでエラーになるんですね。。

こちらの下の方を参考に、nio仕様に変えたら問題は解消しました。環境依存でしょうか、特にJVM引数は必要なかったです。

今の時代、Javaのファイル処理はnioに統一した方がよさそうですね。

カテゴリー: Java

maven dependency-checkを試してみた

 前回から続きのテーマですが、使用しているライブラリのバージョンアップについて、せめて脆弱性が発覚しているものだけでも対応した方がよいかと思い、探していたらぴったりな下記Mavenプラグインの存在を発見

 現在、数年前に作ったWeblogicアプリの変更をしているので、これを試してみます。

mvn dependency-check:check

 どうもWeblogicに依存しているライブラリで結構な数脆弱性が見つかっているようです。これは実行環境でパッチを当てて対応するんだろうなという事で、チェックから無視するようにします。

 それ以外のライブラリでバージョンアップすると現状のコードでは動作しなくなる箇所もあったのですが、CVEのスコア的に今回対象外としました。

カテゴリー: Java

ライブラリのバージョンアップについて

 年末に近いので変更リリースとかは年明け以降に、という事にしていましたが、急遽lo4j2にリモートコード実行の脆弱性が発覚したので、使用しているJavaアプリケーションを洗い出して最新ライブラリへ入れ替えの対応をしていました。

 log4j2について人知れず存在していた便利機能が今になって仇となったような感じですが、影響範囲はログ出力だけで、対応もライブラリの置き換えだけなので、実際の作業自体は大したことはありません。最初の脆弱性発覚後バージョンアップは計3回となり、一度脆弱性が指摘されたものに対しては、連鎖的に問題が指摘されやすくなっているようです。とはいえ、オープンソースとして利用させてもらっているのでメンテナンスをしている方々に感謝ですね。

 今回のようにセキュリティ問題として大々的にアナウンスされたものは即対応が必須となりますが、数年前から稼働させているようなアプリでは、使用しているライブラリがバージョンアップされていても、大抵は従来のままという事が多いような気がします。

 明確に運用方針を挙げている組織であれば、ハードやOS、ミドルウェア、言語についての、特にセキュリティパッチについては適切に対処されていると思いますが、アプリで使用しているライブラリやフレームワークまではあまり手を付けていないように思います。

 筆者の場合、基本的に一人で面倒を見ているようなものですが、セキュリティ対応以外でのライブラリのバージョンアップは正直考えたことも無かったです。今回メンテナンス対象となったアプリでいえば開発当時のlog4j2 2.5を使ってそのまま5年以上が経過、今回の脆弱性発覚でやっと2.17に上げたところです。

 稼働中のアプリが使用しているライブラリのバージョン管理はやった方がよいとは思うのですが、情報収集から対応、稼働確認等、かなりの運用コストが掛かり、かつ機能が増える訳でも無いので、やるとしても何かしら追加の業務要件が発生した時の次いでにバージョンをチェックして、変更するか検討するくらいですかね。

Java mail で Unknown encoding 発生

Javaで書いた、いろんなメールを受信して業務の一部を自動化するツールを何年も運用しているのですが、見慣れないエラーが出ていたので確認すると、

java.io.IOException: Unknown encoding: 8-bit
at javax.mail.internet.MimePartDataSource.getInputStream(MimePartDataSource.java:116) ~[jar:rsrc:javax.mail-1.6.2.jar!/:?]
at com.sun.mail.handlers.text_plain.getContent(text_plain.java:83) ~[jar:rsrc:javax.mail-1.6.2.jar!/:?]
at javax.activation.DataSourceDataContentHandler.getContent(DataHandler.java:795) ~[?:1.8.0_275]
at javax.activation.DataHandler.getContent(DataHandler.java:542) ~[?:1.8.0_275]
at javax.mail.internet.MimeBodyPart.getContent(MimeBodyPart.java:683) ~[jar:rsrc:javax.mail-1.6.2.jar!/:?]

Caused by: javax.mail.MessagingException: Unknown encoding: 8-bit
at javax.mail.internet.MimeUtility.decode(MimeUtility.java:405) ~[jar:rsrc:javax.mail-1.6.2.jar!/:?]
at javax.mail.internet.MimePartDataSource.getInputStream(MimePartDataSource.java:109) ~[jar:rsrc:javax.mail-1.6.2.jar!/:?]
... 13 more

とログに吐き出されています。

String body = (String) mailpart.getContent();

と、コンテンツタイプがtextのメールパートを本文として文字列にキャストしたタイミングで例外に飛んでます。

該当のメールをEMLファイルでメールの中身を確認すると
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: 8-bit

となっています。

通常は
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit

だったり、

Content-Type: text/plain; charset="ISO-2022-JP"
Content-Transfer-Encoding: 7bit

のようです。

Javamailでは、8bitでなく8-bitだと例外になるのか。。。
仕方ないので、キャストに失敗した後に強制的に8bitに置き換えて本文を読み取るようにしました。

part.setHeader( "Content-Transfer-Encoding", "8bit");
String body = (String) p.getContent();

メールの受信処理は、送信側次第でイレギュラーなメールが発生するので面倒です。。

apache.commons.csvでinvalid char between encapsulated token and delimiter

 だいぶ前に作ったapache.commons.csvとapache.poiを使ったCSVファイルからエクセル出力処理で、

java.io.IOException: (line 3) invalid char between encapsulated token and delimiter

 が発生していました。原因は、ダブルクォーテーションで括っているデータ項目の中にダブルクォーテーションが混ざっていたからなのですが、データを出力する側で対処するのが出来そうにないので、CSVファイルを読み込む所で何とかならんものかと検討。
 
 CSVファイルを読む箇所は下記のようにInputStreamが渡され、CSVRecordリストを取得して色々やるという内容です。

 殆どの場合で問題は発生しないので、出来れば失敗した場合のみリトライ出来ればいいかなと、データ内に混ざりこんだダブルクォーテーションをエスケープするようにしてみます。正規表現での変換を3段階かますことで、一部ケース(データ内にカンマとダブルクォーテーションが連続した場合)は問題ですが、今回はまあこの位で。。

 次に失敗した後のフォローとなるので、読込が進んでしまっているInputStreamを何とかしなければなりません。結局、IOUtilsでテンポラリファイルにコピーしてから読み込むようにしました。

JavaMailメール送信でSMTPサーバを指定するもlocalhostへ接続

 メール送受信をする処理が動いているサーバを別のインフラに移動したいという事で、移行作業し稼働させたところ、メール送信が出来なくなっている事が判明。

 正確には、メール送信処理は複数あり、単純なJavaアプリとして稼働しているプロセスでは問題が無く、SpringbootでWebサービスとして稼働している処理のみが問題となっています。どちらも元のサーバ上では何ら問題なく動作していました。新環境ではJavaアプリのテストはしてましたが、問題無かったのでSpringboot側は割愛してしまいました。なお、Javaアプリと比べて、Springboot側はjavamailのバージョンがSpringbootのバージョンに引きずられて微妙に古い状況(1.6.1)。

 アプリ的には正常終了扱いとなっており、どこでメールが止まっているのかと調べてみると、mail.smtp.hostで指定しているSMTPサーバにはメール送信ログは無く、なぜか移行先サーバー内の/var/log/maillogにログが、、
Network is unreachable で終わっています。

 どうやら指定しているSMTPサーバでなく、localhostに対しメール送信要求をしているようです。

 とりあえず、移行先のサーバでpostfixを稼働させる必要は無いので止めてもらい、メール送信テストを行うと、今度は接続出来ないとアプリ側でエラーになりました。

 どうも、、デフォルト設定がlocalhostで、そちらが優先されているようですね。。

アプリ側が
session = Session.getDefaultInstance(props);
だったので、
session = Session.getInstance(props);
に変えて問題は解消しましたが、どこでデフォルト設定されているのかは不明なままでした。。

こちらが参考になりました。影響は軽微で、ちょっと痛い目にあったという感じです。

カテゴリー: Java

SpringBootでZabbixAPIを使ってみる

 Zabbixの作業を自動化したいという事で、ZabbixAPIを使ってみました。対象のZabbixは3.2とちょっと古めのようですが、API自体はあまりバージョンは気にしなくてよさそうでした。ドキュメントが充実しているので助かります。

認証後、2件のホストを指定してホスト情報を取ってくるテストを書いてみました。

で、こんな感じで戻ってきます。

hosts: [{“hostid”:”10387″,”host”:”server01″,”name”:”server01_DB”},{“hostid”:”10388″,”host”:”server02″,”name”:”server02_DB”}]

問題無く使えそうなので、要件を整理してから実装してみます。