OSDN Git Service

modify methods scope of ResourceManager.
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / ResourceManager.java
1 /*
2  * resource manager
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 olyutorskii
6  */
7
8 package jp.sfjp.jindolf;
9
10 import java.awt.image.BufferedImage;
11 import java.io.BufferedInputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.InputStreamReader;
15 import java.io.LineNumberReader;
16 import java.io.Reader;
17 import java.net.URL;
18 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
20 import java.util.Properties;
21 import javax.imageio.ImageIO;
22 import javax.swing.Icon;
23 import javax.swing.ImageIcon;
24 import jp.sfjp.jindolf.view.FlexiIcon;
25
26 /**
27  * 各種リソースファイルの管理。
28  *
29  * <p>{@link Class}用と{@link ClassLoader}用とでは
30  * 微妙に絶対リソース名の形式が異なることに留意せよ。
31  *
32  * <p>基本的に、リソースファイルへのアクセスにおける異常系は
33  * リカバリの対象外とする。(ビルド工程の不手際扱い。)
34  *
35  * @see java.lang.Class#getResource
36  * @see java.lang.ClassLoader#getResource
37  */
38 public final class ResourceManager {
39
40     /**
41      * デフォルトで用いられるルートパッケージ。
42      *
43      * <p>相対リソース名の起点となる。
44      */
45     public static final Package DEF_ROOT_PACKAGE;
46
47     private static final Class<?> ROOT_KLASS = Jindolf.class;
48
49     private static final ClassLoader DEF_LOADER;
50
51     private static final char PKG_SEPCHAR = '.';
52     private static final char RES_SEPCHAR = '/';
53     private static final String RES_SEPARATOR =
54             Character.toString(RES_SEPCHAR);
55
56     private static final Charset CS_UTF8 = StandardCharsets.UTF_8;
57
58     private static final int BTN_SZ = 24;
59
60     static{
61         DEF_ROOT_PACKAGE = ROOT_KLASS.getPackage();
62         DEF_LOADER = ROOT_KLASS.getClassLoader();
63     }
64
65
66     /**
67      * 隠しコンストラクタ。
68      */
69     private ResourceManager(){
70         assert false;
71     }
72
73
74     /**
75      * リソース名が絶対パスか否か判定する。
76      *
77      * <p>リソース名が「/」で始まる場合、
78      * {@link Class}用の絶対パスとみなされる。
79      *
80      * <p>「/」で始まるリソース名表記は{@link Class}用であって
81      * {@link ClassLoader}では不要。
82      *
83      * @param resPath リソース名
84      * @return 絶対パスならtrueを返す。
85      * @see java.lang.Class#getResource
86      * @see java.lang.ClassLoader#getResource
87      */
88     private static boolean isAbsoluteResourcePath(String resPath){
89         if (resPath.startsWith(RES_SEPARATOR)) return true;
90         return false;
91     }
92
93     /**
94      * パッケージ情報を反映するリソース名前置詞を返す。
95      *
96      * <p>パッケージ名のセパレータ「.」は「/」に置き換えられる。
97      * 無名パッケージの場合は長さゼロの空文字列を返す。
98      * 無名パッケージを除き、リソース名前置詞は必ず「/」で終わる。
99      *
100      * <p>この前置詞は{@link ClassLoader}用であって
101      * {@link Class}用ではないので、
102      * 頭に「/」が付かない。
103      *
104      * <p>パッケージ「com.example.test」の
105      * リソース名前置詞は「com/example/test/」
106      *
107      * @param pkg パッケージ設定。nullは無名パッケージと認識される。
108      * @return リソース名前置詞。無名パッケージの場合は空文字列が返る。
109      * @see java.lang.ClassLoader#getResource
110      * @see java.lang.Class#getResource
111      */
112     private static String getResourcePrefix(Package pkg){
113         if(pkg == null) return "";   // 無名パッケージ
114
115         String pkgName = pkg.getName();
116         String result = pkgName.replace(PKG_SEPCHAR, RES_SEPCHAR);
117         if( ! result.isEmpty() ){
118             result += RES_SEPARATOR;
119         }
120
121         assert result.charAt(0) != RES_SEPCHAR;
122
123         return result;
124     }
125
126     /**
127      * リソース名を用いて、
128      * デフォルトのクラスローダとデフォルトのルートパッケージから
129      * リソースのURLを取得する。
130      *
131      * @param resPath リソース名
132      * @return リソースのURL。リソースが見つからなければnull。
133      */
134     public static URL getResource(String resPath){
135         return getResource(DEF_ROOT_PACKAGE, resPath);
136     }
137
138     /**
139      * 任意のルートパッケージと相対リソース名を用いて、
140      * デフォルトのクラスローダからリソースのURLを取得する。
141      *
142      * @param rootPkg ルートパッケージ情報。
143      *     「/」で始まる絶対リソース名が指定された場合は無視される。
144      * @param resPath リソース名
145      * @return リソースのURL。リソースが見つからなければnull。
146      */
147     private static URL getResource(Package rootPkg, String resPath){
148         return getResource(DEF_LOADER, rootPkg, resPath);
149     }
150
151     /**
152      * 任意のルートパッケージと相対リソース名を用いて、
153      * 任意のクラスローダからリソースのURLを取得する。
154      *
155      * @param loader クラスローダ
156      * @param rootPkg ルートパッケージ情報。
157      *     「/」で始まる絶対リソース名が指定された場合は無視される。
158      * @param resPath リソース名
159      * @return リソースのURL。リソースが見つからなければnull。
160      */
161     private static URL getResource(ClassLoader loader,
162                                    Package rootPkg,
163                                    String resPath ){
164         String fullName;
165         if(isAbsoluteResourcePath(resPath)){
166             // chop '/' heading
167             fullName = resPath.substring(1);
168         }else{
169             String pfx = getResourcePrefix(rootPkg);
170             fullName = pfx + resPath;
171         }
172
173         assert ! isAbsoluteResourcePath(fullName);
174
175         URL result = loader.getResource(fullName);
176
177         return result;
178     }
179
180     /**
181      * リソース名を用いて、
182      * デフォルトのクラスローダとデフォルトのルートパッケージから
183      * リソースの入力ストリームを取得する。
184      *
185      * @param resPath リソース名
186      * @return リソースの入力ストリーム。リソースが見つからなければnull。
187      */
188     public static InputStream getResourceAsStream(String resPath){
189         return getResourceAsStream(DEF_ROOT_PACKAGE, resPath);
190     }
191
192     /**
193      * 任意のルートパッケージと相対リソース名を用いて、
194      * デフォルトのクラスローダからリソースの入力ストリームを取得する。
195      *
196      * @param rootPkg ルートパッケージ情報。
197      *     「/」で始まる絶対リソース名が指定された場合は無視される。
198      * @param resPath リソース名
199      * @return リソースの入力ストリーム。リソースが見つからなければnull。
200      */
201     private static InputStream getResourceAsStream(Package rootPkg,
202                                                    String resPath ){
203         return getResourceAsStream(DEF_LOADER, rootPkg, resPath);
204     }
205
206     /**
207      * 任意のルートパッケージと相対リソース名を用いて、
208      * 任意のクラスローダからリソースの入力ストリームを取得する。
209      *
210      * @param loader クラスローダ
211      * @param rootPkg ルートパッケージ情報。
212      *     「/」で始まる絶対リソース名が指定された場合は無視される。
213      * @param resPath リソース名
214      * @return リソースの入力ストリーム。リソースが見つからなければnull。
215      */
216     private static InputStream getResourceAsStream(ClassLoader loader,
217                                                    Package rootPkg,
218                                                    String resPath ){
219         URL url = getResource(loader, rootPkg, resPath);
220         if(url == null) return null;
221
222         InputStream result;
223         try{
224             result = url.openStream();
225         }catch (IOException e){
226             result = null;
227         }
228
229         return result;
230     }
231
232     /**
233      * リソース名を用いてイメージ画像を取得する。
234      *
235      * @param resPath 画像リソース名
236      * @return イメージ画像。リソースが見つからなければnull。
237      */
238     public static BufferedImage getBufferedImage(String resPath){
239         URL url = getResource(resPath);
240         if(url == null) return null;
241
242         BufferedImage result;
243         try{
244             result = ImageIO.read(url);
245         }catch(IOException e){
246             result = null;
247         }
248
249         return result;
250     }
251
252     /**
253      * リソース名を用いてアイコン画像を取得する。
254      *
255      * @param resPath アイコン画像リソース名
256      * @return アイコン画像。リソースが見つからなければnull。
257      */
258     public static ImageIcon getImageIcon(String resPath){
259         URL url = getResource(resPath);
260         if(url == null) return null;
261
262         ImageIcon result = new ImageIcon(url);
263
264         return result;
265     }
266
267     /**
268      * リソース名を用いて正方形ボタン用アイコン画像を取得する。
269      *
270      * @param resPath アイコン画像リソース名
271      * @return アイコン画像。リソースが見つからなければnull。
272      */
273     public static Icon getButtonIcon(String resPath){
274         Icon result = getSquareIcon(resPath, BTN_SZ);
275         return result;
276     }
277
278     /**
279      * リソース名を用いて正方形アイコン画像を取得する。
280      *
281      * @param resPath アイコン画像リソース名
282      * @param sz 正方形アイコン寸法
283      * @return アイコン画像。リソースが見つからなければnull。
284      */
285     public static Icon getSquareIcon(String resPath, int sz){
286         BufferedImage image = getBufferedImage(resPath);
287         Icon result = new FlexiIcon(image, sz, sz);
288         return result;
289     }
290
291     /**
292      * リソース名を用いてプロパティを取得する。
293      *
294      * @param resPath プロパティファイルのリソース名
295      * @return プロパティ。リソースが読み込めなければnull。
296      */
297     public static Properties getProperties(String resPath){
298         InputStream is = getResourceAsStream(resPath);
299         if(is == null) return null;
300
301         Properties properties = new Properties();
302
303         try(InputStream pis = new BufferedInputStream(is)){
304             properties.load(pis);
305         }catch(IOException e){
306             properties = null;
307         }
308
309         return properties;
310     }
311
312     /**
313      * リソース名を用いてUTF-8テキストファイルの内容を取得する。
314      *
315      * <p>「#」で始まる行はコメント行として無視される。
316      *
317      * @param resPath テキストファイルのリソース名
318      * @return テキスト。リソースが読み込めなければnull。
319      */
320     public static String getTextFile(String resPath){
321         InputStream is;
322         is = getResourceAsStream(resPath);
323         if(is == null) return null;
324         is = new BufferedInputStream(is);
325
326         Reader reader = new InputStreamReader(is, CS_UTF8);
327
328         StringBuilder result = new StringBuilder();
329
330         try(LineNumberReader lineReader = new LineNumberReader(reader)){
331             for(;;){
332                 String line;
333                 line = lineReader.readLine();
334                 if(line == null) break;
335                 if(line.startsWith("#")) continue;
336                 result.append(line).append('\n');
337             }
338         }catch(IOException e){
339             result = null;
340         }
341
342         if(result == null) return null;
343
344         return result.toString();
345     }
346
347 }