OSDN Git Service

Merge branch 'Branch_release-'
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / JindolfJre17.java
diff --git a/src/main/java/jp/sfjp/jindolf/JindolfJre17.java b/src/main/java/jp/sfjp/jindolf/JindolfJre17.java
new file mode 100644 (file)
index 0000000..bf12492
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Jindolf main class
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.io.PrintStream;
+import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.swing.JOptionPane;
+
+/**
+ * JRE1.7の利用が解禁されたJindolfエントリ。
+ *
+ * <p>起動クラスJindolfの下請けとしての機能が想定される。
+ *
+ * <p>必ずしも必要ないが、異常系切り分けに有用な、
+ * 実行環境やビルドの成否に関する各種診断を行う。
+ *
+ * <p>各種診断を通過した後、JindolfMainに制御を渡す。
+ */
+public final class JindolfJre17 {
+
+    /** GUI環境に接続できないときの終了コード。 */
+    public static final int EXIT_CODE_HEADLESS = 1;
+    /** アプリのビルド工程の不備を自動検出した時の終了コード。 */
+    public static final int EXIT_CODE_BUILDMISS = 1;
+    /** VM内多重起動を自動検出した時の終了コード。 */
+    public static final int EXIT_CODE_INVOKEDBL = 1;
+
+    private static final PrintStream STDERR = System.err;
+
+    private static final String ERRMSG_GUISESS =
+            "ERROR : GUI session failed.";
+    private static final String ERRMSG_DISPLAY =
+            "{0}\nEnvironment: DISPLAY [{1}]";
+
+    private static final String TITLE_SRCENC = "Build failed";
+    private static final String ERRMSG_SRCENC =
+              "ERROR : Invalid source-code encoding detected.\n"
+            + "Let's check encoding with compiler & source-file.";
+
+    private static final String TITLE_PKGERR = "ビルドエラー";
+    private static final String ERRMSG_PKG =
+            "パッケージ定義と{0}が一致しません。[{1}]≠[{2}]";
+
+    private static final String TITLE_INVOKEDBL = "多重起動";
+    private static final String ERRMSG_INVOKEDBL =
+            "ERROR : 二度目以降の起動がキャンセルされました。";
+
+    private static final char[][] ENCODING_TEST = {
+        {'狼', 0x72fc},
+        {' ', 0x3000},  // 全角スペース
+        {'\\', 0x005c},  // バックスラッシュ
+        {'¥',  0x00a5},  // 半角円通貨
+        {'~',  0x007e},  // チルダ
+        {'~', 0xff5e},  // 全角チルダ
+        {'〜', 0x301c},  // 波ダッシュ
+        {'�', 0xfffd},  // Unicode専用特殊文字
+    };
+
+    /** 多重起動防止用セマフォ。 */
+    private static final AtomicBoolean INVOKE_FLAG =
+            new AtomicBoolean(false);
+
+
+    /**
+     * 隠しコンストラクタ。
+     */
+    private JindolfJre17(){
+        assert false;
+    }
+
+
+    /**
+     * GUI環境の有無をチェックする。
+     * GUI環境に接続できなければJVMを終了させる。
+     * @return 成功すれば0。失敗したら0以外。
+     */
+    private static int proveGuiEnv(){
+        if( ! GraphicsEnvironment.isHeadless() ) return 0;
+
+        String errMsg = ERRMSG_GUISESS;
+
+        String dispEnv;
+        try{
+            dispEnv = System.getenv("DISPLAY"); // for X11
+        }catch(SecurityException e){
+            dispEnv = null;
+        }
+
+        if(dispEnv != null){
+            errMsg = MessageFormat.format(ERRMSG_DISPLAY, errMsg, dispEnv);
+        }
+
+        STDERR.println(errMsg);
+        STDERR.flush();
+
+        return EXIT_CODE_HEADLESS;
+    }
+
+    /**
+     * エラーダイアログの出力。
+     * @param errmsg エラーメッセージ
+     * @param title タイトル
+     */
+    private static void showErrorDialog(String errmsg, String title){
+        Frame parent = null;
+        JOptionPane.showMessageDialog(parent,
+                                      errmsg,
+                                      title,
+                                      JOptionPane.ERROR_MESSAGE);
+        return;
+    }
+
+    /**
+     * ビルド時のエンコーディングミスを判定する。
+     *
+     * <p>※ 非Unicode系の開発環境を使いたい人は適当に無視してね。
+     *
+     * @return 成功すれば0。失敗したら0以外。
+     */
+    private static int checkSourceEncoding(){
+        boolean pass = true;
+        for(char[] pair : ENCODING_TEST){
+            char compiled = pair[0];
+            char expected = pair[1];
+            if(compiled != expected){
+                pass = false;
+                break;
+            }
+        }
+        if(pass) return 0;
+
+        String errmsg = ERRMSG_SRCENC;
+
+        showErrorDialog(errmsg, TITLE_SRCENC);
+
+        return EXIT_CODE_BUILDMISS;
+    }
+
+    /**
+     * MANIFEST.MFパッケージ定義エラーの検出。
+     * @return 成功すれば0。失敗したら0以外。
+     */
+    private static int checkPackageDefinition(){
+        Package rootPkg = ResourceManager.DEF_ROOT_PACKAGE;
+        String implTitle   = rootPkg.getImplementationTitle();
+        String implVersion = rootPkg.getImplementationVersion();
+        String implVendor  = rootPkg.getImplementationVendor();
+
+        String title = TITLE_PKGERR;
+
+        if(implTitle != null && ! VerInfo.TITLE.equals(implTitle) ){
+            String errmsg = MessageFormat.format(
+                    ERRMSG_PKG, "タイトル", implTitle, VerInfo.TITLE );
+            showErrorDialog(errmsg, title);
+            return EXIT_CODE_BUILDMISS;
+        }
+
+        if(implVersion != null && ! VerInfo.VERSION.equals(implVersion)  ){
+            String errmsg = MessageFormat.format(
+                    ERRMSG_PKG,
+                    "バージョン番号", implVersion, VerInfo.VERSION );
+            showErrorDialog(errmsg, title);
+            return EXIT_CODE_BUILDMISS;
+        }
+
+        if(implVendor != null && ! VerInfo.AUTHOR.equals(implVendor) ){
+            String errmsg = MessageFormat.format(
+                    ERRMSG_PKG, "ベンダ", implVendor, VerInfo.AUTHOR );
+            showErrorDialog(errmsg, title);
+            return EXIT_CODE_BUILDMISS;
+        }
+
+        return 0;
+    }
+
+    /**
+     * JVM内で多重起動していないかチェックする。
+     *
+     * <p>多重起動を確認した場合は、GUIにダイアログを出力する。
+     *
+     * @return 成功すれば0。失敗したら0以外。
+     */
+    private static int checkHasInvoked(){
+        boolean successed = INVOKE_FLAG.compareAndSet(false, true);
+        if(successed) return 0;
+
+        showErrorDialog(ERRMSG_INVOKEDBL, TITLE_INVOKEDBL);
+
+        return EXIT_CODE_INVOKEDBL;
+    }
+
+    /**
+     * Jindolf のスタートアップエントリ。
+     *
+     * <p>ここからJRE1.7の利用が解禁される。
+     *
+     * <p>最終的に{@link JindolfMain}へ制御が渡される。
+     *
+     * @param args コマンドライン引数
+     * @return 起動に成功すれば0。失敗したら0以外。
+     */
+    public static int main(String... args){
+        int exitCode;
+
+        exitCode = proveGuiEnv();
+        if(exitCode != 0) return exitCode;
+        // ここから異常系でのみSwingGUI解禁
+
+        exitCode = checkSourceEncoding();
+        if(exitCode != 0) return exitCode;
+        // ここから日本語を含むUnicode出力解禁。
+
+        exitCode = checkPackageDefinition();
+        if(exitCode != 0) return exitCode;
+
+        exitCode = checkHasInvoked();
+        if(exitCode != 0) return exitCode;
+
+        exitCode = JindolfMain.main(args);
+
+        return exitCode;
+    }
+
+}