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 }