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