非推奨となっていた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

ワンライナーでsqliteからCSVファイルを出力する

 開発中のツールで、別のアプリケーションで管理しているマスターデータを使いたいというケースがありました。
 マスターデータはsqliteで管理しているのですが、別アプリのDBに直接接続するようなコードにしたくないなあと。

 なら、コマンドレベルでCSV出力して使えないかとちょっと調べたところ、ちょうどいい記事を発見

sqlite3 -header -csv mst.db "select id, name from tbl_cutomers" > data.csv

 デイリーで動かすシェルからの実行でCSVを更新する感じですかね。

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に上げたところです。

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

GitBucketをバージョンアップしてみた。

 内部Gitとして使用しているGitBucketが導入から3年近く経ったので、バージョンアップを検討する事にしました。

 使用中のGitBucketは、4.13、最新は4.36.2となっているようです。とりあえず、端末上でWARのみ最新バージョンにして試してみたところ、下記が原因で止まってしまいます。

    org.apache.catalina.LifecycleException: org.h2.jdbc.JdbcSQLException: テーブル “PRIORITY” はすでに存在します

 バージョンアップは基本的にDBをエクスポートしてインポートするのが正解のようなので、GitBucketのSystem administrationよりDBをエクスポートし、SQLファイルを取得しておきます。その後、DBを一旦クリアして、最新バージョンを立ち上げ、SQLファイルをインポートしてみますが下記で失敗します。

    org.h2.jdbc.JdbcSQLException: テーブル “ACTIVITY” が見つかりません
    Table “ACTIVITY” not found; SQL statement:
    DELETE FROM ACTIVITY [42102-196]

 どうやら、ACTIVITYデータがDB管理からJSONファイルに移行したようです。

 いろいろ、バージョン毎に動作を確認しながら試したところ、DBをクリアした状態で4.32を立ち上げて、DBをインポート(RELEASEテーブルで怒られるが、データが無かったので、SQLからDELETE文を削除)

 その後、DBはそのままで最新の4.36.2を立ち上げるとうまく動作しました。ついでにDBもH2からpostgresに移行してみましたが、ブランチのマージ操作でエラーが出てました。どうもシーケンスが1からになっているようです。

System Administration -> Database viewerで、

select * from issue_comment_comment_id_seq;
select max(comment_id) from issue_comment;
select setval('issue_comment_comment_id_seq',xxxx);

でシーケンスを更新してとりあえずは解消しました。

正規表現でOR条件がどちらもヒットする時

 Javaでメール本文から正規表現で文言を抜き取るような対応をしていて、例えば

お世話になっております。
〇〇です。
××
▲▲
追伸
 ××
以上

のような文章で「お世話になっております」以降から「以上」より前の文言を抜き取っていたのを、今回、「追伸」以降もカットしたいが、「追伸」がある場合と無い場合がある、というような追加の話がありました。

元々、正規表現でマッチしたグループ1番目の文言を抜き取る形として

お世話になっております。(.*)以上

としてましたが、追伸を考慮すると

お世話になっております。(.*)(追伸.*|以上)

でいいのかなと試すと、マッチグループの1番目に「追伸」以降の箇所が含まれ、グループ2に「以上」が入ります。

ORの場合に優先順でもあるのかな?と、いろいろ調べてみると下記がとても解りやすく書いてました。

 優先順というより、最長マッチによりこうなっているのですね。という事で、最短マッチにすればOKという事。

 あとは最短マッチにした事で、抜き取りたい文言中に「以上」が含まれた場合に困るので、改行を見るようにして下記の正規表現としました。

お世話になっております。(.*?)(追伸.*|\n以上(\n|\r))

長年使ってますが、正規表現って難しい。。

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();

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