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