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 }