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.FileUtil;
020 import org.opengion.fukurou.util.Closer ;
021 import org.opengion.fukurou.util.LogWriter;
022 import org.opengion.fukurou.util.CommentLineParser;
023
024 import java.util.Map ;
025 import java.util.LinkedHashMap ;
026
027 import java.io.File;
028 import java.io.PrintWriter;
029 import java.io.BufferedReader;
030 import java.io.IOException;
031
032 /**
033 * Process_FileCopy は、上流から受け取っ?FileLineModel を??る?
034 * ChainProcess インターフェースの実?ラスです?
035 *
036 * 上流から受け取っ?FileLineModel の ファイルから、inPath の共通パス
037 * 以下?ファイルを?outPath の共通パス以下にコピ?します?
038 * コピ?の種類?、バイナリか??ストで、テキスト?場合?、エンコー?
039 * 変換も行うことが可能です?
040 * inPath と outPath が同じ?また?、outPath が未設定?場合?、?力と出力が
041 * 同じです?で、???身のエンコード変換処?行うことになります?
042 *
043 * コピ?されるファイルのファイル名?、?力ファイル名と同?す?保存される
044 * フォル?異なります?(同?することも可能です?)
045 *
046 * useOmitCmnt=true に設定すると、ファイル中のコメントを除外してコピ?します?
047 * ただし?使用できるのは、アスキーファイル(binary=false)の時だけです?
048 *
049 * 上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク?
050 * である、Process_FileSearch を使用するのが?便利です?それ以外?クラス?
051 * 使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡?
052 * できれば、使用可能です?
053 *
054 * 引数??中に空白を含??合?、ダブルコー??ション("") で括って下さ??
055 * 引数??の ?』?前後には、空白は挟めません。??key=value の様に
056 * 繋げてください?
057 *
058 * @og.formSample
059 * Process_FileCopy -inPath=入力?通パス -inEncode=Windows-31J -outPath=出力?通パス -outEncode=UTF-8
060 *
061 * -inPath=入力?通パス ?上流で検索されたファイルパスの共通部?
062 * [ -inEncode=入力エンコー? ] ??力ファイルのエンコードタイ?
063 * [ -outPath=出力?通パス ] ??力するファイルパスの共通部?
064 * [ -outEncode=出力エンコー? ] ??力ファイルのエンコードタイ?
065 * [ -binary=[false/true] ] ?trueは、バイナリファイルのコピ?(初期値:false)
066 * [ -changeCrLf=[false/true] ] ?trueは、バイナリファイルのコピ?時にCR+LFに変換しま?初期値:false)
067 * [ -keepTimeStamp=[false/true]] ?trueは、コピ???ファイルのタイ?タンプで作?しま?初期値:false)
068 * [ -useOmitCmnt=[false/true] ] ?ファイル中のコメントを除外してコピ?を行うかど?を指?初期値:false)
069 * [ -display=[false/true] ] ?trueは、コピ?状況を表示しま?初期値:false)
070 * [ -debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
071 *
072 * @version 4.0
073 * @author Kazuhiko Hasegawa
074 * @since JDK5.0,
075 */
076 public class Process_FileCopy extends AbstractProcess implements ChainProcess {
077 private File tempFile = null;
078
079 private String inPath = null;
080 private String inEncode = null;
081 private String outPath = null;
082 private String outEncode = null;
083 private boolean binary = false;
084 private boolean changeCrLf = false; // 4.2.2.0 (2008/05/10)
085 private boolean keepTimeStamp = false; // 5.1.5.0 (2010/04/01)
086 private boolean useOmitCmnt = false; // 5.7.4.0 (2014/03/07)
087 private boolean display = false;
088 private boolean debug = false; // 5.7.3.0 (2014/02/07) ????
089
090 private int inPathLen = 0;
091 private boolean isEquals = false;
092 private int inCount = 0;
093
094 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map
095 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map
096
097 static {
098 mustProparty = new LinkedHashMap<String,String>();
099 mustProparty.put( "inPath", "コピ???ファイル基準パス" );
100
101 usableProparty = new LinkedHashMap<String,String>();
102 usableProparty.put( "inEncode", "コピ???ファイルのエンコードタイ? );
103 usableProparty.put( "outPath", "コピ?先?ファイル基準パス" );
104 usableProparty.put( "outEncode", "コピ?先?ファイルのエンコードタイ? );
105 usableProparty.put( "binary", "trueは、バイナリファイルをコピ?しま?初期値:false)" );
106 usableProparty.put( "changeCrLf", "trueは、バイナリファイルのコピ?時にCR+LFに変換しま?初期値:false)" ); // 4.2.2.0 (2008/05/10)
107 usableProparty.put( "keepTimeStamp","trueは、コピ???ファイルのタイ?タンプで作?しま?初期値:false)" ); // 5.1.5.0 (2010/04/01)
108 usableProparty.put( "useOmitCmnt" ,"ファイル中のコメントを除外してコピ?を行うかど?を指?初期値:false)" ); // 5.7.4.0 (2014/03/07)
109 usableProparty.put( "display", "trueは、コピ?状況を表示しま?初期値:false)" );
110 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? +
111 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ????
112 }
113
114 /**
115 * ?ォルトコンストラクター?
116 * こ?クラスは、動??されます??ォルトコンストラクターで?
117 * super クラスに対して、?な初期化を行っておきます?
118 *
119 */
120 public Process_FileCopy() {
121 super( "org.opengion.fukurou.process.Process_FileCopy",mustProparty,usableProparty );
122 }
123
124 /**
125 * プロセスの初期化を行います?初めに??、呼び出されます?
126 * 初期処?ファイルオープン??オープン?に使用します?
127 *
128 * @og.rev 4.2.2.0 (2008/05/10) changeCrLf 属?対?
129 * @og.rev 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
130 *
131 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク?
132 */
133 public void init( final ParamProcess paramProcess ) {
134 Argument arg = getArgument();
135
136 inPath = arg.getProparty("inPath" );
137 outPath = arg.getProparty("outPath" );
138 inEncode = arg.getProparty("inEncode" ,System.getProperty("file.encoding"));
139 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding"));
140 binary = arg.getProparty("binary" ,binary);
141 changeCrLf = arg.getProparty("changeCrLf" ,changeCrLf); // 4.2.2.0 (2008/05/10)
142 keepTimeStamp = arg.getProparty("keepTimeStamp" ,keepTimeStamp); // 5.1.5.0 (2010/04/01)
143 useOmitCmnt = arg.getProparty("useOmitCmnt" ,useOmitCmnt); // 5.7.4.0 (2014/03/07)
144 display = arg.getProparty("display",display);
145 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ????
146 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ????
147
148 inPathLen = inPath.length();
149
150 // 入力と出力が同じか?
151 isEquals = outPath == null || inPath.equalsIgnoreCase( outPath );
152
153 if( binary ) {
154 // 4.2.2.0 (2008/05/10) 判定ミスの修正
155 if( ! inEncode.equalsIgnoreCase( outEncode ) ) {
156 String errMsg = "バイナリコピ?時には、?出力?エンコード?同じ?があります?" + CR
157 + " inEncode=[" + inEncode + "] , outEncode=[" + outEncode + "]" ;
158 throw new RuntimeException( errMsg );
159 }
160 if( isEquals ) {
161 String errMsg = "入出力が同じファイルのバイナリコピ?はできません? + CR
162 + " inPath=[" + inPath + "] , outPath=[" + outPath + "]" ;
163 throw new RuntimeException( errMsg );
164 }
165 // 5.7.4.0 (2014/03/07) コメント部?削除する機?は、binary では使えません?
166 if( useOmitCmnt ) {
167 String errMsg = "コメント部?削除する機?(useOmitCmnt=true)は、バイナリコピ?では使えません? + CR
168 + " inPath=[" + inPath + "] , outPath=[" + outPath + "]" ;
169 throw new RuntimeException( errMsg );
170 }
171 }
172
173 // 入力と出力が同じ場合?、中間ファイルを作?します?
174 if( isEquals ) {
175 try {
176 tempFile = File.createTempFile( "X", ".tmp", new File( outPath ) );
177 tempFile.deleteOnExit();
178 }
179 catch( IOException ex ) {
180 String errMsg = "中間ファイル作?でエラーが発生しました? + CR
181 + " outPath=[" + outPath + "]" ;
182 throw new RuntimeException( errMsg,ex );
183 }
184 }
185 }
186
187 /**
188 * プロセスの終?行います??に??、呼び出されます?
189 * 終???ファイルクローズ??クローズ?に使用します?
190 *
191 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
192 */
193 public void end( final boolean isOK ) {
194 tempFile = null;
195 }
196
197 /**
198 * 引数の LineModel を??るメソ?です?
199 * 変換処?? LineModel を返します?
200 * 後続??行わな?????タのフィルタリングを行う場?は?
201 * null ??タを返します?つまり?null ??タは、後続??行わな?
202 * フラグの代わりにも使用して?す?
203 * なお?変換処?? LineModel と、オリジナルの LineModel が?
204 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す?
205 * ドキュメントに明記されて???合?、副作用が問題になる?合??
206 * ???とに自?コピ?(クローン)して下さ??
207 *
208 * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します?
209 * @og.rev 4.2.2.0 (2008/05/10) changeCrLf 属?対?
210 * @og.rev 4.2.3.0 (2008/05/26) LineModel ?FileLineModel でな??合?処?
211 * @og.rev 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
212 * @og.rev 5.1.6.0 (2010/05/01) changeCrLf 属?が?.FileUtil#changeCrLfcopy メソ?への移動に伴??
213 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
214 *
215 * @param data オリジナルのLineModel
216 *
217 * @return 処?換後?LineModel
218 */
219 public LineModel action( final LineModel data ) {
220 inCount++ ;
221 final FileLineModel fileData ;
222 if( data instanceof FileLineModel ) {
223 fileData = (FileLineModel)data ;
224 }
225 else {
226 // LineModel ?FileLineModel でな??合?オブジェクトを作?します?
227 fileData = new FileLineModel( data );
228 // String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ;
229 // throw new RuntimeException( errMsg );
230 }
231
232 if( debug ) { println( "Before:" + data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
233
234 File inFile = fileData.getFile() ;
235 if( ! inFile.isFile() ) {
236 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
237 return data;
238 }
239
240 // ファイル名を作?します?
241 // ファイル名?、引数ファイル?から、inPath を引き、outPath を加えます?
242 File outFile = new File( outPath, inFile.getAbsolutePath().substring( inPathLen ) );
243 fileData.setFile( outFile );
244
245 // if( display ) { println( inFile + " => " + outFile ); }
246
247 // 入出力が異なる??
248 if( !isEquals ) {
249 tempFile = outFile;
250 File parent = outFile.getParentFile();
251 if( parent != null && ! parent.exists() && !parent.mkdirs() ) {
252 String errMsg = "??フォル?作?できませんでした?" + parent + "]" + CR
253 + " inCount=[" + inCount + "]件" + CR
254 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
255 throw new RuntimeException( errMsg );
256 }
257 }
258
259 if( binary ) {
260 // FileUtil.copy( inFile,tempFile );
261 // FileUtil.copy( inFile,tempFile,changeCrLf ); // 4.2.2.0 (2008/05/10)
262 // 5.1.6.0 (2010/05/01) changeCrLfcopy 対?
263 if( changeCrLf ) { FileUtil.changeCrLfcopy( inFile,tempFile ); }
264 else { FileUtil.copy( inFile,tempFile,keepTimeStamp ); }
265 }
266 else {
267 BufferedReader reader = FileUtil.getBufferedReader( inFile ,inEncode );
268 PrintWriter writer = FileUtil.getPrintWriter( tempFile ,outEncode );
269
270 try {
271 String line1;
272 if( useOmitCmnt ) { // 5.7.4.0 (2014/03/07) コメント部?削除してコピ?
273 CommentLineParser clp = new CommentLineParser();
274 while((line1 = reader.readLine()) != null) {
275 line1 = clp.line( line1 );
276 if( line1 != null ) {
277 writer.println( line1 );
278 }
279 }
280 }
281 else {
282 // 従来のコピ?。ループ中で、if するのが嫌だった?で、?離しました?
283 while((line1 = reader.readLine()) != null) {
284 writer.println( line1 );
285 }
286 }
287 }
288 catch( IOException ex ) {
289 String errMsg = "ファイルコピ?中に例外が発生しました?" + data.getRowNo() + "]件目" + CR
290 + " inFile=[" + inFile + "] , tempFile=[" + tempFile + "]" + CR
291 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
292 throw new RuntimeException( errMsg,ex );
293 }
294 finally {
295 Closer.ioClose( reader ) ;
296 Closer.ioClose( writer ) ;
297 }
298 }
299
300 if( isEquals ) {
301 if( !outFile.delete() ) {
302 String errMsg = "??ファイルを削除できませんでした?" + outFile + "]" + CR
303 + " inCount=[" + inCount + "]件" + CR
304 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
305 throw new RuntimeException( errMsg );
306 }
307
308 if( !tempFile.renameTo( outFile ) ) {
309 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" + CR
310 + " inCount=[" + inCount + "]件" + CR
311 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
312 throw new RuntimeException( errMsg );
313 }
314 }
315
316 // 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
317 if( keepTimeStamp ) {
318 if( !outFile.setLastModified( inFile.lastModified() ) ) {
319 String errMsg = "lastModified 時間の設定が、できませんでした?" + outFile + "]" + CR
320 + " inCount=[" + inCount + "]件" + CR
321 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
322 throw new RuntimeException( errMsg );
323 }
324 }
325
326 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
327 return data ;
328 }
329
330 /**
331 * プロセスの処?果のレポ?ト表現を返します?
332 * 処??ログラ?、?力件数、?力件数などの??です?
333 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
334 * 形式で出してください?
335 *
336 * @return 処?果のレポ??
337 */
338 public String report() {
339 String report = "[" + getClass().getName() + "]" + CR
340 + TAB + "Copy Count : " + inCount + CR
341 + TAB + "inPath : " + inPath + CR
342 + TAB + "inEncode : " + inEncode + CR
343 + TAB + "outPath : " + outPath + CR
344 + TAB + "outEncode : " + outEncode + CR
345 + TAB + "binary : " + binary ;
346
347 return report ;
348 }
349
350 /**
351 * こ?クラスの使用方法を返します?
352 *
353 * @return こ?クラスの使用方?
354 */
355 public String usage() {
356 StringBuilder buf = new StringBuilder();
357
358 buf.append( "Process_FileCopy は、上流から受け取っ?FileLineModelを??る?" ).append( CR );
359 buf.append( "ChainProcess インターフェースの実?ラスです?" ).append( CR );
360 buf.append( CR );
361 buf.append( "上流から受け取っ?FileLineModel の ファイルから、inPath の共通パス" ).append( CR );
362 buf.append( "以下?ファイルを?outPath の共通パス以下にコピ?します?" ).append( CR );
363 buf.append( "コピ?の種類?、バイナリか??ストで、テキスト?場合?、エンコー? ).append( CR );
364 buf.append( "変換も行うことが可能です?" ).append( CR );
365 buf.append( "inPath と outPath が同じ?また?、outPath が未設定?場合?、?力と出力が" ).append( CR );
366 buf.append( "同じです?で、???身のエンコード変換処?行うことになります?" ).append( CR );
367 buf.append( CR );
368 buf.append( "コピ?されるファイルのファイル名?、?力ファイル名と同?す?保存される" ).append( CR );
369 buf.append( "フォル?異なります?(同?することも可能です?)" ).append( CR );
370 buf.append( CR );
371 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR );
372 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR );
373 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR );
374 buf.append( "できれば、使用可能です?" ).append( CR );
375 buf.append( CR );
376 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
377 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR );
378 buf.append( "繋げてください? ).append( CR );
379 buf.append( CR ).append( CR );
380
381 buf.append( getArgument().usage() ).append( CR );
382
383 return buf.toString();
384 }
385
386 /**
387 * こ?クラスは、main メソ?から実行できません?
388 *
389 * @param args コマンド引数配?
390 */
391 public static void main( final String[] args ) {
392 LogWriter.log( new Process_FileCopy().usage() );
393 }
394 }