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.hayabusa.taglib; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.fukurou.util.XHTMLTag; 021import org.opengion.fukurou.util.Attributes; 022import org.opengion.fukurou.util.StringUtil; 023 024import static org.opengion.fukurou.util.StringUtil.nval ; 025 026import java.io.File; 027import java.io.FileFilter; 028import java.io.Serializable; 029import java.io.ObjectOutputStream; 030import java.io.ObjectInputStream; 031import java.io.IOException; 032import java.util.Arrays; 033import java.util.Comparator; 034 035/** 036 * ファイルのプルダウンリストの作成するタグです。 037 * 038 * SelectタグのBODY部に指定します。 039 * 並び替えについては、このタグで指定しますが、ファイルの選別は、 040 * BODY 部に記述する fileWhere タグで指定します。 041 * 042 * @og.formSample 043 * ●形式:<og:fileOption from="…" value="[…]" ・・・ >・・・</og:fileOption> 044 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 045 * 046 * ●Tag定義: 047 * <og:fileOption 048 * from 【TAG】ファイルの検索元となるディレクトリを指定します (初期値:FILE_URL[=filetemp/]) 049 * value 【TAG】Optionの初期値で選ばれる値を指定します 050 * orderBy 【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序) 051 * desc 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false) 052 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 053 * > ... Body ... 054 * </og:fileOption> 055 * 056 * ●使用例 057 * ・<og:fileOption val1="ABCD" val2="{@value}" > 058 * <og:fileWhere startsWith="ABCD" ・・・ /> 059 * </og:fileOption> 060 * 061 * @og.rev 2.1.1.0 (2002/11/11) 新規作成 062 * @og.rev 4.0.0.0 (2005/01/31) 内部ロジック改定 063 * @og.group その他入力 064 * 065 * @version 4.0 066 * @author Kazuhiko Hasegawa 067 * @since JDK5.0, 068 */ 069public class FileOptionTag extends CommonTagSupport { 070 //* このプログラムのVERSION文字列を設定します。 {@value} */ 071 private static final String VERSION = "5.3.4.0 (2011/04/01)" ; 072 073 private static final long serialVersionUID = 534020110401L ; 074 075 private String orderBy = null; // ソート項目 076 private boolean desc = false; // 降順フラグ 077 private String from = HybsSystem.sys( "FILE_URL" ); // 検索起点ファイル 078 private String selValue = null; // 選択済み初期値にする場合 079 private transient FileFilter filter = null; // FileWhere で指定したフィルター 080 081 private static final String[] ORDER_BY = new String[] { 082 "NAME","LASTMODIFIED","FILE_LENGTH","LENGTH" }; // 5.3.4.0 (2011/04/01) FILE_LENGTH 追加 083 084 /** 085 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 086 * 087 * @return 後続処理の指示( EVAL_BODY_BUFFERED ) 088 */ 089 @Override 090 public int doStartTag() { 091 return EVAL_BODY_BUFFERED ; // Body を評価する。( extends BodyTagSupport 時) 092 } 093 094 /** 095 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 096 * 097 * @return 後続処理の指示(SKIP_BODY) 098 */ 099 @Override 100 public int doAfterBody() { 101 return SKIP_BODY ; 102 } 103 104 /** 105 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 106 * 107 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。 108 * 109 * @return 後続処理の指示 110 */ 111 @Override 112 public int doEndTag() { 113 debugPrint(); // 4.0.0 (2005/02/28) 114 OptionAncestorIF select = (OptionAncestorIF)findAncestorWithClass( this, OptionAncestorIF.class ); 115 if( select == null ) { 116 String errMsg = "<b>" + getTagName() + "タグは、SelectTag または、DatalistTag のBODY に記述する必要があります。</b>"; 117 throw new HybsSystemException( errMsg ); 118 } 119 Comparator<File> comp = makeComparator( orderBy,desc ); 120 makeLabel( select,comp ); 121 122 return EVAL_PAGE ; 123 } 124 125 /** 126 * タグリブオブジェクトをリリースします。 127 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 128 * 129 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。 130 * 131 */ 132 @Override 133 protected void release2() { 134 super.release2(); 135 orderBy = null; // ソート項目 136 desc = false; // 降順フラグ 137 from = HybsSystem.sys( "FILE_URL" ); 138 filter = null; 139 selValue = null; 140 } 141 142 /** 143 * オプションを作成します。 144 * 145 * ファイル名を "value" に、 146 * BODY属性 に登録するOptionを作成します。 147 * 148 * @og.rev 5.3.4.0 (2011/04/01) FILE_LENGTH 追加 149 * 150 * @param orderBy ソートする属性[NAME/LASTMODIFIED/FILE_LENGTH/LENGTH] 151 * @param desc 並び順[true:昇順/false:降順] 152 * 153 * @return ファイル比較用のComparatorオブジェクト 154 */ 155 private Comparator<File> makeComparator( final String orderBy,final boolean desc ) { 156 if( orderBy == null ) { return null; } 157 158 Comparator<File> comp = null ; 159 160 if( "NAME".equalsIgnoreCase( orderBy ) ) { 161 comp = new NameComparator( desc ); 162 } 163 else if( "LASTMODIFIED".equalsIgnoreCase( orderBy ) ) { 164 comp = new ModifiedComparator( desc ); 165 } 166 // "LENGTH" を残すのは、互換性のため 167 else if( "FILE_LENGTH".equalsIgnoreCase( orderBy ) || "LENGTH".equalsIgnoreCase( orderBy ) ) { 168 comp = new LengthComparator( desc ); 169 } 170 171 return comp ; 172 } 173 174 /** 175 * オプションを作成します。 176 * 177 * ファイル名を "value" に、 178 * BODY属性 に登録するOptionを作成します。 179 * 180 * @og.rev 3.8.0.9 (2005/10/17) 複数選択可能時に全選択を設定する。 181 * 182 * @param select SelectTagオブジェクト 183 * @param comp 並び順を指定するためのComparatorオブジェクト 184 */ 185 private void makeLabel( final OptionAncestorIF select,final Comparator<File> comp ) { 186 File path = new File( from ); 187 188 File[] list = path.listFiles( filter ); 189 190 boolean multipleAll = select.isMultipleAll(); // 3.8.0.9 (2005/10/17) 191 if( list != null ) { 192 Arrays.sort( list, comp ); 193 for( int i = 0; i < list.length; i++ ) { 194 if( list[i].isDirectory() ) { continue; } // ディレクトリは除外 195 Attributes attri = new Attributes(); 196 String value = list[i].getName(); 197 attri.set( "value", value ); 198 if( ( selValue != null && selValue.equalsIgnoreCase( value ) ) || multipleAll ) { 199 attri.set( "selected", "selected" ); 200 } 201 attri.set( "body", value ); 202 select.addOption( XHTMLTag.option( attri ) ); 203 } 204 } 205 } 206 207 /** 208 * 【TAG】Optionの初期値で選ばれる値を指定します。 209 * 210 * @og.tag 211 * キーになるのは、ファイル属性の NAME です。(ディレクトリなしのファイル名) 212 * ここで value属性に指定した場合、このファイル名と(大文字小文字を無視して) 213 * 一致する場合に、プルダウンの初期値に表示されます。(selected 属性が設定される。) 214 * 215 * @param val 初期値で選ばれる値 216 */ 217 public void setValue( final String val ) { 218 selValue = nval( getRequestParameter( val ),selValue ); 219 } 220 221 /** 222 * 【TAG】ファイルの検索元となるディレクトリを指定します 223 * (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 224 * 225 * @og.tag ファイルの検索元となるディレクトリを指定します。 226 * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 227 * 228 * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。 229 * 230 * @param url ファイルの検索元となるディレクトリ 231 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 232 */ 233 public void setFrom( final String url ) { 234 String furl = nval( getRequestParameter( url ),null ); 235 if( furl != null ) { 236 char ch = furl.charAt( furl.length()-1 ); 237 if( ch != '/' && ch != '\\' ) { furl = furl + "/"; } 238 } 239 furl = StringUtil.urlAppend( from,furl ); 240 furl = StringUtil.urlAppend( furl,"." ); 241 from = HybsSystem.url2dir( furl ); 242 } 243 244 /** 245 * 【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序)。 246 * 247 * @og.tag 248 * ファイルをソートする順(Comparator)を指定します。ソートに指定できる 249 * ファイル属性名は、"NAME","LASTMODIFIED","FILE_LENGTH" の内のどれかひとつです。 250 * 何も指定しない場合は、Fileオブジェクトの自然順序でのソートになります。 251 * (※ 下位互換性のため、LENGTH も残しますが、廃止予定です。) 252 * 253 * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。 254 * @og.rev 4.0.0.0 (2005/01/31) 新規ロジックで改定 255 * @og.rev 5.3.4.0 (2011/04/01) ORDER_BYリストの出力方法 見直し 256 * 257 * @param ordr ソートキー("NAME","LASTMODIFIED","FILE_LENGTH") 258 */ 259 public void setOrderBy( final String ordr ) { 260 orderBy = nval( getRequestParameter( ordr ),orderBy ); 261 262 if( orderBy != null && ! check( orderBy, ORDER_BY ) ) { 263 StringBuilder errMsg = new StringBuilder(); 264 errMsg.append( "orderBy 属性に、下記の属性名以外の値が設定されました。" ); 265 errMsg.append( HybsSystem.CR ); 266 errMsg.append( " orderBy=[" ).append( orderBy ).append( "]" ); 267 errMsg.append( HybsSystem.CR ); 268 errMsg.append( " orderBy List=[" ); 269 errMsg.append( StringUtil.array2csv( ORDER_BY ) ); 270 errMsg.append( "]" ); 271 throw new HybsSystemException( errMsg.toString() ); 272 } 273 } 274 275 /** 276 * 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。 277 * 278 * @og.tag 279 * orderBy 属性で指定した表示順を、逆順にするかどうかを指定できます。 280 * 初期値は、false (昇順) です。 281 * 282 * @param flag 表示順を逆転するかどうか [true:逆順/false:昇順] 283 */ 284 public void setDesc( final String flag ) { 285 desc = nval( getRequestParameter( flag ),desc ); 286 } 287 288 /** 289 * FileFilterオブジェクトをセットします。 290 * これは、BODY 部に登録した、FileWhereタグによって設定された 291 * ファイルフィルターです。 292 * 293 * @param filter オブジェクト 294 */ 295 protected void setFileFilter( final FileFilter filter ) { 296 this.filter = filter; 297 } 298 299 /** 300 * 名前順でのソート順を指定する Comparator の実体内部クラス 301 * 302 * @og.group その他入力 303 * 304 * @version 4.0 305 * @author Kazuhiko Hasegawa 306 * @since JDK5.0, 307 */ 308 static class NameComparator implements Comparator<File>,Serializable { 309 private static final long serialVersionUID = 400020050131L ; // 4.0.0.0 (2005/01/31) 310 311 private final boolean desc ; 312 313 /** 314 * 名前順での比較を行うオブジェクトを作成します。 315 * 316 * @param desc [true:昇順/false:降順] 317 */ 318 public NameComparator( final boolean desc ) { this.desc = desc; } 319 320 /** 321 * Comparator インターフェースの compare( File,File ) メソッド 322 * 323 * @param o1 File 比較元1のファイルオブジェクト 324 * @param o2 File 比較元2のファイルオブジェクト 325 */ 326 public int compare( final File o1, final File o2 ) { 327 File f1 = desc ? o2 : o1 ; 328 File f2 = desc ? o1 : o2 ; 329 return f1.getName().compareTo( f2.getName() ) ; 330 } 331 } 332 333 /** 334 * 更新日順でのソート順を指定する Comparator の実体内部クラス 335 * 336 * @og.group その他入力 337 * 338 * @version 4.0 339 * @author Kazuhiko Hasegawa 340 * @since JDK5.0, 341 */ 342 static class ModifiedComparator implements Comparator<File>,Serializable { 343 private static final long serialVersionUID = 400020050131L ; // 4.0.0.0 (2005/01/31) 344 345 private final boolean desc ; 346 347 /** 348 * 更新日順での比較を行うオブジェクトを作成します。 349 * 350 * @param desc [true:昇順/false:降順] 351 */ 352 public ModifiedComparator( final boolean desc ) { this.desc = desc; } 353 354 /** 355 * Comparator インターフェースの compare( File,File ) メソッド 356 * 357 * @param o1 File 比較元1のファイルオブジェクト 358 * @param o2 File 比較元2のファイルオブジェクト 359 */ 360 public int compare( final File o1, final File o2 ) { 361 File f1 = desc ? o2 : o1 ; 362 File f2 = desc ? o1 : o2 ; 363 return (int)( f1.lastModified() - f2.lastModified() ) ; 364 } 365 } 366 367 /** 368 * ファイルサイズ順でのソート順を指定する Comparator の実体内部クラス 369 * 370 * @og.group その他入力 371 * 372 * @version 4.0 373 * @author Kazuhiko Hasegawa 374 * @since JDK5.0, 375 */ 376 static class LengthComparator implements Comparator<File>,Serializable { 377 private static final long serialVersionUID = 400020050131L ; // 4.0.0.0 (2005/01/31) 378 379 private final boolean desc ; 380 381 /** 382 * ファイルサイズでの比較を行うオブジェクトを作成します。 383 * 384 * @param desc [true:昇順/false:降順] 385 */ 386 public LengthComparator( final boolean desc ) { this.desc = desc; } 387 388 /** 389 * Comparator インターフェースの compare( File,File ) メソッド 390 * 391 * @param o1 File 比較元1のファイルオブジェクト 392 * @param o2 File 比較元2のファイルオブジェクト 393 */ 394 public int compare( final File o1, final File o2 ) { 395 File f1 = desc ? o2 : o1 ; 396 File f2 = desc ? o1 : o2 ; 397 return (int)( f1.length() - f2.length() ) ; 398 } 399 } 400 401 /** 402 * シリアライズ用のカスタムシリアライズ書き込みメソッド 403 * 404 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 405 * @serialData 一部のオブジェクトは、シリアライズされません。 406 * 407 * @param strm ObjectOutputStreamオブジェクト 408 * @throws IOException シリアライズに関する入出力エラーが発生した場合 409 */ 410 private void writeObject( final ObjectOutputStream strm ) throws IOException { 411 strm.defaultWriteObject(); 412 } 413 414 /** 415 * シリアライズ用のカスタムシリアライズ読み込みメソッド 416 * 417 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。 418 * 419 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 420 * @serialData 一部のオブジェクトは、シリアライズされません。 421 * 422 * @param strm ObjectInputStreamオブジェクト 423 * @see #release2() 424 * @throws IOException シリアライズに関する入出力エラーが発生した場合 425 * @throws ClassNotFoundException クラスを見つけることができなかった場合 426 */ 427 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 428 strm.defaultReadObject(); 429 } 430 431 /** 432 * このオブジェクトの文字列表現を返します。 433 * 基本的にデバッグ目的に使用します。 434 * 435 * @return このクラスの文字列表現 436 */ 437 @Override 438 public String toString() { 439 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 440 .println( "VERSION" ,VERSION ) 441 .println( "orderBy" ,orderBy ) 442 .println( "desc" ,desc ) 443 .println( "from" ,from ) 444 .println( "selValue" ,selValue ) 445 .println( "Other..." ,getAttributes().getAttribute() ) 446 .fixForm().toString() ; 447 } 448}