JAR,WAR,EARそれぞれの違いについて

JAR, WAR, EAR はいずれもJava仕様に準拠して定義されたZIP形式のパッケージ(複数のファイルをまとめたアーカイブ) いずれもJavaで実装したプログラムを実行・配布しやすくするための形式である。

JAR

Java プログラムの実行に必要なクラスファイルや設定ファイルがまとめられているアーカイブJavaで作成したソフトウェアを配布する際に関連するファイルを1つにパッケージングする際に利用され、実際に多くのクラスライブラリはこの形式で配布されている。

WAR

Java 製のWebアプリで利用されるクラスファイル(servlet)、設定ファイル、JSPやHTMLファイル、JAR形式のライブラリなどがまとめられているアーカイブ。 また、web.xmlが含まれ、TomcatなどのアプリケーションサーバにWARファイルを配布すると、これを元にデプロイされる。

これはMVCモデルでいえば、MVCすべてまとめてひとつにした感じだと思う。

EAR

Java EEアプリーケーションのパッケージ形式。 任意の数のWARファイルやEJBファイル、またこれらのアプリケーションで必要とするJARファイルを含めることができる。

ファイルの大きさは、

EAR > WAR > JAR

となる。

参考

あるシステム屋による開発の記録 JAR, WAR, EAR の違いについて

SWTでWEBブラウザを操作するアプリケーションを作成してみる 〜その1〜

Javaでブラウザを操作するようなプログラムを作成してみることにしました。以下はその備忘録です。

この記事ではSWTアプリケーション作成の第一歩として「ウィジェットが配置されていない空のウィンドウを出力するまで」を記載しています。

SWTについて

Javaでブラウザを操作するとなるとGUIコンポーネントを利用することになりますが、ここではSWTというものを利用することにします。

SWT(Standard Widget ToolKit)は、Eclipseプロジェクトから提供されているGUI作成用ツールキットです。

このSWTパッケージ内のBrowserというクラスを利用することで、ブラウザを操作するアプリケーションが作れるようです。

他にもSwingにMozSwingという高機能なWEBブラウザコンポーネントがあるようですが、WEB上の情報が少ないので今回はSWTを利用することにします。

http://d.hatena.ne.jp/kaiseh/20090608/1244463562

SWTのダウンロード

SWTは下記URLからダウンロードできます。

http://www.eclipse.org/swt/

ページ上部のStableという文字があるあたりで、OS名がテキストリンクとなっているリンクをクリックし、ダウンロード先ミラーを選択することでダウンロードすることができます(2010/07/19現在)。

SWTはOSのネイティブAPIを利用するものだそうで、純粋なJavaではないようです。したがって、WindowsならWindows用のSWTを、LinuxならLinux用のSWTを利用する必要があります。

Eclipseでの外部Jar追加

ダウンロードしたファイルを解凍すると、swt.jarというJarファイルがあります。

今後SWTを利用したソースコードを書いていく際はこれをインクルードする必要があります。

Eclipseでは適当な名前でプロジェクトを作成したあと、

パッケージエクスプローラ内のプロジェクト名を右クリック → ビルド・パス → ビルド・パスの構成 → ライブラリーのタブを選択し、"外部Jar追加"ボタンを押下 → swt.jarを参照して開く

上記のような手順でswt.jarを追加することができます。

正しくswt.jarを読み込めている場合は、以下のクラスを実行するとタイトルバーに「Hello SWT」という文字が入ったウィンドウが立ち上がります。

適当にHelloSwtなどという名前をつけてクラスを保存して、実行してみてください。

package jp.linuxserver;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class HelloSwt {

        private Display display = new Display();
        private Shell shell = new Shell(display);

        public static void main(String[] args) {
                HelloSwt hello = new HelloSwt();
                hello.openWindow();
        }

        public HelloSwt() {
            shell.setText("Hello SWT");
            shell.setSize(1024, 768);
        }

        public void openWindow() {
            shell.open();
            while (!shell.isDisposed()) {
            	if (!display.readAndDispatch()) {
            		display.sleep();
            	}
            }
            display.dispose();
        }
}

メッセージループ

SWTアプリケーションには、表示中のウィンドウが残っていても、メインメソッドが終了すればプログラムも終了してしまうという特性があります。

したがって、ウィンドウの閉じるボタンが押下されるまで勝手にプログラムが終了しないように、イベントキューからメッセージを拾ってディスパッチするというループ処理が必要です。

上記のテストクラスではwhile文でループしている箇所がそれに相当します。

SWTのクラス

上記のテスト用クラスには様々なSWT固有のクラスが利用されていますが、それらの簡単な解説は以下のとおりです。

Displayクラス
プログラムが動いているOS固有のウィンドウシステムとの橋渡しを行い、そのOSが使っているイベントモデルをSWTのイベントループで処理できるようにするためのもの。

SWTアプリケーションではまずこの操作を最初に行う。

Shellクラス
引数にDisplayクラスのインスタンスを指定した場合はタイトルバーや最小化/最大化/閉じるボタンを持つトップレベルウィンドウとなる。

SWTアプリケーションではこのトップレベルウィンドウ内にウィジェットを配置していくことになる。

参考資料

Javaでの名前空間とパッケージ

名前空間について

名前空間とは?

名前空間とは、対象のものをある名称で確実に識別・特定するための概念です。

"対象のもの"というと非常に抽象的ですが、例えばJavaでのプログラミングにおいてクラス名や変数名などは重複しないように命名し、他と明確に区別しておく必要があります。

例えば、hogeというクラスがいくつもあった場合は、スクリプト中にhogeクラスの構文が書かれていてもコンピューターはどのhogeクラスを実行すればいいのか特定することはできません。

名前空間はこのようなクラス名の衝突を防ぐ役割を担います。

名前空間における名前集合の分割

名前空間では、名前の集合を分割することによって名前の衝突を防いでいます。

例えば、自分に「山田 太郎」さんという友人がいて、その人に手紙を送りたいと思ったとします。

その場合、手紙の宛名に「山田 太郎」とだけ書いて郵便局に持っていっても「山田 太郎」さんに手紙を送ることはできません。

なぜなら、日本全国には「山田 太郎」という名前の人がたくさんいるため、どの「山田 太郎」さんに手紙を届ければいいのか特定することができないからです。

この「山田 太郎」は「氏名」という名前の集合における名称です。

このように、「氏名」というある名前空間では対象のものを特定できない場合は、別の名前の集合を付け加えることで、名前の衝突を低減することができます。

例えば、「町名」という別の名前の集合も付け加えると「中央町に住んでいる山田太郎さん」とより特定が進みます。

同様に、「市区町村」や「都道府県」など大きな名前の集合を付け加えていくと、最終的に「○×県△□区中央町1-2-3に住んでいる山田太郎さん」という風に、最終的に必ず対象のものを特定することができるようになります。

名前空間という聞きなれない単語は一見難しそうに見えますが、普段から我々が日常生活で利用しているもののようです。

package構文について

パッケージとは?

Javaにおけるパッケージとは、クラスをまとめるためのものです。

作成したクラスは任意のパッケージに所属させることができます。

パッケージという名前空間でクラスを区別することによって、hogeパッケージのexampleクラス / hageパッケージのexampleクラスといったように同じ名前のクラス名を別の実体として対応付けることができます。

Javaではpackage構文を利用してパッケージの指定を行うことができます。

パッケージの命名規則

パッケージ名は組織のトップレベルドメイン名と、そのときの組織のドメインといくつかのサブドメインリストが逆順になったもので始まることが推奨されている。
http://ja.wikipedia.org/wiki/%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8_(Java)

と、上記引用文にもありますが、自分で作成したクラスにパッケージを指定する場合は、自分が保持しているドメインを利用すると名前空間の分割が行いやすいでしょう。

ドメイン名をパッケージに使用して組織内でクラス名を一意に保つようにすれば、重複の心配はなくなります。

package文は下記のように引数にパッケージ名を指定するだけで使用することができます。これをソースコードの冒頭に記述してパッケージの指定を行います。

package jp.linuxserver

import構文について

パッケージに所属しているクラスを使用する場合は、import構文を利用してパッケージ名を指定します。

例えば、ioパッケージ内すべてのクラスを使用するにはソースコードの冒頭で下記のように記述します。

import java.io.*;

なお、同じパッケージに属しているクラスはimport文を省略しても利用することができます。

Java で OS を判別する

Javaで実行中のOSを判別

以下のようにSystemクラスのgetPropertyクラスで取得できる。

public class echoOsName {
  public static void main(String[] args) {
    String osName = System.getProperty("os.name");
    System.out.println(osName);
  }
}


# javac echoOsName.java
# java echoOsName
Windows XP Windows XPで実行した場合

# java echoOsName
Linux Ubuntu 10.04で実行した場合

Java での MySQL 接続

本コンテンツはJava での MySQL 接続へ移動しました。

MySQL 用の JDBCドライバのインストール

JDBCドライバのダウンロード

Java から MySQL へ接続するには、"JDBCドライバ"というものが必要なようです。

JDBCドライバの役割についての解説は以下の通りです。

JDBCドライバとは、異なるデータベースに対するアクセスを行う際に、個々のデータベース毎にプログラムを書き換えなくていいように、データベースと Javaプログラムの間にあってデータベース毎の差を吸収してくれるものです。よってJDBCを使えばデータベースが異なってもJavaプログラムの方は変更を最小限にすることが可能です。逆にJDBCドライバはデータベース毎に用意する必要があります。

MySQL用のJDBCドライバはMySQLから提供されており「MySQL Connector/J」というものになります。

下記URLからダウンロードできます。

http://dev.mysql.com/downloads/

上記URLにアクセスし、画面を下にスクロールしていくと Connector/J というリンクがありますので、それをクリックするとダウンロードページに行けます。

なお、このJDBCドライバは、ドライバとは言ってはいるものの、普通のJavaライブラリのようです。

この記事を書いている2010年5月5日現在でのバージョンは 5.1.12 でした。

クラスパスの設定

ダウンロードしたアーカイブを解凍すると、"mysql-connector-java-5.1.12-bin.jar"というファイルがあります。MySQL接続スクリプト実行時には、このJARファイルにクラスパスを通して置く必要があるので、これを適当なディレクトリに保存し、クラスパスを通します。

クラスパスの通し方は以下の通りです。


Linux の場合
CLASSPATH=.:$JAVA_HOME/lib/mysql-connector-java-5.1.12-bin.jar
export CLASSPATH

Windows の場合
SET CLASSPATH=.;%JAVA_HOME%\lib\mysql-connector-java-5.1.12-bin.jar

複数指定する場合は、LinuxなどのUNIX系OSなら:(コロン)、Windowsの場合は;(セミコロン)で区切ります。

また、環境変数で設定されていない場合は、下記のようにjavaコマンドのオプションで指定することもできます。


# java -classpath './;./lib/mysql-connector-java-5.1.12-bin.jar' con2Mysql

JDBCドライバのロード

以下はJDBCドライバをロードできるか確認するための簡易スクリプトです。

適当なディレクトリに保存し、読み込みが成功した旨のメッセージが表示されたらJDBCドライバのロードは成功です。

public class chkLoadJdbc {
  public static void main(String[] args) {
        String msg = "";
        try {
          Class.forName("com.mysql.jdbc.Driver").newInstance();
          msg = "ドライバのロードに成功しました";
        } catch (ClassNotFoundException e){
          msg = "ドライバのロードに失敗しました";
        }
        System.out.println(msg);
    }
}


# javac chkLoadJdbc.java
# java -classpath './lib/mysql-connector-java-5.1.12-bin.jar:.' chkLoadJdbc
ドライバのロードに成功しました

MySQLへの接続

続いて、MySQLへ接続を行ってみます。

以下はMySQLに接続して任意のデータベースを選択し、テーブルからデータを取り出して出力するという簡単なスクリプトです。

なお、スクリプトで接続するホストはローカルホスト、データベース名はtestdb、テーブル構造は以下の通りとしていますので、適宜必要な値に置き換えてください。


mysql> desc test_table;

                                                                                                                    • +
Field Type Null Key Default Extra
                                                                                                                    • +
user_id int(11) YES NULL
user_name varchar(255) YES NULL
                                                                                                                    • +

2 rows in set (0.01 sec)

以下スクリプトです。

import java.sql.*;

public class con2Mysql {
  public static void main(String[] args) {
        String msg = "";
        try {
            // ドライバロード
            Class.forName("org.gjt.mm.mysql.Driver");

            // MySQLに接続
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost/testdb", "root", "hoge");

            // ステートメント生成
            Statement stmt = con.createStatement();

            // SQLを実行
            String sqlStr = "SELECT * FROM test_table";
            ResultSet rs = stmt.executeQuery(sqlStr);

            // 結果行をループ
            while(rs.next()){
                // レコードの値
                int id = rs.getInt("user_id");
                String name = rs.getString("user_name");

                //表示
                System.out.println(id + ":" + name);
            }

            // 接続を閉じる
            rs.close();
            stmt.close();
            con.close();
        }catch (ClassNotFoundException e){
            msg = "ドライバのロードに失敗しました";
            System.out.println(msg);
        }catch (Exception e){
            msg = "ドライバのロードに失敗しました";
            System.out.println(msg);
        }
    }
}


# javac con2Mysql.java
# java -classpath './lib/mysql-connector-java-5.1.12-bin.jar:.' con2Mysql
1 : hoge
2 : hage

スクリプト中のMySQL接続箇所の接続文字列のフォーマットは下記の通りです。


"jdbc:mysql://HOSTNAME/DBNAME", "ID", "PASS"
例 : "jdbc:mysql://localhost/testdb", "user1", "pass4user1"

java.lang.NoClassDefFoundError の解決方法

CLASSPATHの設定

javaコマンドでclassファイルを実行すると、以下のエラーが出る場合


# java HelloWorld
java.lang.NoClassDefFoundError: HelloWorld
Caused by: java.lang.ClassNotFoundException: HelloWorld
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: HelloWorld. Program will exit.
Exception in thread "main" %

これはクラスパスの設定が原因であると考えられます。

下記のようにカレントディレクトリをクラスパスとして指定すると実行できる場合があります。


# java -classpath ./ HelloWorld
HelloWorld

変数について

本コンテンツは変数とはへ移転しました。

変数とは?

変数とは、プログラムの中で利用するデータを保存しておく箱のようなものです。

変数の中に保存したデータは必要なときに取り出して利用したり、中身を入れ替えたりできます。

変数を利用するときは、変数を識別するための名前をつける必要があります。

また、変数に入れるデータの値に合わせてデータ型というものを設定する必要があります。

変数の命名

前述したとおり、変数を利用するときは変数の一意な名前(識別子)をつける必要があります。

変数名に利用できる文字

変数の名前に利用できる文字はあらかじめ決まっています。

以下は、Javaで変数に名前をつけるときの約束事です。

  • 変数名に利用できる文字は、半角英数字・_(アンダースコア)・$(ドル記号)・日本語
  • 先頭の文字を半角数字にすることはできません
  • Javaで利用されているキーワード(classやpublicなど)は利用できません
  • trueやfalse、nullなど、Javaに登録されているリテラルも変数名として利用することはできません

日本語の変数名は文字化けなどの問題を考慮して利用しないのが無難です。

publicやclassなどの語句はJavaであらかじめ意味のある語句として利用され、変数名にすることができません。これらのキーワードは予約語と呼ばれます。

よりよい変数名とは?

変数名が変数の性質を端的に表すようにネーミングされていると、あとからコードを見直す際に何かと便利です。

例えば、足のサイズを表す変数を命名する場合、変数名を s や size ではなく、 footSize という風に意味が一目でわかるように命名したほうがいいでしょう。

以下、書籍や他のWEBサイトでの変数命名規則で参考になったものを挙げてみます。

  • 変数名の重要な部分を先頭にし、修飾子は後ろにする
  • 短すぎず長すぎない適切な長さにする。一般的には8〜20字ぐらいがデバッグしやすい長さとされている


変数の宣言と初期化

変数を利用するために変数のデータ型と変数名を合わせて記述することを「変数の宣言」と呼びます。

また、変数を宣言した後、はじめて変数に値を代入することを「変数の初期化」と呼びます。

この「変数の初期化」は非常に重要な作業のひとつです。

変数はコンピュータのメモリに記憶されます。初期化されていない変数は値が不明で、メモリにどんなデータが入っているかがわかりません。コンピュータはこのようなあいまいなデータを処理することができないため、初期化されていない変数を使用するとコンパイルエラーが起きます。

従って、変数の初期化は必ず行う必要があります。