OSDN Git Service

flattened boot logging.
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / JindolfJre18.java
1 /*
2  * Jindolf main class
3  *
4  * License : The MIT License
5  * Copyright(c) 2012 olyutorskii
6  */
7
8 package jp.sfjp.jindolf;
9
10 import java.awt.Frame;
11 import java.awt.GraphicsEnvironment;
12 import java.io.PrintStream;
13 import java.text.MessageFormat;
14 import java.util.concurrent.atomic.AtomicBoolean;
15 import javax.swing.JOptionPane;
16
17 /**
18  * JRE1.8の利用が解禁されたJindolfエントリ。
19  *
20  * <p>起動クラスJindolfの下請けとしての機能が想定される。
21  *
22  * <p>必ずしも必要ないが、異常系切り分けに有用な、
23  * 実行環境やビルドの成否に関する各種診断を行う。
24  *
25  * <p>各種診断を通過した後、JindolfMainに制御を渡す。
26  */
27 public final class JindolfJre18 {
28
29     /** GUI環境に接続できないときの終了コード。 */
30     public static final int EXIT_CODE_HEADLESS = 1;
31     /** アプリのビルド工程の不備を自動検出した時の終了コード。 */
32     public static final int EXIT_CODE_BUILDMISS = 1;
33     /** VM内多重起動を自動検出した時の終了コード。 */
34     public static final int EXIT_CODE_INVOKEDBL = 1;
35
36     private static final PrintStream STDERR = System.err;
37
38     private static final String ERRMSG_GUISESS =
39             "ERROR : GUI session failed.";
40     private static final String ERRMSG_DISPLAY =
41             "{0}\nEnvironment: DISPLAY [{1}]";
42
43     private static final String TITLE_SRCENC = "Build failed";
44     private static final String ERRMSG_SRCENC =
45               "ERROR : Invalid source-code encoding detected.\n"
46             + "Let's check encoding with compiler & source-file.";
47
48     private static final String TITLE_PKGERR = "ビルドエラー";
49     private static final String ERRMSG_PKG =
50             "パッケージ定義と{0}が一致しません。[{1}]≠[{2}]";
51
52     private static final String TITLE_INVOKEDBL = "多重起動";
53     private static final String ERRMSG_INVOKEDBL =
54             "ERROR : 二度目以降の起動がキャンセルされました。";
55
56     private static final char[][] ENCODING_TEST = {
57         {'狼', 0x72fc},
58         {' ', 0x3000},  // 全角スペース
59         {'\\', 0x005c},  // バックスラッシュ
60         {'¥',  0x00a5},  // 半角円通貨
61         {'~',  0x007e},  // チルダ
62         {'~', 0xff5e},  // 全角チルダ
63         {'〜', 0x301c},  // 波ダッシュ
64         {'�', 0xfffd},  // Unicode専用特殊文字
65     };
66
67     /** 多重起動防止用セマフォ。 */
68     private static final AtomicBoolean INVOKE_FLAG =
69             new AtomicBoolean(false);
70
71
72     /**
73      * 隠しコンストラクタ。
74      */
75     private JindolfJre18(){
76         assert false;
77     }
78
79
80     /**
81      * GUI環境の有無をチェックする。
82      * GUI環境に接続できなければJVMを終了させる。
83      * @return 成功すれば0。失敗したら0以外。
84      */
85     private static int proveGuiEnv(){
86         if( ! GraphicsEnvironment.isHeadless() ) return 0;
87
88         String errMsg = ERRMSG_GUISESS;
89
90         String dispEnv;
91         try{
92             dispEnv = System.getenv("DISPLAY"); // for X11
93         }catch(SecurityException e){
94             dispEnv = null;
95         }
96
97         if(dispEnv != null){
98             errMsg = MessageFormat.format(ERRMSG_DISPLAY, errMsg, dispEnv);
99         }
100
101         STDERR.println(errMsg);
102         STDERR.flush();
103
104         return EXIT_CODE_HEADLESS;
105     }
106
107     /**
108      * エラーダイアログの出力。
109      * @param errmsg エラーメッセージ
110      * @param title タイトル
111      */
112     private static void showErrorDialog(String errmsg, String title){
113         Frame parent = null;
114         JOptionPane.showMessageDialog(parent,
115                                       errmsg,
116                                       title,
117                                       JOptionPane.ERROR_MESSAGE);
118         return;
119     }
120
121     /**
122      * ビルド時のエンコーディングミスを判定する。
123      *
124      * <p>※ 非Unicode系の開発環境を使いたい人は適当に無視してね。
125      *
126      * @return 成功すれば0。失敗したら0以外。
127      */
128     private static int checkSourceEncoding(){
129         boolean pass = true;
130         for(char[] pair : ENCODING_TEST){
131             char compiled = pair[0];
132             char expected = pair[1];
133             if(compiled != expected){
134                 pass = false;
135                 break;
136             }
137         }
138         if(pass) return 0;
139
140         String errmsg = ERRMSG_SRCENC;
141
142         showErrorDialog(errmsg, TITLE_SRCENC);
143
144         return EXIT_CODE_BUILDMISS;
145     }
146
147     /**
148      * MANIFEST.MFパッケージ定義エラーの検出。
149      * @return 成功すれば0。失敗したら0以外。
150      */
151     private static int checkPackageDefinition(){
152         Package rootPkg = ResourceManager.DEF_ROOT_PACKAGE;
153         String implTitle   = rootPkg.getImplementationTitle();
154         String implVersion = rootPkg.getImplementationVersion();
155         String implVendor  = rootPkg.getImplementationVendor();
156
157         String title = TITLE_PKGERR;
158
159         if(implTitle != null && ! VerInfo.TITLE.equals(implTitle) ){
160             String errmsg = MessageFormat.format(
161                     ERRMSG_PKG, "タイトル", implTitle, VerInfo.TITLE );
162             showErrorDialog(errmsg, title);
163             return EXIT_CODE_BUILDMISS;
164         }
165
166         if(implVersion != null && ! VerInfo.VERSION.equals(implVersion)  ){
167             String errmsg = MessageFormat.format(
168                     ERRMSG_PKG,
169                     "バージョン番号", implVersion, VerInfo.VERSION );
170             showErrorDialog(errmsg, title);
171             return EXIT_CODE_BUILDMISS;
172         }
173
174         if(implVendor != null && ! VerInfo.AUTHOR.equals(implVendor) ){
175             String errmsg = MessageFormat.format(
176                     ERRMSG_PKG, "ベンダ", implVendor, VerInfo.AUTHOR );
177             showErrorDialog(errmsg, title);
178             return EXIT_CODE_BUILDMISS;
179         }
180
181         return 0;
182     }
183
184     /**
185      * JVM内で多重起動していないかチェックする。
186      *
187      * <p>多重起動を確認した場合は、GUIにダイアログを出力する。
188      *
189      * @return 成功すれば0。失敗したら0以外。
190      */
191     private static int checkHasInvoked(){
192         boolean successed = INVOKE_FLAG.compareAndSet(false, true);
193         if(successed) return 0;
194
195         showErrorDialog(ERRMSG_INVOKEDBL, TITLE_INVOKEDBL);
196
197         return EXIT_CODE_INVOKEDBL;
198     }
199
200     /**
201      * Jindolf のスタートアップエントリ。
202      *
203      * <p>ここからJRE1.8の利用が解禁される。
204      *
205      * <p>最終的に{@link JindolfMain}へ制御が渡される。
206      *
207      * @param args コマンドライン引数
208      * @return 起動に成功すれば0。失敗したら0以外。
209      */
210     public static int main(String... args){
211         int exitCode;
212
213         exitCode = proveGuiEnv();
214         if(exitCode != 0) return exitCode;
215         // ここから異常系でのみSwingGUI解禁
216
217         exitCode = checkSourceEncoding();
218         if(exitCode != 0) return exitCode;
219         // ここから日本語を含むUnicode出力解禁。
220
221         exitCode = checkPackageDefinition();
222         if(exitCode != 0) return exitCode;
223
224         exitCode = checkHasInvoked();
225         if(exitCode != 0) return exitCode;
226
227         exitCode = JindolfMain.main(args);
228
229         return exitCode;
230     }
231
232 }