やや長い前置き


最近、TomEE 絡みで Java に凝っている。

ワイは、基本的には Java 至上主義者が嫌いなんだが、言語の仕様やコミュニティに関してはそんなに悪い感情を抱いてはいない。

だから、これまでにもいくつかの案件にタッチしたことはある。

 
色んな意味で興味深かったのは、このプロジェクトかな。

ワイは、このシステムに関しては詳しくないし、基本、あっさりとしか関わってないので、自分が関与して興味深かったことと(余裕があれば)その背景に関してまとめてみたい。

まず、Java に関してであるが、現在、Spring 系が猛威を振るっていて、Java EE(Jakarta EE)勢は、いまいちな感じだ。

だが、歴史的に見ると「ある程度信頼性が求められるシステムは Java EE で」という時代があったようで、このプロジェクトの大元は OpenDolphin というオープンソースであった?電子カルテだったようだ。
(OpenDolphin という言葉を出すとなんかあれこれ言ってくる人がいるそうで、ここでもなるべく使わないようにします。いるか君、とか適当に置換)

実際、システム的には、サーバが WildFly でクライアントが Java デスクトップアプリという時代背景を考えれば当然のような構成。

一般の IT でもそうだが、クライアントのデスクトップアプリ→ブラウザの流れは、電子カルテでもおこったようで、いるか君は次第に使われなくなったそうだ。

ただし、電子カルテには保管義務が決められているのだそうで、昔の Java の形式で保管されたデータを抽出したいってのがこのプロジェクトの動機だった。


Java swing JTextPane と直列化

で、ここからが技術的な本題。

クライアントがデスクトップアプリなのだから、その UI は swing ライブラリが使われている。

具体的には swing の JTextPane というやつだ。
実際には JTextPane をカスタマイズしていて、これも面白い部分なのだが、いきなりそこに触れると話がややこしくなるので、今は「普通のコンポーネントをちょっと修正したものを使っていた」くらいに思ってもらえればいい。

ここが面白かったのだが、JTextPane に書き込まれた文字などを保管したい場合、直列化(seriarize)という仕組みがあって、XML に落とし込んでくれる。

へー、そうやるものなんですか、といたく感心した。
確かにビューに html 使ってないなら、そうするしかないわな。

具体的には JTextPane で作られた UI 上に

row1
row2
row3

と書いた際、このままでは保存できないので、一旦、独自の XML 文書に書き下す。
わかりやすく書けば

<jtextpane の書式で黒>row1</jtextpane の書式で黒>
<jtextpane の書式で赤>row2</jtextpane の書式で赤>
<jtextpane の書式で青>row3</jtextpane の書式で青>


となる。
ここまでできれば、これは単なるテキストと扱えるので、データベースでもプレーンなテキストファイルでもなんでも保存できる、という理屈だ。

なお、ワイが Java がけっこう好きなのは、こういう仕様がかっちりと決められているあたり。
仕様を探す手間さえ惜しまなければ、ある程度の人ならここら辺の仕組みを理解することができる。
逆にダメなのは、急激な変化が起こった時、仕様を決めるプロセスが重荷になって、それについて行けなくなること。
アップルと Java の関係が微妙なこともあるが、今、arm アーキテクチャの Mac 向けにデスクトップアプリを作る、なんて発想も浮かばんでしょ?

ちょっと話がそれた。
元に戻す。
前に「JTextPane をカスタマイズしていて」と書いたが、カスタマイズしたのは(わかりやすくいえば)イメージ( jpeg)を取り扱えるようにしたところ。

html なら IMG タグですむ話なんだが、ノーマル JTextPane にそんなものはない。
このシステムを作った人たちは、なんとここで独自タグを取り扱えるようにした
はっきり書いちゃうと <SchemaHolder-0>みたいなタグ。
いやあ、こういうところは昔?の人たちはなんか根性ある。

JTextPane でイメージを取り扱えるようにして

row1
row2
opendolphin-ui
row3


という画面が生成できたとする。

これもノーマルの JTextPane と同じように直列化したい。
すごい苦労したと思うけど、初期の設計者たちは、結局、こういう XML 文書を吐き出すようにした。

<jtextpane の書式で黒>row1</jtextpane の書式で黒>
<jtextpane の書式で赤>row2</jtextpane の書式で赤>
<SchemaHolder-0>
<jtextpane の書式で青>row3</jtextpane の書式で青>


逆にこれを JTextPane に戻したければ、<SchemaHolder-0>というタグを見つけたら、そこは画像を表示するようにすればいい。

一枚の画面に画像を複数枚置いているような場合は、<SchemaHolder-1>、<SchemaHolder-2>... などとする。

いやあ、よく考えたもんだなと。

しかし、感心してばかりもいられない。
最近の医療 IT の業界では、データの秘匿化はダメだそうで、厚労省のガイドラインにも「(データベースに)保存されたカルテのデータは、html などで閲覧できるようなバックアップの仕組みを作りなさい」と明言されるようになった。

あそこまで xml に落とし込まれているなら、これを html に変換するのは楽じゃないかという人もいるかもしれないが、現実のフォーマットはもっと複雑です。
おまけに独自タグもある。

一体、これをどう解決したのかは、実際に解決した人の記事を読んでみてください。

(追記)最近、「実際に解決した人」が、「いるか君」ではどのように画像を取り扱っているか?を動画の途中でチラリとですが、解説してくれています。



余談

(ここから先は余談。もうちょっと踏み込んだ背景」の話。興味ある人だけどうぞ)

JTextPane から文字情報だけを抜いてくるなら、実は、getText メソッドという簡単な方法がある。
インスタンス化された JTextPane に getText を作用させれば、プレーンテキストは取ってこれる。

最初の例の

row1
row2
row3

は、色情報は抜けてしまうが、

row1
row2
row3

となる。
getText は、当然、独自タグは読み飛ばすから、上のイメージ挿入された画面も同様のプレーンテキストになる。

データの抽出に取り組み始めたエンジニアにとって、これは少々悔しい事態だ。
できることなら、画像の位置くらいは再現したい。

一番、最初に思いつくロジックは、
「画面の文字の総数をカウントする(これは容易)。
 次に、イメージを表す独自タグ(<SchemaHolder-?>)が現れたら、それが何番目に現れたか記録しておく。
プレーンテキストとして再構成する際には、
・独自タグがなければそのまま書き出す
・独自タグがあった場合は、それが出現するまでの文字数をプレーンテキストで書き込み、出現した箇所に独自タグ(<SchemaHolder-?>)を加える。
 出現した箇所以降も同様の処理を繰り返す」

だろう。

ちょっと洗練されてない気もするが、実現は可能だ。

これなら、少なくとも

row1
row2
<SchemaHolder-0>
row3

までは再現できる。
9文字目に独自タグが出現するので、ここでその独自タグを表示させればいい。


実際、これを作成した人に聞いてみたが、プロジェクトの初期段階では、おおむねこのロジックだったそうだ。
(この後、XML 自体をパースするという風に方法論はより洗練されて進化していったそうだが)

ここでポイントとなるのは「文字数」だ。
独自タグが出てくるまでの文字数がわかっていないと、このアルゴリズムは成立しない。

背景が面白かったと言ったのは、このロジックに検討外れの批判をした人がいたからだ。
その記事自体はは現在は行方不明になっているようなのだが、以前は公開されていたようなので、ここで引用しても構わないでしょう。以下の通り。

shigeru-masuda-naika-accusation-no-meaning

ある程度、プログラミングに心得のある人からすると、読むに堪えない内容だ。
馬鹿馬鹿しいので多くは語らないが、今回の例に関連するところだけ指摘しておく。

 JTextPane.getText()


一文で可能である。



は、ちょっとあれって思うでしょ?
プレーンテキストで取ってくるだけだったら、getText() で済むのだが、他形式へのコンバートを前提にするとこれでは全くの役不足だ。
独自タグを表示するだけでも、字数のカウントは必要なのはこれまで話した通り。

これには流石に周囲の人たちもドン引きしたようで、現在では「和歌山の先生」と腫物扱いになったようだ(さすがに医師らしいので、気をつかっているわけですね。ここでも「和歌山の先生」という表現にしてみました)