4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sfjp.jindolf;
10 import java.awt.Dimension;
11 import java.awt.EventQueue;
12 import java.awt.Window;
13 import java.io.PrintStream;
14 import java.lang.reflect.InvocationTargetException;
15 import java.text.MessageFormat;
16 import java.util.logging.Level;
17 import java.util.logging.Logger;
18 import javax.swing.ImageIcon;
19 import javax.swing.JFrame;
20 import javax.swing.JLabel;
21 import javax.swing.JWindow;
22 import javax.swing.UIManager;
23 import jp.sfjp.jindolf.config.AppSetting;
24 import jp.sfjp.jindolf.config.CmdOption;
25 import jp.sfjp.jindolf.config.ConfigStore;
26 import jp.sfjp.jindolf.config.EnvInfo;
27 import jp.sfjp.jindolf.config.OptionInfo;
28 import jp.sfjp.jindolf.data.LandsModel;
29 import jp.sfjp.jindolf.log.LogUtils;
30 import jp.sfjp.jindolf.log.LoggingDispatcher;
31 import jp.sfjp.jindolf.util.GUIUtils;
32 import jp.sfjp.jindolf.view.ActionManager;
33 import jp.sfjp.jindolf.view.WindowManager;
38 * <p>{@link JindolfJre17}の下請けとして本格的なJindolf起動処理に入る。
40 public final class JindolfMain {
42 /** クラスロード時のナノカウント。 */
43 public static final long NANOCT_LOADED;
44 /** クラスロード時刻(エポックmsec)。 */
45 public static final long EPOCHMS_LOADED;
49 private static final Logger LOGGER = Logger.getAnonymousLogger();
52 private static final String RES_LOGOICON =
53 "resources/image/logo.png";
55 private static final String LOG_LOADED =
56 "{0} は {1,date} {2,time} に"
57 + "VM上のクラス {3} としてロードされました。 ";
58 private static final String LOG_NANOCT =
59 "Initial Nano-Count : {0}";
60 private static final String LOG_HEAP =
61 "Max-heap : {0} Bytes Total-heap : {1} Bytes";
62 private static final String LOG_CONF =
63 "設定格納ディレクトリに[ {0} ]が指定されました。";
64 private static final String LOG_NOCONF =
66 private static final String WARNMSG_SPLASH =
67 "JRE1.6以降では、Jindolfの-nosplashオプションは無効です。"
68 + "Java実行系の方でスプラッシュ画面の非表示を"
69 + "指示してください(おそらく空の-splash:オプション)";
70 private static final String FATALMSG_INITFAIL =
72 private static final String ERRMSG_HELP =
74 + "起動オプションに「{0}」を指定すると確認できます。";
76 private static final PrintStream STDOUT = System.out;
77 private static final PrintStream STDERR = System.err;
80 NANOCT_LOADED = System.nanoTime();
81 EPOCHMS_LOADED = System.currentTimeMillis();
88 private JindolfMain(){
94 * 標準出力および標準エラー出力をフラッシュする。
96 private static void flush(){
103 * 標準出力端末にヘルプメッセージ(オプションの説明)を表示する。
105 private static void showHelpMessage(){
108 String helpText = CmdOption.getHelpText();
109 STDOUT.print(helpText);
119 * <p>JRE1.6以降では何も表示しない。
121 * @return スプラッシュウィンドウ。JRE1.6以降ならnullを返す。
123 @SuppressWarnings("CallToThreadYield")
124 private static Window showSplash(){
125 if(JreChecker.has16Runtime()) return null;
127 Window splashWindow = new JWindow();
129 ImageIcon logo = ResourceManager.getImageIcon(RES_LOGOICON);
130 JLabel splashLabel = new JLabel(logo);
131 splashWindow.add(splashLabel);
134 splashWindow.setLocationRelativeTo(null); // locate center
135 splashWindow.setVisible(true);
144 * @param splashWindow スプラッシュウィンドウ。nullならなにもしない。
146 private static void hideSplash(final Window splashWindow){
147 if(splashWindow == null) return;
149 EventQueue.invokeLater(new Runnable(){
153 splashWindow.setVisible(false);
154 splashWindow.dispose();
164 * @param appSetting アプリ設定
166 private static void dumpBootInfo(AppSetting appSetting){
169 logArgs = new Object[]{
173 Jindolf.class.getName(),
175 LOGGER.log(Level.INFO, LOG_LOADED, logArgs);
177 LOGGER.log(Level.INFO, LOG_NANOCT, NANOCT_LOADED);
179 Runtime runtime = Runtime.getRuntime();
180 logArgs = new Object[]{
182 runtime.totalMemory(),
184 LOGGER.log(Level.INFO, LOG_HEAP, logArgs);
186 OptionInfo optinfo = appSetting.getOptionInfo();
187 StringBuilder bootArgs = new StringBuilder();
188 bootArgs.append("\n\n").append("起動時引数:\n");
189 for(String arg : optinfo.getInvokeArgList()){
190 bootArgs.append("\u0020\u0020").append(arg).append('\n');
192 bootArgs.append('\n');
193 bootArgs.append(EnvInfo.getVMInfo());
194 LOGGER.info(bootArgs.toString());
196 ConfigStore configStore = appSetting.getConfigStore();
197 if(configStore.useStoreFile()){
198 LOGGER.log(Level.INFO, LOG_CONF, configStore.getConfigPath());
200 LOGGER.info(LOG_NOCONF);
203 if( JreChecker.has16Runtime()
204 && optinfo.hasOption(CmdOption.OPT_NOSPLASH) ){
205 LOGGER.warning(WARNMSG_SPLASH);
212 * JindolfMain のスタートアップエントリ。
213 * @param args コマンドライン引数
214 * @return 起動に成功すれば0。失敗したら0以外。
216 public static int main(String... args){
221 optinfo = OptionInfo.parseOptions(args);
222 }catch(IllegalArgumentException e){
223 String message = e.getLocalizedMessage();
224 STDERR.println(message);
227 MessageFormat.format(ERRMSG_HELP, CmdOption.OPT_HELP);
228 STDERR.println(info);
234 exitCode = main(optinfo);
240 * JindolfMain のスタートアップエントリ。
241 * @param optinfo コマンドライン引数情報
242 * @return 起動に成功すれば0。失敗したら0以外。
244 public static int main(OptionInfo optinfo){
247 if(optinfo.hasOption(CmdOption.OPT_HELP)){
253 if(optinfo.hasOption(CmdOption.OPT_VERSION)){
254 STDOUT.println(VerInfo.ID);
259 // ここ以降、アプリウィンドウの生成と表示に向けてまっしぐら。
261 // あらゆるSwing文字列表示処理より前に必要。
262 // システムプロパティ swing.boldMetal は無視される。
264 if(optinfo.hasOption(CmdOption.OPT_BOLDMETAL)){
265 // もの凄く日本語表示が汚くなるかもよ!注意
266 boldFlag = Boolean.TRUE;
268 boldFlag = Boolean.FALSE;
270 UIManager.put("swing.boldMetal", boldFlag);
272 // JRE1.5用スプラッシュウィンドウ。だけどもういらん。
273 Window splashWindow = null;
274 if( ! optinfo.hasOption(CmdOption.OPT_NOSPLASH) ){
275 splashWindow = showSplash();
279 exitCode = splashedMain(optinfo);
281 hideSplash(splashWindow);
288 * JindolfMain のスタートアップエントリ。
290 * <p>スプラッシュウィンドウが出ている状態。
291 * 時間のかかる初期化処理はなるべくこの中へ。
293 * @param optinfo コマンドライン引数情報
294 * @return 起動に成功すれば0。失敗したら0以外。
296 public static int splashedMain(OptionInfo optinfo){
297 if(optinfo.hasOption(CmdOption.OPT_VMINFO)){
298 STDOUT.println(EnvInfo.getVMInfo());
301 LogUtils.initRootLogger(optinfo.hasOption(CmdOption.OPT_CONSOLELOG));
304 final AppSetting appSetting = new AppSetting(optinfo);
305 dumpBootInfo(appSetting);
307 ConfigStore configStore = appSetting.getConfigStore();
308 configStore.prepareConfigDir();
309 configStore.tryLock();
312 appSetting.loadConfig();
314 final Runtime runtime = Runtime.getRuntime();
315 runtime.addShutdownHook(new Thread(){
318 @SuppressWarnings("CallToThreadYield")
320 LOGGER.info("シャットダウン処理に入ります…");
324 runtime.runFinalization(); // 危険?
330 LoggingDispatcher.replaceEventQueue();
334 EventQueue.invokeAndWait(new Runnable(){
338 startGUI(appSetting);
342 }catch(InvocationTargetException e){
343 LOGGER.log(Level.SEVERE, FATALMSG_INITFAIL, e);
344 e.printStackTrace(STDERR);
346 }catch(InterruptedException e){
347 LOGGER.log(Level.SEVERE, FATALMSG_INITFAIL, e);
348 e.printStackTrace(STDERR);
356 * AWTイベントディスパッチスレッド版スタートアップエントリ。
357 * @param appSetting アプリ設定
359 private static void startGUI(AppSetting appSetting){
360 JFrame topFrame = buildMVC(appSetting);
362 GUIUtils.modifyWindowAttributes(topFrame, true, false, true);
366 Dimension initGeometry =
367 new Dimension(appSetting.initialFrameWidth(),
368 appSetting.initialFrameHeight());
369 topFrame.setSize(initGeometry);
371 if( appSetting.initialFrameXpos() <= Integer.MIN_VALUE
372 || appSetting.initialFrameYpos() <= Integer.MIN_VALUE ){
373 topFrame.setLocationByPlatform(true);
375 topFrame.setLocation(appSetting.initialFrameXpos(),
376 appSetting.initialFrameYpos() );
379 topFrame.setVisible(true);
386 * @param appSetting アプリ設定
387 * @return アプリケーションのトップフレーム
389 private static JFrame buildMVC(AppSetting appSetting){
390 LandsModel model = new LandsModel();
391 WindowManager windowManager = new WindowManager();
392 ActionManager actionManager = new ActionManager();
394 model.loadLandList();
396 Controller controller = new Controller(model,
401 JFrame topFrame = controller.getTopFrame();