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.model.NativeType; 019import org.opengion.fukurou.util.ErrorMessage; 020import org.opengion.fukurou.util.StringUtil; 021 022/** 023 * 一般的な半角文字列を扱う為の、カラム属性を定義します。 024 * 025 * 半角文字列とは、「 c < 0x20 || c > 0x7e 以外」でのみ 026 * 構成された文字列のことです。 027 * 028 * タイプチェックとして、以下の条件を判定します。 029 * ・文字列長は、Byte換算での文字数との比較 030 * ・半角文字列チェック「 c < 0x20 || c > 0x7e 以外」エラー 031 * ・文字パラメータの 正規表現チェック 032 * ・クロスサイトスクリプティングチェック 033 * 034 * @og.group データ属性 035 * 036 * @version 4.0 037 * @author Kazuhiko Hasegawa 038 * @since JDK5.0, 039 */ 040public abstract class AbstractDBType implements DBType { 041 042 private final String defValue ; // データのデフォルト値 043 044 /** 045 * デフォルトコンストラクター 046 * 047 * @og.rev 4.0.0.0 (2005/01/31) type 廃止 048 */ 049 public AbstractDBType() { 050 this( "" ); // データのデフォルト値 051 } 052 053 /** 054 * コンストラクター 055 * 056 * 各サブクラスのタイプ値とデフォルト値を設定して、オブジェクトを構築します。 057 * 058 * @og.rev 4.0.0.0 (2005/01/31) type 廃止 059 * 060 * @param defValue データのデフォルト値 061 */ 062 public AbstractDBType( final String defValue ) { 063 this.defValue = defValue; 064 } 065 066 /** 067 * NATIVEの型の識別コードを返します。 068 * 069 * @og.rev 3.5.4.7 (2004/02/06) 新規作成 070 * @og.rev 4.1.1.2 (2008/02/28) Enum型(fukurou.model.NativeType)に変更 071 * 072 * @return NATIVEの型の識別コード(DBType で規定) 073 * @see org.opengion.fukurou.model.NativeType 074 */ 075 public NativeType getNativeType() { 076 return NativeType.STRING; 077 } 078 079 /** 080 * 半角スペースで固定長(半角換算の数)に変換した文字列を返します。 081 * 082 * 半角スペース埋めは、文字が半角、全角混在でもかまいません。 083 * なお、エラーチェックは行われません。 084 * 実行前に、必ず valueCheck( String value ,int len ) を行う必要があります。 085 * 086 * @og.rev 3.5.4.5 (2004/01/23) エンコード指定に変更します。 087 * 088 * @param value FILL埋めする文字列 089 * @param sizeX 整数部分の文字列の長さ 090 * @param sizeY 少数部分の文字列の長さ 091 * @param encode 固定長で変換する文字エンコード 092 * 093 * @return FILL埋めした新しい文字列 094 */ 095 public String valueFill( final String value ,final int sizeX ,final int sizeY,final String encode ) { 096 int len = (sizeY == 0) ? sizeX : sizeX + sizeY + 1; 097 098 return StringUtil.stringFill( value,len,encode ); 099 } 100 101 /** 102 * そのDBTypeの,デフォルトの値(物理的初期設定値)を返します。 103 * 104 * 一般に、文字列の場合は,ゼロストリング"" 数字の場合は "0" です。 105 * 106 * @return 物理的初期設定値 107 */ 108 public String getDefault() { 109 return defValue; 110 } 111 112 /** 113 * String引数の文字列を+1した文字列を返します。 114 * 115 * これは、英字の場合(A,B,C など)は、B,C,D のように,最終桁の文字コードを 116 * +1 します。 117 * 文字列が数字タイプの場合は, 数字に変換して、+1 します。 118 * 最終桁が、"9","z","Z" および、その全角文字の場合、"0","a","Z" および、その全角文字に 119 * 変換後、ひとつ上の桁で、同様の +1 操作を行います。 120 * 最も上位の桁が、これらの繰り上がり桁の場合は、すべての桁が初期化された状態に戻ります。 121 * 例:123 ⇒ 124 , ABC ⇒ ABD , 789 ⇒ 790 , XYZ ⇒ XXZ , 122 * ABC123 ⇒ ABC124 , AB99 ⇒ AC00 , 12ZZ99 ⇒ 13AA00 , ZZZZ ⇒ AAAA 123 * 引数が null の場合と、ゼロ文字列("")の場合は,物理的初期設定値(String getDefault()) 124 * の値を返します。 125 * 126 * @og.rev 4.0.0.0 (2005/01/31) Addの方法を変更(汎用的なAdd) 127 * 128 * @param value String引数 129 * 130 * @return 引数の文字列を+1した文字列。 131 */ 132 public String valueAdd( final String value ) { 133 if( value == null || value.length() == 0 ) { return getDefault(); } 134 135 char[] chs = value.toCharArray() ; 136 137 for( int i=chs.length-1; i>=0; i-- ) { 138 boolean over = true; 139 switch( chs[i] ) { 140 case '9' : chs[i] = '0' ; break; 141 case 'z' : chs[i] = 'a' ; break; 142 case 'Z' : chs[i] = 'A' ; break; 143 case '9' : chs[i] = '0'; break; 144 case 'z' : chs[i] = 'a'; break; 145 case 'Z' : chs[i] = 'A'; break; 146 default : chs[i]++; over=false; break; 147 } 148 if( !over ) { break; } // キャリーオーバーしていなければ、終了 149 } 150 151 return new String( chs ); 152 } 153 154 /** 155 * String引数の文字列に、第2引数に指定の文字列(数字、日付等)を加算して返します。 156 * 157 * これは、valueAdd( String ) と本質的には同じ動きをしますが、任意の文字列を加算する 158 * ため、主として、数字系や日付系の DBType にのみ実装します。 159 * 実装がない場合は、UnsupportedOperationException を throw します。 160 * 161 * 第2引数 が、null の場合は、+1 する valueAdd( String )が呼ばれます。 162 * これは、将来的には、valueAdd( String ) を無くすことを意味します。 163 * 164 * @og.rev 5.6.0.3 (2012/01/24) ADD に、引数の値を加算する機能を追加します。 165 * 166 * @param value String引数 167 * @param add 加算する文字列(null の場合は、従来と同じ、+1 します。) 168 * 169 * @return 引数の文字列第2引数に指定の文字列(数字、日付等)を加算した文字列。 170 * @throws UnsupportedOperationException 実装が存在しない場合 171 */ 172 public String valueAdd( final String value,final String add ) { 173 if( add == null || add.isEmpty() ) { return valueAdd( value ); } 174 175 String errMsg = "このクラスでは、引数付の任意の加算は実装されていません。" 176 + getClass().getName() + " Action=[ADD]" 177 + " oldValue=[" + value + "] newValue=[" + add + "]" ; 178 throw new UnsupportedOperationException( errMsg ); 179 } 180 181 /** 182 * エディターで編集されたデータを登録する場合に、データそのものを変換して、実登録データを作成します。 183 * 184 * 例えば,大文字のみのフィールドなら、大文字化します。 185 * 実登録データの作成は、DBType オブジェクトを利用しますので, 186 * これと CellEditor とがアンマッチの場合は、うまくデータ変換 187 * されない可能性がありますので、注意願います。 188 * 189 * @og.rev 3.3.3.0 (2003/07/09) 前後のスペースを取り除いておく。 190 * @og.rev 3.3.3.1 (2003/07/18) 後ろスペースを取り除く。(StringUtil#rTrim) 191 * 192 * @param value (一般に編集データとして登録されたデータ) 193 * 194 * @return 修正後の文字列(一般にデータベースに登録するデータ) 195 */ 196 public String valueSet( final String value ) { 197 return StringUtil.rTrim( value ); 198 } 199 200 /** 201 * action で指定されたコマンドを実行して、値の変換を行います。 202 * 203 * oldValue(旧データ)は、元のDBTableModelに設定されていた値です。通常は、 204 * この値を使用してカラム毎に変換を行います。newValue(新データ)は、引数で 205 * 指定された新しい値です。この値には、パラメータを指定して変換方法を 206 * 制御することも可能です。 207 * 指定のアクションがカラムで処理できない場合は、エラーになります。 208 * 209 * @param action アクションコマンド 210 * @param oldValue 入力データ(旧データ) 211 * @param newValue 入力データ(新データ) 212 * 213 * @return 実行後のデータ 214 */ 215 public String valueAction( final String action,final String oldValue,final String newValue ) { 216 String errMsg = "このクラスでは、このアクションは実装されていません。" 217 + getClass().getName() + " Action=[" + action + "]" 218 + " oldValue=[" + oldValue + "] newValue=[" + newValue + "]" ; 219 throw new UnsupportedOperationException( errMsg ); 220 } 221 222 /** 223 * データが登録可能かどうか[true/false]をチェックします。 224 * 225 * データがエラーの場合は、そのエラー内容を返します。 226 * 227 * @og.rev 2.1.1.1 (2002/11/15) HTMLタグチェックのメソッドの共有化。 228 * @og.rev 3.0.1.3 (2003/03/11) DBTypeCheckUtilクラスを利用するように修正 229 * @og.rev 3.6.0.0 (2004/09/22) dbType パラメータを引数に追加 230 * @og.rev 5.2.2.0 (2010/11/01) 厳密にチェック(isStrict=true)するフラグを追加 231 * 232 * @param key キー 233 * @param value 値 234 * @param sizeX 整数部分の文字列の長さ 235 * @param sizeY 少数部分の文字列の長さ 236 * @param typeParam dbType パラメータ 237 * @param isStrict 厳密にチェックするかどうか [true:する/false:標準的] 238 * 239 * @return エラー内容 240 */ 241 public ErrorMessage valueCheck( final String key ,final String value , 242 final int sizeX ,final int sizeY ,final String typeParam ,final boolean isStrict) { 243 244 ErrorMessage msg = new ErrorMessage(); 245 if( value == null || value.length() == 0 ) { return msg; } 246 247 int len = (sizeY == 0) ? sizeX : sizeX + sizeY + 1; 248 if( len < value.length() ) { 249 // 文字列の長さが指定の長さよりも長いです。 250 msg.addMessage( 0,ErrorMessage.NG,"ERR0006",key,value, 251 String.valueOf( value.length() ),String.valueOf( len ) ); 252 } 253 254 StringBuilder val = new StringBuilder(); 255 boolean isError = false; 256 for( int i=0; i<value.length(); i++ ) { 257 char ch = value.charAt( i ); 258 if( ch < 0x20 || ch > 0x7e ) { 259 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 260 isError = true; 261 } 262 else { 263 val.append( ch ); 264 } 265 } 266 if( isError ) { 267 // 指定の文字以外の文字が使われています。 268 msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,val.toString() ); 269 } 270 271 // 3.6.0.0 (2004/09/22) dbType パラメータを使用したマッチチェック 272 String check = DBTypeCheckUtil.matcheCheck( value,typeParam ); 273 if( check != null ) { 274 // 指定の文字以外の文字が使われています。 275 msg.addMessage( 0,ErrorMessage.NG,"ERR0009", key,check ); 276 } 277 278 // クロスサイトスクリプティング対策:'<', '>' は登録させない。 279 msg = xssCheck( key ,value, msg ); 280 return msg; 281 } 282 283 /** 284 * HTMLタグかどうかをチェックします。 285 * 286 * クロスサイトスクリプティング対策として、'<', '>' は登録させない。 287 * 288 * @og.rev 2.1.1.1 (2002/11/15) HTMLタグチェックのメソッドの共有化。 289 * 290 * @param key タグのキー 291 * @param value 対象の値 292 * @param msg ErrorMessageオブジェクト 293 * 294 * @return エラー内容(エラーを追加した、ErrorMessageオブジェクト) 295 */ 296 protected ErrorMessage xssCheck( final String key ,final String value, final ErrorMessage msg ) { 297 StringBuilder val = new StringBuilder(); 298 boolean isError = false; 299 for( int i=0; i<value.length(); i++ ) { 300 char ch = value.charAt( i ); 301 if( ch == '<' || ch == '>' ) { 302 val.append( "<span class=\"NG\">" ).append( ch ).append( "</span>" ); 303 isError = true; 304 } 305 else { 306 val.append( ch ); 307 } 308 } 309 if( isError ) { 310 // HTMLタグは登録できません。 311 msg.addMessage( 0,ErrorMessage.NG,"ERR0010", key,val.toString() ); 312 } 313 return msg; 314 } 315}