throw new IllegalArgumentException();\r
}\r
\r
- // キャラクターデータが格納されている親ディレクトリのリスト\r
+ // キャラクターデータが格納されている親ディレクトリ\r
DirectoryConfig dirConfig = DirectoryConfig.getInstance();\r
- File[] baseDirs = {dirConfig.getCharactersDir(),};\r
+ File baseDir = dirConfig.getCharactersDir();\r
\r
// ファイル名をノーマライズする\r
FileNameNormalizer normalizer = FileNameNormalizer.getDefault();\r
.newFixedThreadPool(numOfProcessors);\r
try {\r
// キャラクターデータ対象ディレクトリを列挙し、並列に解析する\r
- for (File baseDir : baseDirs) {\r
- if (baseDir == null || !baseDir.exists()\r
- || !baseDir.isDirectory()) {\r
- continue;\r
- }\r
- for (File dir : baseDir.listFiles(new FileFilter() {\r
- public boolean accept(File pathname) {\r
- boolean accept = pathname.isDirectory()\r
- && !pathname.getName().startsWith(".");\r
- if (accept) {\r
- File configFile = new File(pathname, CONFIG_FILE);\r
- accept = configFile.exists()\r
- && configFile.canRead();\r
- }\r
- return accept;\r
+ for (File dir : baseDir.listFiles(new FileFilter() {\r
+ public boolean accept(File pathname) {\r
+ boolean accept = pathname.isDirectory()\r
+ && !pathname.getName().startsWith(".");\r
+ if (accept) {\r
+ File configFile = new File(pathname, CONFIG_FILE);\r
+ accept = configFile.exists() && configFile.canRead();\r
}\r
- })) {\r
- String path = normalizer.normalize(dir.getPath());\r
- final File normDir = new File(path);\r
-\r
- executorSrv.submit(new Runnable() {\r
- public void run() {\r
- boolean terminate = false;\r
- File characterDataXml = new File(normDir,\r
- CONFIG_FILE);\r
- if (characterDataXml.exists()) {\r
- try {\r
- File docBaseFile = new File(normDir,\r
- CONFIG_FILE);\r
- URI docBase = docBaseFile.toURI();\r
- CharacterData characterData = loadProfile(docBase);\r
- terminate = !callback\r
- .receiveCharacterData(characterData);\r
-\r
- } catch (Exception ex) {\r
- terminate = !callback.occureException(\r
- normDir, ex);\r
- }\r
- }\r
- if (terminate) {\r
- // 中止が指示されたらスレッドプールを終了する\r
- logger.log(Level.FINE,\r
- "shutdownNow listProfile");\r
- executorSrv.shutdownNow();\r
- cancelled.set(true);\r
+ return accept;\r
+ }\r
+ })) {\r
+ String path = normalizer.normalize(dir.getPath());\r
+ final File normDir = new File(path);\r
+\r
+ executorSrv.submit(new Runnable() {\r
+ public void run() {\r
+ boolean terminate = false;\r
+ File characterDataXml = new File(normDir, CONFIG_FILE);\r
+ if (characterDataXml.exists()) {\r
+ try {\r
+ File docBaseFile = new File(normDir,\r
+ CONFIG_FILE);\r
+ URI docBase = docBaseFile.toURI();\r
+ CharacterData characterData = loadProfile(docBase);\r
+ terminate = !callback\r
+ .receiveCharacterData(characterData);\r
+\r
+ } catch (Exception ex) {\r
+ terminate = !callback.occureException(normDir,\r
+ ex);\r
}\r
}\r
- });\r
- }\r
+ if (terminate) {\r
+ // 中止が指示されたらスレッドプールを終了する\r
+ logger.log(Level.FINE, "shutdownNow listProfile");\r
+ executorSrv.shutdownNow();\r
+ cancelled.set(true);\r
+ }\r
+ }\r
+ });\r
}\r
} finally {\r
// タスクの登録を受付終了し、現在のすべてのタスクが完了したらスレッドは終了する.\r
package charactermanaj.model.io;\r
\r
+import java.io.BufferedInputStream;\r
+import java.io.BufferedOutputStream;\r
import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
import java.net.URI;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
+import java.sql.Timestamp;\r
+import java.util.Properties;\r
import java.util.logging.Level;\r
import java.util.logging.Logger;\r
\r
-import charactermanaj.model.AppConfig;\r
import charactermanaj.model.CharacterData;\r
-import charactermanaj.model.RecentData;\r
import charactermanaj.util.DirectoryConfig;\r
-import charactermanaj.util.UserData;\r
-import charactermanaj.util.UserDataFactory;\r
\r
/**\r
* 最後に使用したデータの使用状況を保存・復元するためのクラス\r
+ * \r
* @author seraphy\r
*/\r
public final class RecentDataPersistent {\r
\r
/**\r
+ * キャラクターデータの親フォルダごとに保存する、最後に使用したキャラクターデータを保存するファイル名\r
+ */\r
+ private static final String RECENT_CAHARCTER_INFO_XML = "recent-character.xml";\r
+\r
+ /**\r
* ロガー\r
*/\r
private static final Logger logger = Logger.getLogger(RecentDataPersistent.class.getName());\r
* シングルトン\r
*/\r
private static final RecentDataPersistent inst = new RecentDataPersistent();\r
- \r
- /**\r
- * 最後に使用したプロファイルのコートベースを保存するファイル名\r
- */\r
- private static final String RECENT_CHARACTER_SER = "recent-character.ser";\r
- \r
\r
/**\r
* プライベートコンストラクタ\r
\r
/**\r
* インスタンスを取得する\r
+ * \r
* @return インスタンス\r
*/\r
public static RecentDataPersistent getInstance() {\r
return inst;\r
}\r
- \r
+\r
/**\r
- * 最後に使用したキャラクターデータとして記録する.\r
+ * キャラクターデータの親フォルダごとに保存する、最後に使用したキャラクターデータを保存するファイル\r
+ * \r
+ * @return\r
+ */\r
+ private File getRecentCharacterXML() {\r
+ File currentCharactersDir = DirectoryConfig.getInstance()\r
+ .getCharactersDir();\r
+ File recentCharacterXML = new File(currentCharactersDir,\r
+ RECENT_CAHARCTER_INFO_XML);\r
+ return recentCharacterXML;\r
+ }\r
+\r
+ /**\r
+ * 最後に使用したキャラクターデータのフォルダ名を親ディレクトリからの相対パスとして保存する.<br>\r
+ * ただし、書き込み禁止である場合は何もしない.<br>\r
+ * \r
* @param characterData\r
- * @throws IOException 保存できなった場合\r
+ * キャラクターデータ\r
+ * @throws IOException\r
+ * 書き込みに失敗した場合\r
*/\r
- public void saveRecent(CharacterData characterData) throws IOException {\r
- if (characterData == null) {\r
- throw new IllegalArgumentException();\r
- }\r
- if (!characterData.isValid()) {\r
- return;\r
+ public boolean saveRecent(CharacterData characterData) throws IOException {\r
+ URI docBase = null;\r
+ if (characterData != null) {\r
+ docBase = characterData.getDocBase();\r
}\r
- \r
- AppConfig appConfig = AppConfig.getInstance();\r
- \r
- RecentData recentData = new RecentData();\r
- recentData.setAppVersion(appConfig.getSpecificationVersion());\r
- recentData.setDocBase(characterData.getDocBase());\r
- \r
- UserData recentCharacterStore = getRecentCharacterStore();\r
-\r
- // 他のキャラクターディレクトリ上のデータを取得しマージする.\r
- Map<File, RecentData> recentDataMap = new HashMap<File, RecentData>();\r
- try {\r
- if (recentCharacterStore.exists()) {\r
- Object rawRecentData = recentCharacterStore.load();\r
- if (rawRecentData instanceof Map) {\r
- @SuppressWarnings("unchecked")\r
- Map<File, RecentData> prevRecentDataMap = (Map<File, RecentData>) rawRecentData;\r
- for (Map.Entry<File, RecentData> entry : prevRecentDataMap.entrySet()) {\r
- File dir = entry.getKey();\r
- if (dir.exists() && dir.isDirectory()) {\r
- // 現在も有効なものだけを保存する.\r
- // (すでに存在しなくなっているものは除外する.)\r
- RecentData prevRecentData = entry.getValue();\r
- recentDataMap.put(dir, prevRecentData);\r
- }\r
- }\r
- }\r
+\r
+ String characterDataName = null;\r
+ if (docBase != null) {\r
+ File currentCharactersDir = DirectoryConfig.getInstance()\r
+ .getCharactersDir();\r
+ File characterXml = new File(docBase);\r
+ File characterDir = characterXml.getParentFile();\r
+ // "Foo/Bar/character.xml"の、「Foo」の部分を取得する.\r
+ File baseDir = characterDir.getParentFile();\r
+ if (currentCharactersDir.equals(baseDir)) {\r
+ // "Foo/Bar/character.xml"の「Bar」の部分を取得する.\r
+ // ※ キャラクターデータの親フォルダ上のフォルダ名だけを保存する.(相対パス)\r
+ characterDataName = characterDir.getName();\r
}\r
+ }\r
+ Properties props = new Properties();\r
+ props.setProperty("lastUseCharacterData", characterDataName == null\r
+ ? ""\r
+ : characterDataName);\r
\r
- } catch (Exception ex) {\r
- logger.log(Level.WARNING, "old recentDataFile load failed.", ex);\r
- // 古い情報が取得できない場合でも最新のものだけは保存できるようにしておく。\r
+ File recentCharacterXML = getRecentCharacterXML();\r
+ if (recentCharacterXML.exists() && !recentCharacterXML.canWrite()) {\r
+ // ファイルが書き込み禁止の場合は何もしない.\r
+ logger.log(Level.FINE, "recent-character.xml is readonly.");\r
+ return false;\r
}\r
\r
- // 保存する.\r
- File currentCharactersDir = DirectoryConfig.getInstance().getCharactersDir();\r
- recentDataMap.put(currentCharactersDir, recentData);\r
- recentCharacterStore.save(recentDataMap);\r
+ // ファイルがまだ実在しないか、書き込み可能である場合のみ保存する.\r
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(\r
+ recentCharacterXML));\r
+ try {\r
+ String comment = "recent-character: lastModified="\r
+ + (new Timestamp(System.currentTimeMillis()).toString());\r
+ props.storeToXML(os, comment);\r
+ } finally {\r
+ os.close();\r
+ }\r
+ return true;\r
}\r
- \r
+\r
/**\r
- * 最後に使用したキャラクターデータを取得する.\r
- * @return キャラクターデータ。最後に使用したデータが存在しない場合はnull\r
- * @throws IOException 読み込みに失敗した場合\r
+ * 親ディレクトリからの相対パスとして記録されている、最後に使用したキャラクターデータのフォルダ名から、\r
+ * 最後に使用したキャラクターデータをロードして返す.<br>\r
+ * 該当するキャラクターデータが存在しないか、読み込みに失敗した場合は「履歴なし」としてnullを返す.<br>\r
+ * \r
+ * @return キャラクターデータ、もしくはnull\r
*/\r
- public CharacterData loadRecent() throws IOException {\r
- UserData recentCharacterStore = getRecentCharacterStore();\r
- if (!recentCharacterStore.exists()) {\r
- return null;\r
- }\r
+ public CharacterData loadRecent() {\r
+ File recentCharacterXML = getRecentCharacterXML();\r
+ if (recentCharacterXML.exists()) {\r
+ try {\r
+ Properties props = new Properties();\r
+ InputStream is = new BufferedInputStream(new FileInputStream(\r
+ recentCharacterXML));\r
+ try {\r
+ props.loadFromXML(is);\r
+ } finally {\r
+ is.close();\r
+ }\r
\r
- RecentData recentData;\r
- try {\r
- File currentCharactersDir = DirectoryConfig.getInstance().getCharactersDir();\r
-\r
- Object rawRecentData = recentCharacterStore.load();\r
- if (rawRecentData instanceof RecentData) {\r
- // 旧形式 (単一)\r
- recentData = (RecentData) rawRecentData;\r
- logger.log(Level.INFO, "old-recentdata-type: " + recentData);\r
- \r
- // 旧形式で保存されているURIが、現在選択しているキャラクターデータと同じ親ディレクトリ\r
- // でなければ復元しない.\r
- URI uri = recentData.getDocBase();\r
- File parentDir = new File(uri).getParentFile().getParentFile(); // 2段上\r
- if (!currentCharactersDir.equals(parentDir)) {\r
- logger.log(Level.INFO,\r
- "unmatched characters-dir. current="\r
- + currentCharactersDir + "/recent="\r
- + parentDir);\r
- recentData = null;\r
+ String characterDataName = props\r
+ .getProperty("lastUseCharacterData");\r
+ if (characterDataName != null\r
+ && characterDataName.trim().length() > 0) {\r
+ // ※ キャラクターデータの親フォルダ上のフォルダ名だけを保存されているので\r
+ // 相対パスから、character.xmlの絶対パスを求める\r
+ File currentCharactersDir = DirectoryConfig.getInstance()\r
+ .getCharactersDir();\r
+ File characterDir = new File(currentCharactersDir,\r
+ characterDataName);\r
+ File characterXml = new File(characterDir,\r
+ CharacterDataPersistent.CONFIG_FILE);\r
+ if (characterXml.exists()) {\r
+ // character.xmlが存在すれば復元を試行する.\r
+ CharacterDataPersistent persist = CharacterDataPersistent\r
+ .getInstance();\r
+ return persist.loadProfile(characterXml.toURI());\r
+ }\r
}\r
\r
- } else if (rawRecentData instanceof Map) {\r
- // 新形式 (複数のキャラクターディレクトリに対応)\r
- @SuppressWarnings("unchecked")\r
- Map<File, RecentData> recentDataMap = (Map<File, RecentData>) rawRecentData;\r
- recentData = recentDataMap.get(currentCharactersDir);\r
- logger.log(Level.FINE, "recent-data: " + currentCharactersDir + "=" + recentData);\r
-\r
- } else {\r
- // 不明な形式\r
- logger.log(Level.SEVERE,\r
- "invalid file format. " + recentCharacterStore\r
- + "/class=" + rawRecentData.getClass());\r
- recentData = null;\r
+ } catch (Exception ex) {\r
+ // 失敗した場合は最後に使用したデータが存在しないものとみなす.\r
+ logger.log(Level.WARNING, "recent data loading failed. "\r
+ + recentCharacterXML, ex);\r
}\r
-\r
- } catch (Exception ex) {\r
- // RecentData情報の復元に失敗した場合は最後に使用したデータが存在しないものとみなす.\r
- logger.log(Level.WARNING, "recent data loading failed. " + recentCharacterStore, ex);\r
- recentData = null;\r
- }\r
-\r
- if (recentData != null) {\r
- CharacterDataPersistent persist = CharacterDataPersistent.getInstance();\r
- return persist.loadProfile(recentData.getDocBase());\r
}\r
\r
// 履歴がない場合、もしくは読み取れなかった場合はnullを返す.\r
return null;\r
}\r
- \r
- /**\r
- * 最後に使用したキャラクタデータの保存先を取得する\r
- * @return 保存先\r
- */\r
- protected UserData getRecentCharacterStore() {\r
- UserDataFactory userDataFactory = UserDataFactory.getInstance();\r
- UserData recentCharacterStore = userDataFactory.getUserData(RECENT_CHARACTER_SER);\r
- return recentCharacterStore;\r
- }\r
+\r
+ // /**\r
+ // * 最後に使用したキャラクターデータを取得する.\r
+ // *\r
+ // * @return キャラクターデータ。最後に使用したデータが存在しない場合はnull\r
+ // * @throws IOException\r
+ // * 読み込みに失敗した場合\r
+ // */\r
+ // private CharacterData loadRecentSer() throws IOException {\r
+ // UserData recentCharacterStore = getRecentCharacterStore();\r
+ // if (!recentCharacterStore.exists()) {\r
+ // return null;\r
+ // }\r
+ //\r
+ // RecentData recentData;\r
+ // try {\r
+ // File currentCharactersDir =\r
+ // DirectoryConfig.getInstance().getCharactersDir();\r
+ //\r
+ // Object rawRecentData = recentCharacterStore.load();\r
+ // if (rawRecentData instanceof RecentData) {\r
+ // // 旧形式 (単一)\r
+ // recentData = (RecentData) rawRecentData;\r
+ // logger.log(Level.INFO, "old-recentdata-type: " + recentData);\r
+ //\r
+ // // 旧形式で保存されているURIが、現在選択しているキャラクターデータと同じ親ディレクトリ\r
+ // // でなければ復元しない.\r
+ // URI uri = recentData.getDocBase();\r
+ // File parentDir = new File(uri).getParentFile().getParentFile(); // 2段上\r
+ // if (!currentCharactersDir.equals(parentDir)) {\r
+ // logger.log(Level.INFO,\r
+ // "unmatched characters-dir. current="\r
+ // + currentCharactersDir + "/recent="\r
+ // + parentDir);\r
+ // recentData = null;\r
+ // }\r
+ //\r
+ // } else if (rawRecentData instanceof Map) {\r
+ // // 新形式 (複数のキャラクターディレクトリに対応)\r
+ // @SuppressWarnings("unchecked")\r
+ // Map<File, RecentData> recentDataMap = (Map<File, RecentData>)\r
+ // rawRecentData;\r
+ // recentData = recentDataMap.get(currentCharactersDir);\r
+ // logger.log(Level.FINE, "recent-data: " + currentCharactersDir + "=" +\r
+ // recentData);\r
+ //\r
+ // } else {\r
+ // // 不明な形式\r
+ // logger.log(Level.SEVERE,\r
+ // "invalid file format. " + recentCharacterStore\r
+ // + "/class=" + rawRecentData.getClass());\r
+ // recentData = null;\r
+ // }\r
+ //\r
+ // } catch (Exception ex) {\r
+ // // RecentData情報の復元に失敗した場合は最後に使用したデータが存在しないものとみなす.\r
+ // logger.log(Level.WARNING, "recent data loading failed. " +\r
+ // recentCharacterStore, ex);\r
+ // recentData = null;\r
+ // }\r
+ //\r
+ // if (recentData != null) {\r
+ // CharacterDataPersistent persist = CharacterDataPersistent.getInstance();\r
+ // return persist.loadProfile(recentData.getDocBase());\r
+ // }\r
+ //\r
+ // // 履歴がない場合、もしくは読み取れなかった場合はnullを返す.\r
+ // return null;\r
+ // }\r
+ //\r
+ // /**\r
+ // * 最後に使用したキャラクタデータの保存先を取得する\r
+ // *\r
+ // * @return 保存先\r
+ // */\r
+ // protected UserData getRecentCharacterStore() {\r
+ // UserDataFactory userDataFactory = UserDataFactory.getInstance();\r
+ // UserData recentCharacterStore =\r
+ // userDataFactory.getUserData(RECENT_CHARACTER_SER);\r
+ // return recentCharacterStore;\r
+ // }\r
\r
\r
}\r