OSDN Git Service

リポジトリ内改行コードのLFへの修正
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / util / SetupLocalization.java
1 package charactermanaj.util;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.net.JarURLConnection;
9 import java.net.URISyntaxException;
10 import java.net.URL;
11 import java.net.URLConnection;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.EnumSet;
15 import java.util.Enumeration;
16 import java.util.jar.JarEntry;
17 import java.util.jar.JarFile;
18 import java.util.logging.Level;
19 import java.util.logging.Logger;
20
21 /**
22  * 言語リソースを管理する.
23  * 
24  * @author seraphy
25  */
26 public class SetupLocalization extends ResourceLoader {
27         
28         private final Logger logger = Logger.getLogger(getClass().getName());
29         
30         public static final String DIRNAME_RESOURCES = "resources";
31
32         /**
33          * リソースフォルダ下のサブディレクトリ一覧.<br>
34          */
35         public enum Resources {
36                 Languages("languages"), Menu("menu"), Template("template");
37
38                 private final String dirName;
39
40                 private Resources(String dirName) {
41                         this.dirName = dirName;
42                 }
43
44                 public String getDirName() {
45                         return dirName;
46                 }
47
48                 @Override
49                 public String toString() {
50                         return getDirName();
51                 }
52         }
53
54         private File baseDir;
55         
56         /**
57          * アプリケーションデータ用ディレクトリを指定して構築する.
58          * 
59          * @param baseDir
60          *            データディレクトリ
61          */
62         public SetupLocalization(File baseDir) {
63                 if (baseDir == null || !baseDir.isDirectory()) {
64                         throw new IllegalArgumentException();
65                 }
66                 this.baseDir = baseDir;
67         }
68         
69         /**
70          * コピー対象とするリソース一覧を取得する.<br>
71          * 
72          * @param resourceSet
73          *            リソースディレクトリのサブディレクトリ名のリスト
74          * @return リソース一覧(言語関連リソース、テンプレートなど)
75          * @throws IOException
76          *             失敗
77          */
78         protected Collection<String> getResourceList(EnumSet<Resources> resourceSet)
79                         throws IOException {
80                 if (resourceSet == null) {
81                         resourceSet = EnumSet.noneOf(Resources.class);
82                 }
83                 ArrayList<String> resources = new ArrayList<String>();
84
85                 ClassLoader cl = getClass().getClassLoader();
86
87                 for (Resources resourceKey : resourceSet) {
88                         String name = resourceKey.getDirName();
89                         URL loc = cl.getResource(name);
90                         if (loc == null) {
91                                 continue;
92                         }
93                         String protocol = loc.getProtocol();
94                         if ("file".equals(protocol)) {
95                                 // ファイル上にクラスやリソースがある場合
96                                 try {
97                                         File dir = new File(loc.toURI());
98                                         File[] files = dir.listFiles();
99                                         if (files != null) {
100                                                 for (File file : files) {
101                                                         if (file.isDirectory()) {
102                                                                 continue;
103                                                         }
104                                                         resources.add(name + "/" + file.getName());
105                                                 }
106                                         }
107                                 } catch (URISyntaxException e) {
108                                         throw new RuntimeException(e);
109                                 }
110
111                         } else if ("jar".equals(protocol)) {
112                                 // jarにクラスやリソースがある場合
113                                 JarURLConnection conn = (JarURLConnection) loc.openConnection();
114                                 JarEntry dirEntry = conn.getJarEntry();
115                                 assert dirEntry != null; // "jar:file:xxxx.jar!yyyy" のyyyyの部分
116                                 String prefix = dirEntry.getName() + "/";
117                                 JarFile jarFile = conn.getJarFile();
118                                 try {
119                                         Enumeration<JarEntry> enm = jarFile.entries();
120                                         while (enm.hasMoreElements()) {
121                                                 JarEntry entry = enm.nextElement();
122                                                 if (entry.isDirectory()) {
123                                                         continue;
124                                                 }
125                                                 String entryName = entry.getName();
126                                                 if (entryName.startsWith(prefix)) {
127                                                         resources.add(entryName);
128                                                 }
129                                         }
130                                 } finally {
131                                         if (!conn.getUseCaches()) {
132                                                 // キャッシュしてある場合は明示的にクローズしない.
133                                                 // (そもそもクローズする必要はないかも)
134                                                 // (たぶん、システムなどがインスタンスを再利用していると思われるため)
135                                                 // (jdk5でクローズすると例外が発生する。jdk7のリビジョンによっても発生するようだ)
136                                                 // http://bugs.sun.com/view_bug.do?bug_id=7050028
137                                                 jarFile.close();
138                                         }
139                                 }
140                         }
141                 }
142
143                 logger.log(Level.FINE, "resource list: " +resources);
144                 return resources;
145         }
146         
147         /**
148          * リソースをファイルにコピーする.<br>
149          * 
150          * @param fromURL
151          * @param toFile
152          * @throws IOException
153          */
154         protected void copyResource(URL fromURL, File toFile) throws IOException {
155                 logger.log(Level.INFO, "copy resource '" + fromURL + "' to '" + toFile + "'");
156                 File dir = toFile.getParentFile();
157                 if ( !dir.exists()) {
158                         if ( !dir.mkdirs()) {
159                                 throw new IOException("can't create directory. " + dir);
160                         }
161                 }
162
163                 URLConnection conn = fromURL.openConnection();
164                 conn.setDoInput(true);
165                 InputStream is = conn.getInputStream();
166                 try {
167                         long lastModified = conn.getLastModified();
168                         OutputStream os = new FileOutputStream(toFile);
169                         try {
170                                 byte[] buf = new byte[4096];
171                                 for (;;) {
172                                         int rd = is.read(buf);
173                                         if (rd <= 0) {
174                                                 break;
175                                         }
176                                         os.write(buf, 0, rd);
177                                 }
178                         } finally {
179                                 os.close();
180                         }
181                         boolean result = toFile.setLastModified(lastModified);
182                         logger.log(Level.FINE, "setLastModified(" + toFile+ ") succeeded=" + result);
183                 } finally {
184                         is.close();
185                 }
186         }
187         
188         /**
189          * リソースディレクトリを返す.
190          * 
191          * @return リソースディレクトリ
192          */
193         public File getResourceDir() {
194                 try {
195                         return new File(baseDir, DIRNAME_RESOURCES).getCanonicalFile();
196                 } catch (Exception ex) {
197                         throw new RuntimeException(ex);
198                 }
199         }
200         
201         /**
202          * ローカルシステム上のアプリケーションデータディレクトリに言語リソースをコピーする.
203          * 
204          * @param resourceSet
205          *            コピーするリソースセット.
206          * @param overwrite
207          *            上書きを許可する場合はtrue、スキップする場合はfalse
208          * @throws IOException
209          *             失敗
210          */
211         public void setupToLocal(EnumSet<Resources> resourceSet, boolean overwrite)
212                         throws IOException {
213                 File toDir = getResourceDir();
214                 ClassLoader cl = getDefaultClassLoader();
215                 for (String resourceName : getResourceList(resourceSet)) {
216                         URL url = cl.getResource(resourceName);
217                         if (url != null) {
218                                 File toFile = new File(toDir, resourceName).getCanonicalFile();
219                                 if (overwrite || !toFile.exists()) {
220                                         // 上書き許可か、まだファイルが存在しなければコピーする.
221                                         copyResource(url, toFile);
222                                 }
223
224                         } else {
225                                 logger.log(Level.WARNING, "missing resource: " + resourceName);
226                         }
227                 }
228         }
229 }