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.HybsEntry ;
020    import org.opengion.fukurou.util.FileUtil;
021    import org.opengion.fukurou.util.Closer ;
022    import org.opengion.fukurou.util.LogWriter;
023    
024    import java.util.Map ;
025    import java.util.LinkedHashMap ;
026    
027    import java.io.File;
028    import java.io.PrintWriter;
029    
030    /**
031     * Process_TableWriter は、上流から受け取ったデータをファイルに書き込ã‚?
032     * CainProcess インターフェースの実è£?‚¯ラスですã?
033     *
034     * 上æµ?プロセスチェインのãƒ??タは上流から下流へと渡されますã?)から
035     * 受け取ったLineModel をå?に、DBTableModel 形式ファイルをå?力しますã?
036     *
037     * 引数æ–?­—å?中にスペã?スを含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
038     * 引数æ–?­—å?の ã€?』ã?前後には、スペã?スは挟めません。å¿?�šã€?key=value の様に
039     * 繋げてくださいã€?
040     *
041     * @og.formSample
042     *  Process_TableWriter -outfile=OUTFILE -sep=, -encode=UTF-8 -append=true
043     *
044     *    -outfile=出力ファ?²?™名       ?šå?力ファ?²?™名
045     *   [-sep=?¾?Š゚レー??–‡å­?        ] ?š区åˆ?‚Šæ–?­?初期値:タãƒ?
046     *   [-encode=æ–?­—エ?�コ?°??¾?     ] ?šå?力ファ?²?™ã??´?�コ?°??¾žï¾?½²?Œï¾?
047     *   [-append=[false/true]    ] ?šå?力ファ?²?™を、追記すã‚?true)か新規作æ?する(false)かã?
048     *   [-useHeader=[true/false] ] ?šヘッ??¾žーæƒ??(#NAMEè¡?をå?力すã‚?true)かå?力しなã�?false)かã?
049     *   [-useNumber=[true/false] ] ?š行番号をå?力すã‚?true)かå?力しなã�?false)かã?
050     *   [-useWquot=[false/true]  ] ?šå?力ï¾?¾žー??‚’??¾žブルク?µ?°??½°?¼?®?�で括ã‚?true)かそのまま(false)かã?
051     *   [-omitCTRL=[false/true]  ] ?šコ?�ï¾?¾›ー?™文字を削除する(true)かそのまま(false)かã?
052     *   [-const_XXXX=固定å?      ] ??const_FGJ=1
053     *                                    LineModel のキー(const_ に続くæ–?­—å?)の値に、固定å?を設定しますã?
054     *                                   キーが異なれã?、è¤?•°のカラãƒ?��を指定できますã?
055     *   [-display=[false/true]   ] ?š結果を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
056     *   [-debug=[false/true]     ] ?šデバッグæƒ??を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
057     *
058     * @version  4.0
059     * @author   Kazuhiko Hasegawa
060     * @since    JDK5.0,
061     */
062    public class Process_TableWriter extends AbstractProcess implements ChainProcess {
063            private static final String CNST_KEY = "const_" ;
064    
065            private String  outfile         = null;
066            private PrintWriter writer      = null;
067            private String  separator       = TAB;  // é ?›®区åˆ?‚Šæ–?­?
068    
069            private String[]        cnstClm         = null;         // 固定å?を設定するカラãƒ?��
070            private int[]           cnstClmNos      = null;         // 固定å?を設定するã?カラãƒ?•ª号
071            private String[]        constVal        = null;         // カラãƒ?•ª号に対応した固定å?
072            private File            file            = null;         // 出力ファイル
073            private String          encode          = System.getProperty("file.encoding");  // 出力ファイルエンコーãƒ?
074            private boolean         append          = false;        // ファイル追åŠ?true:追åŠ?false:通常)
075            private boolean         useHeader       = true;         // ヘッãƒ??æƒ??(#NAMEè¡?をå?力すã‚?true)かå?力しなã�?false)かã?
076            private boolean         useNumber       = true;         // 行番号をå?力すã‚?true)かå?力しなã�?false)かã?
077            private boolean         useWquot        = false;        // 出力データをダブルクオーãƒ??ションで括ã‚?true)かそのまま(false)かã?
078            private boolean         omitCTRL        = false;        // コントロールæ–?­—を削除する(true)かそのまま(false)かã?
079            private boolean         display         = false;        // 表示しなã�?
080            private boolean         debug           = false;        // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
081    
082            private boolean firstRow        = true; // æœ??のä¸?¡Œ目
083            private int             count           = 0;
084    
085            private static final Map<String,String> mustProparty   ;          // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
086            private static final Map<String,String> usableProparty ;          // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
087    
088            static {
089                    mustProparty = new LinkedHashMap<String,String>();
090                    mustProparty.put( "outfile",    "出力ファ?²?™名 (å¿??)" );
091    
092                    usableProparty = new LinkedHashMap<String,String>();
093                    usableProparty.put( "sep",              "区åˆ?‚Šæ–?­?初期値:??¾Œï¾?" );
094                    usableProparty.put( "encode",   "出力ファ?²?™ã??´?�コ?°??¾žï¾?½²?Œï¾? );
095                    usableProparty.put( "append",   "出力ファ?²?™を、追記すã‚?true)か新規作æ?する(false)かã?" );
096                    usableProparty.put( "useHeader",        "?�ッ??¾žーæƒ??(#NAMEè¡?をå?力すã‚?true)かå?力しなã�?false)かã?" );
097                    usableProparty.put( "useNumber",        "行番号をå?力すã‚?true)かå?力しなã�?false)かã?" );
098                    usableProparty.put( "useWquot",         "出力ï¾?¾žー??‚’??¾žブルク?µ?°??½°?¼?®?�で括ã‚?true)かそのまま(false)かã?" );
099                    usableProparty.put( "omitCTRL",         "?º?�ï¾?¾›ー?™文字を削除する(true)かそのまま(false)かã?" );
100                    usableProparty.put( "const_",   "LineModel のキー(const_ に続くæ–?­—å?)の値に、固定å?ã‚? +
101                                                                            CR + "設定しますã?キーが異なれã?、è¤?•°のカラãƒ?��を指定できますã?" +
102                                                                            CR + "ä¾? -const_FGJ=1" );
103                    usableProparty.put( "display",  "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
104                                                                            CR + " (初期値:false:表示しなã�?" );
105                    usableProparty.put( "debug",    "ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�? +
106                                                                            CR + "(初期値:false:表示しなã�?" );                // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
107            }
108    
109            /**
110             * ãƒ?ƒ•ォルトコンストラクターã€?
111             * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
112             * super クラスに対して、å¿?¦�な初期化を行っておきますã?
113             *
114             */
115            public Process_TableWriter() {
116                    super( "org.opengion.fukurou.process.Process_TableWriter",mustProparty,usableProparty );
117            }
118    
119            /**
120             * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
121             * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç­?に使用しますã?
122             *
123             * @param   paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
124             */
125            public void init( final ParamProcess paramProcess ) {
126                    Argument arg = getArgument();
127    
128                    outfile                 = arg.getProparty("outfile");
129                    encode                  = arg.getProparty("encode",encode);
130                    separator               = arg.getProparty("sep",separator );
131                    append                  = arg.getProparty("append",append);
132                    useHeader               = arg.getProparty("useHeader",useHeader);
133                    useNumber               = arg.getProparty("useNumber",useNumber);
134                    useWquot                = arg.getProparty("useWquot",useWquot);
135                    omitCTRL                = arg.getProparty("omitCTRL",omitCTRL);
136                    HybsEntry[] cnstKey = arg.getEntrys( CNST_KEY );                // 配å?
137                    display                 = arg.getProparty("display",display);
138                    debug                   = arg.getProparty("debug",debug);                               // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
139    //              if( debug ) { println( arg.toString() ); }                      // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
140    
141                    int size   = cnstKey.length;
142                    cnstClm    = new String[size];
143                    constVal   = new String[size];
144                    for( int i=0; i<size; i++ ) {
145                            cnstClm[i]  = cnstKey[i].getKey();
146                            constVal[i] = cnstKey[i].getValue();
147                    }
148    
149                    if( outfile == null ) {
150                            String errMsg = "ファイル名がæŒ?®šされてã�?�¾せんã€? ;
151                            throw new RuntimeException( errMsg );
152                    }
153    
154                    file = new File( outfile );
155                    File dir = file.getParentFile() ;
156    
157                    // ãƒ?‚£レクトリが存在しなã�??合ã?処ç�?
158                    if( ! dir.exists() && ! dir.mkdirs() ) {
159                            String errMsg = "ãƒ?‚£レクトリが作æ?できませんでしたã€?" + dir + "]" ;
160                            throw new RuntimeException( errMsg );
161                    }
162            }
163    
164            /**
165             * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
166             * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç­?に使用しますã?
167             *
168             * @param   isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
169             */
170            public void end( final boolean isOK ) {
171                    if( writer != null ) {
172                            writer.flush();
173                            Closer.ioClose( writer );
174                            writer = null;
175                    }
176            }
177    
178            /**
179             * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
180             * 変換処ç�?¾Œã? LineModel を返しますã?
181             * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
182             * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
183             * フラグの代わりにも使用してã�?�¾すã?
184             * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
185             * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
186             * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
187             * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
188             *
189             * @param   data        オリジナルのLineModel
190             *
191             * @return      処ç�?¤‰換後ã?LineModel
192             */
193            public LineModel action( final LineModel data ) {
194                    count++ ;
195    //              if( display ) { println( data.dataLine() ); }
196                    if( firstRow ) {
197                            writer = FileUtil.getPrintWriter( file,encode,append );
198                            if( useHeader && useNumber ) { writeName( data ); }
199    
200                            int size   = cnstClm.length;
201                            cnstClmNos = new int[size];
202                            for( int i=0; i<size; i++ ) {
203                                    cnstClmNos[i] = data.getColumnNo( cnstClm[i] );
204                            }
205    
206                            firstRow = false;
207                            if( display ) { println( data.nameLine() ); }           // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
208                    }
209    
210                    // 固定å?置き換えå?ç�?
211                    for( int j=0; j<cnstClmNos.length; j++ ) {
212                            data.setValue( cnstClmNos[j],constVal[j] );
213                    }
214    
215                    writeData( data );
216    
217                    if( display ) { println( data.dataLine() ); }   // 5.1.2.0 (2010/01/01) display の条件変更
218                    return data;
219            }
220    
221            /**
222             * PrintWriter に LineModelのé ?›®名情報を書き込みますã?
223             * 第ä¸?‚«ラãƒ?›®はã€??目名情報を示ã�?"#Name" を書き込みますã?
224             * こã?行ã?、å?力形式に無関係に、TAB で区åˆ?‚‰れますã?
225             *
226             * @param       data ラインモãƒ?ƒ«
227             */
228            private void writeName( final LineModel data ) {
229                    int size = data.size();
230                    writer.print( "#Name" );
231                    for( int clm=0; clm<size; clm++ ) {
232                            writer.print( TAB );
233                            writer.print( data.getName(clm) );
234                    }
235                    writer.println();
236            }
237    
238            /**
239             * PrintWriter に LineModelのãƒ??ブルæƒ??を書き込みますã?
240             *
241             * @og.rev 5.2.2.0 (2010/11/01) 改行を含ã‚??合ã?、ダブルクオートを強制çš?�«前後に追åŠ?�™るã?
242             * @og.rev 5.2.2.0 (2010/11/01) ãƒ?ƒ–ルクオートを含ã‚??合ã?、その直前にãƒ?ƒ–ルクオートを強制çš?�«追åŠ?�™るã?
243             *
244             * @param       data ラインモãƒ?ƒ«
245             */
246            private void writeData( final LineModel data ) {
247                    int size = data.size();
248    
249                    if( useNumber ) { writer.print( data.getRowNo() ); }            // 行番号
250                    for( int clm=0; clm<size; clm++ ) {
251                            if( useNumber || clm!=0 ) { writer.print( separator ); }
252                            Object val = data.getValue(clm);
253                            if( val == null ) { val = ""; }
254    
255                            String sval = String.valueOf( val );
256                            // 5.2.2.0 (2010/11/01) ãƒ?ƒ–ルクオートを含ã‚??合ã?、その直前にãƒ?ƒ–ルクオートを強制çš?�«追åŠ?�™るã?
257                            if( sval.indexOf( '"' ) >= 0 ) { sval = sval.replaceAll( "\"" ,"\"\"" ) ; }
258                            if( omitCTRL ) { sval = sval.replaceAll( "\\s" ," " ) ; }
259    //                      if( useWquot ) { sval = "\"" + sval + "\"" ; }
260                            // 5.2.2.0 (2010/11/01) 改行を含ã‚??合ã?、ダブルクオートを強制çš?�«前後に追åŠ?�™るã?
261                            if( useWquot || ( !omitCTRL && sval.indexOf( CR ) >= 0 ) ) {
262                                    sval = "\"" + sval + "\"" ;
263                            }
264                            writer.print( sval );
265                    }
266                    writer.println();
267            }
268    
269            /**
270             * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
271             * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
272             * こã?æ–?­—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
273             * 形式で出してくださいã€?
274             *
275             * @return   処ç�?µ�果のレポã?ãƒ?
276             */
277            public String report() {
278                    String report = "[" + getClass().getName() + "]" + CR
279                                    + TAB + "Output File  : " + outfile + CR
280                                    + TAB + "Output Count : " + count ;
281    
282                    return report ;
283            }
284    
285            /**
286             * こã?クラスの使用方法を返しますã?
287             *
288             * @return      こã?クラスの使用方æ³?
289             */
290            public String usage() {
291                    StringBuilder buf = new StringBuilder();
292    
293                    buf.append( "Process_TableWriter は、上流から受け取ったデータをファイルに書き込ã‚?                    ).append( CR );
294                    buf.append( "CainProcess インターフェースの実è£?‚¯ラスですã?"                                                               ).append( CR );
295                    buf.append( CR );
296                    buf.append( "上æµ?プロセスチェインのãƒ??タは上流から下流へと渡されますã?)から"                   ).append( CR );
297                    buf.append( "受け取ったLineModel をå?に、DBTableModel 形式ファイルをå?力しますã?"                        ).append( CR );
298                    buf.append( CR );
299                    buf.append( "引数æ–?­—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
300                    buf.append( "引数æ–?­—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に"             ).append( CR );
301                    buf.append( "繋げてくださいã€?                                                                                                                              ).append( CR );
302                    buf.append( CR ).append( CR );
303    
304                    buf.append( getArgument().usage() ).append( CR );
305    
306                    return buf.toString();
307            }
308    
309            /**
310             * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
311             *
312             * @param       args    コマンド引数配å?
313             */
314            public static void main( final String[] args ) {
315                    LogWriter.log( new Process_TableWriter().usage() );
316            }
317    }