OSDN Git Service

ログおよび作業状態ファイルをAPPDATAフォルダがLOCALAPPDATAフォルダに移動。
authorseraphy <seraphy@users.osdn.me>
Fri, 7 Dec 2018 14:19:41 +0000 (23:19 +0900)
committerseraphy <seraphy@users.osdn.me>
Fri, 7 Dec 2018 14:19:41 +0000 (23:19 +0900)
13 files changed:
pom.xml
src/main/attachment/README_ja.txt
src/main/attachment/README_ja_withJRE.txt
src/main/attachment/README_mac.txt
src/main/java/charactermanaj/Main.java
src/main/java/charactermanaj/model/io/RecentDataPersistent.java
src/main/java/charactermanaj/model/io/WorkingSetPersist.java
src/main/java/charactermanaj/model/util/StartupSupport.java
src/main/java/charactermanaj/ui/RecentCharactersDir.java
src/main/java/charactermanaj/util/ApplicationLogHandler.java
src/main/java/charactermanaj/util/ApplicationLoggerConfigurator.java
src/main/java/charactermanaj/util/ConfigurationDirUtilities.java
src/main/java/charactermanaj/util/UserDataFactory.java

diff --git a/pom.xml b/pom.xml
index 53ebe8b..521a270 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                        <build>
                                <plugins>
                                        <plugin>
-                                               <!-- Launch4jによるjarファイルのexe化を行う. http://launch4j.sourceforge.net/docs.html -->
-                                               <groupId>org.bluestemsoftware.open.maven.plugin</groupId>
-                                               <artifactId>launch4j-plugin</artifactId>
-                                               <version>1.5.0.0</version>
-                                               <executions>
+                                               <!-- Launch4jによるjarファイルのexe化を行う. http://launch4j.sourceforge.net/docs.html
+                                                       プラグインが1.7.24の場合、使用するのはLaunch4j 3.12 である。
+                                                       https://github.com/lukaszlenart/launch4j-maven-plugin/blob/master/pom.xml -->
+                                               <groupId>com.akathist.maven.plugins.launch4j</groupId>
+                                               <artifactId>launch4j-maven-plugin</artifactId>
+                                               <version>1.7.24</version>
+                                               <executions>
                                                        <execution>
                                                                <id>l4j-gui</id>
                                                                <phase>package</phase>
index c18cade..3fcac55 100644 (file)
@@ -1,17 +1,32 @@
-[[リリースノート (キャラクターなんとかJ - 0.998)]]
-2015/07/20
+[[リリースノート (キャラクターなんとかJ - 0.999)]]
+2015/12/07
 
 ホームページ
 http://osdn.jp/projects/charactermanaj/
 
-[ver0.997からの変更点]
+[ver0.998からの変更点]
 
-1. 頂き物の中国語リソース(zh)を本体にマージしました。
-2. フォントの選択で表示できない文字がある場合は除外するようにしました。
+(機能的変更点)
+・お気に入りに登録した場合、アクセサリ等同一のカテゴリに複数のアイテムがある場合の順序がでたらめになっていた問題を修正しました。
+・カスタムレイヤーパターンによる、レイヤー順序の変更に対応しました。
+  ・ これは既定のレイヤー順序を一時的に変更するもので、既存の構造に割り込めるように小数点での指定が可能になっています。
+  ・ デフォルトのキャラクターデータ構造(v3)の場合、自動的に「目を前髪で隠す」設定が追加されます。
+・アプリケーション設定で「ウィンドウサイズ、位置、ズームの復元」をtrueにすると、起動時に前回終了時のズーム状態やウィンドウサイズを復元します。
+・情報ウィンドウをモードレスにし、現在の表示中の画像の重ね順を把握できるように修正しました。
+・ログ、ワーキング状態などのファイルを%APPDATA%フォルダから%LOCALAPPDATA%フォルダに変更しました。
 
-※ Ver0.997で優先フォントの指定をできるように修正したのですが、日本語フォントを優先的に使用させるため、メイリオ等があれば、それを選択するようにしていました。
-しかし、頂いた中国語リソースを使う場合、メイリオがある場合には中国語を使用しつつメイリオで表示させることになるため、中国語文字が文字化けしてしまう問題がありました。
-現在のロケールにあわせた文字列リソースを表示できないフォントは選択から除外するようにしました。
+(内部的変更点)
+・Java11でも実行できるように修正しています。Java6以降で実行できます。(Java6互換でビルドしているためJava5では実行できなくなりました。)
+  ・Windowsの場合、exe形式をサポートするLaunch4jもJava9以降に対応している3系に変更しています。
+・内部的にシリアライズ形式の読み書きは全廃しました。(ver0.997の時点でシリアライズで保存しておらず、ver0.999でソースからも消しました。)
+・古いワーキング状態で対象となるデータセットが存在しなくなっている場合はゴミとみなして削除するようにしました。
+・フォント除外判定をCodePointで行うように修正しました。
+
+[その他]
+
+Windows版ではJava8まではHiDPI環境に対応していないため、Surface Proなどの高解像度モニタでは画面が小さすぎるかもしれません。
+Java11では画面の設定の倍率で拡大して表示されるため、Java11で試してみるのもよいかもしれません。
+(アプリケーション的には何も対応していないので、表示される画像も単純に拡大されたものになります。)
 
 [インストール方法]
 
@@ -31,10 +46,12 @@ charactermanaj.l4j.iniファイルは起動時の設定を調整する場合に
 
 以下の環境での想定を行っております。
 Windows 7(32/64)
-Windows 8.1(32/64)
+Windows 10(32/64)
+
+可能であればJava8での利用をおすすめします。
+Java11でも利用可能です。
+Java6でコンパイルしているため、Java6のデスクトップをサポートする環境であれば基本的には動作すると思います。
 
-可能であればJava7またはJava8での利用をおすすめします。
-JavaSE5で作成されているため、JavaSE5のデスクトップをサポートする環境であれば基本的には動作すると思います。
 
 
 [使用・作成されるファイル等について]
index d64a809..b8cba0e 100644 (file)
@@ -1,24 +1,44 @@
-[[リリースノート (キャラクターなんとかJ - 0.998 - JRE8同梱版)]]
-2015/07/20
+[[リリースノート (キャラクターなんとかJ - 0.999 - JRE8同梱版)]]
+2018/12/07
 
 ホームページ
 http://osdn.jp/projects/charactermanaj/
 
-[ver0.997からの変更点]
-
-1. 頂き物の中国語リソース(zh)を本体にマージしました。
-2. フォントの選択で表示できない文字がある場合は除外するようにしました。
-
-※ Ver0.997で優先フォントの指定をできるように修正したのですが、日本語フォントを優先的に使用させるため、メイリオ等があれば、それを選択するようにしていました。
-しかし、頂いた中国語リソースを使う場合、メイリオがある場合には中国語を使用しつつメイリオで表示させることになるため、中国語文字が文字化けしてしまう問題がありました。
-現在のロケールにあわせた文字列リソースを表示できないフォントは選択から除外するようにしました。
+[ver0.998からの変更点]
+・同梱するJavaランタイム(JRE)は AdoptOpenJDK 8u192-b12 にしています。
+
+(機能的変更点)
+・お気に入りに登録した場合、アクセサリ等同一のカテゴリに複数のアイテムがある場合の順序がでたらめになっていた問題を修正しました。
+・カスタムレイヤーパターンによる、レイヤー順序の変更に対応しました。
+  ・ これは既定のレイヤー順序を一時的に変更するもので、既存の構造に割り込めるように小数点での指定が可能になっています。
+  ・ デフォルトのキャラクターデータ構造(v3)の場合、自動的に「目を前髪で隠す」設定が追加されます。
+・アプリケーション設定で「ウィンドウサイズ、位置、ズームの復元」をtrueにすると、起動時に前回終了時のズーム状態やウィンドウサイズを復元します。
+・情報ウィンドウをモードレスにし、現在の表示中の画像の重ね順を把握できるように修正しました。
+・ログ、ワーキング状態などのファイルを%APPDATA%フォルダから%LOCALAPPDATA%フォルダに変更しました。
+  ・ 既存のログファイル等は自動的には削除しないので不要であれば消してください。
+  ・ 初回起動時に前回の作業状態が無くなっている状態になるのでご注意ください。(キャラクターデータ等はそのままです。)
+
+(内部的変更点)
+・Java11でも実行できるように修正しています。Java6以降で実行できます。(Java6互換でビルドしているためJava5では実行できなくなりました。)
+  ・Windowsの場合、exe形式をサポートするLaunch4jもJava9以降に対応している3系に変更しています。
+・内部的にシリアライズ形式の読み書きは全廃しました。(ver0.997の時点でシリアライズで保存しておらず、ver0.999でソースからも消しました。)
+・古いワーキング状態で対象となるデータセットが存在しなくなっている場合はゴミとみなして削除するようにしました。
+・フォント除外判定をCodePointで行うように修正しました。
+
+[その他]
+
+Windows版ではJava8まではHiDPI環境に対応していないため、Surface Proなどの高解像度モニタでは画面が小さすぎるかもしれません。
+Java11では画面の設定の倍率で拡大して表示されるため、Java11で試してみるのもよいかもしれません。
+(アプリケーション的には何も対応していないので、表示される画像も単純に拡大されたものになります。)
 
 [インストール方法]
 
-CharacterManaJ_0.998_with_JRE8を好きなフォルダに展開して実行するだけです。
+CharacterManaJ_0.999_with_JRE8を好きなフォルダに展開して実行するだけです。
 特にインストール作業は必要ありません。
 
-OracleのJavaランタイムがアプリケーションに同梱されています。
+AdoptOpenJDK 8u192-b12のJavaランタイムがアプリケーションに同梱されています。
+https://adoptopenjdk.net/
+
 マシンにJavaをインストールしていない場合でも、Javaのインストールなしに実行できます。
 
 ※ 本アプリケーションには画像データは含まれていません。
@@ -34,11 +54,12 @@ charactermanaj.l4j.iniファイルは起動時の設定を調整する場合に
 
 以下の環境での想定を行っております。
 Windows 7(32/64)
-Windows 8.1(32/64)
+Windows 10(32/64)
 
-同梱されているJREは、Java8(jdk1.8.0_51 32ビット版)となります。
+AdoptOpenJDK 8u192-b12のJavaランタイムがアプリケーションに同梱されています。
 より新しいJavaを利用したい場合は、jreフォルダの中身を新しいjreのものとまるごと差し替えてください。
-また、jreフォルダを削除するとシステムにインストールされているJavaを利用するようになります。
+Java11での利用も可能です。
+また、jreフォルダを削除するとシステムにインストールされているJavaを利用するようになります。(レジストリに登録されていれば)
 
 
 [使用・作成されるファイル等について]
index 9429d25..2f21843 100644 (file)
@@ -1,44 +1,43 @@
-キャラクターなんとかJ Ver0.998
-2015/07/20
+キャラクターなんとかJ Ver0.999
+2018/12/07
 
 ホームページ
 http://osdn.jp/projects/charactermanaj/
 
-[ver0.997からの変更点]
+[ver0.998からの変更点]
 
-1. 頂き物の中国語リソース(zh)を本体にマージしました。
-2. フォントの選択で表示できない文字がある場合は除外するようにしました。
+・JRE同梱版のJavaランタイム(JRE)は AdoptOpenJDK 8u192-b12 にしています。
 
-※ Ver0.997で優先フォントの指定をできるように修正したのですが、日本語フォントを優先的に使用させるため、メイリオ等があれば、それを選択するようにしていました。
-しかし、頂いた中国語リソースを使う場合、メイリオがある場合には中国語を使用しつつメイリオで表示させることになるため、中国語文字が文字化けしてしまう問題がありました。
-現在のロケールにあわせた文字列リソースを表示できないフォントは選択から除外するようにしました。
+(機能的変更点)
+・お気に入りに登録した場合、アクセサリ等同一のカテゴリに複数のアイテムがある場合の順序がでたらめになっていた問題を修正しました。
+・カスタムレイヤーパターンによる、レイヤー順序の変更に対応しました。
+  ・ これは既定のレイヤー順序を一時的に変更するもので、既存の構造に割り込めるように小数点での指定が可能になっています。
+  ・ デフォルトのキャラクターデータ構造(v3)の場合、自動的に「目を前髪で隠す」設定が追加されます。
+・アプリケーション設定で「ウィンドウサイズ、位置、ズームの復元」をtrueにすると、起動時に前回終了時のズーム状態やウィンドウサイズを復元します。
+・情報ウィンドウをモードレスにし、現在の表示中の画像の重ね順を把握できるように修正しました。
 
-[ファイルの説明]
-
-* キャラクターなんとかJ.app
- OracleのJava7またはJava8を使用するバージョンです。
- あらかじめ、OracleのサイトよりJava7またはJava8をインストールしてください。
- 事前にOracleのJava7以降をインストールしていない場合は起動時にエラーとなります。
+(内部的変更点)
+・Java11でも実行できるように修正しています。Java6以降で実行できます。(Java6互換でビルドしているためJava5では実行できなくなりました。)
+・内部的にシリアライズ形式の読み書きは全廃しました。(ver0.997の時点でシリアライズで保存しておらず、ver0.999でソースからも消しました。)
+・古いワーキング状態で対象となるデータセットが存在しなくなっている場合はゴミとみなして削除するようにしました。
+・フォント除外判定をCodePointで行うように修正しました。
 
- ※ JRE同梱版の場合は、Javaがアプリケーションに含まれていますので、Javaのインストール作業は不要です。
 
+[ファイルの説明]
 
-* java6/キャラクターなんとかJ.app
- AppleのMac OS X用のJava6を使用するバージョンです。
- 起動時に、まだJavaがインストールされていない場合は自動インストールが開始されます。
-  ただし、OSX10.9 Marvericks では、Javaの自動インストールがうまく行かないケースがあるようです。
- その場合は、手動でAppleもしくはOracleのサイトより、Javaランタイムをインストールしてください。
-
- ※ JRE同梱版には含まれていません。
+* キャラクターなんとかJ.app
+  アプリケーション本体です。好きなフォルダにコピーしてください。
 
+  JRE同梱版の場合は、Javaがアプリケーションに含まれていますので、Javaのインストール作業は不要です。
+  ※ バンドルファイルを展開すると Contents/Plugins/JRE というフォルダがあり、ここにあるJavaを利用します。
+  異なるバージョンのJavaを使いたい場合は、このフォルダを差し替えてください。
+  (また、このJREフォルダを消すと、非JRE同梱版と同じになります。)
 
-* CharacterManaJ.jar
- 実行可能jarです。Java6,7,8のいずれかがインストールされていればダブルクリックで実行できます。
- ただし、Java7, 8の場合はJava7u60以降、Java8u5以降の最新のものをお使いください。
- Mac用の設定ファイルがないため、上記appとは、かならずしも同じではありません。
- よくJavaの特性を知っている方向けです。
+  JRE同梱版でない場合、環境変数JAVA_HOME、もしくはシステムにインストールされているjavaが検索して使用されます。
+  Ver0.999よりランチャーはシェルスクリプトになっており JAVA_HOMEまたは/usr/libexec/java_homeでjavaを検索します。
+  ※ 環境変数JAVA_HOMEが設定されていない場合は、/usr/libexec/java_home で示されるものをJAVA_HOMEとして使用します。
 
- ※ JRE同梱版には含まれていません
+  Ver0.999より、~/Library/CharacterManaJ/jvm_options というテキストファイルに起動オプションを指定できようになりました
 
 
 不明な点があればプロジェクトのWikiを参照してください。
index bcff24e..ead0f30 100644 (file)
@@ -293,6 +293,11 @@ public final class Main implements Runnable {
                                }
                        }
 
+                       // スタートアップ時の初期化
+                       // ver0.999ではキャラクターデータディレクトリに依存しない初期化部しかないので最初に移動する。
+                       // (APPDATAからLOCALAPPDATAへの移動処理などがあるため、先に行う必要がある。)
+                       StartupSupport.getInstance().doStartup();
+
                        // 起動時のシステムプロパティでキャラクターディレクトリが指定されていて実在すれば、それを優先する.
                        File currentCharacterDir = null;
                        String charactersDir = System.getProperty("charactersDir");
@@ -319,9 +324,6 @@ public final class Main implements Runnable {
                        // キャラクターデータフォルダの設定
                        DirectoryConfig.getInstance().setCharactersDir(currentCharacterDir);
 
-                       // スタートアップ時の初期化
-                       StartupSupport.getInstance().doStartup();
-
                        // デフォルトのプロファイルを開く.
                        // (最後に使ったプロファイルがあれば、それが開かれる.)
                        final MainFrame mainFrame = ProfileListManager.openDefaultProfile();
index 1aa2286..c18d203 100644 (file)
@@ -19,7 +19,7 @@ import charactermanaj.util.DirectoryConfig;
 
 /**
  * 最後に使用したデータの使用状況を保存・復元するためのクラス
- * 
+ *
  * @author seraphy
  */
 public final class RecentDataPersistent {
@@ -45,10 +45,10 @@ public final class RecentDataPersistent {
        private RecentDataPersistent() {
                super();
        }
-       
+
        /**
         * インスタンスを取得する
-        * 
+        *
         * @return インスタンス
         */
        public static RecentDataPersistent getInstance() {
@@ -57,7 +57,7 @@ public final class RecentDataPersistent {
 
        /**
         * キャラクターデータの親フォルダごとに保存する、最後に使用したキャラクターデータを保存するファイル
-        * 
+        *
         * @return
         */
        private File getRecentCharacterXML() {
@@ -71,7 +71,7 @@ public final class RecentDataPersistent {
        /**
         * 最後に使用したキャラクターデータのフォルダ名を親ディレクトリからの相対パスとして保存する.<br>
         * ただし、書き込み禁止である場合は何もしない.<br>
-        * 
+        *
         * @param characterData
         *            キャラクターデータ
         * @throws IOException
@@ -126,7 +126,7 @@ public final class RecentDataPersistent {
         * 親ディレクトリからの相対パスとして記録されている、最後に使用したキャラクターデータのフォルダ名から、
         * 最後に使用したキャラクターデータをロードして返す.<br>
         * 該当するキャラクターデータが存在しないか、読み込みに失敗した場合は「履歴なし」としてnullを返す.<br>
-        * 
+        *
         * @return キャラクターデータ、もしくはnull
         */
        public CharacterData loadRecent() {
@@ -172,87 +172,4 @@ public final class RecentDataPersistent {
                // 履歴がない場合、もしくは読み取れなかった場合はnullを返す.
                return null;
        }
-
-       // /**
-       // * 最後に使用したキャラクターデータを取得する.
-       // *
-       // * @return キャラクターデータ。最後に使用したデータが存在しない場合はnull
-       // * @throws IOException
-       // * 読み込みに失敗した場合
-       // */
-       // private CharacterData loadRecentSer() throws IOException {
-       // UserData recentCharacterStore = getRecentCharacterStore();
-       // if (!recentCharacterStore.exists()) {
-       // return null;
-       // }
-       //
-       // RecentData recentData;
-       // try {
-       // File currentCharactersDir =
-       // DirectoryConfig.getInstance().getCharactersDir();
-       //
-       // Object rawRecentData = recentCharacterStore.load();
-       // if (rawRecentData instanceof RecentData) {
-       // // 旧形式 (単一)
-       // recentData = (RecentData) rawRecentData;
-       // logger.log(Level.INFO, "old-recentdata-type: " + recentData);
-       //
-       // // 旧形式で保存されているURIが、現在選択しているキャラクターデータと同じ親ディレクトリ
-       // // でなければ復元しない.
-       // URI uri = recentData.getDocBase();
-       // File parentDir = new File(uri).getParentFile().getParentFile(); // 2段上
-       // if (!currentCharactersDir.equals(parentDir)) {
-       // logger.log(Level.INFO,
-       // "unmatched characters-dir. current="
-       // + currentCharactersDir + "/recent="
-       // + parentDir);
-       // recentData = null;
-       // }
-       //
-       // } else if (rawRecentData instanceof Map) {
-       // // 新形式 (複数のキャラクターディレクトリに対応)
-       // @SuppressWarnings("unchecked")
-       // Map<File, RecentData> recentDataMap = (Map<File, RecentData>)
-       // rawRecentData;
-       // recentData = recentDataMap.get(currentCharactersDir);
-       // logger.log(Level.FINE, "recent-data: " + currentCharactersDir + "=" +
-       // recentData);
-       //
-       // } else {
-       // // 不明な形式
-       // logger.log(Level.SEVERE,
-       // "invalid file format. " + recentCharacterStore
-       // + "/class=" + rawRecentData.getClass());
-       // recentData = null;
-       // }
-       //
-       // } catch (Exception ex) {
-       // // RecentData情報の復元に失敗した場合は最後に使用したデータが存在しないものとみなす.
-       // logger.log(Level.WARNING, "recent data loading failed. " +
-       // recentCharacterStore, ex);
-       // recentData = null;
-       // }
-       //
-       // if (recentData != null) {
-       // CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
-       // return persist.loadProfile(recentData.getDocBase());
-       // }
-       //
-       // // 履歴がない場合、もしくは読み取れなかった場合はnullを返す.
-       // return null;
-       // }
-       //
-       // /**
-       // * 最後に使用したキャラクタデータの保存先を取得する
-       // *
-       // * @return 保存先
-       // */
-       // protected UserData getRecentCharacterStore() {
-       // UserDataFactory userDataFactory = UserDataFactory.getInstance();
-       // UserData recentCharacterStore =
-       // userDataFactory.getUserData(RECENT_CHARACTER_SER);
-       // return recentCharacterStore;
-       // }
-       
-       
 }
index dd29aef..03a7105 100644 (file)
@@ -1,7 +1,9 @@
 package charactermanaj.model.io;
 
+import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -36,10 +38,12 @@ public class WorkingSetPersist {
        /**
         * ワーキングセットのサフィックス.
         */
-       public static final String WORKINGSET_FILE_SUFFIX = "workingset.xml";
+       private static final String WORKINGSET_FILE_SUFFIX = "workingset.xml";
 
        private static final WorkingSetPersist singletion = new WorkingSetPersist();
 
+       private final UserDataFactory userDataFactory = UserDataFactory.getLocalInstance();
+
        public static WorkingSetPersist getInstance() {
                return singletion;
        }
@@ -48,15 +52,11 @@ public class WorkingSetPersist {
         * すべてのワーキングセットをクリアする.<br>
         */
        public void removeAllWorkingSet() {
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
-               File dir = userDataFactory.getSpecialDataDir("foo-"
-                               + WORKINGSET_FILE_SUFFIX);
+               File dir = userDataFactory.getSpecialDataDir("foo-" + WORKINGSET_FILE_SUFFIX);
                if (dir.exists() && dir.isDirectory()) {
                        File[] files = dir.listFiles(new FileFilter() {
                                public boolean accept(File pathname) {
-                                       return pathname.isFile()
-                                                       && pathname.getName().endsWith(
-                                                                       WORKINGSET_FILE_SUFFIX);
+                                       return pathname.isFile() && pathname.getName().endsWith(WORKINGSET_FILE_SUFFIX);
                                }
                        });
                        if (files == null) {
@@ -78,7 +78,6 @@ public class WorkingSetPersist {
         *            対象のキャラクターデータ
         */
        public void removeWorkingSet(CharacterData cd) {
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
                UserData workingSetXmlData = userDataFactory.getMangledNamedUserData(
                                cd.getDocBase(), WORKINGSET_FILE_SUFFIX);
                if (workingSetXmlData != null && workingSetXmlData.exists()) {
@@ -106,7 +105,6 @@ public class WorkingSetPersist {
                }
 
                // XML形式でのワーキングセットの保存
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
                UserData workingSetXmlData = userDataFactory.getMangledNamedUserData(
                                characterData.getDocBase(), WORKINGSET_FILE_SUFFIX);
                OutputStream outstm = workingSetXmlData.getOutputStream();
@@ -133,7 +131,6 @@ public class WorkingSetPersist {
                        throw new IllegalArgumentException();
                }
                // XML形式でのワーキングセットの復元
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
                UserData workingSetXmlData = userDataFactory.getMangledNamedUserData(
                                characterData.getDocBase(), WORKINGSET_FILE_SUFFIX);
                if (workingSetXmlData == null || !workingSetXmlData.exists()) {
@@ -211,4 +208,58 @@ public class WorkingSetPersist {
 
                return ws;
        }
+
+       /**
+        * 古いワーキングセットについて、すでに本体データが削除されている場合はワーキングセットも削除する。
+        * まだ存在するものは削除されない。
+        * 生きている場合は、ワーキングセットの検査日時を表すために更新日時を現在日時に設定しなおす。
+        * @param expireDate 判定対象となる日時、それ以前のもののみ判定を行う。
+        */
+       public void purge(final long expireDate) {
+               final String XML_SUFFIX = "-" + WORKINGSET_FILE_SUFFIX;
+
+               UserDataFactory userDataFactory = UserDataFactory.getLocalInstance();
+               File dir = userDataFactory.getSpecialDataDir(XML_SUFFIX);
+
+               File[] xmls = dir.listFiles(new FileFilter() {
+                       @Override
+                       public boolean accept(File pathname) {
+                               return pathname.isFile() && pathname.getName().endsWith(XML_SUFFIX)
+                                               && pathname.lastModified() < expireDate && pathname.length() > 0;
+                       }
+               });
+               if (xmls == null) {
+                       logger.log(Level.WARNING, "workingset-dir access failed.");
+                       return;
+               }
+
+               for (File xmlFile : xmls) {
+                       try {
+                               WorkingSetXMLReader reader = new WorkingSetXMLReader();
+                               IndependentWorkingSet ws;
+                               InputStream is = new BufferedInputStream(new FileInputStream(xmlFile));
+                               try {
+                                       ws = reader.loadWorkingSet(is);
+                               } finally {
+                                       is.close();
+                               }
+
+                               URI docBase = ws.getCharacterDocBase();
+                               if (docBase.getScheme().equals("file")) {
+                                       File characterXml = new File(docBase);
+                                       if (!characterXml.exists()) {
+                                               // キャラクター定義XMLが存在しない = 削除されたキャラクターデータ
+                                               logger.log(Level.INFO, "remove amandone workingset: " + xmlFile + ", docBase=" + docBase);
+                                               xmlFile.delete();
+                                       } else {
+                                               // チェック済みであることを示すためにXMLの更新日時を現在時刻にする
+                                               xmlFile.setLastModified(System.currentTimeMillis());
+                                       }
+                               }
+
+                       } catch (Exception ex) {
+                               logger.log(Level.WARNING, "file access failed. " + xmlFile, ex);
+                       }
+               }
+       }
 }
index ab28d54..e7f86bc 100644 (file)
@@ -1,18 +1,13 @@
 package charactermanaj.model.util;
 
-import java.io.BufferedInputStream;
 import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URI;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import charactermanaj.model.AppConfig;
-import charactermanaj.model.IndependentWorkingSet;
-import charactermanaj.model.io.WorkingSetXMLReader;
-import charactermanaj.util.UserDataFactory;
+import charactermanaj.model.io.WorkingSetPersist;
+import charactermanaj.util.ApplicationLogHandler;
+import charactermanaj.util.ConfigurationDirUtilities;
 
 
 /**
@@ -37,6 +32,7 @@ public abstract class StartupSupport {
                                @Override
                                public void doStartup() {
                                        StartupSupport[] startups = {
+                                                       new MoveAppDataToLocalAppData(),
                                                        new PurgeOldLogs(),
                                                        new PurgeOldWorkingSetXml(),
                                                        //new ConvertRecentCharDirsSerToXmlProps(),
@@ -67,69 +63,68 @@ public abstract class StartupSupport {
 }
 
 /**
- * 使われていないWorkingset.xmlを削除する
+ * APPDATAフォルダにあったワーキングセット類をLOCALAPPDATAに移動する。
  */
-class PurgeOldWorkingSetXml extends StartupSupport {
+class MoveAppDataToLocalAppData extends StartupSupport {
 
+       /**
+        * ロガー
+        */
        private final Logger logger = Logger.getLogger(getClass().getName());
 
        @Override
        public void doStartup() {
+               File appDataDir = ConfigurationDirUtilities.getUserDataDir();
+               File localAppDataDir = ConfigurationDirUtilities.getLocalUserDataDir();
+               if (appDataDir.equals(localAppDataDir)) {
+                       // 移動元・移動先が同一であれば何もしない。
+                       return;
+               }
+
+               // ログフォルダ、ログ設定はすでにログが開始されているので移動しない。
+               String[] files = {"recent-characterdirs.xml", "workingset"};
+               for (String file : files) {
+                       try {
+                               File target = new File(localAppDataDir, file);
+                               if (target.exists()) {
+                                       // すでにあれば何もしない
+                                       continue;
+                               }
+                               File source = new File(appDataDir, file);
+                               if (source.exists()) {
+                                       // まだ移動されていない場合であれば移動を試みる
+                                       boolean result = source.renameTo(target);
+                                       logger.log(Level.INFO, "Move " + source + " to " + target +
+                                                       ". result=" + (result ? "succeeded" : "failed"));
+                               }
+                       } catch (Exception ex) {
+                               logger.log(Level.SEVERE, "Failed to move file. " + file, ex);
+                       }
+               }
+       }
+}
+
+/**
+ * 使われていないWorkingset.xmlを削除する
+ */
+class PurgeOldWorkingSetXml extends StartupSupport {
+
+       @Override
+       public void doStartup() {
                AppConfig appConfig = AppConfig.getInstance();
                long purgeOldLogsMillSec = appConfig.getPurgeLogDays() * 24L * 3600L * 1000L;
                if (purgeOldLogsMillSec <= 0) {
                        return;
                }
 
-               final String XML_SUFFIX = "-workingset.xml";
-
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
-               File dir = userDataFactory.getSpecialDataDir(XML_SUFFIX);
-
                // ワーキングセットの掃除判定日時
                // これよりも新しいものは実際に使われているかを問わず、削除判定しない。
                final long expireDate = System.currentTimeMillis() - purgeOldLogsMillSec;
 
-               File[] xmls = dir.listFiles(new FileFilter() {
-                       @Override
-                       public boolean accept(File pathname) {
-                               return pathname.isFile() && pathname.getName().endsWith(XML_SUFFIX)
-                                               && pathname.lastModified() < expireDate && pathname.length() > 0;
-                       }
-               });
-               if (xmls == null) {
-                       logger.log(Level.WARNING, "workingset-dir access failed.");
-                       return;
-               }
-
-               for (File xmlFile : xmls) {
-                       try {
-                               WorkingSetXMLReader reader = new WorkingSetXMLReader();
-                               IndependentWorkingSet ws;
-                               InputStream is = new BufferedInputStream(new FileInputStream(xmlFile));
-                               try {
-                                       ws = reader.loadWorkingSet(is);
-                               } finally {
-                                       is.close();
-                               }
-
-                               URI docBase = ws.getCharacterDocBase();
-                               if (docBase.getScheme().equals("file")) {
-                                       File characterXml = new File(docBase);
-                                       if (!characterXml.exists()) {
-                                               // キャラクター定義XMLが存在しない = 削除されたキャラクターデータ
-                                               logger.log(Level.INFO, "remove amandone workingset: " + xmlFile + ", docBase=" + docBase);
-                                               xmlFile.delete();
-                                       } else {
-                                               // チェック済みであることを示すためにXMLの更新日時を現在時刻にする
-                                               xmlFile.setLastModified(System.currentTimeMillis());
-                                       }
-                               }
-
-                       } catch (Exception ex) {
-                               logger.log(Level.WARNING, "file access failed. " + xmlFile, ex);
-                       }
-               }
+               // 指定した日時以前のワーキングセットについて本体データが削除されているものは
+               // ワーキングセットも削除する。
+               WorkingSetPersist persist = new WorkingSetPersist();
+               persist.purge(expireDate);
        }
 }
 
@@ -253,46 +248,14 @@ class PurgeOldWorkingSetXml extends StartupSupport {
  */
 class PurgeOldLogs extends StartupSupport {
 
-       /**
-        * ロガー
-        */
-       private final Logger logger = Logger.getLogger(getClass().getName());
-
        @Override
        public void doStartup() {
-               UserDataFactory userDataFactory = UserDataFactory.getInstance();
-               File logsDir = userDataFactory.getSpecialDataDir("*.log");
-               if (logsDir.exists()) {
-                       AppConfig appConfig = AppConfig.getInstance();
-                       long purgeOldLogsMillSec = appConfig.getPurgeLogDays() * 24L * 3600L * 1000L;
-                       if (purgeOldLogsMillSec > 0) {
-                               File[] files = logsDir.listFiles();
-                               if (files == null) {
-                                       logger.log(Level.WARNING, "log-dir access failed.");
-                                       return;
-                               }
-                               long purgeThresold = System.currentTimeMillis()
-                                               - purgeOldLogsMillSec;
-                               for (File file : files) {
-                                       try {
-                                               String name = file.getName();
-                                               if (file.isFile() && file.canWrite()
-                                                               && name.endsWith(".log")) {
-                                                       long lastModified = file.lastModified();
-                                                       if (lastModified > 0
-                                                                       && lastModified < purgeThresold) {
-                                                               boolean result = file.delete();
-                                                               logger.log(Level.INFO, "remove file " + file
-                                                                               + "/succeeded=" + result);
-                                                       }
-                                               }
-
-                                       } catch (Exception ex) {
-                                               logger.log(Level.WARNING,
-                                                               "remove file failed. " + file, ex);
-                                       }
-                               }
-                       }
+               AppConfig appConfig = AppConfig.getInstance();
+               long purgeOldLogsMillSec = appConfig.getPurgeLogDays() * 24L * 3600L * 1000L;
+               if (purgeOldLogsMillSec > 0) {
+                       // 期限切れのログファイルを削除する
+                       long expiredDate = System.currentTimeMillis() - purgeOldLogsMillSec;
+                       ApplicationLogHandler.purge(expiredDate);
                }
        }
 }
index 808226a..74fcf66 100644 (file)
@@ -107,8 +107,8 @@ public class RecentCharactersDir {
                Properties props = new Properties();
 
                // ユーザーディレクトリのルート上に最後に使ったファイルリストをxml形式で保存する.
-               File userDataDir = ConfigurationDirUtilities.getUserDataDir();
-               File recentUseDirs = new File(userDataDir, RECENT_CHARACTERDIRS_XML);
+               File localUserDataDir = ConfigurationDirUtilities.getLocalUserDataDir();
+               File recentUseDirs = new File(localUserDataDir, RECENT_CHARACTERDIRS_XML);
                if (recentUseDirs.exists()) {
                        InputStream is = new BufferedInputStream(new FileInputStream(
                                        recentUseDirs));
@@ -135,6 +135,10 @@ public class RecentCharactersDir {
                                        && lastUseCharacterDataDir.trim().length() > 0) {
                                lastUseCharacterDir = new File(new URI(
                                                lastUseCharacterDataDir));
+                               if (!lastUseCharacterDir.isDirectory()) {
+                                       // 存在しない場合
+                                       lastUseCharacterDir = null;
+                               }
                        }
 
                        Enumeration<?> enmKeys = props.propertyNames();
@@ -143,7 +147,11 @@ public class RecentCharactersDir {
                                if (key.startsWith(DIRS_PREFIX)) {
                                        String value = props.getProperty(key);
                                        if (value != null && value.trim().length() > 0) {
-                                               dirsMap.put(key, new File(new URI(value)));
+                                               File dir = new File(new URI(value));
+                                               if (dir.isDirectory()) {
+                                                       // 実在するフォルダのみ使用可能とする
+                                                       dirsMap.put(key, dir);
+                                               }
                                        }
                                }
                        }
@@ -201,8 +209,8 @@ public class RecentCharactersDir {
                props.put("doNotAskAgain", doNotAskAgain ? "true" : "false");
 
                // ユーザーディレクトリのルート上に最後に使ったファイルリストをxml形式で保存する.
-               File userDataDir = ConfigurationDirUtilities.getUserDataDir();
-               File recentUseDirs = new File(userDataDir, RECENT_CHARACTERDIRS_XML);
+               File localUserDataDir = ConfigurationDirUtilities.getLocalUserDataDir();
+               File recentUseDirs = new File(localUserDataDir, RECENT_CHARACTERDIRS_XML);
                OutputStream os = new BufferedOutputStream(new FileOutputStream(
                                recentUseDirs));
                try {
index d342a9c..9db9db7 100644 (file)
@@ -9,6 +9,7 @@ import java.text.SimpleDateFormat;
 import java.util.logging.Handler;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
+import java.util.logging.Logger;
 
 import charactermanaj.model.AppConfig;
 
@@ -17,31 +18,31 @@ import charactermanaj.model.AppConfig;
  * このアプリケーションの活動を記録するログハンドラ.<br>
  * アプリケーション用のディレクトリのlogsフォルダ下に開始日時のファイル名をもつログファイルを作成し、ログを記録する.<br>
  * ただし、終了時、警告以上のログが一度も書き込まれなかった場合はログファィルは自動的に削除される.<br>
- *  
+ *
  * @author seraphy
  */
 public class ApplicationLogHandler extends Handler {
 
        private static final String LOGS_DIR = "logs";
-       
+
        private final Object lock = new Object();
-       
+
        private final File logFile;
-       
+
        private PrintWriter pw;
-       
+
        private boolean notRemove;
-       
+
        public ApplicationLogHandler() {
-               File appDir = ConfigurationDirUtilities.getUserDataDir();
-               File logsDir = new File(appDir, LOGS_DIR);
+               File localAppDir = ConfigurationDirUtilities.getLocalUserDataDir();
+               File logsDir = new File(localAppDir, LOGS_DIR);
                if (!logsDir.exists()) {
                        if (!logsDir.mkdirs()) {
                                // ログ記録場所が作成できていないのでコンソールに出すしかない.
                                System.err.println("can't create the log directory. " + logsDir);
                        }
                }
-               
+
                String fname = getCurrentTimeForFileName() + ".log";
                logFile = new File(logsDir, fname);
                PrintWriter tmp;
@@ -53,11 +54,11 @@ public class ApplicationLogHandler extends Handler {
                }
                this.pw = tmp;
        }
-       
+
        @Override
        public void close() throws SecurityException {
                synchronized (lock) {
-                       // 終了時にAppConfigにアクセスする. 
+                       // 終了時にAppConfigにアクセスする.
                        // (アプリケーションの終了時にアクセスすることで初期化タイミングの問題を避ける.)
                        try {
                                AppConfig appConfig = AppConfig.getInstance();
@@ -89,7 +90,7 @@ public class ApplicationLogHandler extends Handler {
                        }
                }
        }
-       
+
        @Override
        public void flush() {
                synchronized (lock) {
@@ -98,7 +99,7 @@ public class ApplicationLogHandler extends Handler {
                        }
                }
        }
-       
+
        @Override
        public void publish(LogRecord record) {
                if (record == null) {
@@ -115,13 +116,13 @@ public class ApplicationLogHandler extends Handler {
                        String name = record.getLoggerName();
                        pw.println("#" + getCurrentTime() + " " + name + " "
                                        + lv.getLocalizedName() + " " + record.getMessage());
-                       
+
                        // 例外があれば、例外の記録
-                       Throwable tw = record.getThrown(); 
+                       Throwable tw = record.getThrown();
                        if (tw != null) {
                                tw.printStackTrace(pw); // 例外のコールスタックをロガーに出力
                        }
-                       
+
                        // フラッシュする.(随時、ファイルの中身を見ることができるように.)
                        pw.flush();
 
@@ -131,7 +132,7 @@ public class ApplicationLogHandler extends Handler {
                        }
                }
        }
-       
+
        public String getCurrentTime() {
                Timestamp tm = new Timestamp(System.currentTimeMillis());
                SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -143,4 +144,36 @@ public class ApplicationLogHandler extends Handler {
                SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd_HHmmssSSS");
                return dt.format(tm);
        }
+
+       /**
+        * ログフォルダ上にある、指定した期限以前のログファイルを削除する。
+        * @param expiredDate 期限切れとなる日時
+        */
+       public static void purge(long expiredDate) {
+               Logger logger = Logger.getLogger(ApplicationLogHandler.class.getName());
+
+               File localAppDir = ConfigurationDirUtilities.getLocalUserDataDir();
+               File logsDir = new File(localAppDir, LOGS_DIR);
+
+               File[] files = logsDir.listFiles();
+               if (files == null) {
+                       logger.log(Level.WARNING, "log-dir access failed.");
+                       return;
+               }
+               for (File file : files) {
+                       try {
+                               String name = file.getName();
+                               if (file.isFile() && file.canWrite() && name.endsWith(".log")) {
+                                       long lastModified = file.lastModified();
+                                       if (lastModified > 0 && lastModified < expiredDate) {
+                                               boolean result = file.delete();
+                                               logger.log(Level.INFO, "remove file " + file + "/succeeded=" + result);
+                                       }
+                               }
+
+                       } catch (Exception ex) {
+                               logger.log(Level.WARNING, "remove file failed. " + file, ex);
+                       }
+               }
+       }
 }
index 2667de0..3c164e8 100644 (file)
@@ -13,7 +13,7 @@ import java.util.logging.Logger;
 public final class ApplicationLoggerConfigurator {
 
        private static final String LOGGING_PROPERTIES = "logging.properties";
-       
+
        private ApplicationLoggerConfigurator() {
                super();
        }
@@ -29,15 +29,15 @@ public final class ApplicationLoggerConfigurator {
 
                Exception configurationError = null;
                try {
-                       // ユーザーごとのアプリケーション設定ディレクトリ上の設定ファイルを取得する.
-                       File appDataDir = ConfigurationDirUtilities.getUserDataDir();
-                       File logConfig = new File(appDataDir, LOGGING_PROPERTIES);
+                       // ã\83¦ã\83¼ã\82¶ã\83¼ã\81\94ã\81¨ã\81®ã\83­ã\83¼ã\82«ã\83«ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³è¨­å®\9aã\83\87ã\82£ã\83¬ã\82¯ã\83\88ã\83ªä¸\8aã\81®è¨­å®\9aã\83\95ã\82¡ã\82¤ã\83«ã\82\92å\8f\96å¾\97ã\81\99ã\82\8b.
+                       File localAppDataDir = ConfigurationDirUtilities.getLocalUserDataDir();
+                       File logConfig = new File(localAppDataDir, LOGGING_PROPERTIES);
 
                        if ( !logConfig.exists()) {
                                // ユーザ指定のロギングプロパティがない場合、リソースからコピーする
                                copyDefaultLogProperty(logConfig);
                        }
-                       
+
                        InputStream is = null;
                        if (logConfig.exists()) {
                                // ユーザー指定のロギングプロパティがある場合
@@ -61,24 +61,24 @@ public final class ApplicationLoggerConfigurator {
                        // 処理は継続する.
                        configurationError = ex;
                }
-               
+
                // ロガーを取得
                Logger logger = Logger.getLogger(ApplicationLoggerConfigurator.class.getName());
-               
+
                // 初期化時に失敗した場合、デフォルトのコンソールハンドラを設定し、ログに出力する.
                if (configurationError != null) {
                        logger.addHandler(new ConsoleHandler());
                        logger.addHandler(new ApplicationLogHandler());
                        logger.log(Level.WARNING, "LogConfigurationFailed", configurationError);
                }
-               
+
                // 初期化時のログ
                logger.info("open logger.");
                logger.info("application configuration: baseDir="
                                + ConfigurationDirUtilities.getApplicationBaseDir() + "  appData="
                                + ConfigurationDirUtilities.getUserDataDir());
        }
-       
+
        /**
         * デフォルトのログプロパティをユーザディレクトリにコピーする.
         * @param logConfig ユーザディレクトリ上のログプロパティファイル位置
index 4a419e2..fabc040 100644 (file)
@@ -20,13 +20,15 @@ public final class ConfigurationDirUtilities {
        public static final String CONFIGURATION_DIR_NAME = "CharacterManaJ";
 
        private static File userDataDir;
-       
+
+       private static File localUserDataDir;
+
        private static File applicationBaseDir;
-       
+
        private ConfigurationDirUtilities() {
                throw new RuntimeException("utilities class.");
        }
-       
+
        /**
         * ユーザーごとのアプリケーションデータ保存先を取得する.<br>
         * 環境変数「APPDATA」もしくはシステムプロパティ「appdata.dir」からベース位置を取得する.<br>
@@ -34,10 +36,12 @@ public final class ConfigurationDirUtilities {
         * Mac OS Xでなければ「~/」をベース位置とする.<br>
         * これに対してシステムプロパティ「characterdata.dirname」(デフォルトは「CharacterManaJ」)という
         * フォルダをユーザー毎のアプリケーションデータの保存先ディレクトリとする.<br>
+        *
+        * @return アプリケーションデータの保存先
         */
        public synchronized static File getUserDataDir() {
                if (userDataDir == null) {
-                       
+
                        String appData = null;
                        // システムプロパティ「appdata.dir」を探す
                        appData = System.getProperty("appdata.dir");
@@ -51,22 +55,65 @@ public final class ConfigurationDirUtilities {
                                // ~/Libraryをベースにする.(Mac OS Xならば必ずある。)
                                appData = new File(System.getProperty("user.home"), "Library").getPath();
                        }
-                       if (appData == null) {
+                       if (appData == null || appData.trim().length() == 0) {
                                // なければシステムプロパティ「user.home」を使う
                                // このプロパティは必ず存在する.
                                appData = System.getProperty("user.home");
                        }
 
-                       // システムプロパティ「characterdata.dirname」のディレクトリ名、なければ「CharacterManaJ」を設定する.
-                       String characterDirName = System.getProperty("characterdata.dirname", CONFIGURATION_DIR_NAME);
-                       userDataDir = new File(appData, characterDirName).getAbsoluteFile();
+                       // ディレクトリを準備する
+                       userDataDir = ensureAppDataDir(appData);
+               }
+               return userDataDir;
+       }
 
-                       // ディレクトリを準備する.
-                       if (!userDataDir.exists()) {
-                               if (!userDataDir.mkdirs()) {
-                                       // ログ保管場所も設定されていないのでコンソールに出すしかない.
-                                       System.err.println("can't create the user data directory. " + userDataDir);
-                               }
+       /**
+        * ユーザーごとのローカルアプリケーションデータ保存先を取得する.<br>
+        * システムプロパティlocal.appdata.dir、環境変数LOCALAPPDATAのいずれも設定されていない場合は
+        * {@link #getUserDataDir()}と同じである。
+        *
+        * @return ローカルなアプリケーションデータ保存先
+        */
+       public synchronized static File getLocalUserDataDir() {
+               if (userDataDir == null) {
+
+                       String appData = null;
+                       // システムプロパティ「local.appdata.dir」を探す
+                       appData = System.getProperty("local.appdata.dir");
+                       if (appData == null) {
+                               // なければ環境変数LOCALAPPDATAを探す
+                               // Windows2000/XP/Vista/Windows7には存在する.
+                               appData = System.getenv("LOCALAPPDATA");
+                       }
+
+                       if (appData != null && appData.trim().length() > 0) {
+                               localUserDataDir = ensureAppDataDir(appData);
+
+                       } else {
+                               // local.appdata.dirシステムプロパティ、LOCALAPPDATA環境変数、いずれもない場合は
+                               // getUserDataDir()と同じものとする。
+                               localUserDataDir = getUserDataDir();
+                       }
+               }
+               return localUserDataDir;
+       }
+
+       /**
+        * ベースとなるディレクトリ名を指定し、本アプリケーション名を付与したディレクトリを準備して、
+        * そのパスとなるファイルオブジェクトを返す。
+        * @param baseDir ベースとなるディレクトリ
+        * @return 本アプリケーション用のディレクトリ
+        */
+       private static File ensureAppDataDir(String baseDir) {
+               // システムプロパティ「characterdata.dirname」のディレクトリ名、なければ「CharacterManaJ」を設定する.
+               String characterDirName = System.getProperty("characterdata.dirname", CONFIGURATION_DIR_NAME);
+               File userDataDir = new File(baseDir, characterDirName).getAbsoluteFile();
+
+               // ディレクトリを準備する.
+               if (!userDataDir.exists()) {
+                       if (!userDataDir.mkdirs()) {
+                               // ログ保管場所も設定されていないのでコンソールに出すしかない.
+                               System.err.println("can't create the user data directory. " + userDataDir);
                        }
                }
                return userDataDir;
@@ -82,7 +129,7 @@ public final class ConfigurationDirUtilities {
         */
        public synchronized static File getApplicationBaseDir() {
                if (applicationBaseDir == null) {
-                       
+
                        String appbaseDir = System.getProperty("appbase.dir");
                        if (appbaseDir != null && appbaseDir.length() > 0) {
                                // 明示的にアプリケーションベースディレクトリが指定されている場合.
@@ -101,20 +148,20 @@ public final class ConfigurationDirUtilities {
                                if (codeSource == null) {
                                        throw new RuntimeException("codeSource is null: domain=" + pdomain);
                                }
-                               
+
                                URL codeBaseUrl = codeSource.getLocation();
                                if (!codeBaseUrl.getProtocol().equals("file")) {
                                        throw new RuntimeException("codeLocation is not file protocol.: " + codeBaseUrl);
                                }
-                               
+
                                // クラスパスフォルダ、またはJARファイルの、その親
                                applicationBaseDir = new File(codeBaseUrl.getPath()).getParentFile();
-                               
+
                        }
                }
                return applicationBaseDir;
        }
-       
+
        /**
         * デフォルトのユーザー固有のキャラクターデータディレクトリを取得する.<br>
         * ユーザー固有のキャラクターディレクトリがまだ存在しない場合は作成される.<br>
@@ -130,5 +177,5 @@ public final class ConfigurationDirUtilities {
                }
                return characterBaseDir;
        }
-       
+
 }
index 248c042..6f143bf 100644 (file)
@@ -9,7 +9,7 @@ import java.util.logging.Logger;
 
 /**
  * ユーザーデータの保存先を生成するファクトリ
- * 
+ *
  * @author seraphy
  */
 public class UserDataFactory {
@@ -19,39 +19,53 @@ public class UserDataFactory {
         */
        private static final Logger logger = Logger.getLogger(UserDataFactory.class.getName());
 
-       /**
-        * シングルトン
-        */
-       private static UserDataFactory inst = new UserDataFactory();
+       private final File userDataDir;
+
+       private UserDataFactory(File userDataDir) {
+               this.userDataDir = userDataDir;
+       }
 
        /**
         * インスタンスを取得する.
-        * 
+        *
         * @return インスタンス
         */
        public static UserDataFactory getInstance() {
-               return inst;
+               return new UserDataFactory(ConfigurationDirUtilities.getUserDataDir());
        }
 
        /**
-        * プライベートコンストラクタ
+        * ローカルデータ用のインスタンスを取得する.
+        *
+        * @return インスタンス
         */
-       private UserDataFactory() {
-               super();
+       public static UserDataFactory getLocalInstance() {
+               return new UserDataFactory(ConfigurationDirUtilities.getLocalUserDataDir());
        }
 
        /**
         * 拡張子を含むファイル名を指定し、そのファイルが保存されるべきユーザディレクトリを判定して返す.<br>
         * nullまたは空の場合、もしくは拡張子がない場合はユーザディレクトリのルートを返します.<br>
         * フォルダがなければ作成されます.<br>
-        * 
+        *
         * @param name
         *            ファイル名、もしくはnull
         * @return ファィルの拡張子に対応したデータ保存先フォルダ
         */
        public File getSpecialDataDir(String name) {
-               File userDataDir = ConfigurationDirUtilities.getUserDataDir();
-               
+               return getSpecialDataDir(name, userDataDir);
+       }
+
+       /**
+        * 拡張子を含むファイル名を指定し、そのファイルが保存されるべきユーザディレクトリを判定して返す.<br>
+        * nullまたは空の場合、もしくは拡張子がない場合はユーザディレクトリのルートを返します.<br>
+        * フォルダがなければ作成されます.<br>
+        *
+        * @param name ファイル名、もしくはnull
+        * @param userDataDir ユーザーディレクトリ
+        * @return ファィルの拡張子に対応したデータ保存先フォルダ
+        */
+       private File getSpecialDataDir(String name, File userDataDir) {
                if (name != null && name.length() > 0) {
                        int seppos = name.lastIndexOf('-');
                        if (name.endsWith(".xml") && seppos >= 0) {
@@ -82,13 +96,13 @@ public class UserDataFactory {
                        boolean result = userDataDir.mkdirs();
                        logger.log(Level.INFO, "makeDir: " + userDataDir + " /succeeded=" + result);
                }
-               
+
                return userDataDir;
        }
 
        /**
         * 指定した名前のユーザーデータ保存先を作成する.
-        * 
+        *
         * @param name
         *            ファイル名
         * @return 保存先
@@ -102,7 +116,7 @@ public class UserDataFactory {
 
        /**
         * docBaseの名前ベースのUUIDをプレフィックスをもつユーザーデータ保存先を作成する.<br>
-        * 
+        *
         * @param docBase
         *            URI、null可
         * @param name
@@ -118,7 +132,7 @@ public class UserDataFactory {
         * docBaseをハッシュ値化文字列にした、名前ベースのUUIDを返す.<br>
         * docBaseがnullの場合は空文字とみなして変換する.<br>
         * (衝突の可能性は無視する。)<br>
-        * 
+        *
         * @param docBase
         *            URI、null可
         * @return 名前ベースのUUID
@@ -135,7 +149,7 @@ public class UserDataFactory {
                if (logger.isLoggable(Level.FINEST)) {
                        logger.log(Level.FINEST, "mangledName " + docBase + "=" + mangledName);
                }
-               
+
                return mangledName;
        }
 }