「Java」と一致するもの

ASCII - 100問・6時間!のセキュアプログラミング試験が上陸

「世界唯一」というセキュアプログラミングの認定試験が今年12月、日本に上陸する。試験問題は全部で100問、試験時間は6時間(途中退出は可能)という。

 GSSP試験は、セキュリティに考慮したプログラミング(セキュアプログラミング)のスキル、知識を客観的に証明することを目的としている。ソフトウェアベンダーの技術者などを対象に、「サンプルコードの中から問題点を指摘させる」(SANSのアラン・パーラー代表)といった実践的な内容が特徴だ。

確かに、こういう系統の知識って重要ですが、試験として覚える機会はないような気がしますね。
日本だと、IPAテクニカルエンジニア(情報セキュリティ)にそのような問題が出題されるとの話なのですが、今までの試験ではそのような形式の問題がまだ出題されたことがないみたいですねw

独学で学ぶのは難しいですし、試験のために学習し、一定の水準に満たしているという指標が与えられないとセキュアなプログラムを書くことができると言えないと思うので、このような試験は是非受けてみたいところです。

GSSP試験の場合、C言語とJavaの2つのうちどちらかを選択可能らしいので、私の場合は間違えなくJavaになりそうですが、受験料は5万7000円ってのがなぁorz
ま、すぐに取得できる資格ではなさそうなので、時期見てって感じでしょうか(≧∇≦)

HibernateでNoSuchMethodErrorが発生する問題

Struts + Hibernate Ver3を用いたWebアプリケーション実装中、特定のページの特定のユーザのみエラーが発生し、ページが表示されない現象に見舞われました。

ログを確認してみると、

java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recover(Lantlr/RecognitionException;Lantlr/collections/impl/BitSet;)V
が発生しておりました。

しかし、ググってもなかなか解決方法までたどり着けないんですよね。

日本のサイトで唯一情報源に成り得るのは、守破離 - Hibernate 3.2.1.gaでJPQL解釈時にNoSuchMethodErrorで落ちる事の対処法くらいでした。

(Googleを見るとHibernateネタは日本語サイトより中国語サイトの方が多いようなので)知り合いの中国人にも頼んで調べて貰ったのですが、HQL(Hibernate Query Language)の文字列において「from」を「form」の様に誤字すると発生するという情報くらいしか得られませんでした。

しかし、英語サイトも含めて調べていくと原因と対処法がやっと分かってきました。

Note to self - java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recover
Java Programming - hibernate issue

上記に挙げたサイトの情報をまとめる限り、やはり、HQLの構文に何らかの問題が存在するからなのです。

String HQL = " from User user where user.userId ='" + userId+"' and where user.fname ='" + fname +"' and where user.lname='" +lname + "'and where user.email='" + email +"'"; List result = session.createQuery(HQL);
の場合、「lname + "'and」の場所に注目していただけると理由が分かると思います。 「'」(シングルクォーテーション)と「and」の間に半角スペースが抜けているんです。

しかし、今回、私が体験した場合、もっと根が深く気付きにくい問題でした。
例えば、以下のようなコードです:

String id = "darekanoid";
String pass = "darekanopass";
// ↑上は説明の都合上
String HQL = " from User as user where user.userid = :userId"
                + "and user.password = :password";
Query query = session.createQuery(HQL);
query.setString("userId", id);
query.setString("password", pass);
List result = query.list();

HibernateでPreparedStatement(もどき?)を実施する場合は以上のようなソースコードになりますが、この場合、HQLの2行目が「"and」となっており、一行にまとめると「 from User as user where user.userid = :userIdand user.password = :password」になることでエラーが発生します。
本来なら必要ないと思われるHQLを2行に分割した理由は、開発中のプログラムのコーディング規約による制限があったからです。
ただ、エラーが発生しない場合もあるんですよ。
例えば、「String id = "aregeid "」みたく右側にユーザIDの右側にスペースが詰められている存在する場合です。CHAR型のデータを用いると、特定の文字に見たいない場合はスペースで補われますし、そのようなユーザIDを用いて検索するとNoSuchMethodErrorが発生しないようです。

この問題を解決する方法は、2点あります。

1点目は、antlr.jarのバージョンを2.7.6以上にする。
java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recoverが発生する原因は、HQLが正しくないことが原因です。antlr.jarは文字列の正規表現や文字列から数値への解析に用いられるJARだそうです。Hibernate Ver3では正しくないHQLを回復させるためにantlr.Parser.recover()メソッドを用いようとしているもとの思われます。しかし、antlr.jarが古い環境では読み込めず、今回のようなエラーが発生してしまうと考えれば納得が行きます。
もし、antlr.jarを新しいバージョンに変更できる環境であるならば、2008/02/11現在、Antlr Ver2の最新版である2.7.7に置き換えると良いと思います。

2点目はHQLが正しいか確認することw
今回、開発がある程度進んでしまった為、安定性を保証する為にantlr.jarを入れ替えることができなかったため、こちらの方を選択しました。
不思議なことに、"and"のように「and」の前にスペースがなくともなぜか無事に取得できる場合があるんですね。
HibernateはコンソールにHQLが正しいか出力する方法が存在します。開発中は、コンソールを確認し、HQLに問題が発生しないか確認する必要があると思います。

ぶっちゃげ、ちゃんと見てなかったからこのような事態が発生し、解決まで時間が掛かったということですがorz
そんなわけで、同じ悩みで開発が止まっている人の参考になれば( ̄∇ ̄)ノ♪

StrutsのActionServletからiTextのPDFを出力する

iTextを用いてJava ServletからPDFを作成するに関連する話題です。

iTextを用いてServletからPDFを出力することは、上記の記事で学習いたしました。
しかし、Strutsの場合、作成したPDFを出力させる機構がすぐに思いつきませんでした。

Strutsのアクションサーブレットは、サーブレットファイルに以下のようなメソッドの中でビジネスロジックを記述しますよね。

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
  ...
  return mapping.findForward("ok");
}
「mapping#findForward(文字列)」の部分でstruts-config.xmlの指定した文字列のJSPに飛ばすことで、MVC(Model-View-Controller)モデルを実現しているわけです。

しかし、今回、StrutsでiTextのPDFを出力する場合はそうも言ってられません。
だからと言って、StrutsのActionサーブレットなのにdoPost()やらdoGet()やらを呼び出す方法にしてしまうのはStrutsの意味がなくなってしまいます。

そこでちょっと調べてみましたが、ActionServletからファイルを出力する方法は普通に存在するみたいです。

天使やカイザーと呼ばれて - Strutsでのファイルダウンロードの方法

なるほど。
ActionServletの「return mapping#findForward(文字列);」を「return null;」にし、その前の行に、HTMLソースやバイトコードを出力するようにすれば、HTMLだろうと、ファイルだろうとStrutsから出力できるようです。
CodeZineのiTextを利用してJavaからPDF形式の帳票を出力するのソースを参考に、StrutsからiTextのPDFを出力するための基本体系を書いておきます。

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

  //出力用のStreamをインスタンス化します。
  ByteArrayOutputStream byteout = new ByteArrayOutputStream();

  //文書オブジェクトを生成
  //ページサイズを設定します。
  Document doc = new Document(PageSize.A4, 50, 50, 50, 50);

  try {
    //アウトプットストリームをPDFWriterに設定します。
    PdfWriter pdfwriter = PdfWriter.getInstance(doc, byteout);
  }

  ...

  // PDFの出力を終了します。
  doc.close();

  response.setContentType("application/pdf");
  response.setContentLength(byteout.size());
  OutputStream out = response.getOutputStream();
  out.write(byteout.toByteArray());
  out.close();

  return null;
}

赤字が今回学習の範囲ですw
非常に簡単ですね。

そんなわけで、今後のPDF出力プログラム作成時に使用させていただきます。

iTextを用いてJava ServletからPDFを作成する

現在JSP & Java Servletを用いてWebアプリケーションを開発していますが、PDFの帳票出力が必要になりました。色々調べてみると、JavaプログラムからPDFを出力するためのライブラリが無料で公開されており、意外に簡単にできそうなのです。

CodeZine - iTextを利用してJavaからPDF形式の帳票を出力する
※会員登録することで、iTextを用いたサンプルWebプログラムをダウンロードすることができます。

サイト内のソース解説を見ていただければお分かりの通り、カプセル化のカプセル化で作成する形なので、オブジェクト指向が分かる方には(もしかしたらそうでない方も含め)コーディングしやすいのかななんて感じます。

PDFの中に自分の名前が入るとかたまらないですね(≧∇≦)(何)


解説するもの全て上記サイトで解説されつくしている感じなので、今回はiTextのサンプルプログラムをEclipseに読み込ませようとしたときのトラブルについて対処法を記述しておきます。

Eclipseのワークスペースに、展開したiTextのサンプルプログラムを配置したところ、正しく動作しませんでした。

Unable to find a javac compiler;
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK
みたいなエラーがでたので、ググってみたところ、同様の症状が出た場合の対処法が書かれているサイトを見つけました。

Eclipse 3.2 日本語版の場合、[ウインドウ(W)]→[設定(P)...]→[Tomcat]→[JVM設定]の「クラスパス (生成されたクラスパスの前)」で[Jar/Zip]ボタンをクリックし、「%JAVA_HOME%\\lib\tools.jar」のライブラリを追加してください。
※「%JAVA_HOME%」はJDK 5.0、または、J2SDK 1.4をインストールしたトップフォルダのことです。

サンプルプログラムなのに、ソースを確認したら赤字だらけだって方は、Eclipseを起動すると左側に位置する[パッケージ・エクスプローラー]に存在すると思います。iTextのアプリケーションフォルダを右クリックし、[プロパティ(R)]→[Java のビルドパス]→[ライブラリー(L)]タブを開きます。[JAR の追加(J)...]で、「(iTextのサンプルプログラム)\WEB-INF\lib」の下にある「itext-1.3.jar」と「iText-Asian.jar」を選択し、[OK]ボタンをクリックします。
パッケージ・エクスプローラーのiTextフォルダに先ほどクリックした2つのファイルが表示されれば、赤字だったソースの箇所が消えていると思います。

こんな感じでJavaからPDFを作成してみましょ〜。

Apache Tomcatで動作したWebアプリケーションをOracle Application Server(OAS)で動作させようとしたら正常に動作しなかった問題とその解決法について紹介します。

事の発端は以下の通り:
Eclipse+Tomcatで製作したWebアプリケーションを、一度、WARファイルに固めました。
そして、OASに配置して動作試験を行いました。
しかし、EL(Expression Language)を使用しているページで式言語がそのままの文字で出力されてしまう問題が発生しました。

JSPでEL式が使えない場合の対策で書いたことを疑いましたが、そもそもWARファイルに固めているのでライブラリも含まれています。

なんだかんだで必死に原因を調べたのですが、思わぬところに理由がありました。

@ITのJ2EE 1.4に対応したweb.xmlを記述するの記事に、J2EE 1.3とJ2EE 1.4の場合のweb.xmlが書かれています。

J2EE 1.3の場合のweb.xmlは

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  ...中略...
</web-app>

J2EE 1.4の場合のweb.xmlは

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

  ...中略...
</web-app>

となっています。

問題のWebアプリのweb.xmlは以下のようになっていました:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

  ...中略...
</web-app>

もうお分かりですね、J2EE 1.3の設定とJ2EE 1.4の設定が混ざっていたんですorz

今回の原因を考察してみました。
今回Apache TomcatはVer5.0.24を使用しておりJ2EE 1.4に準拠すること前提で製作されているため元々EL式を読み込むようになっているようです。対して、OASの方はWebサーバこそApache Web Serverのソースを流用していますが、Servletコンテナはそうではないようです。そのため、Apache Tomcatより厳密にweb.xmlを解釈しているものと思われます。
<web-app>タグより前に存在するDOCTYPE宣言を見た上で、J2EE 1.3のアプリケーションと認識してしまったようですね。

説明し忘れましたが、EL式(式言語)がデフォルトで対応になったのはJ2EE 1.4からです。それ以前のバージョンはJSTL(JSP Standard Tag Library)のライブラリとweb.xmlの設定をして初めて対応になります。

OASではELは動作する情報しか出てこない中、OASの情報がそもそも少ないので今回の原因調査には何日も掛かってしまいましたorz
それでも解決できて何よりでした。