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 */
016 package org.opengion.fukurou.process;
017
018 import org.opengion.fukurou.util.Argument;
019 import org.opengion.fukurou.util.SystemParameter;
020 import org.opengion.fukurou.util.StringUtil;
021 import org.opengion.fukurou.util.LogWriter;
022 import org.opengion.fukurou.util.HybsEntry ;
023 import org.opengion.fukurou.util.Closer;
024 import org.opengion.fukurou.model.Formatter;
025 import org.opengion.fukurou.db.ConnectionFactory;
026
027 import java.util.Map ;
028 import java.util.LinkedHashMap ;
029 import java.util.Set ;
030 import java.util.HashSet ;
031
032 import java.sql.Connection;
033 import java.sql.PreparedStatement;
034 import java.sql.ParameterMetaData;
035 import java.sql.SQLException;
036
037 /**
038 * Process_DBWriter は、上流から受け取ったデータをデータベã?スに書き込ã‚?
039 * CainProcess インターフェースの実è£?‚¯ラスですã?
040 *
041 * 上æµ?プロセスチェインのãƒ??タは上流から下流へと渡されますã?)から受け取っã�?
042 * LineModel をå?に、データベã?スへの書き込みを行いますã?
043 *
044 * ãƒ??タベã?ス接続å?等ã?、ParamProcess のサブクラス(Process_DBParam)に
045 * 設定された接ç¶?Connection)を使用しますã?
046 *
047 * 引数æ–?—å?中にスペã?スを含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
048 * 引数æ–?—å?の ã€?』ã?前後には、スペã?スは挟めません。å¿?�šã€?key=value の様に
049 * 繋げてくださいã€?
050 *
051 * SQLæ–?�«は、{@DATE.YMDH}等ã?シスãƒ?ƒ 変数が使用できますã?
052 *
053 * @og.formSample
054 * Process_DBWriter -dbid=DBGE -table=GE41
055 *
056 * [ -dbid=DB接続ID ] ??-dbid=DBGE (ä¾? Process_DBParam の -configFile でæŒ?®šすã‚?DBConfig.xml ファイルで規å®?
057 * [ -table=登録ãƒ??ブルID ] ???³?±?¬æ–?‚’æŒ?®šするå?合ã?不要ã?INSERT する場合ã?ãƒ??ブルID
058 * [ -sql=検索SQLæ–? ] ??-sql="UPDATE GE41 SET NAME_JA = [NAME_JA],LABEL_NAME = [LABEL_NAME]
059 * WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]"
060 * [ -sqlFile=登録SQLファイル ] ??-sqlFile=update.sql
061 * ?? -sql ã‚?-sqlFile が指定されなã�??合ã?ã€?table でæŒ?®šã?ãƒ??ブルに全カラãƒ?insert ですã?
062 * [ -sql_XXXX=固定å? ] ??-sql_SYSTEM_ID=GE
063 * SQLæ–?¸の{@XXXX}æ–?—å?を指定ã?固定å?で置き換えますã?
064 * WHERE SYSTEM_ID='{@SYSTEM_ID}' �WHERE SYSTEM_ID='GE'
065 * [ -const_XXXX=固定å? ] ??-const_FGJ=1
066 * LineModel のキー(const_ に続くæ–?—å?)の値に、固定å?を設定しますã?
067 * キーが異なれã?、è¤?•°のカラãƒ?��を指定できますã?
068 * [ -omitClms=AAA,BBB,… ] ??-omitClms=UNIQ,FGJ,DYSET
069 * -table 属æ?でINSERTæ–?‚’自動作æ?する場合ã?取り除くカラãƒ?��ã‚?
070 * カンマ区åˆ?‚Šでè¤?•°æŒ?®šできますã?
071 * [ -commitCnt=commit処ç�?Œ‡定] ??æŒ?®š数毎にコミットを発行しますã?0 の場合ã?、終äº?�¾でコミットしませんã€?
072 * [ -display=false|true ] ??結果を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
073 *
074 * @version 4.0
075 * @author Kazuhiko Hasegawa
076 * @since JDK5.0,
077 */
078 public class Process_DBWriter extends AbstractProcess implements ChainProcess {
079 private static final String CNST_KEY = "const_" ;
080 private static final String SQL_KEY = "sql_" ;
081
082 private Connection connection = null;
083 private PreparedStatement pstmt = null;
084 private ParameterMetaData pMeta = null; // 5.1.1.0 (2009/11/11) setObject に、Type を渡すã?(PostgreSQL対å¿?
085 private boolean useParamMetaData = false; // 5.1.1.0 (2009/11/11) setObject に、Type を渡すã?(PostgreSQL対å¿?
086
087 private String dbid = null;
088 private String sql = null;
089 private String table = null;
090 private int[] clmNos = null; // ファイルのヘッãƒ??のカラãƒ?•ª号
091 private int commitCnt = 0; // コミットするまとめ件数
092 private boolean display = false; // 表示しなã�?
093
094 private String[] cnstClm = null; // 固定å?を設定するカラãƒ?��
095 private int[] cnstClmNos = null; // 固定å?を設定するカラãƒ?•ª号
096 private String[] constVal = null; // カラãƒ?•ª号に対応した固定å?
097
098 private boolean firstRow = true; // æœ??のä¸?¡Œ目
099 private int count = 0;
100 private String[] omitClms = null; // 4.0.0.0 (2007/09/21) table æŒ?®š時に取り除くカラãƒ?
101
102 private static final Map<String,String> mustProparty ; // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
103 private static final Map<String,String> usableProparty ; // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
104
105 static {
106 mustProparty = new LinkedHashMap<String,String>();
107
108 usableProparty = new LinkedHashMap<String,String>();
109 usableProparty.put( "dbid", "Process_DBParam の -configFile でæŒ?®šすã‚?DBConfig.xml ファイルで規å®? );
110 usableProparty.put( "table", "INSERT する場合ã?ãƒ??ブルID SQLæ–?‚’æŒ?®šするå?合ã?不要ã?" );
111 usableProparty.put( "sql", "更新SQLæ–?sql or sqlFile å¿??)" +
112 CR + "ä¾? \"UPDATE GE41 " +
113 CR + "SET NAME_JA = [NAME_JA],LABEL_NAME = [LABEL_NAME] " +
114 CR + "WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]\"" );
115 usableProparty.put( "sqlFile", "登録SQLファイル(sql or sqlFile å¿??)ä¾? update.sql" );
116 usableProparty.put( "sql_", "SQLæ–?¸の{@XXXX}æ–?—å?を指定ã?固定å?で置き換えますã?" +
117 CR + "WHERE SYSTEM_ID='{@SYSTEM_ID}' �WHERE SYSTEM_ID='GE'" );
118 usableProparty.put( "const_", "LineModel のキー(const_ に続くæ–?—å?)の値に、固定å?ã‚? +
119 CR + "設定しますã?キーが異なれã?、è¤?•°のカラãƒ?��を指定できますã?" +
120 CR + "ä¾? -sql_SYSTEM_ID=GE" );
121 // 4.0.0.0 (2007/09/21) 属æ?を追åŠ?
122 usableProparty.put( "omitClms", "-table 属æ?でINSERTæ–?‚’自動作æ?する場合ã?取り除くカラãƒ?��ã‚? +
123 CR + "カンマ区åˆ?‚Šでè¤?•°æŒ?®šできますã?" +
124 CR + "ä¾? -omitClms=UNIQ,FGJ,DYSET" );
125 usableProparty.put( "commitCnt", "æŒ?®š数毎にコミットを発行しますã?" +
126 CR + "0 の場合ã?、終äº?�¾でコミットしません(初期値:0)" );
127 usableProparty.put( "display", "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
128 CR + "(初期値:false:表示しなã�?" );
129 }
130
131 /**
132 * ãƒ?ƒ•ォルトコンストラクターã€?
133 * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
134 * super クラスに対して、å¿?¦�な初期化を行っておきますã?
135 *
136 */
137 public Process_DBWriter() {
138 super( "org.opengion.fukurou.process.Process_DBWriter",mustProparty,usableProparty );
139 }
140
141 /**
142 * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
143 * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç?に使用しますã?
144 *
145 * @og.rev 4.0.0.0 (2007/09/21) omitClms 属æ?を追åŠ?
146 * @og.rev 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡すã?(PostgreSQL対å¿?
147 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ã‚?ConnectionFactory経由で取得ã?(PostgreSQL対å¿?
148 *
149 * @param paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
150 */
151 public void init( final ParamProcess paramProcess ) {
152 Argument arg = getArgument();
153
154 table = arg.getProparty("table");
155 sql = arg.getFileProparty("sql","sqlFile",false);
156 commitCnt = arg.getProparty("commitCnt",commitCnt);
157 display = arg.getProparty("display",display);
158
159 dbid = arg.getProparty("dbid");
160 connection = paramProcess.getConnection( dbid );
161 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡すã?(PostgreSQL対å¿?
162 // useParamMetaData = ApplicationInfo.useParameterMetaData( connection );
163 useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01)
164
165 // 取り除くカラãƒ?��リストを配å?に変換しますã?
166 String tempClms = arg.getProparty("omitClms",null);
167 if( tempClms != null ) {
168 omitClms = StringUtil.csv2Array( tempClms );
169 }
170
171 if( sql == null && table == null ) {
172 String errMsg = "sql を指定しなã�??合ã?、table をå¿?�šæŒ?®šしてくださいã€?;
173 throw new RuntimeException( errMsg );
174 }
175
176 // 3.8.0.1 (2005/06/17) {@DATE.XXXX} 変換処ç�??追åŠ?
177 // {@DATE.YMDH} などのæ–?—å?をã?yyyyMMddHHmmss 型ã?日付に置き換えますã?
178 // SQLæ–?? {@XXXX} æ–?—å?の固定å?への置き換ã�?
179 HybsEntry[] entry =arg.getEntrys(SQL_KEY); // 配å?
180 SystemParameter sysParam = new SystemParameter( sql );
181 sql = sysParam.replace( entry );
182
183 HybsEntry[] cnstKey = arg.getEntrys( CNST_KEY ); // 配å?
184 int csize = cnstKey.length;
185 cnstClm = new String[csize];
186 constVal = new String[csize];
187 for( int i=0; i<csize; i++ ) {
188 cnstClm[i] = cnstKey[i].getKey();
189 constVal[i] = cnstKey[i].getValue();
190 }
191 }
192
193 /**
194 * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
195 * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç?に使用しますã?
196 *
197 * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処ç�?‚’追åŠ?
198 * @og.rev 5.1.1.0 (2009/11/11) pMeta のクリア
199 *
200 * @param isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
201 */
202 public void end( final boolean isOK ) {
203 boolean flag = Closer.stmtClose( pstmt );
204 pstmt = null;
205 pMeta = null; // 5.1.1.0 (2009/11/11)
206
207 if( isOK ) {
208 Closer.commit( connection );
209 }
210 else {
211 Closer.rollback( connection );
212 }
213 ConnectionFactory.remove( connection,dbid );
214
215 if( !flag ) {
216 String errMsg = "スãƒ??トメントをクローズ出来ませんã€?;
217 throw new RuntimeException( errMsg );
218 }
219 }
220
221 /**
222 * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
223 * 変換処ç�?¾Œã? LineModel を返しますã?
224 * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
225 * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
226 * フラグの代わりにも使用してã�?�¾すã?
227 * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
228 * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
229 * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
230 * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
231 *
232 * @og.rev 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡すã?(PostgreSQL対å¿?
233 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData setNull 対å¿?PostgreSQL対å¿?
234 *
235 * @param data オリジナルのLineModel
236 *
237 * @return 処ç�?¤‰換後ã?LineModel
238 */
239 public LineModel action( final LineModel data ) {
240 count++ ;
241 // if( display ) { println( data.dataLine() ); }
242 try {
243 if( firstRow ) {
244 pstmt = makePrepareStatement( table,data );
245 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡すã?(PostgreSQL対å¿?
246 if( useParamMetaData ) {
247 pMeta = pstmt.getParameterMetaData();
248 }
249
250 int size = cnstClm.length;
251 cnstClmNos = new int[size];
252 for( int i=0; i<size; i++ ) {
253 cnstClmNos[i] = data.getColumnNo( cnstClm[i] );
254 }
255
256 firstRow = false;
257 }
258
259 // 固定å?置き換えå?ç�?
260 for( int j=0; j<cnstClmNos.length; j++ ) {
261 data.setValue( cnstClmNos[j],constVal[j] );
262 }
263
264 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡すã?(PostgreSQL対å¿?
265 if( useParamMetaData ) {
266 for( int i=0; i<clmNos.length; i++ ) {
267 int type = pMeta.getParameterType( i+1 );
268 // 5.3.8.0 (2011/08/01) setNull 対å¿?
269 // pstmt.setObject( i+1,data.getValue(clmNos[i]),type );
270 Object val = data.getValue(clmNos[i]);
271 if( val == null || ( val instanceof String && ((String)val).isEmpty() ) ) {
272 pstmt.setNull( i+1, type );
273 }
274 else {
275 pstmt.setObject( i+1, val, type );
276 }
277 }
278 }
279 else {
280 for( int i=0; i<clmNos.length; i++ ) {
281 pstmt.setObject( i+1,data.getValue(clmNos[i]) );
282 }
283 }
284
285 pstmt.execute();
286 if( commitCnt > 0 && ( count%commitCnt == 0 ) ) {
287 Closer.commit( connection );
288 }
289 }
290 catch (SQLException ex) {
291 String errMsg = "sql=[" + sql + "]" + CR +
292 "errorCode=[" + ex.getErrorCode() + "] State=[" +
293 ex.getSQLState() + "]" + CR ;
294 throw new RuntimeException( errMsg,ex );
295 }
296 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
297 return data;
298 }
299
300 /**
301 * å†?ƒ¨で使用する PreparedStatement を作æ?しますã?
302 * 引数æŒ?®šã? SQL またã?、LineModel から作æ?した SQL より構築しますã?
303 *
304 * @og.rev 4.0.0.0 (2007/09/21) omitClms 属æ?を追åŠ?
305 *
306 * @param table 処ç�?¯¾象のãƒ??ブルID
307 * @param data 処ç�?¯¾象のLineModel
308 *
309 * @return PreparedStatementオブジェクãƒ?
310 */
311 private PreparedStatement makePrepareStatement( final String table,final LineModel data ) {
312 if( sql == null ) {
313 StringBuilder buf = new StringBuilder();
314 String[] names = data.getNames();
315
316 // カラãƒ?‚’取り除くå?å�?
317 if( omitClms != null ) {
318 Set<String> set = new HashSet<String>();
319 for( int i=0; i<names.length; i++ ) {
320 set.add( names[i] );
321 }
322 for( int i=0; i<omitClms.length; i++ ) {
323 set.remove( omitClms[i] );
324 }
325 names = set.toArray( new String[set.size()] );
326 }
327 int size = names.length;
328
329 buf.append( "INSERT INTO " ).append( table ).append( " (" );
330 buf.append( names[0] );
331 for( int i=1; i<size; i++ ) {
332 buf.append( "," ).append( names[i] );
333 }
334 buf.append( " ) VALUES ( ?" );
335 for( int i=1; i<size; i++ ) {
336 buf.append( ",?" );
337 }
338 buf.append( " )" );
339 sql = buf.toString();
340
341 // カラãƒ?•ª号を設定しますã?
342 clmNos = new int[size];
343 for( int i=0; i<size; i++ ) {
344 clmNos[i] = data.getColumnNo( names[i] ); // 4.0.0.0 (2007/09/21)
345 }
346 }
347 else {
348 Formatter format = new Formatter( data );
349 format.setFormat( sql );
350 sql = format.getQueryFormatString();
351 clmNos = format.getClmNos();
352 }
353
354 final PreparedStatement ps ;
355 try {
356 ps = connection.prepareStatement( sql );
357 }
358 catch (SQLException ex) {
359 String errMsg = "PreparedStatement を取得できませんでしたã€? + CR
360 + "sql=[" + sql + "]" + CR
361 + "table=[" + table + "]" + CR
362 + "nameLine=[" + data.nameLine() + "]" ;
363 throw new RuntimeException( errMsg,ex );
364 }
365
366 return ps;
367 }
368
369 /**
370 * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
371 * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
372 * こã?æ–?—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
373 * 形式で出してくださいã€?
374 *
375 * @return 処ç�?µ�果のレポã?ãƒ?
376 */
377 public String report() {
378 String report = "[" + getClass().getName() + "]" + CR
379 + TAB + "DBID : " + dbid + CR
380 + TAB + "Output Count : " + count ;
381
382 return report ;
383 }
384
385 /**
386 * こã?クラスの使用方法を返しますã?
387 *
388 * @return こã?クラスの使用方æ³?
389 */
390 public String usage() {
391 StringBuilder buf = new StringBuilder();
392
393 buf.append( "Process_DBWriter は、上流から受け取ったデータをデータベã?スに書き込ã‚? ).append( CR );
394 buf.append( "CainProcess インターフェースの実è£?‚¯ラスですã?" ).append( CR );
395 buf.append( CR );
396 buf.append( "上æµ?プロセスチェインのãƒ??タは上流から下流へと渡されますã?)から" ).append( CR );
397 buf.append( "受け取っã�?LineModel をå?に、データベã?スへの書き込みを行いますã?" ).append( CR );
398 buf.append( CR );
399 buf.append( "ãƒ??タベã?ス接続å?等ã?、ParamProcess のサブクラス(Process_DBParam)に" ).append( CR );
400 buf.append( "設定された接ç¶?Connection)を使用しますã?" ).append( CR );
401 buf.append( CR );
402 buf.append( "引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
403 buf.append( "引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に" ).append( CR );
404 buf.append( "繋げてくださいã€? ).append( CR );
405 buf.append( CR );
406 buf.append( "SQLæ–?�«は、{@DATE.YMDH}等ã?シスãƒ?ƒ 変数が使用できますã?" ).append( CR );
407 buf.append( CR ).append( CR );
408 buf.append( getArgument().usage() ).append( CR );
409
410 return buf.toString();
411 }
412
413 /**
414 * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
415 *
416 * @param args コマンド引数配å?
417 */
418 public static void main( final String[] args ) {
419 LogWriter.log( new Process_DBWriter().usage() );
420 }
421 }