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