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