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    
146                    if( infile1 == null || infile2 == null ) {
147                            String errMsg = "ファイル名がæŒ?®šされてã�?�¾せんã€?
148                                                    + "File1=[" + infile1 + "] , File2=[" + infile2 + "]" ;
149                            throw new RuntimeException( errMsg );
150                    }
151    
152                    File file1 = new File( infile1 );
153                    File file2 = new File( infile2 );
154    
155                    if( ! file1.exists() || ! file2.exists() ) {
156                            // 4.3.1.1 (2008/08/23) Avoid if (x != y) ..; else ..;
157                            String errMsg = "ファイルが存在しませんã€?
158                                                    + ((file1.exists()) ? "" : "File1=[" + file1 + "] " )
159                                                    + ((file2.exists()) ? "" : "File2=[" + file2 + "]" );
160                            throw new RuntimeException( errMsg );
161                    }
162    
163                    if( ! file1.isFile() || ! file2.isFile() ) {
164                            // 4.3.1.1 (2008/08/23) Avoid if (x != y) ..; else ..;
165                            String errMsg = "フォルãƒ??æŒ?®šできません。ファイル名をæŒ?®šしてくださいã€?
166                                                    + ((file1.isFile()) ? "" : "File1=[" + file1 + "] " )
167                                                    + ((file2.isFile()) ? "" : "File2=[" + file2 + "]" );
168                            throw new RuntimeException( errMsg );
169                    }
170    
171                    reader1 = FileUtil.getBufferedReader( file1,encode1 );
172    //              reader2 = FileUtil.getBufferedReader( file2,encode2 );
173    
174                    final String[] names ;
175                    if( clms != null ) {
176                            names = StringUtil.csv2Array( clms );   // æŒ?®šã?カラãƒ?��配å?
177                    }
178                    else {
179                            String[] clmNames = readName( reader1 );                // ファイルのカラãƒ?��配å?
180                            if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; }
181                            names = clmNames;
182                    }
183    
184                    model = new LineModel();
185                    model.init( names );
186    
187                    if( display ) { println( model.nameLine() ); }
188    
189                    // 入力カラãƒ?��のカラãƒ?•ª号
190                    clmNos = new int[names.length];
191                    for( int i=0; i<names.length; i++ ) {
192                            clmNos[i] = i+1;                                                // 行番号åˆ?‚’?‹1しておくã€?
193    //                      int no = model.getColumnNo( names[i] );
194    //                      if( no >= 0 ) { clmNos[no] = i+1; }          // 行番号åˆ?‚’?‹1しておくã€?
195                    }
196    
197                    // 比è¼?�™るå?の基準カラãƒ?��
198                    if( debug ) { println( "DEBUG:\tkeyClms=" + keyClms ); }
199                    final String[] keyClmNms = StringUtil.csv2Array( keyClms );
200                    keyClmNos = new int[keyClmNms.length];
201                    for( int i=0; i<keyClmNms.length; i++ ) {
202                            keyClmNos[i] = model.getColumnNo( keyClmNms[i] );
203            //              if( debug ) { println( "DEBUG:" + keyClmNms[i] + ":[" + keyClmNos[i] + "]" ); }
204            //              int no = model.getColumnNo( keyClmNms[i] );
205            //              if( no >= 0 ) { keyClmNos[no] = i+1; }               // 行番号åˆ?‚’?‹1しておくã€?
206                    }
207    
208                    // 比è¼?�™るカラãƒ?��
209                    if( debug ) { println( "DEBUG:\tdiffClms=" + diffClms ); }
210                    final String[] diffClmNms = StringUtil.csv2Array( diffClms );
211                    diffClmNos = new int[diffClmNms.length];
212                    for( int i=0; i<diffClmNms.length; i++ ) {
213                            diffClmNos[i] = model.getColumnNo( diffClmNms[i] );
214            //              if( debug ) { println( "DEBUG:" + diffClmNms[i] + ":[" + diffClmNos[i] + "]" ); }
215            //              int no = model.getColumnNo( diffClmNms[i] );
216            //              if( no >= 0 ) { diffClmNos[no] = i+1; }              // 行番号åˆ?‚’?‹1しておくã€?
217                    }
218    
219                    readF2Data( file2,encode2 );
220            }
221    
222            /**
223             * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
224             * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç­?に使用しますã?
225             *
226             * @param   isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
227             */
228            public void end( final boolean isOK ) {
229                    Closer.ioClose( reader1 );
230                    reader1 = null;
231            }
232    
233            /**
234             * こã?ãƒ??タの処ç�?�«おいて、次の処ç�?�Œ出来るかどã�?�‹を問ã�?�ˆわせますã?
235             * こã?呼び出し1回毎に、次のãƒ??タを取得する準備を行いますã?
236             *
237             * @return      処ç�?�§きる:true / 処ç�?�§きなã�?false
238             */
239            public boolean next() {
240                    if( nameNull ) { return false; }
241    
242                    boolean flag = false;
243                    try {
244                            while((line = reader1.readLine()) != null) {
245                                    inCount1++ ;
246                                    if( line.length() == 0 || line.charAt( 0 ) == '#' ) { continue; }
247                                    else {
248                                            flag = true;
249                                            break;
250                                    }
251                            }
252                    }
253                    catch (IOException ex) {
254                            String errMsg = "ファイル読込みエラー[" + infile1 + "]:(" + inCount1 + ")"  ;
255                            throw new RuntimeException( errMsg,ex );
256                    }
257                    return flag;
258            }
259    
260            /**
261             * æœ??にã€?行データである LineModel を作æ?しまã�?
262             * FirstProcess は、次ã€?�¨処ç�?‚’チェインしてã�?��æœ??の行データã‚?
263             * 作æ?して、後続ã? ChainProcess クラスに処ç�?ƒ‡ータを渡しますã?
264             *
265             * ファイルより読み込んだ?‘行ã?ãƒ??タã‚?ãƒ??ブルモãƒ?ƒ«に
266             * セãƒ?ƒˆするようにåˆ?‰²しまã�?
267             * なおã?読込みは?ŒNAMEé ?›®åˆ?‚’読み込みますã?ãƒ??タ件数が少なã�??合ã?ã€?
268             * "" をセãƒ?ƒˆしておきますã?
269             *
270             * @param       rowNo   処ç�?¸­の行番号
271             *
272             * @return      処ç�?¤‰換後ã?LineModel
273             */
274            public LineModel makeLineModel( final int rowNo ) {
275                    outCount++ ;
276                    String[] vals = StringUtil.csv2Array( line ,separator1.charAt(0) );
277    
278                    int len = vals.length;
279                    for( int clmNo=0; clmNo<model.size(); clmNo++ ) {
280                            int no = clmNos[clmNo];
281                            if( len > no ) {
282                                    model.setValue( clmNo,vals[no] );
283                            }
284                            else {
285                                    // EXCEL がã?終端TABを削除してしまã�?�Ÿめã?少なã�??合ã?埋めるã?
286                                    model.setValue( clmNo,"" );
287                            }
288                    }
289                    model.setRowNo( rowNo ) ;
290    
291    //              if( display ) { println( model.dataLine() ); }          // 5.1.2.0 (2010/01/01) display の条件変更
292    
293                    return action( model );
294            }
295    
296            /**
297             * キーと、DIFF設定å?を比è¼?�—、action に応じã�?LineModel を返しますã?
298             * action には、ONLY,DIFF,INTERSEC が指定できますã?
299             *   ONLY      inFile1 のみに存在する行ã?場合ã?inFile1 のレコードを返しますã?
300             *   DIFF      inFile1 と inFile2 に存在しã?かつ、DIFF値が異なるã?inFile1 のレコードを返しますã?
301             *   INTERSEC  inFile1 と inFile2 に存在しã?かつ、DIFF値も同じã?inFile1 のレコードを返しますã?
302             * inFile2 側をキャãƒ?‚·ュしますã?で、inFile2 側のãƒ??タ量が少なã�?§˜に選んでくださいã€?
303             *
304             * @param       model LineModelオブジェクãƒ?
305             *
306             * @return      実行後ã?LineModel
307             */
308            private LineModel action( final LineModel model ) {
309                    LineModel rtn = null;
310                    Object[] obj = model.getValues();
311    
312                    // キーのカラãƒ?‚’合æ?しますã?
313                    StringBuilder keys = new StringBuilder();
314                    for( int i=0; i<keyClmNos.length; i++ ) {
315                            keys.append( obj[keyClmNos[i]] ).append( "," );
316                    }
317    
318                    String data = file2Map.get( keys.toString() );
319            //      if( debug ) { println( "DEBUG:" + keys.toString() + ":" + data ); }
320    
321                    if( "ONLY".equalsIgnoreCase( actCmnd ) && data == null ) {
322                            if( debug ) { println( "DEBUG:ONLY\t" + keys.toString() ); }
323                            rtn = model;
324                    }
325                    else {
326                            // DIFF値のカラãƒ?‚’合æ?しますã?
327                            StringBuilder vals = new StringBuilder();
328                            for( int i=0; i<diffClmNos.length; i++ ) {
329                                    vals.append( obj[diffClmNos[i]] ).append( "," );
330                            }
331    
332                            boolean eq = ( vals.toString() ).equals( data );
333    
334                            if( "DIFF".equalsIgnoreCase( actCmnd ) && ! eq ) {
335                                    if( debug ) { println( "DEBUG:DIFF\t" + keys.toString() + "\t" + data + "\t" + vals.toString() ); }
336                                    rtn = model;
337                            }
338                            else if( "INTERSEC".equalsIgnoreCase( actCmnd ) && eq ) {
339                                    if( debug ) { println( "DEBUG:INTERSEC\t" + keys.toString() + "\t" + data ); }
340                                    rtn = model;
341                            }
342                    }
343                    if( display && rtn != null ) { println( rtn.dataLine() ); }
344                    return rtn;
345            }
346    
347            /**
348             * BufferedReader よりã€?NAME 行ã?é ?›®名情報を読み取りますã?
349             * ãƒ??タカラãƒ?‚ˆり前にã€??目名情報を示ã�?"#Name" が存在する仮定で取り込みますã?
350             * こã?行ã?、ファイルの形式に無関係に、TAB で区åˆ?‚‰れてã�?�¾すã?
351             *
352             * @param       reader PrintWriterオブジェクãƒ?
353             *
354             * @return      カラãƒ?��配å?(存在しなã�??合ã?、サイズ?�ã?配å?)
355             */
356            private String[] readName( final BufferedReader reader ) {
357                    try {
358                            // 4.0.0 (2005/01/31) line 変数名変更
359                            String line1;
360                            while((line1 = reader.readLine()) != null) {
361                                    inCount1++ ;
362                                    if( line1.length() == 0 ) { continue; }
363                                    if( line1.charAt(0) == '#' ) {
364                                            String key = line1.substring( 0,5 );
365                                            if( key.equalsIgnoreCase( "#NAME" ) ) {
366                                                    // è¶?‚¤レギュラー処ç�?æœ??の TAB 以前ã?æ–?­—ã?無視するã?
367                                                    String line2 = line1.substring( line1.indexOf( TAB )+1 );
368                                                    return StringUtil.csv2Array( line2 ,TAB.charAt(0) );
369                                            }
370                                            else  { continue; }
371                                    }
372                                    else {
373                                            String errMsg = "#NAME が見つかる前にãƒ??タが見つかりましたã€?;
374                                            throw new RuntimeException( errMsg );
375                                    }
376                            }
377                    }
378                    catch (IOException ex) {
379                            String errMsg = "ファイル読込みエラー[" + infile1 + "]:(" + inCount1 + ")"  ;
380                            throw new RuntimeException( errMsg,ex );
381                    }
382                    return new String[0];
383            }
384    
385            /**
386             * ファイル属æ?を読取り、キーæƒ??を作æ?しã?å†?ƒ¨メモリマップにキャãƒ?‚·ュしますã?
387             * こã?マップをもとに、inFile1 のãƒ??タをé?次読み取って、å?ç�?‚’進めますã?
388             *
389             * @param       file2 読取りå…??ファイル
390             * @param       encode2 ファイルのエンコーãƒ?
391             */
392            private void readF2Data( final File file2, final String encode2 ) {
393                    BufferedReader reader2 = null;
394                    try {
395                            if( debug ) { println( "DEBUG:\tFile2="+ file2 + " 初期処ç�? ); }
396                            reader2 = FileUtil.getBufferedReader( file2,encode2 );
397                            // 4.0.0 (2005/01/31) line 変数名変更
398                            String line1;
399                            char sep2 = separator2.charAt(0);
400                            while((line1 = reader2.readLine()) != null) {
401                                    inCount2++ ;
402                                    if( line1.length() == 0 ) { continue; }
403                                    if( line1.charAt(0) == '#' ) { continue; }
404                                    else {
405                                            // è¶?‚¤レギュラー処ç�?æœ??の TAB 以前ã?æ–?­—ã?無視するã?
406                                            String line2 = line1.substring( line1.indexOf( separator2 )+1 );
407                                            Object[] obj = StringUtil.csv2Array( line2 , sep2 );
408    
409                                            // キーのカラãƒ?‚’合æ?しますã?
410                                            StringBuilder keys = new StringBuilder();
411                                            for( int i=0; i<keyClmNos.length; i++ ) {
412                                                    keys.append( obj[keyClmNos[i]] ).append( "," );
413                                            }
414    
415                                            // DIFF値のカラãƒ?‚’合æ?しますã?
416                                            StringBuilder vals = new StringBuilder();
417                                            for( int i=0; i<diffClmNos.length; i++ ) {
418                                                    vals.append( obj[diffClmNos[i]] ).append( "," );
419                                            }
420    
421                                            if( debug ) { println( "DEBUG:\t" + keys.toString() + "\t" + vals.toString() ); }
422    
423                                            file2Map.put( keys.toString(), vals.toString() );
424                                    }
425                            }
426                            if( debug ) { println( "DEBUG:\t======初期処ç�?µ‚äº?=====" ); }
427                    }
428                    catch (IOException ex) {
429                            String errMsg = "ファイル読込みエラー[" + infile2 + "]:(" + inCount2 + ")"  ;
430                            throw new RuntimeException( errMsg,ex );
431                    }
432                    finally {
433                            Closer.ioClose( reader2 );
434                    }
435            }
436    
437            /**
438             * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
439             * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
440             * こã?æ–?­—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
441             * 形式で出してくださいã€?
442             *
443             * @return   処ç�?µ�果のレポã?ãƒ?
444             */
445            public String report() {
446                    String report = "[" + getClass().getName() + "]" + CR
447                                    + TAB + "Input  File1  : " + infile1    + CR
448                                    + TAB + "Input  File2  : " + infile2    + CR
449                                    + TAB + "Input  Count1 : " + inCount1   + CR
450                                    + TAB + "Input  Count2 : " + inCount2   + CR
451                                    + TAB + "Output Count  : " + outCount ;
452    
453                    return report ;
454            }
455    
456            /**
457             * こã?クラスの使用方法を返しますã?
458             *
459             * @return      こã?クラスの使用方æ³?
460             */
461            public String usage() {
462                    StringBuilder buf = new StringBuilder();
463    
464                    buf.append( "Process_TableDiffは、ファイルから読み取ったå?容をã?LineModel に設定後ã?"         ).append( CR );
465                    buf.append( "下流に渡すã?FirstProcess インターフェースの実è£?‚¯ラスですã?"                                    ).append( CR );
466                    buf.append( CR );
467                    buf.append( "DBTableModel 形式ã?ファイルを読み取って、各行を LineModel にセãƒ?ƒˆしてã€?          ).append( CR );
468                    buf.append( "下æµ?プロセスチェインのãƒ??タは上流から下流に渡されますã?)に渡しますã?"              ).append( CR );
469                    buf.append( CR );
470                    buf.append( "引数æ–?­—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
471                    buf.append( "引数æ–?­—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に"             ).append( CR );
472                    buf.append( "繋げてくださいã€?                                                                                                                              ).append( CR );
473                    buf.append( CR ).append( CR );
474    
475                    buf.append( getArgument().usage() ).append( CR );
476    
477                    return buf.toString();
478            }
479    
480            /**
481             * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
482             *
483             * @param       args    コマンド引数配å?
484             */
485            public static void main( final String[] args ) {
486                    LogWriter.log( new Process_TableDiff().usage() );
487            }
488    }