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.hayabusa.common.HybsSystem; 019import org.opengion.fukurou.util.StringUtil; 020import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 021 022/** 023 * DBカラムの属性チェックに使用されるメソッドを集約した、クラスです。 024 * 025 * 全変数は、public static final 宣言されており、全メソッドは、public static synchronized 宣言されています。 026 * 027 * @og.group データ属性 028 * 029 * @version 4.0 030 * @author Kazuhiko Hasegawa 031 * @since JDK5.0, 032 */ 033public final class DBTypeCheckUtil { 034 /** String を Byte[]に変換するコード 035 * 例:) "MS932" , "JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS" 036 */ 037 private static final String CODE = HybsSystem.sys( "DB_ENCODE" ); 038 039 // 5.3.9.0 (2011/09/01) 文字数チェック方式の指定 040 // 6.1.0.0 (2014/12/26) refactoring 041 private static final boolean USE_TEXT_LEN = HybsSystem.sysBool( "DB_USE_TEXT_LENGTH" ); 042 043 /** 044 * オブジェクトを作らせない為の、private コンストラクタ 045 */ 046 private DBTypeCheckUtil() {} 047 048 /** 049 * 文字列に使われている文字の範囲チェックを行います。 050 * 051 * 最小文字から最大文字、および、許可される文字を指定します。 052 * それ以外は、エラーと判定されます。 053 * ここで判定される以外に細かい制限をかけたい場合は、別のチェックと併用してください。 054 * 055 * @og.rev 5.6.0.3 (2012/01/24) 新規追加 056 * 057 * @param value 元の文字列 058 * @param minCh 許可される文字の最小値(含む) 059 * @param maxCh 許可される文字の最大値(含む) 060 * 061 * @return 範囲チェックエラー文字列(正常時は、null) 062 */ 063 public static String rangeCheck( final String value ,final char minCh ,final char maxCh ) { 064 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 065 boolean isError = false; 066 for( int i=0; i<value.length(); i++ ) { 067 final char ch = value.charAt( i ); 068 if( minCh <= ch && ch <= maxCh ) { 069 val.append( ch ); 070 } 071 else { 072 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 073 isError = true; 074 } 075 } 076 077 return isError ? val.toString() : null ; 078 } 079 080 /** 081 * 文字列の長さ(整数部)をチェックします。 082 * 083 * @param value 元の文字列 084 * @param sizeX 整数部分の文字列の長さ 085 * @param sizeY 小数部分の文字列の長さ 086 * 087 * @return エラー文字列長さ(正常時は、null) 088 */ 089 public static String sizeXCheck( final String value ,final int sizeX ,final int sizeY ) { 090 int valuesizeX; 091 final int pos = value.indexOf( '.' ); 092 if( pos >= 0 ) { 093 valuesizeX = pos; 094 } 095 else { 096 valuesizeX = value.length(); 097 } 098 if( value.charAt(0) == '-' ) { valuesizeX--; } 099 100 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 101 return valuesizeX > sizeX 102 ? String.valueOf(valuesizeX) // 整数部の長さが指定の長さよりも長いです。 103 : null; 104 } 105 106 /** 107 * 文字列の長さ(小数部)をチェックします。 108 * 109 * @param value 元の文字列 110 * @param sizeX 整数部分の文字列の長さ 111 * @param sizeY 小数部分の文字列の長さ 112 * 113 * @return エラー文字列長さ(正常時は、null) 114 */ 115 public static String sizeYCheck( final String value ,final int sizeX ,final int sizeY ) { 116 if( sizeY == 0 ) { 117 return null; 118 } 119 int valuesizeY; 120 final int pos = value.indexOf( '.' ); 121 if( pos >= 0 ) { 122 valuesizeY = value.length() - pos - 1; 123 } 124 else { 125 valuesizeY = 0; 126 } 127 128 if( valuesizeY > sizeY ) { 129 // 小数部の長さが指定の長さよりも長いです。 130 return String.valueOf(valuesizeY); 131 } else { 132 return null; 133 } 134 } 135 136 /** 137 * 文字列の小数点の位置をチェックします。 138 * 小数点(.)が、2箇所以上存在する(存在する位置が異なる)場合エラー 139 * 140 * @param value 元の文字列 141 * 142 * @return エラー文字列(正常時は、null) 143 */ 144 public static String decimalPointCheck( final String value ) { 145 String rtn = null; 146 if( value.indexOf( '.' ) != value.lastIndexOf( '.' ) ) { 147 rtn = changeErrorPath( value, '.' ); 148 } 149 return rtn ; 150 } 151 152 /** 153 * 文字列の符号の位置をチェックします。 154 * マイナス(-)が、存在しないか、先頭以外の場合は、エラー 155 * 156 * @param value 元の文字列 157 * 158 * @return エラー文字列(正常時は、null) 159 */ 160 public static String decimalCodeCheck( final String value ) { 161 String rtn = null; 162 if( value.lastIndexOf( '-' ) > 0 ) { 163 rtn = changeErrorPath( value, '-' ); 164 } 165 return rtn ; 166 } 167 168 /** 169 * 文字列の整合性(整数)をチェックします。 170 * 0~9およびマイナス(-)を許可します。 171 * 172 * @param value 元の文字列 173 * 174 * @return エラー文字列(正常時は、null) 175 */ 176 public static String numberFormatCheck( final String value ) { 177 boolean isError = false; 178 int i = 0; 179 char ch; 180 while( i<value.length() ) { 181 ch = value.charAt( i ); 182 if( ( '0'>ch || '9'<ch ) && '-'!=ch ) { 183 isError = true; 184 break; 185 } 186 i++; 187 } 188 if( isError ) { 189 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 190 for( i=0; i<value.length(); i++ ) { 191 ch = value.charAt( i ); 192 if( ( '0'>ch || '9'<ch ) && '-' != ch ) { 193 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 194 } 195 else { 196 val.append( ch ); 197 } 198 } 199 return val.toString(); 200 } else { 201 return null; 202 } 203 } 204 205 /** 206 * 文字列の整合性(小数)をチェックします。 207 * 0~9、マイナス(-)および小数点(.)を許可します。 208 * 209 * og.rev 4.2.4.0 (2008/06/26) '.' or '-' のみはエラー 210 * 211 * @param value 元の文字列 212 * 213 * @return エラー文字列(正常時は、null) 214 */ 215 public static String decimalFormatCheck( final String value ) { 216 boolean isError = false; 217 int i = 0; 218 char ch; 219 while( i<value.length() ) { 220 ch = value.charAt( i ); 221 if( ( '0'>ch || '9'<ch ) && '.'!=ch && '-'!=ch ) { 222 isError = true; 223 break; 224 } 225 i++; 226 } 227 228 // 4.2.4.0 (2008/06/26) '.' or '-' のみはエラー 229 if( value.length() ==1 && ( value.charAt(0) == '.' || value.charAt(0) == '-' ) ) { 230 isError = true; 231 } 232 233 if( isError ) { 234 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 235 for( i=0; i<value.length(); i++ ) { 236 ch = value.charAt( i ); 237 if( ( '0'>ch || '9'<ch ) && '.'!=ch && '-'!=ch ) { 238 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 239 } 240 else { 241 val.append( ch ); 242 } 243 } 244 return val.toString(); 245 } else { 246 return null; 247 } 248 } 249 250 /** 251 * 日付文字列の整合性をチェックします。 252 * 253 * 整合性といっても、DBType_DATE のような厳密なチェックは、行いません。 254 * ここでは、yyyyMM(6桁)、yyyyMMdd(8桁)、yyyyMMddHHmmss(14桁) の3種類のみ 255 * 対象にします。 256 * "0000XXXX" , "9999XXXX" は、常に許可されます。 257 * 月と日の関係も、ありません。(20130231 は OK) 258 * あくまで、月は、1~12 の範囲、日は、1~31の範囲チェックです。 259 * 260 * 厳密な日付チェックを行いたい場合は、DBType_DATE を使用してください。 261 * 262 * @og.rev 5.6.0.3 (2012/01/24) 新規追加 263 * @og.rev 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。 264 * 265 * @param value 元の文字列(nullは不可) 266 * 267 * @return エラー文字列(正常時は、null) 268 */ 269 public static String ymdFormatCheck( final String value ) { 270 if( value.startsWith( "0000" ) || value.startsWith( "9999" ) ) { return null; } // 無条件 OK 271 272 // 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。 273 final String str = rangeCheck( value, '0', '9' ); 274 if( str != null ) { return str; } 275 276 final int len = value.length() ; 277 if( len >= 6 ) { // 月のチェック 278 final String val = ymdhmsCheck( value,4,6,1,12 ); 279 if( val != null ) { return val; } 280 } 281 282 if( len >= 8 ) { // 日のチェック 283 final String val = ymdhmsCheck( value,6,8,1,31 ); 284 if( val != null ) { return val; } 285 } 286 287 if( len >= 10 ) { // 時のチェック 288 final String val = ymdhmsCheck( value,8,10,0,24 ); // 240000 は許可します。 289 if( val != null ) { return val; } 290 } 291 292 if( len >= 12 ) { // 分のチェック 293 final String val = ymdhmsCheck( value,10,12,0,60 ); // 60分は許可します。 294 if( val != null ) { return val; } 295 } 296 297 if( len == 14 ) { // 秒のチェック 298 final String val = ymdhmsCheck( value,12,14,0,60 ); // うるう秒とは言いませんが、60秒は許可します。 299 if( val != null ) { return val; } 300 } 301 302 return null; 303 } 304 305 /** 306 * 時刻文字列の整合性をチェックします。 307 * 308 * 整合性といっても、DBType_DATE のような厳密なチェックは、行いません。 309 * ここでは、HHmmss(6桁) のみ対象にします。 310 * 311 * @og.rev 5.6.0.3 (2012/01/24) 新規追加 312 * @og.rev 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。 313 * 314 * @param value 元の文字列(nullは不可) 315 * 316 * @return エラー文字列(正常時は、null) 317 */ 318 public static String hmsFormatCheck( final String value ) { 319 // 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。 320 final String str = rangeCheck( value, '0', '9' ); 321 if( str != null ) { return str; } 322 323 final int len = value.length() ; 324 325 if( len >= 2 ) { // 時のチェック 326 final String val = ymdhmsCheck( value,0,2,0,24 ); // 240000 は許可します。 327 if( val != null ) { return val; } 328 } 329 330 if( len >= 4 ) { // 分のチェック 331 final String val = ymdhmsCheck( value,2,4,0,60 ); // 60分は許可します。 332 if( val != null ) { return val; } 333 } 334 335 if( len == 6 ) { // 秒のチェック 336 final String val = ymdhmsCheck( value,4,6,0,60 ); // うるう秒とは言いませんが、60秒は許可します。 337 if( val != null ) { return val; } 338 } 339 340 return null; 341 } 342 343 /** 344 * 月、日、時、分、秒 のチェック用メソッド 345 * 346 * 同じようなパターンでチェックする為、共通メソッド化しておきます。 347 * 348 * @og.rev 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。 349 * 350 * @param value 元の文字列 351 * @param st チェック開始桁数 352 * @param ed チェック終了桁数 (val.length() を超えない事) 353 * @param minSu 許可範囲の最小値 354 * @param maxSu 許可範囲の最大値 355 * 356 * @return エラー文字列(正常な場合は、null) 357 */ 358// public static String ymdhmsCheck( final String value, final int st , final int ed , final int minSu , final int maxSu ) { 359 private static String ymdhmsCheck( final String value, final int st , final int ed , final int minSu , final int maxSu ) { 360 String rtn = null; 361 362 final int dt = Integer.parseInt( value.substring( st,ed ) ); 363 if( dt < minSu || maxSu < dt ) { 364 rtn = value.substring( 0,st ) + "<span class=\"NG\">" + value.substring( st,ed ) + "</span>" + value.substring( ed ) ; 365 } 366 return rtn; 367 } 368 369 /** 370 * 文字列のエラー文字列を返します。 371 * 372 * @param val 元の文字列 373 * @param inChar エラー対象文字 374 * 375 * @return エラー文字列 376 * @og.rtnNotNull 377 */ 378 private static String changeErrorPath( final String val, final char inChar ) { 379 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 380 for( int i=0; i<val.length(); i++ ) { 381 final char ch = val.charAt( i ); 382 if( inChar==ch ) { 383 buf.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 384 } else { 385 buf.append( ch ); 386 } 387 } 388 return buf.toString(); 389 } 390 391 /** 392 * 文字列の長さをチェックします。 393 * バイト数に換算して比較チェックします。 394 * 395 * @og.rev 3.0.1.3 (2003/03/11) メソッド新規追加 396 * @og.rev 3.5.5.3 (2004/04/09) StringUtil の CODE を使用したメソッドを削除する。 397 * @og.rev 5.3.9.0 (2011/09/01) DB_USE_TEXT_LENGTH を考慮した、「文字数」、「バイト数」チェック 398 * 399 * @param value 元の文字列 400 * @param len 文字列の長さ 401 * 402 * @return エラー文字列(正常時は、null) 403 */ 404 public static String byteLengthCheck( final String value ,final int len ) { 405 String rtn = null; 406 407 // 5.3.9.0 (2011/09/01) 「文字数」、「バイト数」チェック 408 final int valLen ; 409 if( USE_TEXT_LEN ) { // true:「文字数」チェック方式 410 valLen = value.length(); 411 } 412 else { // false:「バイト数」チェック方式 413 final byte[] byteValue = StringUtil.makeByte( value,CODE ); // 3.5.5.3 (2004/04/09) 414 valLen = byteValue.length; 415 } 416 417 if( valLen > len ) { 418 rtn = String.valueOf( valLen ); 419 } 420 421 return rtn ; 422 } 423 424 /** 425 * 文字列の整合性を、dbType パラメータを利用してチェックします。 426 * regex が、null または、長さゼロの文字列の場合は、なにもしません。 427 * 428 * @og.rev 3.6.0.0 (2004/09/22) 新規作成 429 * 430 * @param value 元の文字列 431 * @param regex チェックする正規表現文字列 432 * 433 * @return エラー文字列(正常時は、null) 434 */ 435 public static String matcheCheck( final String value,final String regex ) { 436 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 437 // 条件変更注意 438 return regex == null || regex.isEmpty() || value.matches( regex ) 439 ? null 440 : "<span class=\"NG\">" + value + "</span> regex=" + regex ; 441 } 442}