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.io.PrintStream;
13 import java.lang.reflect.InvocationTargetException;
14 import java.text.MessageFormat;
15 import java.util.Locale;
16 import java.util.logging.Level;
17 import java.util.logging.Logger;
18 import javax.swing.JFrame;
19 import javax.swing.UIManager;
20 import jp.sfjp.jindolf.config.AppSetting;
21 import jp.sfjp.jindolf.config.CmdOption;
22 import jp.sfjp.jindolf.config.ConfigDirUi;
23 import jp.sfjp.jindolf.config.ConfigStore;
24 import jp.sfjp.jindolf.config.EnvInfo;
25 import jp.sfjp.jindolf.config.FileUtils;
26 import jp.sfjp.jindolf.config.OptionInfo;
27 import jp.sfjp.jindolf.data.LandsTreeModel;
28 import jp.sfjp.jindolf.log.LogUtils;
29 import jp.sfjp.jindolf.log.LoggingDispatcher;
30 import jp.sfjp.jindolf.util.GUIUtils;
31 import jp.sfjp.jindolf.view.ActionManager;
32 import jp.sfjp.jindolf.view.WindowManager;
37 * <p>{@link JindolfJre18}の下請けとして本格的なJindolf起動処理に入る。
39 public final class JindolfMain {
41 /** クラスロード時のナノカウント。 */
42 public static final long NANOCT_LOADED;
43 /** クラスロード時刻(エポックmsec)。 */
44 public static final long EPOCHMS_LOADED;
48 private static final Logger LOGGER = Logger.getAnonymousLogger();
50 private static final String LOG_LOADED =
51 "{0} は {1,date} {2,time} に"
52 + "VM上のクラス {3} としてロードされました。 ";
53 private static final String LOG_NANOCT =
54 "Initial Nano-Count : {0}";
55 private static final String LOG_HEAP =
56 "Max-heap : {0} Bytes Total-heap : {1} Bytes";
57 private static final String LOG_CONF =
58 "設定格納ディレクトリに[ {0} ]が指定されました。";
59 private static final String LOG_NOCONF =
61 private static final String FATALMSG_INITFAIL =
63 private static final String ERRMSG_HELP =
65 + "起動オプションに「{0}」を指定すると確認できます。";
67 private static final PrintStream STDOUT = System.out;
68 private static final PrintStream STDERR = System.err;
71 NANOCT_LOADED = System.nanoTime();
72 EPOCHMS_LOADED = System.currentTimeMillis();
79 private JindolfMain(){
85 * 標準出力および標準エラー出力をフラッシュする。
87 private static void flush(){
94 * 標準出力端末にヘルプメッセージ(オプションの説明)を表示する。
96 private static void showHelpMessage(){
99 String helpText = CmdOption.getHelpText();
100 STDOUT.print(helpText);
110 private static void logBootInfo(){
113 logArgs = new Object[]{
117 Jindolf.class.getName(),
119 LOGGER.log(Level.INFO, LOG_LOADED, logArgs);
121 LOGGER.log(Level.INFO, LOG_NANOCT, NANOCT_LOADED);
123 Runtime runtime = Runtime.getRuntime();
124 logArgs = new Object[]{
126 runtime.totalMemory(),
128 LOGGER.log(Level.INFO, LOG_HEAP, logArgs);
130 if(FileUtils.isWindowsOSFs()){
131 LOGGER.info("Windows環境と認識されました。");
134 if(FileUtils.isMacOSXFs()){
135 LOGGER.info("macOS環境と認識されました。");
138 Locale locale = Locale.getDefault();
139 String localeTxt = locale.toString();
140 LOGGER.log(Level.INFO, "ロケールに{0}が用いられます。", localeTxt);
148 * @param optinfo コマンドラインオプション
150 private static void logBootInfo(OptionInfo optinfo){
151 StringBuilder bootArgs = new StringBuilder();
153 bootArgs.append("\n\n").append("起動時引数:\n");
154 optinfo.getInvokeArgList().forEach(arg ->
155 bootArgs.append("\u0020\u0020").append(arg).append('\n')
157 bootArgs.append('\n');
159 bootArgs.append(EnvInfo.getVMInfo());
161 LOGGER.info(bootArgs.toString());
169 * @param configStore 設定ディレクトリ情報
171 private static void logBootInfo(ConfigStore configStore){
172 if(configStore.useStoreFile()){
173 LOGGER.log(Level.INFO, LOG_CONF, configStore.getConfigDir());
175 LOGGER.info(LOG_NOCONF);
181 * JindolfMain のスタートアップエントリ。
182 * @param args コマンドライン引数
183 * @return 起動に成功すれば0。失敗したら0以外。
185 public static int main(String... args){
190 optinfo = OptionInfo.parseOptions(args);
191 }catch(IllegalArgumentException e){
192 String message = e.getLocalizedMessage();
193 STDERR.println(message);
196 MessageFormat.format(ERRMSG_HELP, CmdOption.OPT_HELP);
197 STDERR.println(info);
203 exitCode = main(optinfo);
209 * JindolfMain のスタートアップエントリ。
210 * @param optinfo コマンドライン引数情報
211 * @return 起動に成功すれば0。失敗したら0以外。
213 public static int main(OptionInfo optinfo){
216 if(optinfo.hasOption(CmdOption.OPT_HELP)){
222 if(optinfo.hasOption(CmdOption.OPT_VERSION)){
223 STDOUT.println(VerInfo.ID);
228 // ここ以降、アプリウィンドウの生成と表示に向けてまっしぐら。
230 // あらゆるSwing文字列表示処理より前に必要。
231 // システムプロパティ swing.boldMetal は無視される。
233 if(optinfo.hasOption(CmdOption.OPT_BOLDMETAL)){
234 // もの凄く日本語表示が汚くなるかもよ!注意
235 boldFlag = Boolean.TRUE;
237 boldFlag = Boolean.FALSE;
239 UIManager.put("swing.boldMetal", boldFlag);
241 exitCode = splashedMain(optinfo);
247 * JindolfMain のスタートアップエントリ。
250 * スプラッシュウィンドウが出ている状態として想定されていた。
251 * 時間のかかる初期化処理はなるべくこの中へ。
253 * @param optinfo コマンドライン引数情報
254 * @return 起動に成功すれば0。失敗したら0以外。
256 public static int splashedMain(OptionInfo optinfo){
257 if(optinfo.hasOption(CmdOption.OPT_VMINFO)){
258 STDOUT.println(EnvInfo.getVMInfo());
261 LogUtils.initRootLogger(optinfo.hasOption(CmdOption.OPT_CONSOLELOG));
265 logBootInfo(optinfo);
267 final AppSetting appSetting = new AppSetting(optinfo);
268 ConfigStore configStore = appSetting.getConfigStore();
269 logBootInfo(configStore);
271 ConfigDirUi.prepareConfigDir(configStore);
272 ConfigDirUi.tryLock(configStore);
275 appSetting.loadConfig();
277 final Runtime runtime = Runtime.getRuntime();
278 runtime.addShutdownHook(new Thread(){
281 @SuppressWarnings("CallToThreadYield")
283 LOGGER.info("シャットダウン処理に入ります…");
287 runtime.runFinalization(); // 危険?
293 LoggingDispatcher.replaceEventQueue();
297 EventQueue.invokeAndWait(() ->
300 }catch(InvocationTargetException | InterruptedException e){
301 LOGGER.log(Level.SEVERE, FATALMSG_INITFAIL, e);
302 e.printStackTrace(STDERR);
310 * AWTイベントディスパッチスレッド版スタートアップエントリ。
311 * @param appSetting アプリ設定
313 private static void startGUI(AppSetting appSetting){
314 JFrame topFrame = buildMVC(appSetting);
316 GUIUtils.modifyWindowAttributes(topFrame, true, false, true);
320 Dimension initGeometry =
321 new Dimension(appSetting.initialFrameWidth(),
322 appSetting.initialFrameHeight());
323 topFrame.setSize(initGeometry);
325 if( appSetting.initialFrameXpos() <= Integer.MIN_VALUE
326 || appSetting.initialFrameYpos() <= Integer.MIN_VALUE ){
327 topFrame.setLocationByPlatform(true);
329 topFrame.setLocation(appSetting.initialFrameXpos(),
330 appSetting.initialFrameYpos() );
333 topFrame.setVisible(true);
340 * @param appSetting アプリ設定
341 * @return アプリケーションのトップフレーム
343 private static JFrame buildMVC(AppSetting appSetting){
344 LandsTreeModel model = new LandsTreeModel();
345 WindowManager windowManager = new WindowManager();
346 ActionManager actionManager = new ActionManager();
348 Controller controller = new Controller(model,
353 JFrame topFrame = controller.getTopFrame();