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 * 110 * @param value 元の文字列 111 * @param sizeX 整数部分の文字列の長さ 112 * @param sizeY 小数部分の文字列の長さ 113 * 114 * @return エラー文字列長さ(正常時は、null) 115 */ 116 public static String sizeYCheck( final String value ,final int sizeX ,final int sizeY ) { 117 if( sizeY == 0 ) { 118 return null; 119 } 120 int valuesizeY; 121 final int pos = value.indexOf( '.' ); 122 if( pos >= 0 ) { 123 valuesizeY = value.length() - pos - 1; 124 } 125 else { 126 valuesizeY = 0; 127 } 128 129 if( valuesizeY > sizeY ) { 130 // 小数部の長さが指定の長さよりも長いです。 131 return String.valueOf(valuesizeY); 132 } else { 133 return null; 134 } 135 } 136 137 /** 138 * 文字列の小数点の位置をチェックします。 139 * 小数点(.)が、2箇所以上存在する(存在する位置が異なる)場合エラー 140 * 141 * @param value 元の文字列 142 * 143 * @return エラー文字列(正常時は、null) 144 */ 145 public static String decimalPointCheck( final String value ) { 146 String rtn = null; 147 if( value.indexOf( '.' ) != value.lastIndexOf( '.' ) ) { 148 rtn = changeErrorPath( value, '.' ); 149 } 150 return rtn ; 151 } 152 153 /** 154 * 文字列の符号の位置をチェックします。 155 * マイナス(-)が、存在しないか、先頭以外の場合は、エラー 156 * 157 * @param value 元の文字列 158 * 159 * @return エラー文字列(正常時は、null) 160 */ 161 public static String decimalCodeCheck( final String value ) { 162 String rtn = null; 163 if( value.lastIndexOf( '-' ) > 0 ) { 164 rtn = changeErrorPath( value, '-' ); 165 } 166 return rtn ; 167 } 168 169 /** 170 * 文字列の整合性(整数)をチェックします。 171 * 0~9およびマイナス(-)を許可します。 172 * 173 * @param value 元の文字列 174 * 175 * @return エラー文字列(正常時は、null) 176 */ 177 public static String numberFormatCheck( final String value ) { 178 boolean isError = false; 179 int i = 0; 180 char ch; 181 while( i<value.length() ) { 182 ch = value.charAt( i ); 183 if( ( '0'>ch || '9'<ch ) && '-'!=ch ) { 184 isError = true; 185 break; 186 } 187 i++; 188 } 189 if( isError ) { 190 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 191 for( i=0; i<value.length(); i++ ) { 192 ch = value.charAt( i ); 193 if( ( '0'>ch || '9'<ch ) && '-' != ch ) { 194 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 195 } 196 else { 197 val.append( ch ); 198 } 199 } 200 return val.toString(); 201 } else { 202 return null; 203 } 204 } 205 206 /** 207 * 文字列の整合性(小数)をチェックします。 208 * 0~9、マイナス(-)および小数点(.)を許可します。 209 * 210 * og.rev 4.2.4.0 (2008/06/26) '.' or '-' のみはエラー 211 * 212 * @param value 元の文字列 213 * 214 * @return エラー文字列(正常時は、null) 215 */ 216 public static String decimalFormatCheck( final String value ) { 217 boolean isError = false; 218 int i = 0; 219 char ch; 220 while( i<value.length() ) { 221 ch = value.charAt( i ); 222 if( ( '0'>ch || '9'<ch ) && '.'!=ch && '-'!=ch ) { 223 isError = true; 224 break; 225 } 226 i++; 227 } 228 229 // 4.2.4.0 (2008/06/26) '.' or '-' のみはエラー 230 if( value.length() ==1 && ( value.charAt(0) == '.' || value.charAt(0) == '-' ) ) { 231 isError = true; 232 } 233 234 if( isError ) { 235 final StringBuilder val = new StringBuilder( BUFFER_MIDDLE ); 236 for( i=0; i<value.length(); i++ ) { 237 ch = value.charAt( i ); 238 if( ( '0'>ch || '9'<ch ) && '.'!=ch && '-'!=ch ) { 239 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 240 } 241 else { 242 val.append( ch ); 243 } 244 } 245 return val.toString(); 246 } else { 247 return null; 248 } 249 } 250 251 /** 252 * 日付文字列の整合性をチェックします。 253 * 254 * 整合性といっても、DBType_DATE のような厳密なチェックは、行いません。 255 * ここでは、yyyyMM(6桁)、yyyyMMdd(8桁)、yyyyMMddHHmmss(14桁) の3種類のみ 256 * 対象にします。 257 * "0000XXXX" , "9999XXXX" は、常に許可されます。 258 * 月と日の関係も、ありません。(20130231 は OK) 259 * あくまで、月は、1~12 の範囲、日は、1~31の範囲チェックです。 260 * 261 * 厳密な日付チェックを行いたい場合は、DBType_DATE を使用してください。 262 * 263 * @og.rev 5.6.0.3 (2012/01/24) 新規追加 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 final int len = value.length() ; 273 if( len >= 6 ) { // 月のチェック 274 final String val = ymdhmsCheck( value,4,6,1,12 ); 275 if( val != null ) { return val; } 276 } 277 278 if( len >= 8 ) { // 日のチェック 279 final String val = ymdhmsCheck( value,6,8,1,31 ); 280 if( val != null ) { return val; } 281 } 282 283 if( len >= 10 ) { // 時のチェック 284 final String val = ymdhmsCheck( value,8,10,0,24 ); // 240000 は許可します。 285 if( val != null ) { return val; } 286 } 287 288 if( len >= 12 ) { // 分のチェック 289 final String val = ymdhmsCheck( value,10,12,0,60 ); // 60分は許可します。 290 if( val != null ) { return val; } 291 } 292 293 if( len == 14 ) { // 秒のチェック 294 final String val = ymdhmsCheck( value,12,14,0,60 ); // うるう秒とは言いませんが、60秒は許可します。 295 if( val != null ) { return val; } 296 } 297 298 return null; 299 } 300 301 /** 302 * 時刻文字列の整合性をチェックします。 303 * 304 * 整合性といっても、DBType_DATE のような厳密なチェックは、行いません。 305 * ここでは、HHmmss(6桁) のみ対象にします。 306 * 307 * @og.rev 5.6.0.3 (2012/01/24) 新規追加 308 * 309 * @param value 元の文字列(nullは不可) 310 * 311 * @return エラー文字列(正常時は、null) 312 */ 313 public static String hmsFormatCheck( final String value ) { 314 final int len = value.length() ; 315 316 if( len >= 2 ) { // 時のチェック 317 final String val = ymdhmsCheck( value,0,2,0,24 ); // 240000 は許可します。 318 if( val != null ) { return val; } 319 } 320 321 if( len >= 4 ) { // 分のチェック 322 final String val = ymdhmsCheck( value,2,4,0,60 ); // 60分は許可します。 323 if( val != null ) { return val; } 324 } 325 326 if( len == 6 ) { // 秒のチェック 327 final String val = ymdhmsCheck( value,4,6,0,60 ); // うるう秒とは言いませんが、60秒は許可します。 328 if( val != null ) { return val; } 329 } 330 331 return null; 332 } 333 334 /** 335 * 月、日、時、分、秒 のチェック用メソッド 336 * 337 * 同じようなパターンでチェックする為、共通メソッド化しておきます。 338 * 339 * @param value 元の文字列 340 * @param st チェック開始桁数 341 * @param ed チェック終了桁数 (val.length() を超えない事) 342 * @param minSu 許可範囲の最小値 343 * @param maxSu 許可範囲の最大値 344 * 345 * @return エラー文字列(正常な場合は、null) 346 */ 347 public static String ymdhmsCheck( final String value, final int st , final int ed , final int minSu , final int maxSu ) { 348 String rtn = null; 349 350 final int dt = Integer.parseInt( value.substring( st,ed ) ); 351 if( dt < minSu || maxSu < dt ) { 352 rtn = value.substring( 0,st ) + "<span class=\"NG\">" + value.substring( st,ed ) + "</span>" + value.substring( ed ) ; 353 } 354 return rtn; 355 } 356 357 /** 358 * 文字列のエラー文字列を返します。 359 * 360 * @param val 元の文字列 361 * @param inChar エラー対象文字 362 * 363 * @return エラー文字列 364 * @og.rtnNotNull 365 */ 366 private static String changeErrorPath( final String val, final char inChar ) { 367 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 368 for( int i=0; i<val.length(); i++ ) { 369 final char ch = val.charAt( i ); 370 if( inChar==ch ) { 371 buf.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 372 } else { 373 buf.append( ch ); 374 } 375 } 376 return buf.toString(); 377 } 378 379 /** 380 * 文字列の長さをチェックします。 381 * バイト数に換算して比較チェックします。 382 * 383 * @og.rev 3.0.1.3 (2003/03/11) メソッド新規追加 384 * @og.rev 3.5.5.3 (2004/04/09) StringUtil の CODE を使用したメソッドを削除する。 385 * @og.rev 5.3.9.0 (2011/09/01) DB_USE_TEXT_LENGTH を考慮した、「文字数」、「バイト数」チェック 386 * 387 * @param value 元の文字列 388 * @param len 文字列の長さ 389 * 390 * @return エラー文字列(正常時は、null) 391 */ 392 public static String byteLengthCheck( final String value ,final int len ) { 393 String rtn = null; 394 395 // 5.3.9.0 (2011/09/01) 「文字数」、「バイト数」チェック 396 final int valLen ; 397 if( USE_TEXT_LEN ) { // true:「文字数」チェック方式 398 valLen = value.length(); 399 } 400 else { // false:「バイト数」チェック方式 401 final byte[] byteValue = StringUtil.makeByte( value,CODE ); // 3.5.5.3 (2004/04/09) 402 valLen = byteValue.length; 403 } 404 405 if( valLen > len ) { 406 rtn = String.valueOf( valLen ); 407 } 408 409 return rtn ; 410 } 411 412 /** 413 * 文字列の整合性を、dbType パラメータを利用してチェックします。 414 * regex が、null または、長さゼロの文字列の場合は、なにもしません。 415 * 416 * @og.rev 3.6.0.0 (2004/09/22) 新規作成 417 * 418 * @param value 元の文字列 419 * @param regex チェックする正規表現文字列 420 * 421 * @return エラー文字列(正常時は、null) 422 */ 423 public static String matcheCheck( final String value,final String regex ) { 424 // 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 425 // 条件変更注意 426 return regex == null || regex.isEmpty() || value.matches( regex ) 427 ? null 428 : "<span class=\"NG\">" + value + "</span> regex=" + regex ; 429 430 } 431}