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.StringUtil;
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.HashMap ;
026    import java.util.LinkedHashMap ;
027    
028    import java.io.File;
029    import java.io.BufferedReader;
030    import java.io.IOException;
031    
032    /**
033     * Process_TableDiffは、ファイルから読み取ったå?容をã?LineModel に設定後ã?
034     * 下流に渡すã?FirstProcess インターフェースの実è£?‚¯ラスですã?
035     *
036     * DBTableModel 形式ã?ファイルを読み取って、各行を LineModel にセãƒ?ƒˆしてã€?
037     * 下æµ?プロセスチェインのãƒ??タは上流から下流に渡されますã?)に渡しますã?
038     *
039     * 引数æ–?­—å?中にスペã?スを含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
040     * 引数æ–?­—å?の ã€?』ã?前後には、スペã?スは挟めません。å¿?�šã€?key=value の様に
041     * 繋げてくださいã€?
042     *
043     * @og.formSample
044     *  Process_TableDiff -infile1=INFILE -infile2=INFILE2 -action=DIFF1 -encode=UTF-8 -columns=AA,BB,CC
045     *
046     *    -infile1=入力ファイルå�?    ?šå?力ファイルå�?
047     *    -infile2=入力ファイルå�?    ?šå?力ファイルå�?
048     *    -action=比è¼?µ�果の方æ³?     ?šONLY,DIFF,INTERSEC
049     *   [-sep1=セパレータæ–?­?     ] ?š区åˆ?‚Šæ–?­?(初期値:タãƒ?
050     *   [-sep2=セパレータæ–?­?     ] ?š区åˆ?‚Šæ–?­?(初期値:タãƒ?
051     *   [-encode1=æ–?­—エンコーãƒ?  ] ?šå?力ファイルのエンコードタイãƒ?
052     *   [-encode2=æ–?­—エンコーãƒ?  ] ?šå?力ファイルのエンコードタイãƒ?
053     *   [-columns=読み取りカラãƒ?�� ] ?šå?力カラãƒ?��(カンマ区åˆ?‚Š)
054     *   [-keyClms=比è¼?�™るカラãƒ?�� ] ?š比è¼?�™るå?の基準カラãƒ?��(カンマ区åˆ?‚Š)
055     *   [-diffClms=比è¼?�™るカラãƒ?��] ?š比è¼?�™るカラãƒ?��(カンマ区åˆ?‚Š)
056     *   [-display=[false/true]     ] ?š結果を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
057     *   [-debug=[false/true]       ] ?šデバッグæƒ??を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
058     *
059     * @og.rev 4.2.3.0 (2008/05/26) 新規作æ?
060     *
061     * @version  4.0
062     * @author   Kazuhiko Hasegawa
063     * @since    JDK5.0,
064     */
065    public class Process_TableDiff extends AbstractProcess implements FirstProcess {
066            private static final String ENCODE = System.getProperty("file.encoding");
067    
068            private String                  separator1      = TAB;  // é ?›®区åˆ?‚Šæ–?­?
069            private String                  separator2      = TAB;  // é ?›®区åˆ?‚Šæ–?­?
070            private String                  infile1         = null;
071            private String                  infile2         = null;
072            private BufferedReader  reader1         = null;
073    //      private BufferedReader  reader2         = null;
074            private LineModel               model           = null;
075            private String                  line            = null;
076            private int[]                   clmNos          = null;         // ファイルのヘッãƒ??のカラãƒ?•ª号
077            private int[]                   keyClmNos       = null;         // 比è¼?�™るå?の基準カラãƒ?��のカラãƒ?•ª号
078            private int[]                   diffClmNos      = null;         // 比è¼?�™るカラãƒ?��のカラãƒ?•ª号
079    //      private String                  action          = null;
080            private String                  actCmnd         = null;         // action から名称変更
081            private boolean                 display         = false;        // 表示しなã�?
082            private boolean                 debug           = false;        // 表示しなã�?
083            private boolean                 nameNull        = false;        // ?�件ãƒ??タæ™?true
084    
085            private final Map<String,String> file2Map = new HashMap<String,String>();   // 4.3.1.1 (2008/08/23) final�
086    
087            private int                             inCount1        = 0;
088            private int                             inCount2        = 0;
089            private int                             outCount        = 0;
090    
091            private static final Map<String,String> mustProparty   ;          // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
092            private static final Map<String,String> usableProparty ;          // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
093    
094            static {
095                    mustProparty = new LinkedHashMap<String,String>();
096                    mustProparty.put( "infile1",    "入力ファイルå�? (å¿??)" );
097                    mustProparty.put( "infile2",    "入力ファイルå�? (å¿??)" );
098                    mustProparty.put( "action",             "(å¿??)ONLY,DIFF,INTERSEC" );
099                    mustProparty.put( "keyClms",    "比è¼?�™るå?の基準カラãƒ?��(å¿??)(カンマ区åˆ?‚Š)" );
100                    mustProparty.put( "diffClms",   "比è¼?�™るカラãƒ?��(å¿??)(カンマ区åˆ?‚Š)" );
101    
102                    usableProparty = new LinkedHashMap<String,String>();
103                    usableProparty.put( "sep1",                     "区åˆ?‚Šæ–?­? (初期値:タãƒ?" );
104                    usableProparty.put( "sep2",                     "区åˆ?‚Šæ–?­? (初期値:タãƒ?" );
105                    usableProparty.put( "encode1",          "入力ファイルのエンコードタイãƒ?" );
106                    usableProparty.put( "encode2",          "入力ファイルのエンコードタイãƒ?" );
107                    usableProparty.put( "columns",          "入力カラãƒ?��(カンマ区åˆ?‚Š)" );
108                    usableProparty.put( "display",          "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
109                                                                                            CR + " (初期値:false:表示しなã�?" );
110                    usableProparty.put( "debug",            "ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�? +
111                                                                                            CR + " (初期値:false:表示しなã�?" );
112            }
113    
114            /**
115             * ãƒ?ƒ•ォルトコンストラクターã€?
116             * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
117             * super クラスに対して、å¿?¦�な初期化を行っておきますã?
118             *
119             */
120            public Process_TableDiff() {
121                    super( "org.opengion.fukurou.process.Process_TableDiff",mustProparty,usableProparty );
122            }
123    
124            /**
125             * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
126             * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç­?に使用しますã?
127             *
128             * @param   paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
129             */
130            public void init( final ParamProcess paramProcess ) {
131                    Argument arg = getArgument();
132    
133                    infile1                         = arg.getProparty( "infile1" );
134                    infile2                         = arg.getProparty( "infile2" );
135                    actCmnd                         = arg.getProparty( "action"  );
136                    String  encode1         = arg.getProparty( "encode1",ENCODE );
137                    String  encode2         = arg.getProparty( "encode2",ENCODE );
138                    separator1                      = arg.getProparty( "sep1",separator1 );
139                    separator2                      = arg.getProparty( "sep2",separator2 );
140                    String  clms            = arg.getProparty( "columns"  );
141                    String  keyClms         = arg.getProparty( "keyClms"  );
142                    String  diffClms        = arg.getProparty( "diffClms" );
143                    display                         = arg.getProparty( "display",display );
144                    debug                           = arg.getProparty( "debug"  ,debug );
145    //              if( debug ) { println( arg.toString() ); }                      // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
146    
147                    if( infile1 == null || infile2 == null ) {
148                            String errMsg = "ファイル名がæŒ?®šされてã�?�¾せんã€?
149                                                    + "File1=[" + infile1 + "] , File2=[" + infile2 + "]" ;
150                            throw new RuntimeException( errMsg );
151                    }
152    
153                    File file1 = new File( infile1 );
154                    File file2 = new File( infile2 );
155    
156                    if( ! file1.exists() || ! file2.exists() ) {
157                            // 4.3.1.1 (2008/08/23) Avoid if (x != y) ..; else ..;
158                            String errMsg = "ファイルが存在しませんã€?
159                                                    + ((file1.exists()) ? "" : "File1=[" + file1 + "] " )
160                                                    + ((file2.exists()) ? "" : "File2=[" + file2 + "]" );
161                            throw new RuntimeException( errMsg );
162                    }
163    
164                    if( ! file1.isFile() || ! file2.isFile() ) {
165                            // 4.3.1.1 (2008/08/23) Avoid if (x != y) ..; else ..;
166                            String errMsg = "フォルãƒ??æŒ?®šできません。ファイル名をæŒ?®šしてくださいã€?
167                                                    + ((file1.isFile()) ? "" : "File1=[" + file1 + "] " )
168                                                    + ((file2.isFile()) ? "" : "File2=[" + file2 + "]" );
169                            throw new RuntimeException( errMsg );
170                    }
171    
172                    reader1 = FileUtil.getBufferedReader( file1,encode1 );
173    //              reader2 = FileUtil.getBufferedReader( file2,encode2 );
174    
175                    final String[] names ;
176                    if( clms != null ) {
177                            names = StringUtil.csv2Array( clms );   // æŒ?®šã?カラãƒ?��配å?
178                    }
179                    else {
180                            String[] clmNames = readName( reader1 );                // ファイルのカラãƒ?��配å?
181                            if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; }
182                            names = clmNames;
183                    }
184    
185                    model = new LineModel();
186                    model.init( names );
187    
188                    if( display ) { println( model.nameLine() ); }
189    
190                    // 入力カラãƒ?��のカラãƒ?•ª号
191                    clmNos = new int[names.length];
192                    for( int i=0; i<names.length; i++ ) {
193                            clmNos[i] = i+1;                                                // 行番号åˆ?‚’?‹1しておくã€?
194    //                      int no = model.getColumnNo( names[i] );
195    //                      if( no >= 0 ) { clmNos[no] = i+1; }          // 行番号åˆ?‚’?‹1しておくã€?
196                    }
197    
198                    // 比è¼?�™るå?の基準カラãƒ?��
199                    if( debug ) { println( "DEBUG:\tkeyClms=" + keyClms ); }
200                    final String[] keyClmNms = StringUtil.csv2Array( keyClms );
201                    keyClmNos = new int[keyClmNms.length];
202                    for( int i=0; i<keyClmNms.length; i++ ) {
203                            keyClmNos[i] = model.getColumnNo( keyClmNms[i] );
204            //              if( debug ) { println( "DEBUG:" + keyClmNms[i] + ":[" + keyClmNos[i] + "]" ); }
205            //              int no = model.getColumnNo( keyClmNms[i] );
206            //              if( no >= 0 ) { keyClmNos[no] = i+1; }               // 行番号åˆ?‚’?‹1しておくã€?
207                    }
208    
209                    // 比è¼?�™るカラãƒ?��
210                    if( debug ) { println( "DEBUG:\tdiffClms=" + diffClms ); }
211                    final String[] diffClmNms = StringUtil.csv2Array( diffClms );
212                    diffClmNos = new int[diffClmNms.length];
213                    for( int i=0; i<diffClmNms.length; i++ ) {
214                            diffClmNos[i] = model.getColumnNo( diffClmNms[i] );
215            //              if( debug ) { println( "DEBUG:" + diffClmNms[i] + ":[" + diffClmNos[i] + "]" ); }
216            //              int no = model.getColumnNo( diffClmNms[i] );
217            //              if( no >= 0 ) { diffClmNos[no] = i+1; }              // 行番号åˆ?‚’?‹1しておくã€?
218                    }
219    
220                    readF2Data( file2,encode2 );
221            }
222    
223            /**
224             * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
225             * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç­?に使用しますã?
226             *
227             * @param   isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
228             */
229            public void end( final boolean isOK ) {
230                    Closer.ioClose( reader1 );
231                    reader1 = null;
232            }
233    
234            /**
235             * こã?ãƒ??タの処ç�?�«おいて、次の処ç�?�Œ出来るかどã�?�‹を問ã�?�ˆわせますã?
236             * こã?呼び出し1回毎に、次のãƒ??タを取得する準備を行いますã?
237             *
238             * @return      処ç�?�§きる:true / 処ç�?�§きなã�?false
239             */
240            public boolean next() {
241                    if( nameNull ) { return false; }
242    
243                    boolean flag = false;
244                    try {
245                            while((line = reader1.readLine()) != null) {
246                                    inCount1++ ;
247                                    if( line.length() == 0 || line.charAt( 0 ) == '#' ) { continue; }
248                                    else {
249                                            flag = true;
250                                            break;
251                                    }
252                            }
253                    }
254                    catch (IOException ex) {
255                            String errMsg = "ファイル読込みエラー[" + infile1 + "]:(" + inCount1 + ")"  ;
256                            throw new RuntimeException( errMsg,ex );
257                    }
258                    return flag;
259            }
260    
261            /**
262             * æœ??にã€?行データである LineModel を作æ?しまã�?
263             * FirstProcess は、次ã€?�¨処ç�?‚’チェインしてã�?��æœ??の行データã‚?
264             * 作æ?して、後続ã? ChainProcess クラスに処ç�?ƒ‡ータを渡しますã?
265             *
266             * ファイルより読み込んだ?‘行ã?ãƒ??タã‚?ãƒ??ブルモãƒ?ƒ«に
267             * セãƒ?ƒˆするようにåˆ?‰²しまã�?
268             * なおã?読込みは?ŒNAMEé ?›®åˆ?‚’読み込みますã?ãƒ??タ件数が少なã�??合ã?ã€?
269             * "" をセãƒ?ƒˆしておきますã?
270             *
271             * @param       rowNo   処ç�?¸­の行番号
272             *
273             * @return      処ç�?¤‰換後ã?LineModel
274             */
275            public LineModel makeLineModel( final int rowNo ) {
276                    outCount++ ;
277                    String[] vals = StringUtil.csv2Array( line ,separator1.charAt(0) );
278    
279                    int len = vals.length;
280                    for( int clmNo=0; clmNo<model.size(); clmNo++ ) {
281                            int no = clmNos[clmNo];
282                            if( len > no ) {
283                                    model.setValue( clmNo,vals[no] );
284                            }
285                            else {
286                                    // EXCEL がã?終端TABを削除してしまã�?�Ÿめã?少なã�??合ã?埋めるã?
287                                    model.setValue( clmNo,"" );
288                            }
289                    }
290                    model.setRowNo( rowNo ) ;
291    
292    //              if( display ) { println( model.dataLine() ); }          // 5.1.2.0 (2010/01/01) display の条件変更
293    
294                    return action( model );
295            }
296    
297            /**
298             * キーと、DIFF設定å?を比è¼?�—、action に応じã�?LineModel を返しますã?
299             * action には、ONLY,DIFF,INTERSEC が指定できますã?
300             *   ONLY      inFile1 のみに存在する行ã?場合ã?inFile1 のレコードを返しますã?
301             *   DIFF      inFile1 と inFile2 に存在しã?かつ、DIFF値が異なるã?inFile1 のレコードを返しますã?
302             *   INTERSEC  inFile1 と inFile2 に存在しã?かつ、DIFF値も同じã?inFile1 のレコードを返しますã?
303             * inFile2 側をキャãƒ?‚·ュしますã?で、inFile2 側のãƒ??タ量が少なã�?§˜に選んでくださいã€?
304             *
305             * @param       model LineModelオブジェクãƒ?
306             *
307             * @return      実行後ã?LineModel
308             */
309            private LineModel action( final LineModel model ) {
310                    LineModel rtn = null;
311                    Object[] obj = model.getValues();
312    
313                    // キーのカラãƒ?‚’合æ?しますã?
314                    StringBuilder keys = new StringBuilder();
315                    for( int i=0; i<keyClmNos.length; i++ ) {
316                            keys.append( obj[keyClmNos[i]] ).append( "," );
317                    }
318    
319                    String data = file2Map.get( keys.toString() );
320            //      if( debug ) { println( "DEBUG:" + keys.toString() + ":" + data ); }
321    
322                    if( "ONLY".equalsIgnoreCase( actCmnd ) && data == null ) {
323                            if( debug ) { println( "DEBUG:ONLY\t" + keys.toString() ); }
324                            rtn = model;
325                    }
326                    else {
327                            // DIFF値のカラãƒ?‚’合æ?しますã?
328                            StringBuilder vals = new StringBuilder();
329                            for( int i=0; i<diffClmNos.length; i++ ) {
330                                    vals.append( obj[diffClmNos[i]] ).append( "," );
331                            }
332    
333                            boolean eq = ( vals.toString() ).equals( data );
334    
335                            if( "DIFF".equalsIgnoreCase( actCmnd ) && ! eq ) {
336                                    if( debug ) { println( "DEBUG:DIFF\t" + keys.toString() + "\t" + data + "\t" + vals.toString() ); }
337                                    rtn = model;
338                            }
339                            else if( "INTERSEC".equalsIgnoreCase( actCmnd ) && eq ) {
340                                    if( debug ) { println( "DEBUG:INTERSEC\t" + keys.toString() + "\t" + data ); }
341                                    rtn = model;
342                            }
343                    }
344                    if( display && rtn != null ) { println( rtn.dataLine() ); }
345                    return rtn;
346            }
347    
348            /**
349             * BufferedReader よりã€?NAME 行ã?é ?›®名情報を読み取りますã?
350             * ãƒ??タカラãƒ?‚ˆり前にã€??目名情報を示ã�?"#Name" が存在する仮定で取り込みますã?
351             * こã?行ã?、ファイルの形式に無関係に、TAB で区åˆ?‚‰れてã�?�¾すã?
352             *
353             * @param       reader PrintWriterオブジェクãƒ?
354             *
355             * @return      カラãƒ?��配å?(存在しなã�??合ã?、サイズ?�ã?配å?)
356             */
357            private String[] readName( final BufferedReader reader ) {
358                    try {
359                            // 4.0.0 (2005/01/31) line 変数名変更
360                            String line1;
361                            while((line1 = reader.readLine()) != null) {
362                                    inCount1++ ;
363                                    if( line1.length() == 0 ) { continue; }
364                                    if( line1.charAt(0) == '#' ) {
365                                            String key = line1.substring( 0,5 );
366                                            if( key.equalsIgnoreCase( "#NAME" ) ) {
367                                                    // è¶?‚¤レギュラー処ç�?æœ??の TAB 以前ã?æ–?­—ã?無視するã?
368                                                    String line2 = line1.substring( line1.indexOf( TAB )+1 );
369                                                    return StringUtil.csv2Array( line2 ,TAB.charAt(0) );
370                                            }
371                                            else  { continue; }
372                                    }
373                                    else {
374                                            String errMsg = "#NAME が見つかる前にãƒ??タが見つかりましたã€?;
375                                            throw new RuntimeException( errMsg );
376                                    }
377                            }
378                    }
379                    catch (IOException ex) {
380                            String errMsg = "ファイル読込みエラー[" + infile1 + "]:(" + inCount1 + ")"  ;
381                            throw new RuntimeException( errMsg,ex );
382                    }
383                    return new String[0];
384            }
385    
386            /**
387             * ファイル属æ?を読取り、キーæƒ??を作æ?しã?å†?ƒ¨メモリマップにキャãƒ?‚·ュしますã?
388             * こã?マップをもとに、inFile1 のãƒ??タをé?次読み取って、å?ç�?‚’進めますã?
389             *
390             * @param       file2 読取りå…??ファイル
391             * @param       encode2 ファイルのエンコーãƒ?
392             */
393            private void readF2Data( final File file2, final String encode2 ) {
394                    BufferedReader reader2 = null;
395                    try {
396                            if( debug ) { println( "DEBUG:\tFile2="+ file2 + " 初期処ç�? ); }
397                            reader2 = FileUtil.getBufferedReader( file2,encode2 );
398                            // 4.0.0 (2005/01/31) line 変数名変更
399                            String line1;
400                            char sep2 = separator2.charAt(0);
401                            while((line1 = reader2.readLine()) != null) {
402                                    inCount2++ ;
403                                    if( line1.length() == 0 ) { continue; }
404                                    if( line1.charAt(0) == '#' ) { continue; }
405                                    else {
406                                            // è¶?‚¤レギュラー処ç�?æœ??の TAB 以前ã?æ–?­—ã?無視するã?
407                                            String line2 = line1.substring( line1.indexOf( separator2 )+1 );
408                                            Object[] obj = StringUtil.csv2Array( line2 , sep2 );
409    
410                                            // キーのカラãƒ?‚’合æ?しますã?
411                                            StringBuilder keys = new StringBuilder();
412                                            for( int i=0; i<keyClmNos.length; i++ ) {
413                                                    keys.append( obj[keyClmNos[i]] ).append( "," );
414                                            }
415    
416                                            // DIFF値のカラãƒ?‚’合æ?しますã?
417                                            StringBuilder vals = new StringBuilder();
418                                            for( int i=0; i<diffClmNos.length; i++ ) {
419                                                    vals.append( obj[diffClmNos[i]] ).append( "," );
420                                            }
421    
422                                            if( debug ) { println( "DEBUG:\t" + keys.toString() + "\t" + vals.toString() ); }
423    
424                                            file2Map.put( keys.toString(), vals.toString() );
425                                    }
426                            }
427                            if( debug ) { println( "DEBUG:\t======初期処ç�?µ‚äº?=====" ); }
428                    }
429                    catch (IOException ex) {
430                            String errMsg = "ファイル読込みエラー[" + infile2 + "]:(" + inCount2 + ")"  ;
431                            throw new RuntimeException( errMsg,ex );
432                    }
433                    finally {
434                            Closer.ioClose( reader2 );
435                    }
436            }
437    
438            /**
439             * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
440             * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
441             * こã?æ–?­—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
442             * 形式で出してくださいã€?
443             *
444             * @return   処ç�?µ�果のレポã?ãƒ?
445             */
446            public String report() {
447                    String report = "[" + getClass().getName() + "]" + CR
448                                    + TAB + "Input  File1  : " + infile1    + CR
449                                    + TAB + "Input  File2  : " + infile2    + CR
450                                    + TAB + "Input  Count1 : " + inCount1   + CR
451                                    + TAB + "Input  Count2 : " + inCount2   + CR
452                                    + TAB + "Output Count  : " + outCount ;
453    
454                    return report ;
455            }
456    
457            /**
458             * こã?クラスの使用方法を返しますã?
459             *
460             * @return      こã?クラスの使用方æ³?
461             */
462            public String usage() {
463                    StringBuilder buf = new StringBuilder();
464    
465                    buf.append( "Process_TableDiffは、ファイルから読み取ったå?容をã?LineModel に設定後ã?"         ).append( CR );
466                    buf.append( "下流に渡すã?FirstProcess インターフェースの実è£?‚¯ラスですã?"                                    ).append( CR );
467                    buf.append( CR );
468                    buf.append( "DBTableModel 形式ã?ファイルを読み取って、各行を LineModel にセãƒ?ƒˆしてã€?          ).append( CR );
469                    buf.append( "下æµ?プロセスチェインのãƒ??タは上流から下流に渡されますã?)に渡しますã?"              ).append( CR );
470                    buf.append( CR );
471                    buf.append( "引数æ–?­—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
472                    buf.append( "引数æ–?­—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に"             ).append( CR );
473                    buf.append( "繋げてくださいã€?                                                                                                                              ).append( CR );
474                    buf.append( CR ).append( CR );
475    
476                    buf.append( getArgument().usage() ).append( CR );
477    
478                    return buf.toString();
479            }
480    
481            /**
482             * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
483             *
484             * @param       args    コマンド引数配å?
485             */
486            public static void main( final String[] args ) {
487                    LogWriter.log( new Process_TableDiff().usage() );
488            }
489    }