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.LinkedHashMap ;
026
027 import java.io.File;
028 import java.io.BufferedReader;
029 import java.io.IOException;
030
031 /**
032 * Process_TableReaderは、ファイルから読み取った?容を?LineModel に設定後?
033 * 下流に渡す?FirstProcess インターフェースの実?ラスです?
034 *
035 * DBTableModel 形式?ファイルを読み取って、各行を LineModel にセ?して?
036 * 下?プロセスチェインの??タは上流から下流に渡されます?)に渡します?
037 *
038 * columns 属?は?NAME で列カラ?外部から?する?合に使用します?
039 * こ?属?とuseNumber属?は独立して?すが、?には?NAME を指?
040 * する場合?、useNumber="true"として、行番号??使用しますし、外部から
041 * ?する?合?、useNumber="false"にして先?から読み取ります?
042 * (自動セ?ではな??で、?に応じて設定してください)
043 * useNumber の初期値は?true" です?
044 *
045 * ※ 注?
046 * Process_TableReader では、セパレータ??で区?て読み込???、前後???゚ー??
047 * 削除して?す?
048 *
049 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ??
050 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に
051 * 繋げてください?
052 *
053 * @og.formSample
054 * Process_TableReader -infile=INFILE -sep=, -encode=UTF-8 -columns=AA,BB,CC
055 *
056 * -infile=入力ファイル? ??力ファイル?
057 * [-existCheck=存在確? ] ?ファイルが存在しな??合エラーにする(初期値:true)
058 * [-sep=セパレータ?? ] ?区???初期値:タ?
059 * [-encode=?エンコー? ] ??力ファイルのエンコードタイ?
060 * [-columns=読み取りカラ?] ??力カラ?(カンマ区?)
061 * [-useNumber=[true/false] ] ?行番号を使用する(true)か使用しな?false)か?
062 * [-display=[false/true] ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
063 * [-debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
064 *
065 * @version 4.0
066 * @author Kazuhiko Hasegawa
067 * @since JDK5.0,
068 */
069 public class Process_TableReader extends AbstractProcess implements FirstProcess {
070 private String separator = TAB; // ?区???
071 private String infile = null;
072 private BufferedReader reader = null;
073 private LineModel model = null;
074 private String line = null;
075 private int[] clmNos = null; // ファイルのヘッ??のカラ?号
076 private boolean useNumber = true; // 5.2.2.0 (2010/11/01) 行番号を使用する(true)か使用しな?false)?
077 private boolean nameNull = false; // ?件??タ?true
078 private boolean display = false; // 表示しな?
079 private boolean debug = false; // 5.7.3.0 (2014/02/07) ????
080
081 private int inCount = 0;
082 private int outCount = 0;
083
084 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map
085 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map
086
087 static {
088 mustProparty = new LinkedHashMap<String,String>();
089 mustProparty.put( "infile", "入力ファイル?(??)" );
090
091 usableProparty = new LinkedHashMap<String,String>();
092 usableProparty.put( "existCheck", "ファイルが存在しな??合エラーにする(初期値:true)" );
093 usableProparty.put( "sep", "区???初期値:タ?" );
094 usableProparty.put( "encode", "入力ファイルのエンコードタイ? );
095 usableProparty.put( "columns", "入力カラ?(カンマ区?)" );
096 usableProparty.put( "useNumber", "行番号を使用する(true)か使用しな?false)? ); // 5.2.2.0 (2010/11/01)
097 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? +
098 CR + " (初期値:false:表示しな?" );
099 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? +
100 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ????
101 }
102
103 /**
104 * ?ォルトコンストラクター?
105 * こ?クラスは、動??されます??ォルトコンストラクターで?
106 * super クラスに対して、?な初期化を行っておきます?
107 *
108 */
109 public Process_TableReader() {
110 super( "org.opengion.fukurou.process.Process_TableReader",mustProparty,usableProparty );
111 }
112
113 /**
114 * プロセスの初期化を行います?初めに??、呼び出されます?
115 * 初期処?ファイルオープン??オープン?に使用します?
116 *
117 * @og.rev 5.2.2.0 (2010/11/01) useNumber属?の追?
118 *
119 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク?
120 */
121 public void init( final ParamProcess paramProcess ) {
122 Argument arg = getArgument();
123
124 infile = arg.getProparty("infile");
125 boolean existCheck = arg.getProparty("existCheck",true);
126 String encode = arg.getProparty("encode",System.getProperty("file.encoding"));
127 separator = arg.getProparty("sep",separator );
128 String clms = arg.getProparty("columns" );
129 useNumber = arg.getProparty("useNumber",useNumber); // 5.2.2.0 (2010/11/01)
130 display = arg.getProparty("display",display);
131 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ????
132 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ????
133
134 if( infile == null ) {
135 String errMsg = "ファイル名が?されて?せん? ;
136 throw new RuntimeException( errMsg );
137 }
138
139 File file = new File( infile );
140
141 if( ! file.exists() ) {
142 if( existCheck ) {
143 String errMsg = "ファイルが存在しません?ile=[" + file + "]" ;
144 throw new RuntimeException( errMsg );
145 }
146 else {
147 nameNull = true; return ;
148 }
149 }
150
151 if( ! file.isFile() ) {
152 String errMsg = "ファイル名を?してください?ile=[" + file + "]" ;
153 throw new RuntimeException( errMsg );
154 }
155
156 reader = FileUtil.getBufferedReader( file,encode );
157
158 // 5.2.2.0 (2010/11/01) names の外部??処?先に行う?
159 // String[] clmNames = readName( reader ); // ファイルのカラ?配?
160 // if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; }
161
162 final String[] names ;
163 if( clms != null ) {
164 names = StringUtil.csv2Array( clms ); // ??カラ?配?
165 }
166 else {
167 // 5.2.2.0 (2010/11/01) names の外部??処?先に行う?
168 String[] clmNames = readName( reader ); // ファイルのカラ?配?
169 if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; }
170 names = clmNames;
171 }
172
173 model = new LineModel();
174 model.init( names );
175
176 if( display ) { println( model.nameLine() ); }
177
178 // clmNos = new int[names.length];
179 // for( int i=0; i<clmNames.length; i++ ) {
180 // int no = model.getColumnNo( clmNames[i] );
181 // if( no >= 0 ) { clmNos[no] = i+1; } // 行番号??1しておく?
182 // }
183 clmNos = new int[names.length];
184 for( int i=0; i<names.length; i++ ) {
185 int no = model.getColumnNo( names[i] );
186 // 5.2.2.0 (2010/11/01) useNumber="true"の場合?、行番号??1しておく?
187 if( no >= 0 ) { clmNos[no] = (useNumber) ? i+1 : i ; }
188 }
189 }
190
191 /**
192 * プロセスの終?行います??に??、呼び出されます?
193 * 終???ファイルクローズ??クローズ?に使用します?
194 *
195 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
196 */
197 public void end( final boolean isOK ) {
198 Closer.ioClose( reader );
199 reader = null;
200 }
201
202 /**
203 * こ???タの処?おいて、次の処?出来るかど?を問?わせます?
204 * こ?呼び出し1回毎に、次の??タを取得する準備を行います?
205 *
206 * @og.rev 5.2.2.0 (2010/11/01) ""で囲われて???タに改行が入って?場合?対?
207 *
208 * @return 処?きる:true / 処?きな?false
209 */
210 public boolean next() {
211 if( nameNull ) { return false; }
212
213 boolean flag = false;
214 try {
215 while((line = reader.readLine()) != null) {
216 inCount++ ;
217 if( line.length() == 0 || line.charAt( 0 ) == '#' ) { continue; }
218 else {
219 // 5.2.2.0 (2010/11/01) findbugs 対???の + 連結と、?判定ロジ?)
220 int quotCount = StringUtil.countChar( line, '"' );
221 if( quotCount % 2 != 0 ) {
222 String addLine = null;
223 StringBuilder buf = new StringBuilder( line );
224 while(quotCount % 2 != 0 && (addLine = reader.readLine()) != null) {
225 if( addLine.length() == 0 || addLine.charAt( 0 ) == '#' ) { continue; }
226 buf.append( CR ).append( addLine );
227 quotCount += StringUtil.countChar( addLine, '"' );
228 }
229 line = buf.toString();
230 }
231 flag = true;
232 break;
233 }
234 }
235 }
236 catch (IOException ex) {
237 String errMsg = "ファイル読込みエラー[" + reader.toString() + "]" ;
238 throw new RuntimeException( errMsg,ex );
239 }
240 if( debug ) { println( line ); } // 5.7.3.0 (2014/02/07) ????
241 return flag;
242 }
243
244 /**
245 * ??に?行データである LineModel を作?しま?
246 * FirstProcess は、次?処?チェインして???の行データ?
247 * 作?して、後続? ChainProcess クラスに処?ータを渡します?
248 *
249 * ファイルより読み込んだ?行???タ???ブルモ?に
250 * セ?するように?しま?
251 * なお?読込みは?NAME??読み込みます???タ件数が少な??合??
252 * "" をセ?しておきます?
253 *
254 * @param rowNo 処?の行番号
255 *
256 * @return 処?換後?LineModel
257 */
258 public LineModel makeLineModel( final int rowNo ) {
259 outCount++ ;
260 String[] vals = StringUtil.csv2Array( line ,separator.charAt(0) );
261
262 int len = vals.length;
263 for( int clmNo=0; clmNo<model.size(); clmNo++ ) {
264 int no = clmNos[clmNo];
265 if( len > no ) {
266 model.setValue( clmNo,vals[no] );
267 }
268 else {
269 // EXCEL が?終端TABを削除してしま?め?少な??合?埋める?
270 model.setValue( clmNo,"" );
271 }
272 }
273 model.setRowNo( rowNo ) ;
274
275 if( display ) { println( model.dataLine() ); }
276
277 return model;
278 }
279
280 /**
281 * BufferedReader より?NAME 行??名情報を読み取ります?
282 * ??タカラ?り前に??目名情報を示?"#Name" が存在する仮定で取り込みます?
283 * こ?行?、ファイルの形式に無関係に、TAB で区?れて?す?
284 *
285 * @param reader PrintWriterオブジェク?
286 *
287 * @return カラ?配?(存在しな??合?、サイズ??配?)
288 */
289 private String[] readName( final BufferedReader reader ) {
290 try {
291 // 4.0.0 (2005/01/31) line 変数名変更
292 String line1;
293 while((line1 = reader.readLine()) != null) {
294 inCount++ ;
295 if( line1.length() == 0 ) { continue; }
296 if( line1.charAt(0) == '#' ) {
297 String key = line1.substring( 0,5 );
298 if( key.equalsIgnoreCase( "#NAME" ) ) {
299 // ?レギュラー処???の TAB 以前???無視する?
300 String line2 = line1.substring( line1.indexOf( TAB )+1 );
301 return StringUtil.csv2Array( line2 ,TAB.charAt(0) );
302 }
303 else { continue; }
304 }
305 else {
306 String errMsg = "#NAME が見つかる前に??タが見つかりました?;
307 throw new RuntimeException( errMsg );
308 }
309 }
310 }
311 catch (IOException ex) {
312 String errMsg = "ファイル読込みエラー[" + reader.toString() + "]" ;
313 throw new RuntimeException( errMsg,ex );
314 }
315 return new String[0];
316 }
317
318 /**
319 * プロセスの処?果のレポ?ト表現を返します?
320 * 処??ログラ?、?力件数、?力件数などの??です?
321 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
322 * 形式で出してください?
323 *
324 * @return 処?果のレポ??
325 */
326 public String report() {
327 String report = "[" + getClass().getName() + "]" + CR
328 + TAB + "Input File : " + infile + CR
329 + TAB + "Input Count : " + inCount + CR
330 + TAB + "Output Count : " + outCount ;
331
332 return report ;
333 }
334
335 /**
336 * こ?クラスの使用方法を返します?
337 *
338 * @og.rev 5.2.2.0 (2010/11/01) useNumber属?のコメント追?
339 *
340 * @return こ?クラスの使用方?
341 */
342 public String usage() {
343 StringBuilder buf = new StringBuilder();
344
345 buf.append( "Process_TableReaderは、ファイルから読み取った?容を?LineModel に設定後?" ).append( CR );
346 buf.append( "下流に渡す?FirstProcess インターフェースの実?ラスです?" ).append( CR );
347 buf.append( CR );
348 buf.append( "DBTableModel 形式?ファイルを読み取って、各行を LineModel にセ?して? ).append( CR );
349 buf.append( "下?プロセスチェインの??タは上流から下流に渡されます?)に渡します?" ).append( CR );
350 buf.append( CR );
351 buf.append( "columns 属?は?NAME で列カラ?外部から?する?合に使用します?" ).append( CR );
352 buf.append( "こ?属?とuseNumber属?は独立して?すが、?には?NAME を指? ).append( CR );
353 buf.append( "する場合?、useNumber=\"true\"として、行番号??使用しますし、外部から" ).append( CR );
354 buf.append( "?する?合?、useNumber=\"false\"にして先?から読み取ります?" ).append( CR );
355 buf.append( "(自動セ?ではな??で、?に応じて設定してください)" ).append( CR );
356 buf.append( "useNumber の初期値は、\"true\" です?" ).append( CR );
357 buf.append( CR );
358 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
359 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR );
360 buf.append( "繋げてください? ).append( CR );
361 buf.append( CR ).append( CR );
362
363 buf.append( getArgument().usage() ).append( CR );
364
365 return buf.toString();
366 }
367
368 /**
369 * こ?クラスは、main メソ?から実行できません?
370 *
371 * @param args コマンド引数配?
372 */
373 public static void main( final String[] args ) {
374 LogWriter.log( new Process_TableReader().usage() );
375 }
376 }