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.taglib; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.hayabusa.db.DBColumn; 021import org.opengion.hayabusa.db.DBTableModel; 022import org.opengion.hayabusa.db.DBTableModelUtil; 023 024import org.opengion.fukurou.util.StringUtil; 025import static org.opengion.fukurou.util.StringUtil.nval ; 026 027import java.util.Map; 028import java.util.LinkedHashMap; 029import java.util.Locale ; 030 031/** 032 * 2つの DBTableModel の 集合処理を行うタグです。 033 * 034 * マスタとスレーブのそれぞれの DBTableModel を取得し、マージ、差分、排他などの 035 * データ処理を行います。結果を、指定の tableId と scope に書き出します。 036 * マスタテーブルは、masterTableId と masterScope より取り出します。スレーブテーブルは、 037 * slaveTableId と slaveScope より取り出します。 038 * 取り出された DBTableModel は、マスタテーブルに対して、スレーブテーブル情報を参照する形で行われ、 039 * 結果はマスタテーブルに上書きされる形で行われます。 040 * 指定できるアクションは、全体集合(UNION_ALL)、和集合(UNION)、積集合(INTERSECT)、 041 * 差集合(MINUS)、差分集合(DIFFERENCE)、列合成(UNION_CLM)、 列追加(ADD_CLM)、 グループ(GROUP)です。 042 * 列合成と列追加、グループ以外の処理では、カラム順とカラム数は同数でなければなりません。 043 * primaryKeys や unionClms などの指定のキー名は、マスタテーブルに存在する必要があります。 044 * マスタテーブルと同じカラム番号でスレーブテーブルよりデータを読み出します。 045 * (カラム名や属性は、異なってもかまいませんが、マスタテーブルに準拠します。) 046 * また、単独(マスタテーブルのみ)で、和集合と同等の、グループ(GROUP)を使用すると、指定の 047 * カラムでのユニーク化を行うことが可能になります。グループ処理では、先行優先とし、 048 * 2回目に現れた情報を削除することになります。グループ が指定された場合は、 049 * スレーブテーブルは無視されます。いずれの処理においても、集合処理を行う主キーで 050 * 一旦グループ化されます。全体集合(UNION_ALL)で処理する場合でも、主キーがユニークで 051 * ない場合は、マスター、スレーブの各テーブルで一旦グループ化された後で、マージされます。 052 * (マージ後には、同一主キーを持つ行は存在します。) 053 * 全体集合(UNION_ALL)の場合のみ、mergeKeys を指定する必要はありません。その場合は、 054 * キーなしのため、マスターとスレーブのテーブルを単に合成するだけになります。 055 * 056 * 処理前後でのDBTableModelの件数は、以下の変数で取得することが可能です。 057 * 処理前のマスターテーブル : {@DB.MASTER_COUNT} 058 * 処理前のスレーブテーブル : {@DB.SLAVE_COUNT} 059 * 処理後 : {@DB.COUNT} 060 * 061 * @og.formSample 062 * ●形式: 063 * ・<og:tableMerge 064 * action = "UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|ADD_CLM|GROUP|UNION_SELROW" 065 * tableId = "DEFAULT" 出力テーブルの tableId 066 * scope = "session" 出力テーブルの scope 067 * masterTableId = "DEFAULT" マスタテーブルの tableId 068 * masterScope = "session" マスタテーブルの scope 069 * slaveTableId = "DEFAULT" スレーブテーブルの tableId 070 * slaveScope = "request" スレーブテーブルの scope 071 * masterKeys = "AA,BB,CC" マスタテーブルの集合処理を行う主キー 072 * slaveKeys = "AA,BB,CC" スレーブテーブルの集合処理を行う主キー(null時=masterKeys) 073 * diffKeys = "DD,EE" マスタテーブルのDIFFERENCE時の差分カラム名 074 * unionClms = "DD,EE" UNION_CLM,ADD_CLM時にスレーブからマスタへ追加するカラム名 075 * modifyClms = "FF,GG" DIFFERENCE時にスレーブからマスタへ値を更新するカラム名 076 * noSideEffect = "false" テーブルモデルに対する副作用(true:ない/false:ある) 077 * useDiffData = "true" DIFFERENCE時に差分のスレーブデータを追加するかどうか 078 * useCheckOnly = "false" マスタテーブルの選択行のデータのみを対象に処理を行うかどうか 079 * groupAddClms = "FF,GG" masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名 080 * display = "true" 処理概要を表示するかどうか 081 * /> 082 * ●body:なし 083 * 084 * ●Tag定義: 085 * <og:tableMerge 086 * command 【TAG】コマンド(NEW,RENEW)をセットします(初期値:NEW) 087 * action 【TAG】アクションを指定します(UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|ADD_CLM|GROUP|UNION_SELROW) 088 * tableId 【TAG】出力先のtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl]) 089 * scope 【TAG】出力先のscopeを指定します(初期値:session) 090 * masterTableId 【TAG】マスタテーブルのtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl]) 091 * masterScope 【TAG】マスタテーブルのscopeを指定します(初期値:session) 092 * slaveTableId 【TAG】スレーブテーブルのtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl]) 093 * slaveScope 【TAG】スレーブテーブルのscopeを指定します(初期値:session) 094 * masterKeys 【TAG】マスタテーブルの集合処理を行う主キーを指定します 095 * slaveKeys 【TAG】スレーブテーブルの集合処理を行う主キーを指定します 096 * diffKeys 【TAG】マスタテーブルのDIFFERENCE時の差分カラム名を(CSV形式)指定します 097 * unionClms 【TAG】スレーブからマスタへ追加するカラム名をCSV形式で指定します 098 * modifyClms 【TAG】スレーブからマスタへ値を更新するカラム名をCSV形式で指定します 099 * groupAddClms 【TAG】集合処理するときに、相違データをCSV連結して残すカラム名をCSV形式で指定します 100 * noSideEffect 【TAG】テーブルモデルに対する副作用の有無[true:ない/false:ある]を指定します(初期値:false:ある) 101 * useDiffData 【TAG】差分のスレーブデータを結果テーブルに追加するかどうかを指定します(初期値:true) 102 * useCheckOnly 【TAG】マスタテーブルの選択行のデータのみを対象に処理を行うかどうかを指定します(初期値:false) 103 * stopZero 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する]) 104 * display 【TAG】マージの結果を表示するかどうかを指定します(初期値:true) 105 * mainTrans 【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false) 106 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 107 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 108 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true) 109 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true) 110 * separator 【TAG】groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",") 111 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 112 * /> 113 * 114 * ●使用例 115 * 例1)デフォルト以外に必要な属性のみ指定するサンプル 116 * <og:tableMerge action="UNION" 117 * slaveScope = "request" masterKeys = "AA,BB,CC" 118 * /> 119 * 120 * ・出力先、マスターともに初期値は、tableId="DEFAULT" scope="session" です。 121 * スレーブは、tableId か scope をける必要がある為、scope="request" を指定しています。 122 * 比較するカラム名は、マスタ、スレーブ同じであれば、マスタのみ指定でかまいません。 123 * 124 * 例2)マスタ、スレーブともメモリに残らないように request で作成します。 125 * <og:tableMerge action="INTERSECT" 126 * masterScope = "request" 127 * slaveScope = "request" 128 * slaveTableId = "SLAVE" 129 * masterKeys = "AA,BB,CC" 130 * /> 131 * 132 * ・マスタ、スレーブともメモリに残らないように request で作成した場合は、 133 * どちらかの TableId を変える必要があります。 134 * 出力先は初期値の、tableId="DEFAULT" scope="session" です。 135 * 136 * @og.rev 3.8.0.9 (2005/10/17) 新規追加 137 * @og.group DB登録 138 * 139 * @version 0.9.0 2000/10/17 140 * @author Kazuhiko Hasegawa 141 * @since JDK5.0, 142 */ 143public class TableMergeTag extends CommonTagSupport { 144 //* このプログラムのVERSION文字列を設定します。 {@value} */ 145 private static final String VERSION = "5.7.6.2 (2014/05/16)" ; 146 147 private static final long serialVersionUID = 576220140516L ; 148 149 /** action 引数に渡す事の出来る アクションコマンド 全体集合 {@value} */ 150 public static final String ACT_UNION_ALL = "UNION_ALL" ; 151 /** action 引数に渡す事の出来る アクションコマンド 和集合 {@value} */ 152 public static final String ACT_UNION = "UNION" ; 153 /** action 引数に渡す事の出来る アクションコマンド 積集合 {@value} */ 154 public static final String ACT_INTERSECT = "INTERSECT" ; 155 /** action 引数に渡す事の出来る アクションコマンド 差集合{@value} */ 156 public static final String ACT_MINUS = "MINUS" ; 157 /** action 引数に渡す事の出来る アクションコマンド 差分集合{@value} */ 158 public static final String ACT_DIFFERENCE = "DIFFERENCE" ; 159 /** action 引数に渡す事の出来る アクションコマンド 列合成{@value} */ 160 public static final String ACT_UNION_CLM = "UNION_CLM" ; 161 /** action 引数に渡す事の出来る アクションコマンド 列合成{@value} */ 162 public static final String ACT_ADD_CLM = "ADD_CLM" ; 163 /** action 引数に渡す事の出来る アクションコマンド グループ {@value} */ 164 public static final String ACT_GROUP = "GROUP" ; 165 /** action 引数に渡す事の出来る アクションコマンド グループ {@value} */ 166 public static final String ACT_UNION_SELROW = "UNION_SELROW" ;// 4.3.2.0 (2008/09/11) 167 168 /** action 引数に渡す事の出来る アクションコマンド リスト */ 169 private static final String[] ACTION_LIST = new String[] { 170 ACT_UNION_ALL , ACT_UNION , ACT_INTERSECT , ACT_MINUS , ACT_DIFFERENCE , ACT_UNION_CLM , ACT_ADD_CLM , ACT_GROUP, ACT_UNION_SELROW }; 171 172 /** command 引数に渡す事の出来る コマンド 新規 {@value} */ 173 public static final String CMD_NEW = "NEW" ; 174 /** command 引数に渡す事の出来る コマンド 再検索 {@value} */ 175 public static final String CMD_RENEW = "RENEW" ; 176 /** command 引数に渡す事の出来る コマンド リスト */ 177 private static final String[] COMMAND_LIST = new String[] { CMD_NEW , CMD_RENEW }; 178 179 private String command = CMD_NEW; 180 181 private String action = null; 182 private String tableId = HybsSystem.TBL_MDL_KEY; // 出力先の tableId 183 private String scope = "session"; // 出力先の scope 184 185 private String masterTableId = HybsSystem.TBL_MDL_KEY; // マスタテーブルの tableId 186 private String masterScope = "session"; // マスタテーブルの scope 187 private String slaveTableId = HybsSystem.TBL_MDL_KEY; // スレーブテーブルの tableId 188 private String slaveScope = "request"; // スレーブテーブルの scope 189 private String masterKeys = null; // マスタテーブルの集合処理を行う主キー 190 private String slaveKeys = null; // スレーブテーブルの集合処理を行う主キー(null時=masterKeys) 191 private String diffKeys = null; // マスタテーブルのDIFFERENCE時の差分カラム名 192 private String unionClms = null; // UNION_CLM時にスレーブからマスタへ追加するカラム名 193 private String modifyClms = null; // DIFFERENCE時にスレーブからマスタへ値を更新するカラム名 194 private String groupAddClms = null; // 5.1.4.0 (2010/03/01) masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名 195 private boolean noSideEffect = false; // テーブルモデルに対する副作用(true:ない/false:ある) 196 private boolean useDiffData = true; // DIFFERENCE時に差分のスレーブデータを追加するかどうか 197 private boolean useCheckOnly = false; // マスタテーブルの選択行のデータのみを対象に処理を行うかどうか 198 private boolean display = true; 199 private boolean isMainTrans = true; // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し 200 private String separator = ","; // 5.3.1.0 (2011/01/01) groupAddClmnsで結合する際の区切り文字 201 private boolean stopZero = false; // 5.7.6.2 (2014/05/16) stopZero属性追加 202 203 /** 204 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 205 * 206 * @og.rev 4.3.2.0 (2008/09/11) UNION_SELROWアクション対応 207 * @og.rev 4.3.3.0 (2008/10/01) 処理前後のテーブル件数を取得できるようにする 208 * @og.rev 4.3.3.1 (2008/10/08) スレーブのnullチェック追加 209 * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。 210 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応 211 * @og.rev 5.7.6.2 (2014/05/16) stopZero属性、DB.COUNT キーで検索件数をリクエストにセットする。 212 * 213 * @return 後続処理の指示 214 */ 215 @Override 216 public int doEndTag() { 217 debugPrint(); // 4.0.0 (2005/02/28) 218 // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応 219 if( !useTag() || ! check( command, COMMAND_LIST ) ) { return EVAL_PAGE ; } 220 221 // 整合性チェック:アクションリストとの存在チェック 222 if( !check( action, ACTION_LIST ) ) { 223 String errMsg = "指定のアクションは実行できません。アクションエラー" 224 + HybsSystem.CR 225 + "action=[" + action + "] " 226 + HybsSystem.CR 227 + "指定可能なアクション:" 228 + StringUtil.array2csv( ACTION_LIST ) ; 229 throw new HybsSystemException( errMsg ); 230 } 231 232 // スレーブテーブルの集合処理を行う主キー(null時=masterKeys) 233 if( slaveKeys == null ) { slaveKeys = masterKeys; } 234 235 super.setScope( masterScope ); 236 DBTableModel masterTable = (DBTableModel)getObject( masterTableId ); 237 238 // 整合性チェック:マスタテーブルは必須 239 if( masterTable == null ) { 240 String errMsg = "マスタテーブルは必須です。" 241 + HybsSystem.CR 242 + "action=[" + action + "] " 243 + "masterTableId=[" + masterTableId + "] " 244 + "masterScope=[" + masterScope + "] " ; 245 throw new HybsSystemException( errMsg ); 246 } 247 if( noSideEffect ) { masterTable = cloneTable( masterTable ); } 248 Map<String,Integer> masterMap = makeKeyMap( masterTable,masterKeys,useCheckOnly ); 249 250 DBTableModel slaveTable = null; 251 Map<String,Integer> slaveMap = null; 252 253 // 整合性チェック:action="GROUP" と "ADD_CLM" 以外では、スレーブテーブルは必須 254 if( ! ACT_GROUP.equalsIgnoreCase( action ) && !ACT_ADD_CLM.equalsIgnoreCase( action ) ) { 255 super.setScope( slaveScope ); 256 slaveTable = (DBTableModel)getObject( slaveTableId ); 257 258 if( slaveTable == null ) { 259 String errMsg = "action=\"" + action + "\" 時には、スレーブテーブルが必要です。" 260 + HybsSystem.CR 261 + "slaveTableId=[" + slaveTableId + "] " 262 + "slaveScope=[" + slaveScope + "] " ; 263 throw new HybsSystemException( errMsg ); 264 } 265 if( noSideEffect ) { slaveTable = cloneTable( slaveTable ); } 266 slaveMap = makeKeyMap( slaveTable,slaveKeys,false ); // スレーブはuseCheckOnly無関係 267 268 // その場合、マスタとスレーブが同一メモリ上のテーブル(物理的に同じ)でない事。 269 if( slaveTable == masterTable ) { 270 String errMsg = "マスタとスレーブが同一メモリになっています。" 271 + "通常、検索結果は TableId と Scope を別々に指定します。" 272 + HybsSystem.CR 273 + "action=[" + action + "] " 274 + "masterTableId=[" + masterTableId + "] " 275 + "slaveTableId=[" + slaveTableId + "] " 276 + "masterScope=[" + masterScope + "] " 277 + "slaveScope=[" + slaveScope + "] " ; 278 throw new HybsSystemException( errMsg ); 279 } 280 } 281 282 super.setScope( scope ); 283 useMainTrans( isMainTrans ); // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し 284 startQueryTransaction( tableId ); // 3.6.0.8 (2004/11/19) 285 286 // 設定値の整合性チェック 287 // 整合性チェック:action="UNION_ALL" と "GROUP"と "ADD_CLM"と "UNION_CLM" 以外では、masterKeys が必須 288 if( ! ACT_UNION_ALL.equalsIgnoreCase( action ) 289 && !ACT_UNION_SELROW.equalsIgnoreCase( action ) // 4.3.2.0 (2008/09/11) 290 && !ACT_GROUP.equalsIgnoreCase( action ) 291 && !ACT_ADD_CLM.equalsIgnoreCase( action ) 292 && !ACT_UNION_CLM.equalsIgnoreCase( action ) 293 && masterKeys == null ) { 294 String errMsg = "action=\"" + action + "\" 時には、masterKeys が必須です。" 295 + HybsSystem.CR 296 + "masterKeys=[" + masterKeys + "] "; 297 throw new HybsSystemException( errMsg ); 298 } 299 300 // 設定値の整合性チェック 301 // 整合性チェック:action="DIFFERENCE" では、diffKeys が必須 302 if( ACT_DIFFERENCE.equalsIgnoreCase( action ) && diffKeys == null ) { 303 String errMsg = "action=\"" + action + "\" 時には、diffKeys が必須です。" 304 + HybsSystem.CR 305 + "diffKeys=[" + diffKeys + "] "; 306 throw new HybsSystemException( errMsg ); 307 } 308 309 // 設定値の整合性チェック 310 // 整合性チェック:列合成(UNION_CLM) と グループ(GROUP) と 列追加(ADD_CLM) 以外では、テーブルカラム数が同じである必要がある。 311 if( ! ACT_UNION_CLM.equalsIgnoreCase( action ) 312 && !ACT_GROUP.equalsIgnoreCase( action ) 313 && !ACT_ADD_CLM.equalsIgnoreCase( action ) ) { 314 int mClmSize = masterTable.getColumnCount(); 315 int sClmSize = slaveTable.getColumnCount(); 316 317 if( mClmSize != sClmSize ) { 318 String errMsg = "action=\"" + action + "\" 時には、テーブルカラム数が異なってはいけません。" 319 + HybsSystem.CR 320 + "Master=" + mClmSize + " ,[" 321 + StringUtil.array2csv( masterTable.getNames() ) + "]" 322 + HybsSystem.CR 323 + "Slave =" + sClmSize + " ,[" 324 + StringUtil.array2csv( slaveTable.getNames() ) + "]"; 325 throw new HybsSystemException( errMsg ); 326 } 327 } 328 329 StringBuilder buf = null; 330 if( display ) { 331 buf = new StringBuilder(); 332 buf.append( action ).append( "(" ); 333 buf.append( " M[" ).append( masterTable.getRowCount() ).append( "]" ); 334 if( slaveTable != null ) { 335 buf.append( ",S[" ).append( slaveTable.getRowCount() ).append( "]" ); 336 } 337 } 338 339 // 4.3.3.0 (2008/10/01) 340 setRequestAttribute( "DB.MASTER_COUNT" , String.valueOf( masterTable.getRowCount() ) ); 341 // 4.3.3.1 (2008/10/08) nullチェック 342 if( slaveTable != null ) { 343 setRequestAttribute( "DB.SLAVE_COUNT", String.valueOf( slaveTable.getRowCount() ) ); 344 } 345 346 DBTableModel table = null; 347 if( ACT_UNION_ALL.equalsIgnoreCase( action ) ) { // 全体集合 348 table = makeUnionAll( masterTable,slaveTable ); 349 } 350 else if( ACT_UNION_SELROW.equalsIgnoreCase( action ) ) { // 4.3.2.0 (2008/09/11) 全体集合(slave表をmaster表のチェック行から追加) 351 table = makeUnionSelrow( masterTable,slaveTable ); 352 } 353 else if( ACT_UNION.equalsIgnoreCase( action ) ) { // 和集合 354 table = makeUnion( masterTable,masterMap,slaveTable,slaveMap ); 355 } 356 else if( ACT_INTERSECT.equalsIgnoreCase( action ) ) { // 積集合 357 table = makeIntersect( masterTable,masterMap,slaveMap ); 358 } 359 else if( ACT_MINUS.equalsIgnoreCase( action ) ) { // 差集合 360 table = makeMinus( masterTable,masterMap,slaveMap ); 361 } 362 else if( ACT_DIFFERENCE.equalsIgnoreCase( action ) ) { // 差分集合 363 table = makeDifference( masterTable,masterMap,slaveTable,slaveMap ); 364 } 365 else if( ACT_UNION_CLM.equalsIgnoreCase( action ) ) { // 列合成 366 if( unionClms == null ) { 367 String errMsg = "action=\"UNION_CLM\" 時には、unionClms が必須です。" ; 368 throw new HybsSystemException( errMsg ); 369 } 370 371 table = makeUnionClm( masterTable,slaveKeys,slaveTable,slaveMap ); 372 } 373 else if( ACT_ADD_CLM.equalsIgnoreCase( action ) ) { // 列追加 374 if( unionClms == null ) { 375 String errMsg = "action=\"ADD_CLM\" 時には、unionClms が必須です。" ; 376 throw new HybsSystemException( errMsg ); 377 } 378 379 table = makeAddClm( masterTable ); 380 } 381 else if( ACT_GROUP.equalsIgnoreCase( action ) ) { // グループ 382 table = makeGroup( masterTable ); 383 } 384 385 if( table != null ) { 386 // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。 387 super.setScope( scope ); 388 if( ! commitTableObject( tableId, table ) ) { 389 return SKIP_PAGE ; 390 } 391 } 392 393 // 5.7.6.2 (2014/05/16) マージした結果の DBTableModel のデータ件数 394 int rowCnt = table.getRowCount(); 395 396 if( display ) { 397// buf.append( " ) = [" ).append( table.getRowCount() ).append( "]" ); 398 buf.append( " ) = [" ).append( rowCnt ).append( "]" ); 399 jspPrint( buf.toString() ); 400 } 401 402 // 5.7.6.2 (2014/05/16) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。 403 setRequestAttribute( "DB.COUNT" , String.valueOf( rowCnt ) ); 404 405 // 5.7.6.2 (2014/05/16) 件数0件かつ stopZero = true 406 if( rowCnt == 0 && stopZero ) { return SKIP_PAGE; } 407 408 // 4.3.4.4 (2009/01/01) 409// setRequestAttribute( "DB.COUNT" , ( table == null ? 0 :String.valueOf( table.getRowCount() ) ) ); 410 411 return EVAL_PAGE ; // ページの残りを評価する。 412 } 413 414 /** 415 * タグリブオブジェクトをリリースします。 416 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 417 * 418 * @og.rev 5.1.4.0 (2010/03/01) groupAddClms 追加 419 * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。 420 * @og.rev 5.3.1.0 (2011/01/01) separator追加 421 * @og.rev 5.7.6.2 (2014/05/16) stopZero属性追加 422 */ 423 @Override 424 protected void release2() { 425 super.release2(); 426 command = CMD_NEW; 427 action = null; 428 tableId = HybsSystem.TBL_MDL_KEY; // 出力先の tableId 429 scope = "session"; // 出力先の scope 430 masterTableId = HybsSystem.TBL_MDL_KEY; // マスタテーブルの tableId 431 masterScope = "session"; // マスタテーブルの scope 432 slaveTableId = HybsSystem.TBL_MDL_KEY; // スレーブテーブルの tableId 433 slaveScope = "request"; // スレーブテーブルの scope 434 masterKeys = null; // マスタテーブルの集合処理を行う主キー 435 slaveKeys = null; // スレーブテーブルの集合処理を行う主キー(null時=masterKeys) 436 diffKeys = null; // マスタテーブルのDIFFERENCE時の差分カラム名 437 unionClms = null; // スレーブからマスタへ追加するカラム名 438 modifyClms = null; // スレーブからマスタへ値を更新するカラム名 439 groupAddClms = null; // 5.1.4.0 (2010/03/01) masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名 440 noSideEffect = false; // テーブルモデルに対する副作用(true:ない/false:ある) 441 useDiffData = true; // DIFFERENCE時に差分のスレーブデータを追加するかどうか 442 useCheckOnly = false; // マスタテーブルの選択行のデータのみを対象に処理を行うかどうか 443 display = true; 444 stopZero = false; // 5.7.6.2 (2014/05/16) stopZero属性追加 445 isMainTrans = true; // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し 446 separator = ","; 447 } 448 449 /** 450 * 指定のテーブルの指定のカラム(CSV)より、行番号をマップ化します。 451 * なお、引数のテーブルについては、主キーによるグループ処理が行われます。(副作用あり) 452 * 453 * @og.rev 4.3.2.0 (2008/09/11) マスタキー未指定時は何もしない 454 * @og.rev 5.1.4.0 (2010/03/01) groupAddClms 追加 455 * @og.rev 5.3.1.0 (2011/01/01) groupAddClms の separator指定対応 456 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 457 * 458 * @param table マップ作成元のデータテーブル(副作用あり) 459 * @param keys マップ作成の主キー(CSV形式) 460 * @param useCheckOnly チェック行のみを対象にするかどうか 461 * 462 * @return マップ化された主キーと行番号 463 */ 464 private Map<String,Integer> makeKeyMap( final DBTableModel table, final String keys, final boolean useCheckOnly ) { 465 466 // カラム名をカラム番号に変換します。 467 int[] clmNo = makeColumnNo( table,keys ); 468 int clmSize = clmNo.length; 469 if( clmSize == 0 ) { // マスタキー未指定時には全カラムを使用します。 470 return null; // 4.3.2.0 (2008/09/11) 471 } 472 473 // groupAddClms をカラム番号に変換します。 474 int[] grpClmNo = makeColumnNo( table,groupAddClms ); 475 int grpClmSize = grpClmNo.length; 476 477 Map<String,Integer> tempMap = new LinkedHashMap<String,Integer>(); 478 479 // 注意:GROUP化の過程で テーブル件数が動的に変化します。 480 StringBuilder buf ; 481 for( int row=0; row<table.getRowCount(); row++ ) { 482 if( useCheckOnly && table.getModifyType( row ).length() == 0 ) { 483 continue; 484 } 485 486 buf = new StringBuilder(); 487 for( int i=0; i<clmSize; i++ ) { 488 buf.append( table.getValue( row,clmNo[i] ) ).append( "|" ); 489 } 490 // 主キー連結文字列 491 String key = buf.toString().toUpperCase(Locale.JAPAN); // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 492 if( tempMap.containsKey( key ) ) { 493 // 5.1.4.0 (2010/03/01) groupAddClms 追加 494 int orgRow = tempMap.get( key ).intValue() ; // 追加済みの行番号を取得 495 for( int i=0; i<grpClmSize; i++ ) { 496 int clm = grpClmNo[i]; 497 String val1 = table.getValue( orgRow,clm ) ; // 既存の行・カラムのデータ 498 String val2 = table.getValue( row,clm ) ; // 削除する行・カラムのデータ 499 // 5.3.1.0 (2011/01/01) 500 table.setValueAt( val1 + separator + val2,orgRow,clm ); // CSV 連結、データを戻す。 501 } 502 table.removeValue( row ); 503 row-- ; 504 } 505 else { // まだ、未登録の場合 506 tempMap.put( key,Integer.valueOf( row ) ); 507 } 508 } 509 510 return tempMap; 511 } 512 513 /** 514 * 指定のマスタ,スレーブテーブルを使用して 全体集合 処理を実行します。 515 * 516 * @param masterTbl マスターテーブルモデル 517 * @param slaveTbl スレーブテーブルモデル 518 * 519 * @return 処理結果のテーブルモデル 520 */ 521 private DBTableModel makeUnionAll( final DBTableModel masterTbl,final DBTableModel slaveTbl ) { 522 DBTableModel table = masterTbl; 523 524 for( int row=0; row<slaveTbl.getRowCount(); row++ ) { 525 String[] vals = slaveTbl.getValues( row ); 526 table.addColumnValues( vals ); 527 } 528 529 return table; 530 } 531 532 /** 533 * 指定のマスタ,スレーブテーブルを使用して 全体集合 処理を実行します。 534 * スレーブ表は、マスタ表のチェックされた行を起点として登録されます。 535 * チェックされていない場合は、スレーブ表は先頭から追加されます。 536 * 537 * @og.rev 4.3.2.0 (2008/09/11) 新規作成 538 * 539 * @param masterTbl マスターテーブルモデル 540 * @param slaveTbl スレーブテーブルモデル 541 * 542 * @return 処理結果のテーブルモデル 543 */ 544 private DBTableModel makeUnionSelrow( final DBTableModel masterTbl,final DBTableModel slaveTbl ) { 545 DBTableModel table = masterTbl; 546 547 int insRowNo = ( getParameterRows().length > 0 ) ? getParameterRows()[0] + 1 : 0 ; 548 for( int row=0; row<slaveTbl.getRowCount(); row++ ) { 549 String[] vals = slaveTbl.getValues( row ); 550 table.addValues( vals, insRowNo + row, false ); 551 } 552 553 return table; 554 } 555 556 /** 557 * 指定のマスタ,スレーブテーブルを使用して 和集合 処理を実行します。 558 * 559 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 560 * 561 * @param masterTbl マスターテーブルモデル 562 * @param masterMap マスターテーブルの主キーマップ 563 * @param slaveTbl スレーブテーブルモデル 564 * @param slaveMap スレーブテーブルの主キーマップ 565 * 566 * @return 処理結果のテーブルモデル 567 */ 568 private DBTableModel makeUnion( final DBTableModel masterTbl,final Map<String,Integer> masterMap, 569 final DBTableModel slaveTbl,final Map<String,Integer> slaveMap ) { 570 DBTableModel table = masterTbl; 571 572 @SuppressWarnings("rawtypes") 573 Map.Entry[] entry = slaveMap.entrySet().toArray( new Map.Entry[slaveMap.size()] ); 574 575 int size = entry.length; 576 for( int i=0; i<size; i++ ) { 577 String key = (String)entry[i].getKey(); 578 if( key != null ) { key = key.toUpperCase(Locale.JAPAN); } // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 579 if( ! masterMap.containsKey( key ) ) { // マスタにスレーブデータが存在しない 580 int row = ((Integer)entry[i].getValue()).intValue(); 581 String[] vals = slaveTbl.getValues( row ); 582 table.addColumnValues( vals ); 583 } 584 } 585 return table; 586 } 587 588 /** 589 * 指定のマスタ,スレーブテーブルを使用して 積集合 処理を実行します。 590 * 591 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 592 * 593 * @param masterTbl マスターテーブルモデル 594 * @param masterMap マスターテーブルの主キーマップ 595 * @param slaveMap スレーブテーブルの主キーマップ 596 * 597 * @return 処理結果のテーブルモデル 598 */ 599 private DBTableModel makeIntersect( final DBTableModel masterTbl,final Map<String,Integer> masterMap, final Map<String,Integer> slaveMap ) { 600 DBTableModel table = masterTbl; 601 602 @SuppressWarnings("rawtypes") 603 Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] ); 604 605 int size = entry.length; 606 for( int i=0; i<size; i++ ) { 607 String key = (String)entry[i].getKey(); 608 if( key != null ) { key = key.toUpperCase(Locale.JAPAN); } // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 609 if( ! slaveMap.containsKey( key ) ) { // スレーブにマスタが存在しない 610 int row = ((Integer)entry[i].getValue()).intValue(); 611 table.rowDelete( row ); // 論理削除 612 } 613 } 614 615 // 行番号が変わらないように逆順削除します。 616 for( int row=table.getRowCount()-1; row>=0; row-- ) { 617 if( DBTableModel.DELETE_TYPE.equalsIgnoreCase( table.getModifyType( row ) ) ) { // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 618 table.removeValue( row ); 619 } 620 } 621 622 return table; 623 } 624 625 /** 626 * 指定のマスタ,スレーブテーブルを使用して 差集合 処理を実行します。 627 * 628 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 629 * 630 * @param masterTbl マスターテーブルモデル 631 * @param masterMap マスターテーブルの主キーマップ 632 * @param slaveMap スレーブテーブルの主キーマップ 633 * 634 * @return 処理結果のテーブルモデル 635 */ 636 private DBTableModel makeMinus( final DBTableModel masterTbl,final Map<String,Integer> masterMap, 637 final Map<String,Integer> slaveMap ) { 638 DBTableModel table = masterTbl; 639 640 @SuppressWarnings("rawtypes") 641 Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] ); 642 643 int size = entry.length; 644 for( int i=0; i<size; i++ ) { 645 String key = (String)entry[i].getKey(); 646 if( key != null ) { key = key.toUpperCase(Locale.JAPAN); } // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 647 if( slaveMap.containsKey( key ) ) { // スレーブにマスタが存在する 648 int row = ((Integer)entry[i].getValue()).intValue(); 649 table.rowDelete( row ); // 論理削除 650 } 651 } 652 653 // 行番号が変わらないように逆順削除します。 654 for( int row=table.getRowCount()-1; row>=0; row-- ) { 655 if( DBTableModel.DELETE_TYPE.equalsIgnoreCase( table.getModifyType( row ) ) ) { // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 656 table.removeValue( row ); 657 } 658 } 659 660 return table; 661 } 662 663 /** 664 * 指定のマスタ,スレーブテーブルを使用して 差分集合 処理を実行します。 665 * 666 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 667 * 668 * @param masterTbl マスターテーブルモデル 669 * @param masterMap マスターテーブルの主キーマップ 670 * @param slaveTbl スレーブテーブルモデル 671 * @param slaveMap スレーブテーブルの主キーマップ 672 * 673 * @return 処理結果のテーブルモデル 674 */ 675 private DBTableModel makeDifference( final DBTableModel masterTbl,final Map<String,Integer> masterMap, 676 final DBTableModel slaveTbl ,final Map<String,Integer> slaveMap ) { 677 DBTableModel table = masterTbl; 678 679 // テーブルの差分属性のカラム番号を求めます。(マスタ、スレーブ共通) 680 int[] diffClmNo = makeColumnNo( table,diffKeys ); 681 int diffClmSize = diffClmNo.length; 682 683 // スレーブからマスタへ値の再セットを行うカラム番号を求めます。(マスタ、スレーブ共通) 684 int[] modClmNo = makeColumnNo( table,modifyClms ); 685 int modClmSize = modClmNo.length; 686 687 int clmSize = table.getColumnCount(); 688 DBTableModel newTable = DBTableModelUtil.newDBTable(); 689 newTable.init( clmSize ); 690 691 // テーブルの全カラムを新たに作成するテーブルにコピーします。 692 for( int i=0; i<clmSize; i++ ) { 693 newTable.setDBColumn( i,table.getDBColumn( i ) ); 694 } 695 696 // スレーブの先頭カラムが、WRITABLE かどうか 697 boolean writeFlag = "WRITABLE".equalsIgnoreCase( slaveTbl.getColumnName(0) ); 698 699 @SuppressWarnings("rawtypes") 700 Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] ); 701 702 int size = entry.length; 703 for( int i=0; i<size; i++ ) { 704 String key = (String)entry[i].getKey(); 705 if( key != null ) { key = key.toUpperCase(Locale.JAPAN); } // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 706 if( slaveMap.containsKey( key ) ) { // スレーブにマスタが存在する 707 int mrow = ((Integer)entry[i].getValue()).intValue(); 708 int srow = slaveMap.get( key ).intValue(); 709 boolean unmatched = false; 710 for( int j=0; j<diffClmSize; j++ ) { 711 String mval = table.getValue( mrow,diffClmNo[j] ); 712 String sval = slaveTbl.getValue( srow,diffClmNo[j] ); 713 if( mval != null && !mval.equalsIgnoreCase( sval ) ) { unmatched = true; break; } // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 714 } 715 716 if( unmatched ) { // 属性情報が異なる場合のみ処理 717 // データのコピー 718 String[] mvals = new String[clmSize]; 719 System.arraycopy( table.getValues( mrow ),0,mvals,0 ,clmSize ); 720 721 // スレーブの値をマスタの値にセットする。 722 for( int j=0; j<modClmSize; j++ ) { 723 String val = slaveTbl.getValue( srow,modClmNo[j] ); 724 mvals[modClmNo[j]] = val; 725 } 726 newTable.addColumnValues( mvals ); 727 728 if( useDiffData ) { 729 // データのコピー 730 String[] svals = new String[clmSize]; 731 System.arraycopy( slaveTbl.getValues( srow ),0,svals,0 ,clmSize ); 732 if( writeFlag ) { svals[0] = "0"; } // 書き込み不許可 733 for( int j=0; j<diffClmSize; j++ ) { 734 int dclmNo = diffClmNo[j]; 735 String mval = mvals[dclmNo]; 736 String sval = svals[dclmNo]; 737 if( mval != null && !mval.equalsIgnoreCase( sval ) ) { // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 738 svals[dclmNo] = "<span class=\"unmatched\">" + sval + "</span>" ; 739 } 740 } 741 newTable.addColumnValues( svals ); 742 // newTable.setRowWritable( newTable.getRowCount()-1,false ); // 書き込み不許可 743 } 744 } 745 } 746 } 747 return newTable; 748 } 749 750 /** 751 * 指定のマスタ,スレーブテーブルを使用して 列合成 処理を実行します。 752 * 753 * すでに、マスタ にカラムが存在している場合は、値の書き換えを、 754 * カラムが存在しなければ、カラムを追加します。 755 * マスタとスレーブのデータ突合せ時のキーは、slaveKeys になります。 756 * これは、masterMap を使用しないことを意味します。(masterKeys 指定によるGROUP化は 757 * 行います。masterKeys を指定しない場合は、サマライズなしで処理します。) 758 * 具体的には、マスタテーブルの複数の行に対して、スレーブデータの値が設定 759 * される可能性があることを意味します。 760 * 761 * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 762 * 763 * @param masterTbl マスターテーブルモデル 764 * @param slaveKeys スレーブキー 765 * @param slaveTbl スレーブテーブルモデル 766 * @param slaveMap スレーブテーブルの主キーマップ 767 * 768 * @return 処理結果のテーブルモデル 769 */ 770 private DBTableModel makeUnionClm( final DBTableModel masterTbl ,final String slaveKeys , 771 final DBTableModel slaveTbl ,final Map<String,Integer> slaveMap ) { 772 773 DBTableModel table = makeAddClm( masterTbl ); 774 775 // カラム名をカラム番号に変換します。 776 int[] keyClmNo = makeColumnNo( table,slaveKeys ); 777 778 int[] mClmNo = makeColumnNo( table ,unionClms ); 779 int[] sClmNo = makeColumnNo( slaveTbl,unionClms ); 780 int addSize = mClmNo.length; // unionClms の個数なので、マスタ、スレーブは同一 781 782 // 突合せを行い、マッチするカラムについて、値をセットし直します。 783 for( int row=0; row<table.getRowCount(); row++ ) { 784 String[] mvals = table.getValues( row ); 785 StringBuilder buf = new StringBuilder(); 786 for( int i=0; i<keyClmNo.length; i++ ) { 787 buf.append( mvals[keyClmNo[i]] ).append( "|" ); 788 } 789 // 主キー連結文字列 790 String key = buf.toString().toUpperCase(Locale.JAPAN); // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。 791 if( slaveMap.containsKey( key ) ) { // スレーブにマスタに対応するデータが存在する 792 int slvRow = slaveMap.get( key ).intValue(); 793 String[] svals = slaveTbl.getValues( slvRow ); // スレーブの行番号 794 for( int j=0; j<addSize; j++ ) { 795 mvals[mClmNo[j]] = svals[sClmNo[j]]; 796 } 797 table.setValues( mvals,row ); 798 } 799 } 800 table.resetModify(); 801 802 return table; 803 } 804 805 /** 806 * 指定のマスタテーブルに 列追加 処理を実行します。 807 * 808 * すでに、マスタ にカラムが存在している場合は、値の書き換えを、 809 * カラムが存在しなければ、カラムを追加します。 810 * 811 * @param masterTbl マスターテーブルモデル 812 * 813 * @return 処理結果のテーブルモデル 814 */ 815 private DBTableModel makeAddClm( final DBTableModel masterTbl ) { 816 String[] addClms = StringUtil.csv2Array( unionClms ); 817 int addClmSize = addClms.length; 818 boolean[] useAdd = new boolean[addClmSize]; 819 int addSize = 0; 820 for( int i=0; i<addClmSize; i++ ) { 821 if( masterTbl.getColumnNo( addClms[i],false ) < 0 ) { // 存在しなければ -1 822 useAdd[i] = true; 823 addSize++ ; 824 } 825 else { 826 useAdd[i] = false; // マスタに存在すれば、追加不要 827 } 828 } 829 830 int mstrClmSize = masterTbl.getColumnCount(); 831 int clmSize = mstrClmSize + addSize; 832 833 DBTableModel table = DBTableModelUtil.newDBTable(); 834 table.init( clmSize ); 835 int clmNo = 0; 836 // マスタテーブルの全カラムを新たに作成するテーブルにコピーします。 837 for( int i=0; i<mstrClmSize; i++ ) { 838 table.setDBColumn( clmNo++,masterTbl.getDBColumn( i ) ); 839 } 840 // 追加するカラムを新たに作成するテーブルに追加します。 841 String[] addClmVal = new String[addSize]; // 追加分のみ 842 int addCnt = 0; 843 for( int i=0; i<addClmSize; i++ ) { 844 if( useAdd[i] ) { 845 DBColumn column = getDBColumn( addClms[i] ); 846 addClmVal[addCnt++] = nval( column.getDefault(),"" ); 847 table.setDBColumn( clmNo++,column ); 848 } 849 } 850 // 一旦、すべてのマスタデータを新テーブルにコピーします。 851 for( int row=0; row<masterTbl.getRowCount(); row++ ) { 852 String[] vals = new String[clmSize]; 853 System.arraycopy( masterTbl.getValues( row ),0,vals,0 ,mstrClmSize ); // マスタデータのコピー 854 System.arraycopy( addClmVal,0,vals,mstrClmSize ,addSize ); // 追加列情報の初期値 855 table.addColumnValues( vals ); 856 } 857 858 return table; 859 } 860 861 /** 862 * 指定のマスタテーブルを使用して グループ 処理を実行します。 863 * 864 * @param masterTbl マスターテーブルモデル 865 * 866 * @return 処理結果のテーブルモデル 867 */ 868 private DBTableModel makeGroup( final DBTableModel masterTbl ) { 869 DBTableModel table = masterTbl; 870 871 return table; 872 } 873 874 /** 875 * 指定のテーブルと同じテーブルを別オブジェクトとして作成します。 876 * 877 * @param tbl コピー元テーブルモデル 878 * 879 * @return コピーされた新テーブルモデル 880 */ 881 private DBTableModel cloneTable( final DBTableModel tbl ) { 882 int clmSize = tbl.getColumnCount(); 883 884 DBTableModel table = DBTableModelUtil.newDBTable(); 885 table.init( clmSize ); 886 887 // テーブルの全カラムを新たに作成するテーブルにコピーします。 888 for( int i=0; i<clmSize; i++ ) { 889 table.setDBColumn( i,tbl.getDBColumn( i ) ); 890 } 891 // すべてのデータを新テーブルにコピーします。 892 for( int row=0; row<tbl.getRowCount(); row++ ) { 893 String[] vals = new String[clmSize]; 894 System.arraycopy( tbl.getValues( row ),0,vals,0 ,clmSize ); // データのコピー 895 table.addColumnValues( vals ); 896 } 897 return table; 898 } 899 900 /** 901 * 指定のテーブルより、カラム列名に対応するカラム番号配列を作成します。 902 * 903 * カラム名のCSVデータが 指定されない場合(clmcsv == null)は、長さ0の配列を返します。 904 * 905 * @param table テーブルモデル 906 * @param clmcsv カラム名のCSVデータ 907 * 908 * @return カラム名に対応する、列番号配列(なければ、長さ0配列) 909 */ 910 private int[] makeColumnNo( final DBTableModel table,final String clmcsv ) { 911 912 // マスタテーブルの差分属性のカラム番号を求めます。 913 String[] clms = StringUtil.csv2Array( clmcsv ); 914 int[] clmNo = new int[clms.length]; 915 916 // カラム名をカラム番号に変換します。 917 for( int i=0; i<clms.length; i++ ) { 918 clmNo[i] = table.getColumnNo( clms[i] ); 919 } 920 921 return clmNo; 922 } 923 924 /** 925 * 【TAG】コマンド(NEW,RENEW)をセットします(初期値:NEW)。 926 * 927 * @og.tag 928 * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される 929 * フィールド定数値のいづれかを、指定できます。 930 * 初期値は NEW です。 931 * 932 * @param cmd コマンド(public static final 宣言されている文字列) 933 * @see <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.TableMergeTag.CMD_NEW">コマンド定数</a> 934 */ 935 public void setCommand( final String cmd ) { 936 String cmd2 = getRequestParameter( cmd ); 937 if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); } 938 } 939 940 /** 941 * 【TAG】アクションを指定します(UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|ADD_CLM|GROUP|UNION_SELROW)。 942 * 943 * @og.tag 944 * 指定できるアクションは、全体集合(UNION_ALL)、全体集合(挿入位置指定)(UNION_SELROW)、和集合(UNION) 945 * 、積集合(INTERSECT)、差集合(MINUS)、差分集合(DIFFERENCE)、列合成(UNION_CLM)、列追加(ADD_CLM)、 グループ(GROUP)です。 946 * 列合成とグループ以外の処理では、カラム順とカラム数は同数でなければなりません。 947 * primaryKeys や unionClms などの指定のキー名は、マスタテーブルに存在する必要があります。 948 * マスタテーブルと同じカラム番号でスレーブテーブルよりデータを読み出します。 949 * (カラム名や属性は、異なってもかまいませんが、マスタテーブルに準拠します。) 950 * また、単独(マスタテーブルのみ)で、和集合と同等の、グループ(GROUP)を使用すると、指定の 951 * カラムでのユニーク化を行うことが可能になります。グループ処理では、先行優先とし、 952 * 2回目に現れた情報を削除することになります。グループ が指定された場合は、 953 * スレーブテーブルは無視されます。いずれの処理においても、集合処理を行う主キーで 954 * 一旦グループ化されます。全体集合(UNION_ALL)で処理する場合でも、主キーがユニークで 955 * ない場合は、マスター、スレーブの各テーブルで一旦グループ化された後で、マージされます。 956 * (マージ後には、同一主キーを持つ行は存在します。) 957 * 全体集合(UNION_ALL)の場合のみ、mergeKeys を指定する必要はありません。その場合は、 958 * キーなしのため、マスターとスレーブのテーブルを単に合成するだけになります。 959 * 960 * <table border="1" frame="box" rules="all" > 961 * <caption>アクションの説明</caption> 962 * <tr><th>action </th><th>名称 </th><th>処理概要 </th><th>1</th><th>2</th><th>3</th><th>4</th><tr> 963 * <tr><td>UNION_ALL </td><td>全体集合</td><td>マスタとスレーブを合成 964 * <tr><td>UNION_SELROW</td><td>全体集合</td><td>マスタとスレーブを合成(マスタ表のチェック行を起点に追加</td><td>○</td><td> </td><td> </td><td> </td><tr> 965 * <tr><td>UNION </td><td>和集合 </td><td>マスタとスレーブのユニーク部のみ合成 </td><td>○</td><td>○</td><td> </td><td> </td><tr> 966 * <tr><td>INTERSECT </td><td>積集合 </td><td>マスタとスレーブのユニーク部が一致するマスタのみ選択 </td><td>○</td><td>○</td><td> </td><td> </td><tr> 967 * <tr><td>MINUS </td><td>差集合 </td><td>マスタからスレーブに存在するユニーク部を削除した残り </td><td>○</td><td>○</td><td> </td><td> </td><tr> 968 * <tr><td>DIFFERENCE </td><td>差分集合</td><td>ユニーク部が一致し、差分カラムが異なるマスタのみ選択 </td><td>○</td><td>○</td><td> </td><td>○</td><tr> 969 * <tr><td>UNION_CLM </td><td>列合成 </td><td>マスタとキー一致するスレーブのカラム情報を追加 </td><td>○</td><td>○</td><td>○</td><td> </td><tr> 970 * <tr><td>ADD_CLM </td><td>列追加 </td><td>UNION_CLMとの違いは、カラムのみ追加することです。 </td><td> </td><td> </td><td>○</td><td> </td><tr> 971 * <tr><td>GROUP </td><td>グループ</td><td>マスタのユニーク部化 </td><td> </td><td> </td><td> </td><td> </td><tr> 972 * </table> 973 * 974 * ※:マスタテーブルオブジェクトは、常に必須 975 * 1:スレーブテーブルオブジェクト必須 976 * 2:masterKeys 属性必須 977 * 3:unionClms 属性必須(スレーブテーブルのカラム名または追加するカラム名) 978 * 4:diffKeys 属性必須(DIFFERENCE時の差分カラム名)、modifyClms 属性使用可能 979 * 980 * @param action アクション(UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|ADD_CLM|GROUP|UNION_SELROW) 981 */ 982 public void setAction( final String action ) { 983 this.action = nval( getRequestParameter( action ),this.action ); 984 } 985 986 /** 987 * 【TAG】出力先のtableIdを指定します 988 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 989 * 990 * @og.tag 991 * 集合処理結果の DBTableModel をメモリにセットする場合のキー(tableId)を指定します。 992 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 993 * 994 * @param tableId 出力先のtableId 995 * @see org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY 996 */ 997 public void setTableId( final String tableId ) { 998 this.tableId = nval( getRequestParameter( tableId ),this.tableId ); 999 } 1000 1001 /** 1002 * 【TAG】出力先のscopeを指定します(初期値:session)。 1003 * 1004 * @og.tag 1005 * 集合処理結果の DBTableModel をメモリにセットする場合のスコープを指定します。 1006 * ここでは、マスタやスレーブのスコープ設定が必要な為、superクラスのメソッドを 1007 * オーバーライドしてこのオブジェクト内でキープしています。 1008 * 初期値は、session です。 1009 * 1010 * @param scope 出力先のscope 1011 */ 1012 @Override 1013 public void setScope( final String scope ) { 1014 this.scope = nval( getRequestParameter( scope ),this.scope ); 1015 } 1016 1017 /** 1018 * 【TAG】マスタテーブルのtableIdを指定します 1019 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 1020 * 1021 * @og.tag 1022 * 集合処理のマスタとなる DBTableModel をメモリから取り出す場合のキー(tableId)を指定します。 1023 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 1024 * 1025 * @param masterTableId マスタテーブルのtableId 1026 * @see org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY 1027 */ 1028 public void setMasterTableId( final String masterTableId ) { 1029 this.masterTableId = nval( getRequestParameter( masterTableId ),this.masterTableId ); 1030 } 1031 1032 /** 1033 * 【TAG】マスタテーブルのscopeを指定します(初期値:session)。 1034 * 1035 * @og.tag 1036 * 集合処理のマスタとなる DBTableModel をメモリから取り出す場合のスコープを指定します。 1037 * 初期値は、session です。 1038 * 1039 * @param masterScope マスタテーブルのscope 1040 */ 1041 public void setMasterScope( final String masterScope ) { 1042 this.masterScope = nval( getRequestParameter( masterScope ),this.masterScope ); 1043 } 1044 1045 /** 1046 * 【TAG】マスタテーブルの集合処理を行う主キーを指定します。 1047 * 1048 * @og.tag 1049 * 集合処理を行う場合の、カラム名を、カンマ区切り文字(CSV形式)で指定します。 1050 * このキーの組み合わせを元に、集合処理の突合せを行います。 1051 * なお、アクションがグループ(GROUP)以外の処理では、マスタとスレーブのカラム数と 1052 * 並び順は、同じでなければなりません。カラム名は、各々別々でもかまいません。 1053 * アクションが全体集合(UNION_ALL)以外の場合は、必須属性になります。 1054 * 1055 * @param masterKeys マスタテーブルの主キーをCSV形式で指定 1056 */ 1057 public void setMasterKeys( final String masterKeys ) { 1058 this.masterKeys = nval( getRequestParameter( masterKeys ),this.masterKeys ); 1059 } 1060 1061 /** 1062 * 【TAG】スレーブテーブルの集合処理を行う主キーを指定します。 1063 * 1064 * @og.tag 1065 * 集合処理を行う場合の、カラム名を、カンマ区切り文字(CSV形式)で指定します。 1066 * このキーの組み合わせを元に、集合処理の突合せを行います。 1067 * なお、アクションがグループ(GROUP)以外の処理では、マスタとスレーブのカラム数と 1068 * 並び順は、同じでなければなりません。カラム名は、各々別々でもかまいません。 1069 * null の場合は、masterKeys と同じとします。 1070 * 1071 * @param slaveKeys スレーブテーブルの主キーをCSV形式で指定 1072 */ 1073 public void setSlaveKeys( final String slaveKeys ) { 1074 this.slaveKeys = nval( getRequestParameter( slaveKeys ),this.slaveKeys ); 1075 } 1076 1077 /** 1078 * 【TAG】マスタテーブルのDIFFERENCE時の差分カラム名を(CSV形式)指定します。 1079 * 1080 * @og.tag 1081 * アクションが差分処理(DIFFERENCE)の場合に、差分チェックを行うカラム名を、 1082 * カンマ区切り文字(CSV形式)で指定します。 1083 * 差分処理とは、masterKeys で指定されたキーでは、マスタ、スレーブともに存在し 1084 * かつ、このキー(diffKeys)で指定されたキーの値が異なるマスタレコードを 1085 * 抜き出します。 1086 * つまり、主キーは存在し、属性が異なる情報のピックアップになりますので、 1087 * データ更新(UPDATE)対象を見つける場合に使用できます。 1088 * アクションが差分処理(DIFFERENCE)の場合は、必須属性になります。 1089 * 1090 * @param diffKeys マスタテーブルの差分カラム名をCSV形式で指定 1091 * @see #setMasterKeys( String ) 1092 */ 1093 public void setDiffKeys( final String diffKeys ) { 1094 this.diffKeys = nval( getRequestParameter( diffKeys ),this.diffKeys ); 1095 } 1096 1097 /** 1098 * 【TAG】スレーブテーブルのtableIdを指定します 1099 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 1100 * 1101 * @og.tag 1102 * 集合処理のスレーブとなる DBTableModel をメモリから取り出す場合のキー(tableId)を指定します。 1103 * なお、アクションがグループ(GROUP)の場合は、スレーブテーブルは使用されません。 1104 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 1105 * 1106 * @param slaveTableId スレーブテーブルのtableId 1107 * @see org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY 1108 */ 1109 public void setSlaveTableId( final String slaveTableId ) { 1110 this.slaveTableId = nval( getRequestParameter( slaveTableId ),this.slaveTableId ); 1111 } 1112 1113 /** 1114 * 【TAG】スレーブテーブルのscopeを指定します(初期値:session)。 1115 * 1116 * @og.tag 1117 * 集合処理のスレーブとなる DBTableModel をメモリから取り出す場合のスコープを指定します。 1118 * なお、アクションがグループ(GROUP)の場合は、スレーブテーブルは使用されません。 1119 * 初期値は、session です。 1120 * 1121 * @param slaveScope スレーブテーブルのscope 1122 */ 1123 public void setSlaveScope( final String slaveScope ) { 1124 this.slaveScope = nval( getRequestParameter( slaveScope ),this.slaveScope ); 1125 } 1126 1127 /** 1128 * 【TAG】スレーブからマスタへ追加するカラム名をCSV形式で指定します。 1129 * 1130 * @og.tag 1131 * アクションが列合成(UNION_CLM)または列追加(ADD_CLM)の場合に使用されます。 1132 * 列合成(UNION_CLM)は、マスタとスレーブの主キーに対して、ここで指定のスレーブの 1133 * カラム列名を、マスタの列に追加します。主キーがマッチしない行に関しては、 1134 * カラムの初期値が適用されたデータを作成します。 1135 * 列追加(ADD_CLM)は、マスタテーブルに指定のカラムを追加するだけです、スレーブテーブルは 1136 * 参照しません。よって、主キーも指定不要です。 1137 * 1138 * @param unionClms 列合成するカラム名をCSV形式で指定 1139 */ 1140 public void setUnionClms( final String unionClms ) { 1141 this.unionClms = nval( getRequestParameter( unionClms ),this.unionClms ); 1142 } 1143 1144 /** 1145 * 【TAG】スレーブからマスタへ値を更新するカラム名をCSV形式で指定します。 1146 * 1147 * @og.tag 1148 * アクションが差分処理(DIFFERENCE)の場合に、結果にマスタテーブルが抜き出されますが、 1149 * 更新する場合に、スレーブ特有のユニークキー(例:UNIQ)を用いて更新する場合、 1150 * 指定のカラム値は、スレーブの値にセットしておきたい場合があります。 1151 * ここでは、指定のカラムについて、値だけスレーブからマスタへセットします。 1152 * なお、値の更新については、マスタとスレーブが同一キーという制約があります。 1153 * 1154 * @param modifyClms 値を更新するカラム名をCSV形式で指定 1155 */ 1156 public void setModifyClms( final String modifyClms ) { 1157 this.modifyClms = nval( getRequestParameter( modifyClms ),this.modifyClms ); 1158 } 1159 1160 /** 1161 * 【TAG】集合処理するときに、相違データをCSV連結して残すカラム名をCSV形式で指定します。 1162 * 1163 * @og.tag 1164 * masterKeysで集合処理するときに、通常、最初に見つかった行データのみ残りますが、 1165 * ここに指定したカラムについては、発生都度、自分自身の情報に、CSV形式で連結して 1166 * いきます。 1167 * この操作により、本来削除された情報が、1行のCSV形式で取得できる効果が得られます。 1168 * これは、value タグの action="APPEND" を、DBTableModel に対して実施するような感じです。 1169 * 1170 * @og.rev 5.1.4.0 (2010/03/01) 新規追加 1171 * 1172 * @param groupAddClms 相違データをCSV連結して残すカラム名をCSV形式で指定 1173 */ 1174 public void setGroupAddClms( final String groupAddClms ) { 1175 this.groupAddClms = nval( getRequestParameter( groupAddClms ),this.groupAddClms ); 1176 } 1177 1178 /** 1179 * 【TAG】テーブルモデルに対する副作用の有無[true:ない/false:ある]を指定します(初期値:false:ある)。 1180 * 1181 * @og.tag 1182 * すべての処理で、DBTableModel に対して、ユニーク化やグループ化などの集合処理を 1183 * 行う過程で、マスタテーブルに対して直接処理を行うと、副作用が発生します。 1184 * 同様に、スレーブテーブルにおいても、一旦キー列でグループ化されるため、副作用が 1185 * 発生します。これは、無駄なメモリ領域の確保と、テーブル(マスタ、スレーブとも)の 1186 * コピー処理時間の節約になります。初期値の設定も副作用がある状態になっています。 1187 * ところが、都合によっては、色々な action を連続して行いたい場合など、毎回、 1188 * データベースを検索するよりもメモリ上でコピーしたほうが都合がよいケースでは、 1189 * 副作用が出ないように、noSideEffect="true" に設定します。 1190 * ただし、マスタ、スレーブともテーブルをコピーを行い、結果のテーブルも派生する為、 1191 * 通常、2つの領域(マスタと結果は同じテーブルに書かれる)で良い所を、5つの領域が 1192 * 作成されます。 1193 * 初期値は、副作用がある(noSideEffect="false")です。 1194 * 1195 * @param noSideEffect テーブルモデルに対する副作用 [true:ない/false:ある] 1196 */ 1197 public void setNoSideEffect( final String noSideEffect ) { 1198 this.noSideEffect = nval( getRequestParameter( noSideEffect ),this.noSideEffect ); 1199 } 1200 1201 /** 1202 * 【TAG】差分のスレーブデータを結果テーブルに追加するかどうかを指定します(初期値:true)。 1203 * 1204 * @og.tag 1205 * アクションが差分処理(DIFFERENCE)の場合に、結果にマスタテーブルが抜き出されますが、 1206 * 差分対象のスレーブデータと比較したい場合があります。 1207 * このフラグを true にセットすると、書込み禁止属性が付いた状態で、スレーブデータが 1208 * 結果テーブルに追加されます。 1209 * なお、この処理では、通常と異なり、マスタテーブルにはグループ化の副作用は発生しますが、 1210 * 結果テーブルは新規に作成され、先頭行に必ず WRITABLE カラムが付加されます。 1211 * 初期値は、true:追加する です。 1212 * 1213 * @param flag スレーブデータを結果テーブルに追加するかどうか(初期値:true) 1214 */ 1215 public void setUseDiffData( final String flag ) { 1216 useDiffData = nval( getRequestParameter( flag ),useDiffData ); 1217 } 1218 1219 /** 1220 * 【TAG】マスタテーブルの選択行のデータのみを対象に処理を行うかどうかを指定します(初期値:false)。 1221 * 1222 * @og.tag 1223 * 処理対象のマスタテーブルについて、選択行が指定された場合に、選択行のみを処理対象に 1224 * するか、全件を対象にするかを指定します。 1225 * 積集合や差分集合など通常は、全件を対象にすることになりますが、列合成や列追加など、 1226 * マスタテーブルに対してのみ作用を及ぼす処理では、選択行のみを対象に処理を行う事が 1227 * 考えられます。その場合、初期グループ化と同じで、対象とする行が選択行のみになります。 1228 * 初期値は、false:全件対象 です。 1229 * 1230 * @param flag マスタテーブルの選択行のデータのみを対象に処理を行うかどうか(初期値:false) 1231 */ 1232 public void setUseCheckOnly( final String flag ) { 1233 useCheckOnly = nval( getRequestParameter( flag ),useCheckOnly ); 1234 } 1235 1236 /** 1237 * 【TAG】マージの結果を表示するかどうかを指定します(初期値:true)。 1238 * 1239 * @og.tag 1240 * true で、マージ結果を表示します。 false では、何も表示しません(初期値:true) 1241 * マスタテーブルの件数は、通常、キーでグループ化されるため、入力件数と異なります。 1242 * 同様に、スレーブ件数も異なります。結果の件数は、処理結果が現実的かどうかの 1243 * 判断に使用されます。 1244 * 初期値は、true:表示する です。 1245 * 1246 * @param flag 接続の結果を表示するかどうか(初期値:false) 1247 */ 1248 public void setDisplay( final String flag ) { 1249 display = nval( getRequestParameter( flag ),display ); 1250 } 1251 1252 /** 1253 * 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])。 1254 * 1255 * @og.tag 1256 * 初期値は、false(続行する)です。 1257 * 1258 * @og.rev 5.7.6.2 (2014/05/16) 新規追加 1259 * 1260 * @param cmd 検索結果が0件のとき、[true:処理を中止する/false:続行する] 1261 */ 1262 public void setStopZero( final String cmd ) { 1263 stopZero = nval( getRequestParameter( cmd ),stopZero ); 1264 } 1265 1266 /** 1267 * 【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)。 1268 * 1269 * @og.tag 1270 * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが 1271 * ファイルダウンロードの対象の表になります。 1272 * 1273 * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。 1274 * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい 1275 * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から 1276 * 除外することができます。 1277 * 1278 * @og.rev 5.1.6.0 (2010/05/01) 新規作成 1279 * 1280 * @param flag メイントランザクションかどうか 1281 */ 1282 public void setMainTrans( final String flag ) { 1283 isMainTrans = nval( getRequestParameter( flag ),isMainTrans ); 1284 } 1285 1286 /** 1287 * 【TAG】groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",")。 1288 * 1289 * @og.tag 1290 * groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",")。 1291 * 初期値は、"," に設定されています。 1292 * 1293 * @og.rev 5.3.1.0 (2011/01/01) 1294 * 1295 * @param sepa 項目区切り文字(初期値:",") 1296 */ 1297 public void setSeparator( final String sepa ) { 1298 separator = nval( getRequestParameter( sepa ),separator ); 1299 } 1300 1301 /** 1302 * このオブジェクトの文字列表現を返します。 1303 * 基本的にデバッグ目的に使用します。 1304 * 1305 * @return このクラスの文字列表現 1306 */ 1307 @Override 1308 public String toString() { 1309 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 1310 .println( "VERSION" ,VERSION ) 1311 .println( "action" ,action ) 1312 .println( "tableId" ,tableId ) 1313 .println( "scope" ,scope ) 1314 .println( "masterTableId" ,masterTableId ) 1315 .println( "masterScope" ,masterScope ) 1316 .println( "slaveTableId" ,slaveTableId ) 1317 .println( "slaveScope" ,slaveScope ) 1318 .println( "masterKeys" ,masterKeys ) 1319 .println( "diffKeys" ,diffKeys ) 1320 .println( "unionClms" ,unionClms ) 1321 .println( "modifyClms" ,modifyClms ) 1322 .println( "noSideEffect" ,noSideEffect ) 1323 .println( "useDiffData" ,useDiffData ) 1324 .println( "useCheckOnly" ,useCheckOnly ) 1325 .println( "display" ,display ) 1326 .println( "ACTION_LIST" ,ACTION_LIST ) 1327 .println( "Other..." ,getAttributes().getAttribute() ) 1328 .fixForm().toString() ; 1329 } 1330}