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.db; 017 018import org.opengion.fukurou.system.HybsConst ; // 6.1.0.0 (2014/12/26) 019import org.opengion.fukurou.util.ErrorMessage; 020import org.opengion.fukurou.util.StringUtil; 021import org.opengion.fukurou.model.NativeType; 022 023/** 024 * 一般的な半角文字列を扱う為の、カラム属性を定義します。 025 * 026 * 半角文字列とは、「 c < 0x20 || c > 0x7e 以外」でのみ 027 * 構成された文字列のことです。 028 * 029 * タイプチェックとして、以下の条件を判定します。 030 * ・文字列長は、Byte換算での文字数との比較 031 * ・半角文字列チェック「 c < 0x20 || c > 0x7e 以外」エラー 032 * ・文字パラメータの 正規表現チェック 033 * ・クロスサイトスクリプティングチェック 034 * 035 * 8.0.0.1 (2021/10/08) 036 * そして、要素に対して class 属性も設定できます。 037 * 但し、class 属性が設定されている場合は、マッチチェックを実施しない 038 * 039 * @og.group データ属性 040 * 041 * @version 4.0 042 * @author Kazuhiko Hasegawa 043 * @since JDK5.0, 044 */ 045public abstract class AbstractDBType implements DBType { 046 private final String defValue ; // データのデフォルト値 047 048 /** システムの改行コードを設定します。*/ 049 protected static final String CR = HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 050 /** StringBilderなどの初期値を設定します。 {@value} */ 051 protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 052 053 /** 054 * デフォルトコンストラクター 055 * 056 * @og.rev 4.0.0.0 (2005/01/31) type 廃止 057 */ 058 public AbstractDBType() { 059 this( "" ); // データのデフォルト値 060 } 061 062 /** 063 * コンストラクター 064 * 065 * 各サブクラスのタイプ値とデフォルト値を設定して、オブジェクトを構築します。 066 * 067 * @og.rev 4.0.0.0 (2005/01/31) type 廃止 068 * 069 * @param defValue データのデフォルト値 070 */ 071 public AbstractDBType( final String defValue ) { 072 this.defValue = defValue; 073 } 074 075 /** 076 * NATIVEの型の識別コードを返します。 077 * 078 * @og.rev 3.5.4.7 (2004/02/06) 新規作成 079 * @og.rev 4.1.1.2 (2008/02/28) Enum型(fukurou.model.NativeType)に変更 080 * 081 * @return NATIVEの型の識別コード(DBType で規定) 082 * @og.rtnNotNull 083 * @see org.opengion.fukurou.model.NativeType 084 */ 085 @Override // DBType 086 public NativeType getNativeType() { 087 return NativeType.STRING; 088 } 089 090 /** 091 * 半角スペースで固定長(半角換算の数)に変換した文字列を返します。 092 * 093 * 半角スペース埋めは、文字が半角、全角混在でもかまいません。 094 * なお、エラーチェックは行われません。 095 * 実行前に、必ず valueCheck( String value ,int len ) を行う必要があります。 096 * 097 * @og.rev 3.5.4.5 (2004/01/23) エンコード指定に変更します。 098 * 099 * @param value FILL埋めする文字列 100 * @param sizeX 整数部分の文字列の長さ 101 * @param sizeY 小数部分の文字列の長さ 102 * @param encode 固定長で変換する文字エンコード 103 * 104 * @return FILL埋めした新しい文字列 105 * @og.rtnNotNull 106 */ 107 @Override // DBType 108 public String valueFill( final String value ,final int sizeX ,final int sizeY,final String encode ) { 109 final int len = (sizeY == 0) ? sizeX : sizeX + sizeY + 1; 110 111 return StringUtil.stringFill( value,len,encode ); 112 } 113 114 /** 115 * そのDBTypeのデフォルトの値(物理的初期設定値)を返します。 116 * 117 * 一般に、文字列の場合は、ゼロストリング"" 数字の場合は "0" です。 118 * 119 * @return 物理的初期設定値 120 */ 121 @Override // DBType 122 public String getDefault() { 123 return defValue; 124 } 125 126 /** 127 * String引数の文字列を+1した文字列を返します。 128 * 129 * これは、英字の場合(A,B,C など)は、B,C,D のように、最終桁の文字コードを 130 * +1 します。 131 * 文字列が数字タイプの場合は、数字に変換して、+1 します。 132 * 最終桁が、"9","z","Z" および、その全角文字の場合、"0","a","Z" および、その全角文字に 133 * 変換後、ひとつ上の桁で、同様の +1 操作を行います。 134 * 最も上位の桁が、これらの繰り上がり桁の場合は、すべての桁が初期化された状態に戻ります。 135 * 例:123 ⇒ 124 , ABC ⇒ ABD , 789 ⇒ 790 , XYZ ⇒ XXZ , 136 * ABC123 ⇒ ABC124 , AB99 ⇒ AC00 , 12ZZ99 ⇒ 13AA00 , ZZZZ ⇒ AAAA 137 * 引数が null の場合と、ゼロ文字列("")の場合は、物理的初期設定値(String getDefault()) 138 * の値を返します。 139 * 140 * @og.rev 4.0.0.0 (2005/01/31) Addの方法を変更(汎用的なAdd) 141 * 142 * @param value String引数 143 * 144 * @return 引数の文字列を+1した文字列。 145 */ 146 @Override // DBType 147 public String valueAdd( final String value ) { 148 if( value == null || value.isEmpty() ) { return getDefault(); } 149 150 char[] chs = value.toCharArray() ; 151 152 for( int i=chs.length-1; i>=0; i-- ) { 153 boolean over = true; 154 switch( chs[i] ) { 155 case '9' : chs[i] = '0' ; break; 156 case 'z' : chs[i] = 'a' ; break; 157 case 'Z' : chs[i] = 'A' ; break; 158 case '9' : chs[i] = '0'; break; 159 case 'z' : chs[i] = 'a'; break; 160 case 'Z' : chs[i] = 'A'; break; 161 default : chs[i]++; over=false; break; 162 } 163 if( !over ) { break; } // キャリーオーバーしていなければ、終了 164 } 165 166 return new String( chs ); 167 } 168 169 /** 170 * String引数の文字列に、第2引数に指定の文字列(数字、日付等)を加算して返します。 171 * 172 * これは、valueAdd( String ) と本質的には同じ動きをしますが、任意の文字列を加算する 173 * ため、主として、数字系や日付系の DBType にのみ実装します。 174 * 実装がない場合は、UnsupportedOperationException を throw します。 175 * 176 * 第2引数 が、null の場合は、+1 する valueAdd( String )が呼ばれます。 177 * これは、将来的には、valueAdd( String ) を無くすことを意味します。 178 * 179 * @og.rev 5.6.0.3 (2012/01/24) ADD に、引数の値を加算する機能を追加します。 180 * 181 * @param value String引数 182 * @param add 加算する文字列(null の場合は、従来と同じ、+1 します。) 183 * 184 * @return 引数の文字列第2引数に指定の文字列(数字、日付等)を加算した文字列。 185 * @throws UnsupportedOperationException 実装が存在しない場合 186 */ 187 @Override // DBType 188 public String valueAdd( final String value,final String add ) { 189 if( add == null || add.isEmpty() ) { return valueAdd( value ); } 190 191 final String errMsg = "このクラスでは、引数付の任意の加算は実装されていません。" 192 + getClass().getName() + " Action=[ADD]" 193 + " oldValue=[" + value + "] newValue=[" + add + "]" ; 194 throw new UnsupportedOperationException( errMsg ); 195 } 196 197 /** 198 * エディターで編集されたデータを登録する場合に、データそのものを変換して、実登録データを作成します。 199 * 200 * 例えば、大文字のみのフィールドなら、大文字化します。 201 * 実登録データの作成は、DBType オブジェクトを利用しますので、 202 * これと CellEditor とがアンマッチの場合は、うまくデータ変換 203 * されない可能性がありますので、注意願います。 204 * 205 * @og.rev 3.3.3.0 (2003/07/09) 前後のスペースを取り除いておく。 206 * @og.rev 3.3.3.1 (2003/07/18) 後ろスペースを取り除く。(StringUtil#rTrim) 207 * 208 * @param value (一般に編集データとして登録されたデータ) 209 * 210 * @return 修正後の文字列(一般にデータベースに登録するデータ) 211 */ 212 @Override // DBType 213 public String valueSet( final String value ) { 214 return StringUtil.rTrim( value ); 215 } 216 217 /** 218 * action で指定されたコマンドを実行して、値の変換を行います。 219 * 220 * oldValue(旧データ)は、元のDBTableModelに設定されていた値です。通常は、 221 * この値を使用してカラム毎に変換を行います。newValue(新データ)は、引数で 222 * 指定された新しい値です。この値には、パラメータを指定して変換方法を 223 * 制御することも可能です。 224 * 指定のアクションがカラムで処理できない場合は、エラーになります。 225 * 226 * @param action アクションコマンド 227 * @param oldValue 入力データ(旧データ) 228 * @param newValue 入力データ(新データ) 229 * 230 * @return 実行後のデータ 231 */ 232 @Override // DBType 233 public String valueAction( final String action,final String oldValue,final String newValue ) { 234 final String errMsg = "このクラスでは、このアクションは実装されていません。" 235 + getClass().getName() + " Action=[" + action + "]" 236 + " oldValue=[" + oldValue + "] newValue=[" + newValue + "]" ; 237 throw new UnsupportedOperationException( errMsg ); 238 } 239 240 /** 241 * データが登録可能かどうか[true/false]をチェックします。 242 * 243 * データがエラーの場合は、そのエラー内容を返します。 244 * 245 * @og.rev 2.1.1.1 (2002/11/15) HTMLタグチェックのメソッドの共有化。 246 * @og.rev 3.0.1.3 (2003/03/11) DBTypeCheckUtilクラスを利用するように修正 247 * @og.rev 3.6.0.0 (2004/09/22) dbType パラメータを引数に追加 248 * @og.rev 5.2.2.0 (2010/11/01) 厳密にチェック(isStrict=true)するフラグを追加 249 * @og.rev 8.0.0.1 (2021/10/08) dbType パラメータのclass属性対応 250 * 251 * @param key キー 252 * @param value 値 253 * @param sizeX 整数部分の文字列の長さ 254 * @param sizeY 小数部分の文字列の長さ 255 * @param typeParam dbType パラメータ 256 * @param isStrict 厳密にチェックするかどうか [true:する/false:標準的] 257 * 258 * @return エラー内容 259 */ 260 @Override // DBType 261 public ErrorMessage valueCheck( final String key ,final String value , 262 final int sizeX ,final int sizeY ,final String typeParam ,final boolean isStrict) { 263 264 ErrorMessage msg = new ErrorMessage(); 265 if( value == null || value.isEmpty() ) { return msg; } 266 267 final int len = (sizeY == 0) ? sizeX : sizeX + sizeY + 1; 268 if( len < value.length() ) { 269 // 文字列の長さが指定の長さよりも長いです。 270 msg.addMessage( 0,ErrorMessage.NG,"ERR0006",key,value, 271 String.valueOf( value.length() ),String.valueOf( len ) ); 272 } 273 274 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 275 boolean isError = false; 276 for( int i=0; i<value.length(); i++ ) { 277 final char ch = value.charAt( i ); 278 if( ch < 0x20 || ch > 0x7e ) { 279 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 280 isError = true; 281 } 282 else { 283 val.append( ch ); 284 } 285 } 286 if( isError ) { 287 // 指定の文字以外の文字が使われています。 288 msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,val.toString() ); 289 } 290 291 // 3.6.0.0 (2004/09/22) dbType パラメータを使用したマッチチェック 292 if( typeParam != null ) { 293 // class属性はマッチチェックを実施しない 8.0.0.1 (2021/10/08) 294 String newTypePram = typeParam; 295 final int st = typeParam.indexOf( "class=" ); 296 if( st >= 0 ) { 297 final int ed = newTypePram.indexOf( ';' , st ); 298 // 文字パラメータの文字列から class属性の文字列を消す 299 if( ed >= 0 ) { 300 // [0-9]|class=sel2sel;[A-z] の場合、[0-9]|[A-z] を取得 301 newTypePram = newTypePram.replaceAll( newTypePram.substring( st , ed + 1 ) , "" ); 302 } 303 else { 304 // [0-9A-z]class=sel2sel の場合、[0-9A-z] を取得 305 newTypePram = newTypePram.substring( 0 , st ); 306 } 307 } 308 309// final String check = DBTypeCheckUtil.matcheCheck( value,typeParam ); // 8.0.0.1 (2021/10/08) 310 final String check = DBTypeCheckUtil.matcheCheck( value,newTypePram ); 311 if( check != null ) { 312 // 指定の文字以外の文字が使われています。 313 msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check ); 314 } 315 } 316 317 // クロスサイトスクリプティング対策:'<', '>' は登録させない。 318 msg = xssCheck( key ,value, msg ); 319 return msg; 320 } 321 322 /** 323 * HTMLタグかどうかをチェックします。 324 * 325 * クロスサイトスクリプティング対策として、'<', '>' は登録させない。 326 * 327 * @og.rev 2.1.1.1 (2002/11/15) HTMLタグチェックのメソッドの共有化。 328 * @og.rev 6.2.0.0 (2015/02/27) ERR0010 の引数が、変更されているので、修正します。 329 * 330 * @param key タグのキー 331 * @param value 対象の値 332 * @param msg ErrorMessageオブジェクト 333 * 334 * @return エラー内容(エラーを追加した、ErrorMessageオブジェクト) 335 */ 336 protected ErrorMessage xssCheck( final String key ,final String value, final ErrorMessage msg ) { 337 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 338 boolean isError = false; 339 for( int i=0; i<value.length(); i++ ) { 340 final char ch = value.charAt( i ); 341 if( ch == '<' || ch == '>' ) { 342 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 343 isError = true; 344 } 345 else { 346 val.append( ch ); 347 } 348 } 349 if( isError ) { 350 // 6.2.0.0 (2015/02/27) ERR0010:HTMLタグは登録できません。key={0} value={1}({2}) char={3} 351 // {2} が何を想定していたのか不明ですが、エラー発生元のクラス名を設定しておきます。 352 final String clsName = this.getClass().getSimpleName(); 353 354 // HTMLタグは登録できません。 355 msg.addMessage( 0,ErrorMessage.NG,"ERR0010", key,val.toString(),clsName,"<,>" ); 356 } 357 return msg; 358 } 359}