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.fukurou.process;
017
018import java.sql.Connection;
019import java.sql.ResultSet;
020import java.sql.PreparedStatement;
021import java.sql.SQLException;
022import java.io.File ;
023import java.io.PrintWriter ;
024import java.util.Map ;
025import java.util.LinkedHashMap ;
026import java.util.Calendar ;
027
028import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
029import org.opengion.fukurou.system.LogWriter;
030import org.opengion.fukurou.system.Closer;
031import org.opengion.fukurou.model.Formatter;
032import org.opengion.fukurou.util.Argument;
033import org.opengion.fukurou.util.SystemParameter;
034import org.opengion.fukurou.util.FileUtil;
035import org.opengion.fukurou.util.HybsDateUtil;
036import org.opengion.fukurou.util.HybsEntry ;
037import org.opengion.fukurou.db.DBUtil ;
038import org.opengion.fukurou.db.ConnectionFactory;
039
040/**
041 * Process_DBFileout は、SELECT文 を指定し データベースの値を抜き出して、
042 * 個々のファイルにセーブする、ChainProcess インターフェースの実装クラスです。
043 * 上流(プロセスチェインのデータは上流から下流へと渡されます。)から
044 * 受け取った LineModel を元に、1行単位に、SELECT文を実行します。
045 *
046 * 上流のカラムを、[カラム]変数で使用できます。
047 * また、セーブするファイル名、更新日付等も、都度、更新可能です。
048 *
049 * データベース接続先等は、ParamProcess のサブクラス(Process_DBParam)に
050 * 設定された接続(Connection)を使用します。
051 *
052 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。
053 * 引数文字列の 『=』 の前後には、スペースは挟めません。必ず、-key=value の様に
054 * 繋げてください。
055 *
056 * SQL文には、{@DATE.YMDH}等のシステム変数が使用できます。
057 *
058 * @og.formSample
059 *  Process_DBFileout -dbid=DBGE -insertTable=GE41
060 *
061 *   [ -dbid=DB接続ID           ] : -dbid=DBGE (例: Process_DBParam の -configFile で指定する DBConfig.xml ファイルで規定)
062 *   [ -select=検索SQL文        ] : -select="SELECT * FROM GE41 WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]"
063 *   [ -selectFile=登録SQLファイル  ] : -selectFile=select.sql
064 *                                :   -select や -selectFile が指定されない場合は、エラーです。
065 *   [ -select_XXXX=固定値      ] : -select_SYSTEM_ID=GE
066 *                                     SQL文中の{@XXXX}文字列を指定の固定値で置き換えます。
067 *                                     WHERE SYSTEM_ID='{@SYSTEM_ID}' ⇒ WHERE SYSTEM_ID='GE'
068 *   [ -const_XXXX=固定値       ] : -const_FGJ=1
069 *                                     LineModel のキー(const_ に続く文字列)の値に、固定値を設定します。
070 *                                     キーが異なれば、複数のカラム名を指定できます。
071 *   [ -addHeader=ヘッダー      ] : -addHeader="CREATE OR REPLACE "
072 *   [ -addFooter=フッター      ] : -addFooter="/\nSHOW ERROR;"
073 *   [ -outFile=出力ファイル名  ] : -outFile=[NAME].sql
074 *   [ -append=[false/true]     ] : 出力ファイルを、追記する(true)か新規作成する(false)か。
075 *   [ -sep=セパレータ文字      ] : 各カラムを区切る文字列(初期値:TAB)
076 *   [ -useLineCR=[false/true]  ] : 各行の最後に、改行文字をつかるかどうか(初期値:true[付ける])
077 *   [ -timestamp=更新日付      ] : -timestamp="LAST_DDL_TIME"
078 *   [ -fetchSize=1000          ] :フェッチする行数(初期値:1000)  6.9.4.1 (2018/04/09)
079 *   [ -display=[false/true]    ] : 結果を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない])
080 *   [ -debug=[false/true]      ] : デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない])
081 *
082 * @og.rev 6.4.8.3 (2016/07/15) 新規作成。
083 *
084 * @version  4.0
085 * @author   Kazuhiko Hasegawa
086 * @since    JDK5.0,
087 */
088public class Process_DBFileout extends AbstractProcess implements ChainProcess {
089        private static final String SELECT_KEY  = "select_" ;
090        private static final String CNST_KEY    = "const_" ;
091
092        private static final String ENCODE = "UTF-8" ;
093
094//      /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  {@value} */
095//      private static final int DB_FETCH_SIZE = 1001 ;
096
097        private Connection      connection              ;
098        private PreparedStatement selPstmt      ;
099
100        private String          dbid            ;
101        private String          select          ;
102        private int[]           selClmNos       ;                       // select 時のファイルのヘッダーのカラム番号
103        private String          outFilename     ;                       // 出力ファイル名
104        private boolean         append          ;                       // ファイル追加(true:追加/false:通常)
105        private String          timestamp       ;                       // 出力ファイルの更新日時
106        private int                     tmstmpClm       = -1;           // 出力ファイルの更新日時のカラム番号
107        private String          separator       = "\t";         // 各カラムを区切る文字列(初期値:TAB)
108        private String          addHeader       ;                       // ヘッダー
109        private String          addFooter       ;                       // フッター
110        private boolean         useLineCR       = true;         // 各行の最後に、改行文字をつかるかどうか(初期値:true[付ける])
111        private int                     fetchSize       = 1000;         // 6.9.4.1 (2018/04/09) 初期値を 1000 に設定
112        private boolean         display         ;                       // false:表示しない
113        private boolean         debug           ;                       // 5.7.3.0 (2014/02/07) デバッグ情報
114
115        private String[]        cnstClm         ;                       // 固定値を設定するカラム名
116        private int[]           cnstClmNos      ;                       // 固定値を設定するカラム番号
117        private String[]        constVal        ;                       // カラム番号に対応した固定値
118
119        private boolean         firstRow        = true;         // 最初の一行目
120        private int                     count           ;
121
122        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
123        private static final Map<String,String> MUST_PROPARTY   ;               // [プロパティ]必須チェック用 Map
124        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
125        private static final Map<String,String> USABLE_PROPARTY ;               // [プロパティ]整合性チェック Map
126
127        static {
128                MUST_PROPARTY = new LinkedHashMap<>();
129
130                USABLE_PROPARTY = new LinkedHashMap<>();
131                USABLE_PROPARTY.put( "dbid",    "Process_DBParam の -configFile で指定する DBConfig.xml ファイルで規定" );
132                USABLE_PROPARTY.put( "select",  "検索SQL文(select or selectFile 必須)" +
133                                                                        CR + "例: \"SELECT * FROM GE41 WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]\"" );
134                USABLE_PROPARTY.put( "selectFile",      "検索SQLファイル(select or selectFile 必須)例: select.sql" );
135                USABLE_PROPARTY.put( "select_",         "SQL文中の{&#064;XXXX}文字列を指定の固定値で置き換えます。" +
136                                                                        CR + "WHERE SYSTEM_ID='{&#064;SYSTEM_ID}' ⇒ WHERE SYSTEM_ID='GE'" );
137                USABLE_PROPARTY.put( "const_",  "LineModel のキー(const_ に続く文字列)の値に、固定値を" +
138                                                                        CR + "設定します。キーが異なれば、複数のカラム名を指定できます。" +
139                                                                        CR + "例: -sql_SYSTEM_ID=GE" );
140                USABLE_PROPARTY.put( "addHeader" ,      "ヘッダー" );
141                USABLE_PROPARTY.put( "addFooter" ,      "フッター" );
142                USABLE_PROPARTY.put( "outFile"  ,       "出力ファイル名 例: [NAME].sql" );
143                USABLE_PROPARTY.put( "append"   ,       "出力ファイルを、追記する(true)か新規作成する(false)か。" );
144                USABLE_PROPARTY.put( "sep"              ,       "各カラムを区切る文字列(初期値:TAB)" );
145                USABLE_PROPARTY.put( "useLineCR",       "各行の最後に、改行文字をつかるかどうか(初期値:true[付ける])" );
146                USABLE_PROPARTY.put( "timestamp",       "出力ファイルの更新日付例: [LAST_DDL_TIME]" );
147                USABLE_PROPARTY.put( "fetchSize","フェッチする行数 (初期値:1000)" );                                       // 6.9.4.1 (2018/04/09) 初期値を 1000 に設定
148                USABLE_PROPARTY.put( "display", "結果を標準出力に表示する(true)かしない(false)か" +
149                                                                                CR + "(初期値:false:表示しない)" );
150                USABLE_PROPARTY.put( "debug",   "デバッグ情報を標準出力に表示する(true)かしない(false)か" +
151                                                                                CR + "(初期値:false:表示しない)" );             // 5.7.3.0 (2014/02/07) デバッグ情報
152        }
153
154        /**
155         * デフォルトコンストラクター。
156         * このクラスは、動的作成されます。デフォルトコンストラクターで、
157         * super クラスに対して、必要な初期化を行っておきます。
158         *
159         */
160        public Process_DBFileout() {
161                super( "org.opengion.fukurou.process.Process_DBFileout",MUST_PROPARTY,USABLE_PROPARTY );
162        }
163
164        /**
165         * プロセスの初期化を行います。初めに一度だけ、呼び出されます。
166         * 初期処理(ファイルオープン、DBオープン等)に使用します。
167         *
168         * @og.rev 6.4.8.3 (2016/07/15) 新規作成。
169         * @og.rev 6.9.4.1 (2018/04/09) fetchSize 指定を行います。
170         *
171         * @param   paramProcess データベースの接続先情報などを持っているオブジェクト
172         */
173        public void init( final ParamProcess paramProcess ) {
174                final Argument arg = getArgument();
175
176                select          = arg.getFileProparty( "select","selectFile",false );
177                separator       = arg.getProparty( "sep"                , separator             );
178                outFilename     = arg.getProparty( "outFile"    , outFilename   );
179                append          = arg.getProparty( "append"             , append                );
180                addHeader       = arg.getProparty( "addHeader"  , addHeader             );
181                addFooter       = arg.getProparty( "addFooter"  , addFooter             );
182                useLineCR       = arg.getProparty( "useLineCR"  , useLineCR             );
183                timestamp       = arg.getProparty( "timestamp"  , timestamp             );
184                fetchSize       = arg.getProparty( "fetchSize"  , fetchSize             );              // 6.9.4.1 (2018/04/09) fetchSize 指定
185                display         = arg.getProparty( "display"    , display               );
186                debug           = arg.getProparty( "debug"              , debug                 );
187
188                addHeader = addHeader.replaceAll( "\\\\t" , "\t" ).replaceAll( "\\\\n" , "\n" );        // 「\t」と、「\n」の文字列を、タブと改行に変換します。
189                addFooter = addFooter.replaceAll( "\\\\t" , "\t" ).replaceAll( "\\\\n" , "\n" );        // 「\t」と、「\n」の文字列を、タブと改行に変換します。
190
191                dbid            = arg.getProparty( "dbid" );
192                connection      = paramProcess.getConnection( dbid );
193
194                if( select == null ) {
195                        final String errMsg = "select または、selectFile は必ず指定してください。";
196                        throw new OgRuntimeException( errMsg );
197                }
198
199                // 3.8.0.1 (2005/06/17) {@DATE.XXXX} 変換処理の追加
200                // {@DATE.YMDH} などの文字列を、yyyyMMddHHmmss 型の日付に置き換えます。
201                // SQL文の {@XXXX} 文字列の固定値への置き換え
202                final HybsEntry[] entry =arg.getEntrys(SELECT_KEY);                             // 配列
203                final SystemParameter sysParam = new SystemParameter( select );
204                select = sysParam.replace( entry );
205
206                final HybsEntry[] cnstKey = arg.getEntrys( CNST_KEY );          // 配列
207                final int csize = cnstKey.length;
208                cnstClm         = new String[csize];
209                constVal        = new String[csize];
210                for( int i=0; i<csize; i++ ) {
211                        cnstClm[i]  = cnstKey[i].getKey();
212                        constVal[i] = cnstKey[i].getValue();
213                }
214        }
215
216        /**
217         * プロセスの終了を行います。最後に一度だけ、呼び出されます。
218         * 終了処理(ファイルクローズ、DBクローズ等)に使用します。
219         *
220         * @og.rev 6.4.8.3 (2016/07/15) 新規作成。
221         *
222         * @param   isOK トータルで、OKだったかどうか[true:成功/false:失敗]
223         */
224        public void end( final boolean isOK ) {
225                final boolean flag1 = Closer.stmtClose( selPstmt );
226                selPstmt = null;
227
228                // close に失敗しているのに commit しても良いのか?
229                if( isOK ) {
230                        Closer.commit( connection );
231                }
232                else {
233                        Closer.rollback( connection );
234                }
235                ConnectionFactory.remove( connection,dbid );
236
237                if( ! flag1 ) {
238                        final String errMsg = "select ステートメントをクローズ出来ません。" + CR
239                                                                + " select=[" + select + "] , commit=[" + isOK + "]" ;
240                        System.err.println( errMsg );
241                }
242        }
243
244        /**
245         * 引数の LineModel を処理するメソッドです。
246         * 変換処理後の LineModel を返します。
247         * 後続処理を行わない場合(データのフィルタリングを行う場合)は、
248         * null データを返します。つまり、null データは、後続処理を行わない
249         * フラグの代わりにも使用しています。
250         * なお、変換処理後の LineModel と、オリジナルの LineModel が、
251         * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。
252         * ドキュメントに明記されていない場合は、副作用が問題になる場合は、
253         * 各処理ごとに自分でコピー(クローン)して下さい。
254         *
255         * @og.rev 6.4.8.3 (2016/07/15) 新規作成。
256         * @og.rev 6.9.4.1 (2018/04/09) fetchSize 指定を行います。
257         * @og.rev 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド(mkdirs)
258         * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 ExceptionAsFlowControl 対応
259         *
260         * @param       data オリジナルのLineModel
261         *
262         * @return      処理変換後のLineModel
263         */
264        @Override       // ChainProcess
265        public LineModel action( final LineModel data ) {
266                count++ ;
267//              try {
268                        if( firstRow ) {
269                                makePrepareStatement( data );
270
271                                final int size   = cnstClm.length;
272                                cnstClmNos = new int[size];
273                                for( int i=0; i<size; i++ ) {
274                                        cnstClmNos[i] = data.getColumnNo( cnstClm[i] );
275                                }
276
277                                if( display ) { println( data.nameLine() ); }           // 5.7.3.0 (2014/02/07) デバッグ情報
278
279                                if( timestamp != null ) {
280                                        tmstmpClm = data.getColumnNo( timestamp );
281                                }
282                                firstRow = false;
283                        }
284
285                        // 固定値置き換え処理
286                        for( int j=0; j<cnstClmNos.length; j++ ) {
287                                data.setValue( cnstClmNos[j],constVal[j] );
288                        }
289
290                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ExceptionAsFlowControl 対応
291                final String[][] rtn ;
292                try {
293                        if( selClmNos != null ) {
294                                for( int i=0; i<selClmNos.length; i++ ) {
295                                        selPstmt.setObject( i+1,data.getValue(selClmNos[i]) );
296                                }
297                        }
298
299//                      final Formatter fileFmt = new Formatter( data,outFilename );
300//                      final File outFile = new File( fileFmt.getFormatString(0) );
301//                      // 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド
302////                    if( !outFile.getParentFile().exists() ) {
303////                            outFile.getParentFile().mkdirs();
304////                    }
305//                      final File parent = outFile.getParentFile();    // 親フォルダを取得。nullもありえる
306//                      if( parent == null || !parent.exists() && !parent.mkdirs() ) {
307//                              final String errMsg = "親フォルダを作成できませんでした。[" + data.getRowNo() + "]件目"    + CR
308//                                                                      + " outFile=[" + fileFmt.getFormatString(0) + "]"       + CR ;
309//                              throw new OgRuntimeException( errMsg );
310//                      }
311
312//                      final String[][] rtn ;
313                        try( ResultSet resultSet = selPstmt.executeQuery() ) {
314                                rtn = DBUtil.resultToArray( resultSet,false );          // useHeader = false
315                        }
316                }
317                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ExceptionAsFlowControl 対応
318                catch( final SQLException ex) {
319                        final String errMsg = "検索処理でエラーが発生しました。[" + data.getRowNo() + "]件目"     + CR
320                                                                + " select=[" + select + "]"                                                                            + CR
321                                                                + " errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
322                                                                + " data=[" + data.dataLine() + "]" + CR ;
323                        throw new OgRuntimeException( errMsg,ex );
324                }
325
326                        final Formatter fileFmt = new Formatter( data,outFilename );
327                        final File outFile = new File( fileFmt.getFormatString(0) );
328                        // 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド
329//                      if( !outFile.getParentFile().exists() ) {
330//                              outFile.getParentFile().mkdirs();
331//                      }
332                        final File parent = outFile.getParentFile();    // 親フォルダを取得。nullもありえる
333                        if( parent == null || !parent.exists() && !parent.mkdirs() ) {
334                                final String errMsg = "親フォルダを作成できませんでした。[" + data.getRowNo() + "]件目"    + CR
335                                                                        + " outFile=[" + fileFmt.getFormatString(0) + "]"       + CR ;
336                                throw new OgRuntimeException( errMsg );
337                        }
338
339                        // 0件の場合は、ヘッダーもフッターも出力しません。
340                        if( rtn.length > 0 ) {
341                                try( PrintWriter writer = FileUtil.getPrintWriter( outFile,ENCODE,append ) ) {
342                                        if( addHeader != null ) {
343                                                final Formatter headerFmt = new Formatter( data,addHeader );
344                                                final String header = headerFmt.getFormatString(0);
345                                                writer.print( header );
346                                        }
347                                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach
348//                                      for( int i=0; i<rtn.length; i++ ) {
349//                                              for( int j=0; j<rtn[i].length; j++ ) {
350//                                                      writer.print( rtn[i][j] );
351//                                                      writer.print( separator );
352//                                              }
353//                                              if( useLineCR ) { writer.println(); }
354//                                      }
355                                        for( final String[] row : rtn ) {
356                                                for( final String clm : row ) {
357                                                        writer.print( clm );
358                                                        writer.print( separator );
359                                                }
360                                                if( useLineCR ) { writer.println(); }
361                                        }
362                                        if( addFooter != null ) {
363                                                final Formatter footerFmt = new Formatter( data,addFooter );
364                                                final String footer = footerFmt.getFormatString(0);
365                                                writer.print( footer );
366                                        }
367                                }
368                        }
369
370                        if( tmstmpClm >= 0 ) {
371                                final String tmStmp = String.valueOf( data.getValue( tmstmpClm ) );
372                                final Calendar cal = HybsDateUtil.getCalendar( tmStmp );
373                                // 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド
374//                              outFile.setLastModified( cal.getTimeInMillis() );
375                                if( !outFile.setLastModified( cal.getTimeInMillis() ) ) {
376                                        final String errMsg = "タイムスタンプの更新が出来ませんでした。[" + data.getRowNo() + "]件目" + CR
377                                                                                        + " outFile= [" + outFile + "]" + CR ;
378                                        System.err.println( errMsg );
379                                }
380                        }
381
382                        if( display ) { println( data.dataLine() ); }
383//              }
384//              catch( final SQLException ex) {
385//                      final String errMsg = "検索処理でエラーが発生しました。[" + data.getRowNo() + "]件目"     + CR
386//                                                              + " select=[" + select + "]"                                                                            + CR
387//                                                              + " errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
388//                                                              + " data=[" + data.dataLine() + "]" + CR ;
389//                      throw new OgRuntimeException( errMsg,ex );
390//              }
391                return data;
392        }
393
394        /**
395         * 内部で使用する PreparedStatement を作成します。
396         * 引数指定の SQL または、LineModel から作成した SQL より構築します。
397         *
398         * @og.rev 6.4.8.3 (2016/07/15) 新規作成。
399         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
400         * @og.rev 6.9.4.1 (2018/04/09) fetchSize 指定を行います。
401         *
402         * @param       data    処理対象のLineModel
403         */
404        private void makePrepareStatement( final LineModel data ) {
405
406                final Formatter format = new Formatter( data,select );          // 6.4.3.4 (2016/03/11)
407                select = format.getQueryFormatString();
408                selClmNos = format.getClmNos();
409
410                for( int i=0; i<selClmNos.length; i++ ) {
411                        // 指定のカラムが存在しない場合は、エラーにします。
412                        if( selClmNos[i] < 0 ) {
413                                final String errMsg = "フォーマットに対応したカラムが存在しません。" + CR
414                                                                        + "select=[" + select + "]" + CR
415                                                                        + "ClmKey=[" + format.getClmKeys()[i] + "]" + CR
416                                                                        + "nameLine=[" + data.nameLine() + "]" + CR
417                                                                        + "data=[" + data.dataLine() + "]" + CR ;
418                                throw new OgRuntimeException( errMsg );
419                        }
420                }
421
422                try {
423                        selPstmt = connection.prepareStatement( select );
424//                      selPstmt.setFetchSize( DB_FETCH_SIZE );                         // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
425                        selPstmt.setFetchSize( fetchSize );                                     // 6.9.4.1 (2018/04/09) fetchSize 指定
426                }
427                catch( final SQLException ex) {
428                        // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します。
429                        final String errMsg = "PreparedStatement を取得できませんでした。" + CR
430                                                                + "errMsg=[" + ex.getMessage() + "]" + CR
431                                                                + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
432                                                                + "select=[" + select + "]" + CR
433                                                                + "nameLine=[" + data.nameLine() + "]" + CR
434                                                                + "data=[" + data.dataLine() + "]" + CR ;
435                        throw new OgRuntimeException( errMsg,ex );
436                }
437        }
438
439        /**
440         * プロセスの処理結果のレポート表現を返します。
441         * 処理プログラム名、入力件数、出力件数などの情報です。
442         * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような
443         * 形式で出してください。
444         *
445         * @return   処理結果のレポート
446         */
447        public String report() {
448                // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX'
449                return "[" + getClass().getName() + "]" + CR
450//              final String report = "[" + getClass().getName() + "]" + CR
451                                                        + TAB + "DBID         : " + dbid + CR
452                                                        + TAB + "Input  Count : " + count ;
453
454//              return report ;
455        }
456
457        /**
458         * このクラスの使用方法を返します。
459         *
460         * @return      このクラスの使用方法
461         * @og.rtnNotNull
462         */
463        public String usage() {
464                final StringBuilder buf = new StringBuilder( BUFFER_LARGE )
465                        .append( "Process_DBFileout は、SELECT文 を指定し データベースの値を抜き出して、"             ).append( CR )
466                        .append( "個々のファイルにセーブする、ChainProcess インターフェースの実装クラスです。" ).append( CR )
467                        .append( "上流(プロセスチェインのデータは上流から下流へと渡されます。)から"                            ).append( CR )
468                        .append( "受け取った LineModel を元に、1行単位に、SELECT文を実行します。"                             ).append( CR )
469                        .append( CR )
470                        .append( "上流のカラムを、[カラム]変数で使用できます。"                                                                      ).append( CR )
471                        .append( "また、セーブするファイル名、更新日付等も、都度、更新可能です。"                              ).append( CR )
472                        .append( CR )
473//                      .append( "データベース接続先等は、ParamProcess のサブクラス(Process_DBParam)に"                    ).append( CR )
474//                      .append( "設定された接続(Connection)を使用します。"                                                                           ).append( CR )
475//                      .append( CR )
476//                      .append( "SQL文には、{&#064;DATE.YMDH}等のシステム変数が使用できます。"                                     ).append( CR )
477                        .append( DB_PARAM_USAGE )               // 8.5.6.1 (2024/03/29) 継承元使用
478                        .append( CR )
479//                      .append( "引数文字列中にスペースを含む場合は、ダブルコーテーション(\"\") で括って下さい。").append( CR )
480//                      .append( "引数文字列の 『=』 の前後には、スペースは挟めません。必ず、-key=value の様に"        ).append( CR )
481//                      .append( "繋げてください。"                                                                                                                             ).append( CR )
482                        .append( PROCESS_PARAM_USAGE )  // 8.5.6.1 (2024/03/29) 継承元使用
483                        .append( CR ).append( CR )
484                        .append( getArgument().usage() ).append( CR );
485
486                return buf.toString();
487        }
488
489        /**
490         * このクラスは、main メソッドから実行できません。
491         *
492         * @param       args    コマンド引数配列
493         */
494        public static void main( final String[] args ) {
495                LogWriter.log( new Process_DBFileout().usage() );
496        }
497}