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.plugin.column;
017
018import java.util.Calendar;
019
020import org.opengion.fukurou.util.ErrorMessage;
021import org.opengion.fukurou.util.StringUtil;
022import org.opengion.hayabusa.db.AbstractDBType;
023import org.opengion.hayabusa.db.DBTypeCheckUtil;
024import org.opengion.fukurou.util.HybsDateUtil;
025
026/**
027 * 文字列の時間属性(時:分:秒)の半角の時間を扱う為の、カラム属性を定義します。
028 *
029 * HHmmss に対応している必要があります。
030 * (HHmmのデータでも利用可能です)
031 *
032 * ただし、日付の整合性チェックは行いませんが、valueAdd( String value )での
033 * 日付の加算時には、正式な日付データにて加算します。
034 *
035 * タイプチェックとして、以下の条件を判定します。
036 * ・文字列長は、直接計算で文字数との比較
037 * ・日付使用文字チェック「('0' > c || '9' < c)以外」エラー
038 * ・文字パラメータの 正規表現チェック
039 *     例えば、24時や60分をエラーにしたい場合、「([0-1][0-9]|[2][0-3])[0-5][0-9]」 という
040 *     正規表現を文字パラメータに登録すれば、チェックできます。
041 *
042 * @og.group データ属性
043 * @og.rev 5.4.3.6 (2012/01/20)  タイプチェックが抜けているので追加
044 *
045 * @version  4.0
046 * @author   Kazuhiko Hasegawa
047 * @since    JDK5.0,
048 */
049public class DBType_HMS extends AbstractDBType {
050        /** このプログラムのVERSION文字列を設定します。   {@value} */
051        private static final String VERSION = "7.2.5.1 (2020/06/05)" ;
052
053        /**
054         * デフォルトコンストラクター
055         *
056         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
057         */
058        public DBType_HMS() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
059
060        /**
061         * String引数の文字列を+1した文字列を返します。
062         * これは、英字の場合(A,B,C など)は、B,C,D のように、最終桁の文字コードを
063         * +1 します。
064         * 文字列が数字タイプの場合は、数字に変換して、+1 します。(桁上がりもあり)
065         * 混在タイプの場合は、最後の桁だけを確認して +1します。
066         * 引数が null の場合と、ゼロ文字列("")の場合は、物理的初期設定値(String getDefault())
067         * の値を返します。
068         * 24時間を超えた場合は、25時となります。
069         *
070         * @og.rev 6.2.2.2 (2015/04/03) 桁数可変に対応
071         *
072         * @param       value   String引数の文字列
073         *
074         * @return  String引数の文字列を+1した文字列(1時間加算)
075         */
076        @Override
077        public String valueAdd( final String value ) {
078                if( value == null || value.isEmpty() ) { return getDefault(); }
079
080                // 6.2.2.2 (2015/04/03) 4桁より小さいとHHmm、それ以外は、HHmmss
081                final boolean isHM = value.length() <= 4 ;
082
083                //                        HHmm    HHmmss
084                final int hms = ( isHM ? 10100 : 1010000 ) + Integer.parseInt( value );
085
086                // 元の形式に準拠して返す。
087                return String.valueOf( hms ).substring( 1 );
088        }
089
090        /**
091         * String引数の文字列に、第2引数に指定の文字列(数字、日付等)を加算して返します。
092         *
093         * ここでは、HHmmss 形式のデータに、時間を加算します。
094         *
095         * この HMS は、引数に、日付単位を指定できます。単位は、HHmmss 形式の
096         * 1文字を指定します。大文字、小文字も識別します。value="5H" とすれば、5時間、
097         * value="5m"とすれば、5分 追加します。
098         * 指定しない場合は、時を加算します。
099         *
100         * ここのデータは、時間が繰り越しても、日付に影響しません。
101         * また、24時間を超えた場合は、00 時に戻ります。
102         *
103         * @og.rev 5.6.0.3 (2012/01/24) ADD に、引数の値を加算する機能を追加します。
104         * @og.rev 5.6.1.0 (2013/02/01) 加算する引数に、日付単位('H','m','s')を指定可能にします。
105         * @og.rev 6.2.2.2 (2015/04/03) 桁数可変に対応
106         *
107         * @param   value  String引数
108         * @param   add    加算する時間文字列(単位付き:['H','m','s'])
109         *
110         * @return  引数の文字列に時間を加算します。
111         */
112        @Override
113        public String valueAdd( final String value,final String add ) {
114                if( value == null || value.isEmpty() ) { return getDefault(); }
115                // 日付文字列にダミーの年月日を追加しておく。
116
117                final boolean isHM = value.length() <= 4 ;
118
119                // ※ yyyymmd + 1HHmmss で、日付データのダミーの年月日を追加
120                final int hms = 1000000 + Integer.parseInt( isHM ? value + "00" : value );
121
122                // 元の形式に準拠して返す。
123                return HybsDateUtil.getDatePlus( ( "2010010" + hms ),add,Calendar.HOUR_OF_DAY, isHM ? "HHmm" : "HHmmss" );
124        }
125
126        /**
127         * エディターで編集されたデータを登録する場合に、データそのものを
128         * 変換して、実登録データを作成します。
129         * 例えば、大文字のみのフィールドなら、大文字化します。
130         * 実登録データの作成は、DBType オブジェクトを利用しますので、
131         * これと Editor とがアンマッチの場合は、うまくデータ変換
132         * されない可能性がありますので、注意願います。
133         *
134         * @og.rev 6.2.2.2 (2015/04/03) 桁数可変に対応
135         * @og.rev 6.2.2.3 (2015/04/10) 数値変換エラーを発生させない様にします。
136         *
137         * @param       value   (一般に編集データとして登録されたデータ)
138         *
139         * @return  修正後の文字列(一般にデータベースに登録するデータ)
140         */
141        @Override
142        public String valueSet( final String value ) {
143                if( value == null || value.isEmpty() ) { return ""; }
144
145                // 6.2.2.2 (2015/04/03) 4桁より小さいとHHmm、それ以外は、HHmmss
146                final String val = StringUtil.deleteChar( value,':' );
147                final boolean isHM = val.length() <= 4 ;                // 6.2.2.3 (2015/04/10) バグ修正
148
149                try {
150                        //                        HHmm    HHmmss
151        //              final int hms = ( isHM ? 10000 : 1000000 ) + Integer.parseInt( value );
152                        final int hms = ( isHM ? 10000 : 1000000 ) + Integer.parseInt( val );           // 6.2.2.3 (2015/04/10) バグ修正
153
154                        // 元の形式に準拠して返す。
155                        return String.valueOf( hms ).substring( 1 );
156                }
157                catch( final NumberFormatException ex ) {
158                        return val;             // 6.2.2.3 (2015/04/10) 一応、":" 削除後の文字列を返す。
159                }
160        }
161
162        /**
163         * データが登録可能かどうかをチェックします。
164         * データがエラーの場合は、そのエラー内容を返します。
165         *
166         * @og.rev 5.2.3.6 (2012/01/20) 数値のみに限定するために追加
167         * @og.rev 5.6.0.3 (2012/01/24) ADD に、引数の値を加算する機能を追加します。
168         * @og.rev 6.2.2.2 (2015/04/03) 桁数可変に対応
169         * @og.rev 6.8.4.1 (2017/12/18) 24時間以上の表記に対応するため、isStrict属性を加味します。
170         * @og.rev 7.2.5.1 (2020/06/05) 数値変換エラーの前にチェックを入れます。
171         *
172         * @param   key         キー
173         * @param   value       値
174         * @param   sizeX       整数部分の文字列の長さ
175         * @param   sizeY       小数部分の文字列の長さ
176         * @param   typeParam   dbType パラメータ(文字パラメータ)
177         * @param   isStrict    厳密にチェックするかどうか[true:する/false:標準的]
178         *
179         * @return  エラー内容
180         * @og.rtnNotNull
181         */
182        @Override
183        public ErrorMessage valueCheck( final String key ,final String value ,
184                                                                        final int sizeX ,final int sizeY ,final String typeParam ,final boolean isStrict) {
185                final String checkVal = valueSet(value); // :は念のため外しておく
186
187                final ErrorMessage msg = new ErrorMessage();
188                if( checkVal == null || checkVal.isEmpty() ) { return msg; }
189
190                final int len = (sizeY == 0) ? sizeX : sizeX + sizeY + 1;
191                if( isStrict ) {
192                        if( len != checkVal.length() ) {
193                                // 文字列の長さが指定の長さと異なります。
194                                msg.addMessage( 0,ErrorMessage.NG,"ERR0011", key,value, String.valueOf( value.length() ), String.valueOf( len ) );
195                        }
196                }
197                else {
198                        if( len < checkVal.length() ) {
199                                // 文字列の長さが指定の長さよりも長いです。
200                                msg.addMessage( 0,ErrorMessage.NG,"ERR0006",key,value,
201                                                                                String.valueOf( value.length() ),String.valueOf( len ) );
202                        }
203                }
204
205                // 7.2.5.1 (2020/06/05) 文字の範囲チェックは、ymdFormatCheck の中で行っている。
206//              // 5.6.0.3 (2012/01/24) 文字の範囲チェック
207//              String check = DBTypeCheckUtil.rangeCheck( checkVal, '0', '9' );
208//              if( check != null ) {
209//                      // 指定の文字以外の文字が使われています。
210//                      msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check );
211//              }
212
213                String check = null;
214                // 6.8.4.1 (2017/12/18) 24時間以上の表記に対応するため、isStrict属性を加味します。
215                if( isStrict ) {
216                        // 5.6.0.3 (2012/01/24) 時分秒の整合性チェック
217                        check = DBTypeCheckUtil.hmsFormatCheck( checkVal );
218                        if( check != null ) {
219                                // 指定の文字以外の文字が使われています。
220                                msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check );
221                        }
222                }
223                else {
224                        check = DBTypeCheckUtil.rangeCheck( checkVal, '0', '9' );
225                        if( check != null ) {
226                                // 指定の文字以外の文字が使われています。
227                                msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check );
228                        }
229                }
230
231                // 3.6.0.0 (2004/09/22) dbType パラメータ(文字パラメータ)を使用したマッチチェック
232                check = DBTypeCheckUtil.matcheCheck( checkVal,typeParam );
233                if( check != null ) {
234                        // 指定の文字以外の文字が使われています。
235                        msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check );
236                }
237
238                return msg;
239        }
240}