4 * License : The MIT License
5 * Copyright(c) 2011 olyutorskii
8 package jp.sfjp.jindolf;
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;
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;
29 * <p>{@link Class}用と{@link ClassLoader}用とでは
30 * 微妙に絶対リソース名の形式が異なることに留意せよ。
32 * <p>基本的に、リソースファイルへのアクセスにおける異常系は
33 * リカバリの対象外とする。(ビルド工程の不手際扱い。)
35 * @see java.lang.Class#getResource
36 * @see java.lang.ClassLoader#getResource
38 public final class ResourceManager {
41 * デフォルトで用いられるルートパッケージ。
45 public static final Package DEF_ROOT_PACKAGE;
47 private static final Class<?> ROOT_KLASS = Jindolf.class;
49 private static final ClassLoader DEF_LOADER;
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);
56 private static final Charset CS_UTF8 = StandardCharsets.UTF_8;
58 private static final int BTN_SZ = 24;
61 DEF_ROOT_PACKAGE = ROOT_KLASS.getPackage();
62 DEF_LOADER = ROOT_KLASS.getClassLoader();
69 private ResourceManager(){
78 * {@link Class}用の絶対パスとみなされる。
80 * <p>「/」で始まるリソース名表記は{@link Class}用であって
81 * {@link ClassLoader}では不要。
83 * @param resPath リソース名
84 * @return 絶対パスならtrueを返す。
85 * @see java.lang.Class#getResource
86 * @see java.lang.ClassLoader#getResource
88 private static boolean isAbsoluteResourcePath(String resPath){
89 if (resPath.startsWith(RES_SEPARATOR)) return true;
94 * パッケージ情報を反映するリソース名前置詞を返す。
96 * <p>パッケージ名のセパレータ「.」は「/」に置き換えられる。
97 * 無名パッケージの場合は長さゼロの空文字列を返す。
98 * 無名パッケージを除き、リソース名前置詞は必ず「/」で終わる。
100 * <p>この前置詞は{@link ClassLoader}用であって
101 * {@link Class}用ではないので、
104 * <p>パッケージ「com.example.test」の
105 * リソース名前置詞は「com/example/test/」
107 * @param pkg パッケージ設定。nullは無名パッケージと認識される。
108 * @return リソース名前置詞。無名パッケージの場合は空文字列が返る。
109 * @see java.lang.ClassLoader#getResource
110 * @see java.lang.Class#getResource
112 private static String getResourcePrefix(Package pkg){
113 if(pkg == null) return ""; // 無名パッケージ
115 String pkgName = pkg.getName();
116 String result = pkgName.replace(PKG_SEPCHAR, RES_SEPCHAR);
117 if( ! result.isEmpty() ){
118 result += RES_SEPARATOR;
121 assert result.charAt(0) != RES_SEPCHAR;
128 * デフォルトのクラスローダとデフォルトのルートパッケージから
131 * @param resPath リソース名
132 * @return リソースのURL。リソースが見つからなければnull。
134 public static URL getResource(String resPath){
135 return getResource(DEF_ROOT_PACKAGE, resPath);
139 * 任意のルートパッケージと相対リソース名を用いて、
140 * デフォルトのクラスローダからリソースのURLを取得する。
142 * @param rootPkg ルートパッケージ情報。
143 * 「/」で始まる絶対リソース名が指定された場合は無視される。
144 * @param resPath リソース名
145 * @return リソースのURL。リソースが見つからなければnull。
147 private static URL getResource(Package rootPkg, String resPath){
148 return getResource(DEF_LOADER, rootPkg, resPath);
152 * 任意のルートパッケージと相対リソース名を用いて、
153 * 任意のクラスローダからリソースのURLを取得する。
155 * @param loader クラスローダ
156 * @param rootPkg ルートパッケージ情報。
157 * 「/」で始まる絶対リソース名が指定された場合は無視される。
158 * @param resPath リソース名
159 * @return リソースのURL。リソースが見つからなければnull。
161 private static URL getResource(ClassLoader loader,
165 if(isAbsoluteResourcePath(resPath)){
167 fullName = resPath.substring(1);
169 String pfx = getResourcePrefix(rootPkg);
170 fullName = pfx + resPath;
173 assert ! isAbsoluteResourcePath(fullName);
175 URL result = loader.getResource(fullName);
182 * デフォルトのクラスローダとデフォルトのルートパッケージから
185 * @param resPath リソース名
186 * @return リソースの入力ストリーム。リソースが見つからなければnull。
188 public static InputStream getResourceAsStream(String resPath){
189 return getResourceAsStream(DEF_ROOT_PACKAGE, resPath);
193 * 任意のルートパッケージと相対リソース名を用いて、
194 * デフォルトのクラスローダからリソースの入力ストリームを取得する。
196 * @param rootPkg ルートパッケージ情報。
197 * 「/」で始まる絶対リソース名が指定された場合は無視される。
198 * @param resPath リソース名
199 * @return リソースの入力ストリーム。リソースが見つからなければnull。
201 private static InputStream getResourceAsStream(Package rootPkg,
203 return getResourceAsStream(DEF_LOADER, rootPkg, resPath);
207 * 任意のルートパッケージと相対リソース名を用いて、
208 * 任意のクラスローダからリソースの入力ストリームを取得する。
210 * @param loader クラスローダ
211 * @param rootPkg ルートパッケージ情報。
212 * 「/」で始まる絶対リソース名が指定された場合は無視される。
213 * @param resPath リソース名
214 * @return リソースの入力ストリーム。リソースが見つからなければnull。
216 private static InputStream getResourceAsStream(ClassLoader loader,
219 URL url = getResource(loader, rootPkg, resPath);
220 if(url == null) return null;
224 result = url.openStream();
225 }catch (IOException e){
233 * リソース名を用いてイメージ画像を取得する。
235 * @param resPath 画像リソース名
236 * @return イメージ画像。リソースが見つからなければnull。
238 public static BufferedImage getBufferedImage(String resPath){
239 URL url = getResource(resPath);
240 if(url == null) return null;
242 BufferedImage result;
244 result = ImageIO.read(url);
245 }catch(IOException e){
253 * リソース名を用いてアイコン画像を取得する。
255 * @param resPath アイコン画像リソース名
256 * @return アイコン画像。リソースが見つからなければnull。
258 public static ImageIcon getImageIcon(String resPath){
259 URL url = getResource(resPath);
260 if(url == null) return null;
262 ImageIcon result = new ImageIcon(url);
268 * リソース名を用いて正方形ボタン用アイコン画像を取得する。
270 * @param resPath アイコン画像リソース名
271 * @return アイコン画像。リソースが見つからなければnull。
273 public static Icon getButtonIcon(String resPath){
274 Icon result = getSquareIcon(resPath, BTN_SZ);
279 * リソース名を用いて正方形アイコン画像を取得する。
281 * @param resPath アイコン画像リソース名
282 * @param sz 正方形アイコン寸法
283 * @return アイコン画像。リソースが見つからなければnull。
285 public static Icon getSquareIcon(String resPath, int sz){
286 BufferedImage image = getBufferedImage(resPath);
287 Icon result = new FlexiIcon(image, sz, sz);
292 * リソース名を用いてプロパティを取得する。
294 * @param resPath プロパティファイルのリソース名
295 * @return プロパティ。リソースが読み込めなければnull。
297 public static Properties getProperties(String resPath){
298 InputStream is = getResourceAsStream(resPath);
299 if(is == null) return null;
301 Properties properties = new Properties();
303 try(InputStream pis = new BufferedInputStream(is)){
304 properties.load(pis);
305 }catch(IOException e){
313 * リソース名を用いてUTF-8テキストファイルの内容を取得する。
315 * <p>「#」で始まる行はコメント行として無視される。
317 * @param resPath テキストファイルのリソース名
318 * @return テキスト。リソースが読み込めなければnull。
320 public static String getTextFile(String resPath){
322 is = getResourceAsStream(resPath);
323 if(is == null) return null;
324 is = new BufferedInputStream(is);
326 Reader reader = new InputStreamReader(is, CS_UTF8);
328 StringBuilder result = new StringBuilder();
330 try(LineNumberReader lineReader = new LineNumberReader(reader)){
333 line = lineReader.readLine();
334 if(line == null) break;
335 if(line.startsWith("#")) continue;
336 result.append(line).append('\n');
338 }catch(IOException e){
342 if(result == null) return null;
344 return result.toString();