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