001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.util; 017 018import java.io.File; 019import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 020import java.util.concurrent.ConcurrentHashMap; // 6.4.3.1 (2016/02/12) refactoring 021import java.util.Locale ; 022import java.util.Set; 023 024import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system 025 026/** 027 * FileMap は、ファイルを読み取って、キー情報から、ファイルへのリンクを作成するための 028 * 情報を返します。 029 * ファイルそのものは、指定のディレクトリをすべて読み取り、拡張子以外の部分を、キーとして 030 * 登録します。(キーは大文字に統一されます。) 031 * 実際のファイルの拡張子は、リンク作成時の処理で付与されます。 032 * 例えば、HELPファイルを、XXXX.html や、XXXX.htm、XXXX.pdf など、色々な形態で作成した 033 * 場合でも、キーとしては、XXXX で存在チェックをかけることができるようになります。 034 * 035 * ファイルは、一旦すべて読み取ってメモリ上で管理されます。 036 * ディレクトリの再読取が必要な場合は、オブジェクトを再作成する必要があります。 037 * 038 * @version 4.0 039 * @author Kazuhiko Hasegawa 040 * @since JDK5.0, 041 */ 042public final class FileMap implements Cleanable { 043 /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */ 044 private final ConcurrentMap<String,String> fMap = new ConcurrentHashMap<>(); // 6.4.3.1 (2016/02/12) 変数名も変えておきます。 045 046 /** 047 * デフォルトコンストラクター 048 * 049 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 050 */ 051 public FileMap() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 052 053// /** 054// * 読み取るディレクトリを指定して、ファイルマップを構築します。 055// * 056// * このディレクトリは、OSに対する物理アドレスになります。 057// * 058// * @og.rev 5.5.4.2 (2012/07/13) makeFileMap() を直接コンストラクターとして使用 059// * @og.rev 6.3.8.4 (2015/10/09) 別のコンストラクターを呼ぶようにします。 060// * @og.rev 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 061// * @og.rev 6.3.9.0 (2015/11/06) コンストラクターを止めて、初期化メソッドに変更する。 062// * @og.rev 7.3.2.0 (2021/03/19) 廃止 063// * 064// * @param dir ディレクトリ 065// */ 066// public void init( final String dir ) { 067// init( dir , null , null ); 068// } 069 070 /** 071 * 読み取るディレクトリを指定して、ファイルマップを構築します。 072 * 073 * このディレクトリは、OSに対する物理アドレスになります。 074 * 075 * @og.rev 5.5.4.2 (2012/07/13) makeFileMap() を直接コンストラクターとして使用 076 * @og.rev 6.3.8.4 (2015/10/09) 別のコンストラクターを呼ぶようにします。 077 * @og.rev 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 078 * @og.rev 6.3.9.0 (2015/11/06) コンストラクターを止めて、初期化メソッドに変更する。 079 * 080 * @param dir ディレクトリ 081 * @param path ファイル名に付与するパス文字列 082 */ 083 public void init( final String dir , final String path ) { 084 init( dir , path , null ); 085 } 086 087// /** 088// * すでに読み取った Set オブジェクトを指定して、ファイルマップを構築します。 089// * 090// * これは、ServletContext を利用した、META-INF/resources からの読み取り対応になります。 091// * 一覧を取得するのは、ServletContext 関連の実装が必要になるため、fukurou では 092// * java の一般的なオブジェクトである Set を処理するだけとします。 093// * 094// * ファイル名は、dir を削除した残りで構築します。フォルダ階層を含みます。 095// * Mapのキーは、フォルダ階層を含まない、ファイル名のみとします。 096// * つまり、フォルダ階層を持ってリソースを用意しておいても、キーとしては、 097// * ファイル名のみを使用します。 098// * 099// * @og.rev 5.5.4.2 (2012/07/13) 新規作成 100// * @og.rev 6.3.8.4 (2015/10/09) 別のコンストラクターを呼ぶようにします。 101// * @og.rev 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 102// * @og.rev 6.3.9.0 (2015/11/06) コンストラクターを止めて、初期化メソッドに変更する。 103// * @og.rev 7.3.2.0 (2021/03/19) 廃止 104// * 105// * @param dir ディレクトリ 106// * @param resourcePaths リソースパス 107// */ 108// public void init( final String dir , final Set<?> resourcePaths ) { 109// init( dir , null , resourcePaths ); 110// } 111 112 /** 113 * すでに読み取った Set オブジェクトを指定して、ファイルマップを構築します。 114 * 115 * これは、ServletContext を利用した、META-INF/resources からの読み取り対応になります。 116 * 一覧を取得するのは、ServletContext 関連の実装が必要になるため、fukurou では 117 * java の一般的なオブジェクトである Set を処理するだけとします。 118 * 119 * ファイル名は、dir を削除した残りで構築します。フォルダ階層を含みます。 120 * Mapのキーは、フォルダ階層を含まない、ファイル名のみとします。 121 * つまり、フォルダ階層を持ってリソースを用意しておいても、キーとしては、 122 * ファイル名のみを使用します。 123 * 124 * @og.rev 5.5.4.2 (2012/07/13) 新規作成 125 * @og.rev 6.3.8.4 (2015/10/09) 別のコンストラクターを呼ぶようにします。 126 * @og.rev 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 127 * @og.rev 6.3.9.0 (2015/11/06) null になっている可能性があるメソッドの戻り値のnullチェックを追加。 128 * @og.rev 6.3.9.0 (2015/11/06) コンストラクターを止めて、初期化メソッドに変更する。 129 * @og.rev 6.4.2.0 (2016/01/29) StringUtil にあったメソッドを移動するとともに、メソッド名を、ogThrowMsgPrint → ogThrowMsgPrint に変更。 130 * @og.rev 6.4.3.2 (2016/02/19) 指定のフォルダが存在しない場合、作成します。 131 * @og.rev 7.3.2.0 (2021/03/19) dir と path の nullチェック(エラーでも止めない) 132 * @og.rev 8.5.5.1 (2024/02/29) dir のみ nullチェック(エラーで止める) 133 * 134 * @param dir ディレクトリ 135 * @param path ファイル名に付与するパス文字列 136 * @param resourcePaths リソースパス 137 */ 138// public void init( final String dir , final String path , final Set<?> resourcePaths ) { 139 public void init( final String dir , final String path , final Set<String> resourcePaths ) { 140 // 7.3.2.0 (2021/03/19) dir と path の nullチェック(エラーでも止めない) 141// if( dir == null || path == null ) { 142// final String errMsg1 = "指定のディレクトリかパスが、nullです。dir=[" + dir + "] , path=[" + path + "]" ; 143 if( dir == null ) { 144 final String errMsg1 = "指定のディレクトリが、nullです。path=[" + path + "]" ; 145 System.err.println( ThrowUtil.ogThrowMsg( errMsg1 ) ); 146 return ; // 8.5.5.1 (2024/02/29) spotbugs NP_GUARANTEED_DEREF 147 } 148 149 if( resourcePaths == null ) { 150 final File directory = new File( dir ); 151 if( ! directory.exists() ) { 152 final String errMsg = "指定のディレクトリは、存在しません。dir=[" + directory + "] , path=[" + path + "]" ; 153 // 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 154// System.out.println( errMsg ); 155 System.err.println( ThrowUtil.ogThrowMsg( errMsg ) ); // 7.3.2.0 (2021/03/19) フォルダなしは、積極的なエラーにする。 156 // // 7.3.2.0 (2021/03/19) フォルダを作成する必要はない。あくまでイメージを用意しておいて利用するだけでよい。 157 // // 6.4.3.2 (2016/02/19) 指定のフォルダが存在しない場合、作成します。 158 // if( directory.mkdirs() ) { 159 // final String errMsg2 = "指定のディレクトリを自動作成しました。[" + directory + "]"; 160 // System.out.println( errMsg2 ); 161 // } 162 // else { 163 // final String errMsg3 = "指定のディレクトリの自動作成に失敗しました。[" + directory + "]"; 164 // System.err.println( ThrowUtil.ogThrowMsg( errMsg3 ) ); 165 // } 166 return ; 167 } 168 169 if( ! directory.isDirectory() ) { 170 final String errMsg = "指定のキーは、ディレクトリではありません。[" + directory + "]"; 171 // 6.3.8.5 (2015/10/16) コンストラクターで、Exception を throw しないようにします。 172 System.err.println( ThrowUtil.ogThrowMsg( errMsg ) ); 173 return ; 174 } 175 // 6.3.8.4 (2015/10/09) ファイルのみ取り込む 176 // 6.3.9.0 (2015/11/06) null になっている可能性があるメソッドの戻り値のnullチェックを追加。 177 final File[] files = directory.listFiles(); 178 if( files != null ) { 179 for( final File file : files ) { 180 if( file != null && file.isFile() ) { 181 dataSet( file.getName() , path ); 182 } 183 } 184 } 185 } 186 else { 187 final int len = dir.length() ; 188// for( final Object rpath : resourcePaths ) { 189// final String fname = String.valueOf( rpath ).substring( len ); // ファイル名 190// dataSet( fname , path ); 191// } 192 for( final String rpath : resourcePaths ) { // 7.3.2.0 (2021/03/19) 193 final String fname = rpath.substring( len ); // ファイル名 194 dataSet( fname , path ); 195 } 196 } 197 } 198 199 /** 200 * ファイルマップを構築する内部処理。 201 * 202 * これは、ServletContext を利用した、META-INF/resources からの読み取り対応と、 203 * 通常のフォルダスキャンの読み取りの共通処理をまとめた目疎度です。 204 * 205 * @og.rev 6.3.8.4 (2015/10/09) 新規作成 206 * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。変数名も変えておきます。 207 * 208 * @param fname ファイル名 209 * @param path ファイル名に付与するパス文字列 210 */ 211 private void dataSet( final String fname , final String path ) { 212 final String upkey = fname.toUpperCase( Locale.JAPAN ) ; 213 String tmpName = fname; 214 215 // path が、nullやゼロ文字列以外の場合は、最後の文字を判定して、ファイル名に連結します。 216 if( path != null && !path.isEmpty() ) { 217 final char ch = path.charAt( path.length()-1 ) ; 218 if( ch == '/' || ch == '\\' ) { 219 tmpName = path + fname; 220 } 221 else { 222 tmpName = path + '/' + fname; 223 } 224 } 225 226 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。変数名も変えておきます。 227 final int idx = upkey.lastIndexOf( '.' ); 228 if( idx >= 0 ) { 229 fMap.put( upkey.substring( 0,idx ), tmpName ); 230 } 231 else { 232 fMap.put( upkey, tmpName ); 233 } 234 } 235 236 /** 237 * 指定のキーのファイルが存在しているかどうかを返します。 238 * 存在している場合は、true , 存在していない場合は、false になります。 239 * 240 * @og.rev 6.3.8.5 (2015/10/16) Exception を throw しないようにします。 241 * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 242 * 243 * @param key 指定のキー 244 * 245 * @return 存在しているかどうか(true:存在する/false:存在しない) 246 */ 247 public boolean exists( final String key ) { 248 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。変数名も変えておきます。 249 return key != null && fMap.containsKey( key.toUpperCase( Locale.JAPAN ) ); 250 } 251 252 /** 253 * キーに対応したファイル名を返します。 254 * 指定のキーに対するファイル名が存在しない場合は、null を返します。 255 * 256 * 引数を可変長引数にして、前から順番にMapを調べます。最初に、null でない 257 * 値を返します。最後まで一致しなければ、null を返します。 258 * 引数のキーが、nullや、ゼロ配列の場合も、nullになります。 259 * 260 * @og.rev 6.3.8.4 (2015/10/09) FileMap のコンストラクタ変更に伴う対応。 261 * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 262 * 263 * @param keys 指定のキー配列(可変長引数) 264 * 265 * @return ファイル名(ディレクトリパスは含まず)、存在しない場合は、null 266 */ 267 public String getFilename( final String... keys ) { 268 // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要 269 String rtn = null; 270 if( keys != null ) { 271 for( final String key : keys ) { 272 // 6.3.8.4 (2015/10/09) 最初に見つけた値を返す。 273 if( key != null ) { 274 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。変数名も変えておきます。 275// final String rtn = fMap.get( key.toUpperCase( Locale.JAPAN ) ); 276// if( rtn != null ) { return rtn; } 277 rtn = fMap.get( key.toUpperCase( Locale.JAPAN ) ); 278 if( rtn != null ) { break; } 279 } 280 } 281 } 282// return null; 283 return rtn; 284 } 285 286 /** 287 * 初期化が完了しているかどうかを、返します。 288 * 完了している場合は、true を返します。未完了、または、clear() 実行後は、falseです。 289 * 290 * インスタンスは、init処理が完了するまでは、false が返る為、簡易的な同期処理は 291 * 行われています。 292 * (内部のMapへの書き込みは、init処理でのみ行われます。) 293 * 294 * @og.rev 6.3.9.0 (2015/11/06) 新規作成。 295 * @og.rev 6.4.3.2 (2016/02/19) initFlagを廃止し、直接 Mapが空かどうかで判定します。 296 * 297 * @return 初期化が完了していればtrue 298 */ 299 public boolean isInit() { return !fMap.isEmpty(); } 300 301 /** 302 * 初期化(クリア)します。 303 * 304 * @og.rev 6.3.9.0 (2015/11/06) 新規作成。 305 * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 306 */ 307 @Override // Cleanable 308 public void clear() { 309 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。変数名も変えておきます。 310 fMap.clear(); 311 } 312}