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.table; 017 018import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 019import org.opengion.fukurou.db.DBUtil; 020import org.opengion.fukurou.db.Transaction; // 5.5.2.6 (2012/05/25) 021import org.opengion.fukurou.model.Formatter; 022import org.opengion.fukurou.util.ErrorMessage; 023import org.opengion.fukurou.util.StringUtil; 024import org.opengion.hayabusa.db.AbstractTableFilter; 025import org.opengion.hayabusa.db.DBTableModel; 026 027/** 028 * TableFilter_DBSELECT は、TableFilter インターフェースを継承した、DBTableModel 処理用の 029 * 実装クラスです。 030 * 031 * ここでは、Body部にかかれたSQLを実行した結果を、テーブルモデルにセットします。 032 * SQL文から取得されるカラム名とテーブルモデルのカラム名は一致している必要があります。 033 * 検索結果のカラムがテーブルモデルに存在していない場合はエラーとなります。 034 * 以下の属性を指定しないと、データが存在しない場合はNULLがセットされます。 035 * また、2行以上検索された場合でも、1行目のデータのみをセットします。 036 * 037 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。 038 * ただし、このフィルターは、BODY部に、SQL文も記述する為、注意が必要です。 039 * ルール的には、一番最初に見つけた "{" と、"}" の間の文字列がパラメータと認識します。 040 * よって、SQL文を記述する場合は、このパラメータの後ろに記述するか、keys,vals を利用ください。 041 * 【パラメータ】 042 * { 043 * INNER_JOIN : データが存在しない場合、テーブルの該当行を削除します。(初期値:false) 044 * APPEND : 2行以上検索された場合、データをアペンドします。 (初期値:false) 045 * SEPARATOR : APPENDする場合の区切り文字を指定します。 (初期値:" "スペース) 046 * } 047 * 048 * Body部にかかれたSQLには[XXXX]形式の変数が指定できます。 049 * 050 * @og.formSample 051 * ●形式: 052 * ① <og:tableFilter classId="DBSELECT" > 053 * 054 * </og:tableFilter> 055 * 056 * ② <og:tableFilter classId="DBSELECT" > 057 * { 058 * INNER_JOIN : true ; 059 * } 060 * select AAA,BBB,CCC from XXX 061 * </og:tableFilter> 062 * 063 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加 064 * 065 * @version 0.9.0 2000/10/17 066 * @author Hiroki Nakamura 067 * @since JDK1.1, 068 */ 069public class TableFilter_DBSELECT extends AbstractTableFilter { 070 /** このプログラムのVERSION文字列を設定します。 {@value} */ 071 private static final String VERSION = "6.5.0.1 (2016/10/21)" ; 072 073 private DBTableModel table ; // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加 074 075 /** 076 * デフォルトコンストラクター 077 * 078 * @og.rev 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更。 079 */ 080 public TableFilter_DBSELECT() { 081 super(); 082 initSet( "INNER_JOIN" , "データが存在しない場合、テーブルの該当行を削除します(初期値:false)" ); 083 initSet( "APPEND" , "2行以上検索された場合、データをアペンドします (初期値:false)" ); 084 initSet( "SEPARATOR" , "APPENDする場合の区切り文字を指定します (初期値:\" \"スペース)" ); 085 } 086 087 /** 088 * DBTableModel処理を実行します。 089 * 090 * @og.rev 4.3.7.0 (2009/06/01) 実装大幅変更 091 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応 092 * @og.rev 5.5.2.6 (2012/05/25) protected変数を、private化したため、getterメソッドで取得するように変更 093 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 094 * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。 095 * @og.rev 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。 096 * 097 * @return 処理結果のDBTableModel 098 */ 099 public DBTableModel execute() { 100 table = getDBTableModel(); // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加 101 102 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 103 if( table == null ) { 104 final String errMsg = "DBTableModel が設定されていません。" ; 105 throw new OgRuntimeException( errMsg ); 106 } 107 108 final boolean innerJoin = StringUtil.nval( getValue("INNER_JOIN"), false ); 109 final boolean isAppend = StringUtil.nval( getValue("APPEND"), false ); 110 final String separator = StringUtil.nval( getValue("SEPARATOR"), " " ); 111 112 final Formatter format = new Formatter( table,getSql() ); // 6.4.3.4 (2016/03/11) 113 final int[] sqlClmNo = format.getClmNos(); 114 final String query = format.getQueryFormatString(); 115 116 String[] data = null; 117 String[] param = null; 118 int[] clmNo = null; 119 final Transaction tran = getTransaction(); // 5.5.2.6 (2012/05/25) 120 final String dbid = getDbid(); // 5.5.2.6 (2012/05/25) 121 final int[] rowNo = getParameterRows(); // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加 122 final int rowCount = rowNo.length; 123 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 124 for( int row=rowCount-1; row>=0; row-- ) { 125 try { 126 param = getTableModelData( rowNo[row], sqlClmNo ); 127 128 final String[][] dbData; 129 if( row == rowCount - 1 ) { 130 final String[][] rtn = DBUtil.dbExecute( query, param, tran, dbid, true ); // 5.1.9.0 (2010/08/01) Transaction 対応 131 clmNo = getTableColumnNo( rtn[0] ); 132 dbData = new String[rtn.length - 1][rtn[0].length]; 133 System.arraycopy( rtn, 1, dbData, 0, dbData.length ); 134 } 135 else { 136 dbData = DBUtil.dbExecute( query, param, tran, dbid, false ); // 5.1.9.0 (2010/08/01) Transaction 対応 137 } 138 139 data = table.getValues( rowNo[row] ); 140 if( dbData != null && dbData.length > 0 && dbData[0] != null && dbData[0].length > 0 ) { 141 for( int i=0; i<clmNo.length; i++ ) { 142 if( isAppend ) { 143 buf.setLength(0); 144 for( int j=0; j<dbData.length; j++ ) { 145 if( j > 0 ) { 146 buf.append( separator ); 147 } 148 buf.append( dbData[j][i] ); 149 } 150 data[clmNo[i]] = buf.toString(); 151 } 152 else { 153 data[clmNo[i]] = dbData[0][i]; // 副作用を及ぼしています。注意 154 } 155 } 156 } 157 else if( innerJoin ) { 158 table.removeValue(rowNo[row]); 159 } 160 } 161 catch( final RuntimeException ex ) { 162 // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。 163 makeErrorMessage( "TableFilter_DBSELECT Error", ErrorMessage.NG ) 164 .addMessage( rowNo[row] + 1, ErrorMessage.NG,"DBSELECT" 165 , "SQL=[" + getSql() + "]" 166 , StringUtil.array2csv( data ) 167 , StringUtil.array2csv( param ) 168 ) 169 .addMessage( ex ); 170 } 171 } 172 173 return table; 174 } 175 176 /** 177 * 指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。 178 * 179 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を 180 * 処理の対象とします。 181 * 182 * @param row 行番号 183 * @param clmNo カラムNo配列(可変長引数) 184 * 185 * @return 行番号とカラムNo配列に対応した、値の配列 186 */ 187 private String[] getTableModelData( final int row, final int... clmNo ) { 188 String[] values = new String[clmNo.length]; 189 for( int i=0; i<values.length; i++ ) { 190 values[i] = table.getValue( row, clmNo[i] ); 191 } 192 return values; 193 } 194}