Java EEアプリをJava SEで起動する(Glassfish V3を埋め込む)

メールアドレスくださーいみたいなことをいきなりyone098氏にいわれたので教えると、「T2sampleコミットしてくださいね♪」と圧力がきたので少しネタを考える。


普通に考えてNetBeans用のシンプルな足し算程度を行うブランクプロジェクトに近いものを固めるのだろうと思ったあなた。それは正解です。NetBeansのデフォルトのプロジェクトはNetBeansといいつつ、antで全部設定してくれているので別にNetBeansに依存しているわけではないですし、手軽です。ビルドやテスト、実行、Javadoc生成など全部勝手にやってくれます。

でもそれだけじゃつまらないよね。



せっかくなので実行や動作確認が簡単なパッケージがほしいね。というわけでJavaSEのみでWebアプリが起動すればいいんじゃね?ということで探す。

普通に考えて一番簡単なのはSDLoader。ただ、Servlet API 2.3っぽい(?)のが非常に気になる。ライブラリを残したままだとTomcat等で怒られる。また、T2のサンプルはすでにSDLoaderで起動するようになっているのでインパクトも何も無い。


そうだ、せっかくなのでWebアプリどころかEJBCDIもぜんぶ動かしてしまえばいいんじゃないか?というのに気がついた。これならT2Framework 0.6.3でCDIの対応をできるようなのでそのテストにももってこいだ。EJBも注入できるしいろんなテストにいいのではないか。TomcatでもCDIは使えるが、いろいろと手順がめんどくさいし。


なーんだ簡単じゃないか。

というわけでGlassfishV3のEmbeddedモードを使う。これでmainからWEBアプリやEJBなどを起動できるのだ。


ダウンロードは以下の場所から。

WEBプロファイルとALLと2つある。WEBプロファイルは機能が少ない分ファイルサイズが小さい。

ファイルの拡張子を見てびびるかもしれない。

「jar」である。つまり、Glassfishを組み込んで起動する場合依存ライブラリがたったjar1つだけなのだ。すばらしい。


以下Webアプリを起動するコード。いろいろと追加し、修正、削除していったら結局サンプルコードとほとんど変わらないという落ちがついたが気にしない。インポート名すら省略してないのでこれが本当に全てだ。

package embedded;

import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.embedded.ContainerBuilder;
import org.glassfish.api.embedded.EmbeddedDeployer;
import org.glassfish.api.embedded.EmbeddedFileSystem;
import org.glassfish.api.embedded.LifecycleException;
import org.glassfish.api.embedded.Server;


public class EmbeddedServer {
    private static final String APPLICATION_NAME = "hogeApplication";
    private static final String CONTEXT = "hoge";
    private static final int PORT = 18080;

    private Server server;
    private EmbeddedDeployer deployer;
    private String fileName;


    public EmbeddedServer(String fileName) {
        this.fileName = fileName;
    }

    public void start() throws IOException, LifecycleException {
        System.out.println("サーバー起動開始…");
        Server.Builder serverBuilder = new Server.Builder("testBuilder");

        EmbeddedFileSystem.Builder fsBuilder = new EmbeddedFileSystem.Builder();
        EmbeddedFileSystem fs = fsBuilder.build();
        serverBuilder.embeddedFileSystem(fs);
        server = serverBuilder.build();

        ContainerBuilder containerBuilder = server.createConfig(ContainerBuilder.Type.web);
        server.addContainer(containerBuilder);
        containerBuilder.create(server);
        server.createPort(PORT);

        server.start();
        System.out.println("サーバー起動完了");
    }

    public void deploy() {
        System.out.println("デプロイ開始…");
        deployer = server.getDeployer();   
        DeployCommandParameters deployParams = new DeployCommandParameters();
        deployParams.name = APPLICATION_NAME;
        deployParams.contextroot = CONTEXT;

        File archive = new File(fileName);
        deployer.deploy(archive, deployParams);
        System.out.println("デプロイ完了");
    }

    public void undeploy() throws LifecycleException {
        System.out.println("アンデプロイ開始…");
        deployer.undeploy(APPLICATION_NAME, null);
        System.out.println("サーバー停止…");
        server.stop();
        System.out.println("サーバー停止完了");
    }
    public void browse(){
        try {
            Desktop.getDesktop().browse(new URI("http://localhost:" + PORT + "/" + CONTEXT + "/"));
        } catch (Exception ex) {
            Logger.getLogger(EmbeddedServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void main(String[] args) throws Exception {

        EmbeddedServer server = new EmbeddedServer("ほげproject\\build\\web");
//        EmbeddedServer server  = new EmbeddedServer("ほげproject\\dist\\ほげproject.war");
        server.start();

        server.deploy();

        server.browse();

        //入力があるまで待つ(出力ウインドウでリターンキーを押すと終了する)
        new BufferedReader(new InputStreamReader(System.in)).readLine();

        //これよばないとワークファイルが残ったままになる
        server.undeploy();
    }
}

ブラウザ起動はJavaSEの機能で立ち上げてある。

引数でディレクトリを渡しているところと直下にコメントしてあるがwarファイルを指定しているところがあるが、これはどちらでもいけるということ。ディレクトリデプロイとwarアーカイブデプロイどちらもいける。


これ普通にフル機能のアプリケーションサーバーが立ち上がってるので、たとえばJSP変更したら再起動せずとも反映される。

もともとGlassfish自体非常に軽くて、すぐ立ち上がるので組み込みを選ぶ意味も無いと思うが手軽に試せるのでそれもいいのかな。必要なファイルがひとつのjarのみというのは評価されてよいと思う。


とにかくJava EE 6の機能を試してほしい。ELでメソッドが使えるとか絶対に便利だって。


とりあえず0.6.3正式版が出たらサンプル上げまくる予定。NetBeansプロジェクトですぐに開けるように。Eclipseも3.4くらいならなんとか動かせるようなのは用意できるかな。需要が無いかもしれないがCDIスタンドアロンで簡単に試せるのは魅力かなーとか。