• R/O
  • HTTP
  • SSH
  • HTTPS

CharacterManaJ: Commit

キャラクターなんとかJの本体


Commit MetaInfo

Revision2bd92ce171339392c73353dbabec0c2907a75a0c (tree)
Time2019-02-07 08:29:10
Authorseraphy <seraphy@user...>
Commiterseraphy

Log Message

mangled名をutf-8をベースにするように変更。旧mangledは置換する。

Change Summary

Incremental Difference

--- a/src/main/java/charactermanaj/model/io/PartsImageDirectoryWatchAgentThread.java
+++ b/src/main/java/charactermanaj/model/io/PartsImageDirectoryWatchAgentThread.java
@@ -22,16 +22,16 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
2222 * ロガー
2323 */
2424 private static final Logger logger = Logger.getLogger(PartsImageDirectoryWatchAgent.class.getName());
25-
25+
2626 private final CharacterData characterData;
27-
27+
2828 private final File baseDir;
29-
29+
3030 /**
3131 * リスナーとサスペンド要求マップのロックオブジェクト
3232 */
3333 private final Object lockListeners = new Object();
34-
34+
3535 /**
3636 * 監視を通知されるリスナー.
3737 */
@@ -43,46 +43,46 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
4343 */
4444 private IdentityHashMap<PartsImageDirectoryWatchListener, Integer> suspendStateMap
4545 = new IdentityHashMap<PartsImageDirectoryWatchListener, Integer>();
46-
47-
46+
47+
4848 /**
4949 * ロックオブジェクト
5050 */
5151 private final Object lock = new Object();
52-
53-
52+
53+
5454 /**
5555 * 停止フラグ
5656 */
5757 private volatile boolean stopFlag;
58-
58+
5959 /**
6060 * 監視インターバル
6161 */
6262 private int dirWatchInterval;
63-
63+
6464 /**
6565 * スレッド、生成されていなければnull
6666 */
6767 private Thread thread;
68-
68+
6969 /**
7070 * 監視結果1、まだ監視されていなければnull
7171 */
7272 private volatile Long signature;
73-
73+
7474 /**
7575 * 監視結果2、検出されたアイテムの個数
7676 */
7777 private volatile int itemCount;
78-
78+
7979 /**
8080 * 監視結果3、検出されたアイテムの最終更新日。ただし未来の日付は除外する。
8181 */
8282 private volatile long maxLastModified;
8383
84-
85-
84+
85+
8686 public PartsImageDirectoryWatchAgentThread(CharacterData characterData) {
8787 if (characterData == null) {
8888 throw new IllegalArgumentException();
@@ -98,11 +98,11 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
9898 this.baseDir = baseDir;
9999 this.dirWatchInterval = AppConfig.getInstance().getDirWatchInterval();
100100 }
101-
101+
102102 public CharacterData getCharcterData() {
103103 return characterData;
104104 }
105-
105+
106106 /**
107107 * 監視を開始する.<br>
108108 * 一定時間待機後、フォルダを監視し、前回監視結果と比較して変更があれば通知を行う.<br>
@@ -150,10 +150,10 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
150150 thread.start();
151151 }
152152 }
153-
153+
154154 /**
155155 * 監視を停止する.<br>
156- *
156+ *
157157 * @return 停止した場合はtrue、すでに停止していたか開始されていない場合はfalse
158158 */
159159 private boolean stop() {
@@ -173,14 +173,14 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
173173 }
174174 stopped = true;
175175 }
176-
176+
177177 // スレッドは停止されていると見なす.
178178 thread = null;
179179 }
180180 return stopped;
181181 }
182-
183-
182+
183+
184184 /**
185185 * スレッドの停止フラグがたてられるまで、一定時間待機と監視とを永久に繰り返す.<br>
186186 * ただし、スレッド自身はデーモンとして動作させているので他の非デーモンスレッドが存在しなくなれば停止する.<br>
@@ -190,7 +190,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
190190
191191 // 初回スキャンは無視するためリセット状態とする.
192192 this.signature = null;
193-
193+
194194 // スキャンループ
195195 while (!stopFlag) {
196196 try {
@@ -211,11 +211,11 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
211211 }
212212 logger.log(Level.FINE, "watch-dir thead stopped. " + this);
213213 }
214-
214+
215215 /**
216216 * 監視を行う.<br>
217217 * 停止フラグが設定されるか、割り込みされた場合は処理を中断してInterruptedException例外を返して終了する.<br>
218- *
218+ *
219219 * @param notifier
220220 * 通知するためのオブジェクト
221221 * @throws InterruptedException
@@ -229,7 +229,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
229229 int itemCount = 0;
230230 long maxLastModified = 0;
231231 long now = System.currentTimeMillis() + dirWatchInterval;
232-
232+
233233 CRC32 crc = new CRC32();
234234 for (PartsCategory partsCategory : characterData.getPartsCategories()) {
235235 for (Layer layer : partsCategory.getLayers()) {
@@ -261,6 +261,8 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
261261 Collections.sort(files);
262262 }
263263 for (String file : files) {
264+ // 同一動作環境上でのファイル名の比較に使うためなので
265+ // 文字コードは現在のデフォルトで良い。
264266 crc.update(file.getBytes());
265267 }
266268 }
@@ -281,12 +283,12 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
281283 this.signature = Long.valueOf(signature);
282284 this.maxLastModified = maxLastModified;
283285 this.itemCount = itemCount;
284-
286+
285287 }
286-
288+
287289 /**
288290 * イベントリスナを登録する
289- *
291+ *
290292 * @param l
291293 * リスナ
292294 */
@@ -298,10 +300,10 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
298300 changeSuspendState();
299301 }
300302 }
301-
303+
302304 /**
303305 * イベントリスナを登録解除する
304- *
306+ *
305307 * @param l
306308 * リスナ
307309 */
@@ -314,7 +316,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
314316 changeSuspendState();
315317 }
316318 }
317-
319+
318320 public void suspend(PartsImageDirectoryWatchListener l) {
319321 if (l != null) {
320322 synchronized (lockListeners) {
@@ -330,7 +332,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
330332 changeSuspendState();
331333 }
332334 }
333-
335+
334336 public void resume(PartsImageDirectoryWatchListener l) {
335337 if (l != null) {
336338 synchronized (lockListeners) {
@@ -347,7 +349,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
347349 changeSuspendState();
348350 }
349351 }
350-
352+
351353 protected void changeSuspendState() {
352354 boolean active;
353355 synchronized (lockListeners) {
@@ -360,7 +362,7 @@ public class PartsImageDirectoryWatchAgentThread implements Runnable {
360362 stop();
361363 }
362364 }
363-
365+
364366 /**
365367 * イベントを通知する.
366368 */
--- a/src/main/java/charactermanaj/util/FileUserData.java
+++ b/src/main/java/charactermanaj/util/FileUserData.java
@@ -34,6 +34,10 @@ public class FileUserData implements UserData {
3434 this.file = file;
3535 }
3636
37+ public File getFile() {
38+ return file;
39+ }
40+
3741 @Override
3842 public boolean exists() {
3943 return file.exists() && file.isFile();
--- a/src/main/java/charactermanaj/util/UserDataFactory.java
+++ b/src/main/java/charactermanaj/util/UserDataFactory.java
@@ -2,6 +2,8 @@ package charactermanaj.util;
22
33 import java.io.File;
44 import java.net.URI;
5+import java.nio.charset.Charset;
6+import java.util.Arrays;
57 import java.util.UUID;
68 import java.util.logging.Level;
79 import java.util.logging.Logger;
@@ -124,8 +126,31 @@ public class UserDataFactory {
124126 * @return 保存先
125127 */
126128 public UserData getMangledNamedUserData(URI docBase, String name) {
127- String mangledName = getMangledName(docBase);
128- return getUserData(mangledName + "-" + name);
129+ // Mangled名はファイル名を既定でUTF-8変換しハッシュ化したものを使用する
130+ Charset fileNameEncoding = getMangledEncoding();
131+ String mangledName = getMangledName(docBase, fileNameEncoding);
132+ FileUserData userData = (FileUserData) getUserData(mangledName + "-" + name);
133+
134+ if (!userData.exists()) {
135+ // 指定されたMangled名が、まだ実在しない場合
136+ // システムデフォルトの文字コードでMangledされた旧名があれば
137+ // 旧名のファイル名をUTF-8によるMangledされたものにリネームする。
138+ // (ver0.999まではmangledの文字コードを明示していなかったため、
139+ // java5以前はシステム固有、java6以降ではfile.encodingのシステムプロパティで変動していた)
140+ for (Charset defaultEncoding : getSystemEncodings()) {
141+ if (!fileNameEncoding.equals(defaultEncoding)) {
142+ String oldMangledName = getMangledName(docBase, defaultEncoding);
143+ FileUserData oldUserData = (FileUserData) getUserData(oldMangledName + "-" + name);
144+ if (oldUserData.exists()) {
145+ logger.log(Level.INFO, "rename mangled: (" + defaultEncoding + ")" + oldUserData.getFile()
146+ + " -> (" + fileNameEncoding + ")" + userData.getFile());
147+ oldUserData.getFile().renameTo(userData.getFile());
148+ break;
149+ }
150+ }
151+ }
152+ }
153+ return userData;
129154 }
130155
131156 /**
@@ -135,16 +160,18 @@ public class UserDataFactory {
135160 *
136161 * @param docBase
137162 * URI、null可
163+ * @param encoding
164+ * docBase名をハッシュ化するための文字コード
138165 * @return 名前ベースのUUID
139166 */
140- private String getMangledName(URI docBase) {
167+ private String getMangledName(URI docBase, Charset encoding) {
141168 String docBaseStr;
142169 if (docBase == null) {
143170 docBaseStr = "";
144171 } else {
145172 docBaseStr = docBase.toString();
146173 }
147- String mangledName = UUID.nameUUIDFromBytes(docBaseStr.getBytes()).toString();
174+ String mangledName = UUID.nameUUIDFromBytes(docBaseStr.getBytes(encoding)).toString();
148175
149176 if (logger.isLoggable(Level.FINEST)) {
150177 logger.log(Level.FINEST, "mangledName " + docBase + "=" + mangledName);
@@ -152,5 +179,88 @@ public class UserDataFactory {
152179
153180 return mangledName;
154181 }
182+
183+ /**
184+ * Mangled名生成に使う文字コード
185+ */
186+ private static Charset mangledEncoding;
187+
188+ /**
189+ * システムのデフォルトの文字コードの候補。
190+ */
191+ private static Charset[] systemEncodings;
192+
193+ /**
194+ * Mandled名生成に使う文字コードを指定するシステムプロパティ名
195+ */
196+ public static final String KEY_MANGLED_ENCODING = "charactermanaj.mangled.encoding";
197+
198+ /**
199+ *
200+ * @return
201+ */
202+ private static Charset getMangledEncoding() {
203+ if (mangledEncoding == null) {
204+ String encName = System.getProperty(KEY_MANGLED_ENCODING, "UTF-8");
205+ Charset fileNameEncoding = null;
206+ if (encName != null && encName.length() > 0) {
207+ try {
208+ fileNameEncoding = Charset.forName(encName);
209+ } catch (Exception ex) {
210+ logger.log(Level.SEVERE, "unsupported charset: " + encName, ex);
211+ }
212+ }
213+ if (fileNameEncoding == null) {
214+ // だめならシステム標準にする
215+ fileNameEncoding = Charset.defaultCharset();
216+ }
217+ mangledEncoding = fileNameEncoding;
218+ }
219+ return mangledEncoding;
220+ }
221+
222+ /**
223+ * システムのデフォルトの文字コードの候補リストを取得する。
224+ * コンテンツの文字コード(file.encoding)とファイル名の文字コード(sun.jnu.encoding)の両方を取得する。
225+ * ただし、どちらも同じコードである場合は1つにまとめられる。
226+ * これらのシステムプロパティのデフォルト値が、どのように決定されるかは以下参照。
227+ * https://stackoverflow.com/questions/1006276/what-is-the-default-encoding-of-the-jvm
228+ * http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/System.c#l169
229+ * http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/solaris/native/java/lang/java_props_md.c#l427
230+ * @return システムのデフォルトの文字コードの候補リスト
231+ */
232+ private static Charset[] getSystemEncodings() {
233+ if (systemEncodings == null) {
234+ String[] keys = { "file.encoding", "sun.jnu.encoding" };
235+ Charset[] encodings = new Charset[keys.length];
236+ int cnt = 0;
237+ for (String key : keys) {
238+ String encodingName = System.getProperty(key);
239+ if (encodingName != null && encodingName.length() > 0) {
240+ Charset encoding;
241+ try {
242+ encoding = Charset.forName(encodingName);
243+ } catch (Exception ex) {
244+ // 基本的にはありえない
245+ logger.log(Level.SEVERE, "invalid charset:" + encodingName, ex);
246+ continue;
247+ }
248+
249+ boolean found = false;
250+ for (int idx = 0; idx < cnt; idx++) {
251+ if (encodings[idx].equals(encoding)) {
252+ found = true;
253+ break;
254+ }
255+ }
256+ if (!found) {
257+ encodings[cnt++] = encoding;
258+ }
259+ }
260+ }
261+ systemEncodings = Arrays.copyOf(encodings, cnt);
262+ }
263+ return systemEncodings;
264+ }
155265 }
156266
Show on old repository browser