OSDN Git Service

6b1b1311cfa71d48de6cf0e9158593a72727e0cd
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / model / io / CharacterDataDirectoryFile.java
1 package charactermanaj.model.io;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.URI;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.logging.Level;
11 import java.util.logging.Logger;
12
13 import charactermanaj.model.CharacterData;
14 import charactermanaj.util.FileNameNormalizer;
15
16 /**
17  * ディレクトリをアーカイブと見立てる
18  * 
19  * @author seraphy
20  */
21 public class CharacterDataDirectoryFile extends AbstractCharacterDataArchiveFile {
22         
23         /**
24          * ロガー
25          */
26         private static final Logger logger = Logger.getLogger(CharacterDataDirectoryFile.class.getName());
27
28         
29         /**
30          * 対象ディレクトリ
31          */
32         protected File baseDir;
33         
34         /**
35          * ディレクトリ上のファイルコンテンツ
36          * 
37          * @author seraphy
38          */
39         protected static class DirFileContent implements FileContent {
40
41                 /**
42                  * ディレクトリ名 + ファイル名からなるエントリ名.<br>
43                  * エントリ名の区切り文字は常に「/」とする.<br>
44                  */
45                 private String entryName;
46
47                 /**
48                  * 実際のファイルへのパス
49                  */
50                 private File entry;
51                 
52                 protected DirFileContent(File entry, String entryName) {
53                         this.entry = entry;
54                         this.entryName = entryName;
55                 }
56                 
57                 public String getEntryName() {
58                         return entryName;
59                 }
60                 
61                 public long lastModified() {
62                         return entry.lastModified();
63                 }
64
65                 public InputStream openStream() throws IOException {
66                         return new FileInputStream(entry);
67                 }
68         }
69         
70         /**
71          * アーカイブファイルをベースとしたURIを返す.<br>
72          * 
73          * @param name
74          *            コンテンツ名
75          * @return URI
76          * @throws IOException
77          *             URIを生成できない場合
78          */
79         protected URI getContentURI(String name) throws IOException {
80                 return new File(baseDir, name).toURI();
81         }
82         
83         @Override
84         public Collection<PartsImageContent> getPartsImageContents(
85                         CharacterData characterData, boolean newly) {
86                 if (!newly && isOverlapped(characterData)) {
87                         // 既存のプロファイルへのインポートで指定されたインポートもととなるディレクトリが
88                         // 既存のプロファイルのディレクトリと重なっていれば自分自身のインポートであるとして
89                         // 空のパーツリストを返す.
90                         return Collections.emptyList();
91                 }
92                 return super.getPartsImageContents(characterData, newly);
93         }
94         
95         /**
96          * このディレクトリに対してターゲットプロファイルのディレクトリがかぶっているか? つまり、ターゲット自身のディレクトリをソースとしていないか?
97          * 
98          * @param characterData
99          *            ソースプロファイル
100          * @return 被っている場合はtrue、被っていない場合はfalse
101          */
102         protected boolean isOverlapped(CharacterData characterData) {
103                 if (characterData == null) {
104                         return false;
105                 }
106                 URI docBase = characterData.getDocBase();
107                 if (docBase == null || !"file".equals(docBase.getScheme())) {
108                         return false;
109                 }
110
111                 String folderPlace = File.separator;
112                 String basePath = new File(docBase).getParent() + folderPlace;
113                 String sourcePath = baseDir.getPath() + folderPlace;
114                 
115                 // インポートもとディレクトリがインポート先のキャラクター定義のディレクトリを含むか?
116                 boolean result = basePath.contains(sourcePath);
117                 logger.log(Level.FINE, "checkOverlapped: " + basePath + " * " + sourcePath + " :" + result);
118                 
119                 return result;
120         }
121
122         public void close() throws IOException {
123                 // ディレクトリなのでクローズ処理は必要ない.
124         }
125         
126         public CharacterDataDirectoryFile(File file) throws IOException {
127                 super(file);
128                 baseDir = file;
129                 load(baseDir, "");
130                 searchRootPrefix();
131         }
132         
133         private void load(File dir, String prefix) {
134                 if (!dir.exists() || !dir.isDirectory()) {
135                         // ディレクトリでなければ何もせず戻る
136                         return;
137                 }
138                 
139                 // ファイル名をノーマライズする
140                 FileNameNormalizer normalizer = FileNameNormalizer.getDefault();
141                 
142                 File[] files = dir.listFiles();
143                 if (files != null) {
144                         for (File file : files) {
145                                 String name = normalizer.normalize(file.getName());
146                                 String entryName = prefix + name;
147                                 if (file.isDirectory()) {
148                                         // エントリ名の区切り文字は常に「/」とする. (ZIP/JARのentry互換のため)
149                                         load(file, entryName + "/");
150                                 } else {
151                                         addEntry(new DirFileContent(file, entryName));
152                                 }
153                         }
154                 }
155         }
156
157 }