長らく、ここの更新をできずにいた。
私生活での大きな変化があった(※昨年結婚しますた)、年末年始に少し体調を崩していた(※もう回復しました)、また、それはそれとして、仕事いくつかで多忙を極めていた(※来年度からは准教授になります)、などなどで、なんかもう非常にバタバタしていたためである。
しかし、ここ数日で、ようやく生活が安定してきた。今週末からは新婚旅行。14年ぶりにフランスを再訪する。
そういうわけで、このタイミングで、日記の更新を再開しようと思う。
ただし、これから再開をするにあたっては、今まで長らく使ってきたhttp://sqs.cmr.sfc.keio.ac.jp/tdiary/ ではなく、http://sqs-xml.sourceforge.jp/cgi-bin/tdiary/index.rb のほうに切り替えるべく、準備をしている。
ぼくは千葉商科大学の専任教員であるし、SQSはさすがにもう「慶應」ブランドのものではないので、自分の個人ホームページ、SQSのプロジェクトページの作り直しも含めて、自分についてのパブリシティ戦略の見直しを図っていくことにしたのだ。
現在は、移行先の環境整備中。sourceforge.jp上でtdiaryを使えるように設定するのは、ちょっと面倒くさい…。
ここでの日記は、次のエントリが最後になるだろう。
■ test
java.net.ProxySelector.setDefault(null)を実行すると、JavaWebStartのカスタムProxySelectorが解除されてしまうため、freemarker.template.Configuration#setClassForTemplateLoading(Class clazz, String pathPrefix)を使おうとすると、 getTemplateの内部で、jarURLConnectionを得ることができずに、ぬるぽになってしまう。やはり、setDefault(null)をしてはダメということか。
Caused by: java.lang.NullPointerException at freemarker.cache.URLTemplateSource.lastModified(URLTemplateSource.java:108) at freemarker.cache.URLTemplateLoader.getLastModified(URLTemplateLoader.java:91) at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:363) at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:235) at freemarker.template.Configuration.getTemplate(Configuration.java:487) at freemarker.template.Configuration.getTemplate(Configuration.java:466)
94 long lastModified() { 95 if (conn instanceof JarURLConnection) { 96 // There is a bug in sun's jar url connection that causes file handle leaks when calling getLastModified() 97 // Since the time stamps of jar file contents can't vary independent from the jar file timestamp, just use 98 // the jar file timestamp 99 URL jarURL=((JarURLConnection)conn).getJarFileURL(); 100 if (jarURL.getProtocol().equals("file")) { 101 // Return the last modified time of the underlying file - saves some opening and closing 102 return new File(jarURL.getFile()).lastModified(); 103 } else { 104 // Use the URL mechanism 105 URLConnection jarConn=null; 106 try { 107 jarConn=jarURL.openConnection(); 108 return jarConn.getLastModified(); 109 } catch (NullPointerException e) { 110 return -1; 111 } catch (IOException e) { 112 return -1; 113 } finally { 114 try { 115 if (jarConn!=null) jarConn.getInputStream().close(); 116 } catch (IOException e) { } 117 } 118 } 119 } else { 120 long lastModified = conn.getLastModified(); 121 if (lastModified == -1L && url.getProtocol().equals("file")) { 122 // Hack for obtaining accurate last modified time for 123 // URLs that point to the local file system. This is fixed 124 // in JDK 1.4, but prior JDKs returns -1 for file:// URLs. 125 return new File(url.getFile()).lastModified(); 126 } else { 127 return lastModified; 128 } 129 } 130 }
SQSの比較的新しい開発版(2009/01/31よりも前のもの、テンプレートライブラリとしてFreeMarkerを使用しているもの)では、特定の条件下で、Javaコンソールに、延々と、次のようなエラーが出て動かなくなるという障害が発生することがあった。
[INFO] HttpMethodDirector - I/O exception (java.net.SocketException) caught when processing request: Malformed reply from SOCKS server [INFO] HttpMethodDirector - Retrying request [INFO] HttpMethodDirector - I/O exception (java.net.SocketException) caught when processing request: Malformed reply from SOCKS server [INFO] HttpMethodDirector - Retrying request [INFO] HttpMethodDirector - I/O exception (java.net.SocketException) caught when processing request: Malformed reply from SOCKS server [INFO] HttpMethodDirector - Retrying request [INFO] HttpMethodDirector - I/O exception (java.net.SocketException) caught when processing request: Malformed reply from SOCKS server [INFO] HttpMethodDirector - Retrying request
今回、この原因を解明できたので、以下にメモしておく。
問題の背景:
対策方法:
現在の実装では、Javaアプリケーション内部からに、イントラネットのファイアーウォールを通じて外部のネットワークにアクセスする必要はない。つまり、Webブラウザ内のproxy設定を利用する必要はない。
そこで、Javaアプリケーション側で、Webブラウザのproxy設定を利用するというデフォルトのしくみを、無効化することとした。そのために、Java5から導入されたjava.net.ProxySelectorを利用する(参考:Java ネットワークとプロキシ)。
具体的には、次の一行を加えれば良い。
java.net.ProxySelector.setDefault(null);
これで、そのJavaアプリケーションプロセス内からの、すべてのプロキシ接続設定を無効化できる。
ともあれ、全部を無効化するのではなく、より選択的に無効化するためには、いずれ、自前でProxySelectorを実装したものに置き換えてやる必要があるだろう。
SunのJava Web Start開発者ガイドの1.5.0版には、次のように書いてある。
resources 要素に指定可能なサブ要素は、jar、nativelib、j2se、property、package、extension の 6 つです。この開発者ガイドでは、package 要素と extension 要素については説明しません。詳細については、「Java Network Launching Protocol & API Specification (JSR-56) version 1.5」を参照してください。
そういうわけで、package要素というものについて、きちんと調べずに読み飛ばしてしまっていたのだが…、偶然、MOYO Laboratory ≫ JNLP リファレンス を見つけて、今日ようやく、この package要素というものについての理解を得た。いわく、次のような機能があるそうである。
JWS はどの JAR にどのクラスが含まれているかを知を知らないため、ロード 済みの JAR に存在しないクラスが参照された場合は lazy の JAR を順次ダウンロードして検索しようとします。<package> を 使用することで該当する JAR のみを適切にダウンロードさせることができ ます。このため <package> 要素は遅延ダウンロードを指定 した JAR ファイルに対してのみ意味を成します。
そんな重要なものだったとは…
そういうわけで、さっそく、各国語のTrueTypeフォントをlazy download機能を使って取得するように部分に、これを応用してみようと思ったのだが…、
こんどは、Java SEの1.6.0のドキュメントを見てみた。すると、
Jar インデックスが完全にサポートされ、JNLPClassLoader が URLClassLoader のインスタンスになる
JNLPClassLoader が書き換えられ、URLClassLoader の拡張となりました。 これには、いくつかの強力な利点があります。
まず、Jar インデックスが完全にサポートされます。 複数の jar ファイルが存在し、すべての jar ファイルをインデックス化する jar インデックスをメイン jar ファイル内に作成する場合、追加する各 jar に遅延のマークを付けて、その内部のリソースまたはクラスが参照されるまでダウンロードされないようにできます。 これにより、古い part や package 要素が不要になり、遅延 jar が使用に先立ってダウンロードされないことが保証されます。
また、JNLPClassLoader が URLClassLoader を拡張するようになったため、アプリケーションは getURLs() を呼び出して jnlp ファイル内に記述されている jar 要素 (または jnlp ファイルに記述されていなくても、DownloadService API を使用してダウンロードされた jar 要素、前述の説明を参照) の一覧を取得できます。
また、ClassLoader.getResource() の呼び出しで返される URL が、ネット上の項目の適切な JAR URL になります。 以前のバージョンでは、返される URL はキャッシュ内の項目のファイル url の jar url でした。 URLClassLoader を拡張することにより、キャッシュされた場所 (存在する場合) は意味がなくなり、Java Web Start がキャッシュなしで動作することが可能になりました。
などと書いてあったのを、今更ながらに発見。つまりは、JavaSE6上であれば、単に download="lazy" を書くだけで良い、ということだ。便利だ…。
現行版2.0のバグを修正したSourceEditor改訂版: http://sqs-xml.sourceforge.jp/2008/12/13/SourceEditor.jnlpを作成しました。
以下、SourceEditor改訂版の機能について。
頃合いを見て、トップページに貼られたリンク先を、この更新版に変更します。
以下、やや優先度低めの課題として:
SQS MarkReader2.0からのマーク読み取り・データ出力の状況を、ユーザに詳細に提示する方法のひとつとして、Apache Chainsawを使えないだろうか?
Chainsaw v2 is a companion application to Log4j written by members of the Log4j development community. Like a number of Open Source projects, this new version was built upon inspirations, ideas and creations of others. Chainsaw v2 has it's roots from the original Chainsaw utility written by Oliver Burn, and with inspiration from the Log Factor 5 utility contributed by ThoughtWorks Inc.
現在のSQSのコードでは、java.util.logging.Logger.getAnonymousLogger()で、info, warn, severeのレベルごとに、ログの出力をしている。まずこの、anonymousというのがダメ。きちんとしたログに名前をつけて、階層化されたセッションごとにユニークなものとして再設定する必要があるのだろう。
また、この導入を決断するにあたって、Chainsawで、「巨大なログ」(一定サイズのバッファから溢れた「過去ログ」)を表示検索する機能をどうやって実現するかを考えなければならない。
ほんとうは、JTailerくらいのシンプルなものが欲しいんだけれど。
「一般利用者向けIPAフォント使用許諾契約書」によれば、
5. 受領者は、デジタル・コンテンツにおいて使用した文字(サブセット文字)に限り、本契約において許諾されている範囲内で埋め込んで(エンベットして)デジタル・ドキュメント・ファイルとし、かかるデジタル・ドキュメント・ファイルの複製その他の利用をすることができます。この場合には、かかるデジタル・ドキュメント・ファイルの受領者に対しては、本契約に従うことを求める必要はありません。
というわけで、 IPAフォントをPDFファイルに埋め込むことはライセンス的に可能な筈だが…、dvipdfmxをかけると、
** NOTICE: This document contains `Preview & Print' only licensed font **
となってしまう。IPAフォントの、フォントファイル内のライセンスのフラグが、IPAフォントの使用許諾契約書の内容に即した形で更新されていない、ということだと思われる。
(追記)Ubuntu8.10日本語版では、IPAフォントを改変してASCIIアート表示用に幅調整を施したIPAモナーフォントの配布が「公式には出来ない」(non-free扱い)ということになったそうだが、フォントの改変さえしなければ、再配布もPDF埋め込みも問題ない。
■ まあしぃ [えー、結婚されていたんですか!? おめでとうございます!!]
■ hiroya [ありがとうございます、実はもう四ヶ月が経ったところです。ようやく、落ち着いてきたかな、と。]
■ test [this is test.]