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 */ 016package org.opengion.fukurou.util; 017 018import java.io.File; 019import java.io.IOException; 020 021import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 022import org.opengion.fukurou.system.HybsConst; // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system 023import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system 024 025/** 026 * AbstractConnect.java は、共通的に使用される ファイル伝送関連の基本機能を実装した、Abstractクラスです。 027 * 028 * -host=サーバー -user=ユーザー -passwd=パスワード -remoteFile=接続先のファイル名 を必須設定します。 029 * -localFile=ローカルのファイル名は、必須ではありませんが、-command=DEL の場合にのみ不要であり、 030 * それ以外の command の場合は、必要です。 031 * 032 * -command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] は、サーバーに対しての処理の方法を指定します。 033 * GET:サーバーからローカルにファイル転送します(初期値) 034 * PUT:ローカルファイルをサーバーに PUT(STORE、SAVE、UPLOAD、などと同意語)します。 035 * DEL:サーバーの指定のファイルを削除します。この場合のみ、-localFile 属性の指定は不要です。 036 * GETDIR,PUTDIR,DELDIR:指定のフォルダ以下のファイルを処理します。 037 * 038 * -mkdirs=[true/false] は、受け側のファイル(GET時:LOCAL、PUT時:サーバー)に取り込むファイルのディレクトリが 039 * 存在しない場合に、作成するかどうかを指定します(初期値:true) 040 * 通常、サーバーに、フォルダ階層を作成してPUTする場合、動的にフォルダ階層を作成したいケースで便利です。 041 * 逆に、フォルダは確定しており、指定フォルダ以外に PUT するのはバグっていると事が分かっている場合には 042 * false に設定して、存在しないフォルダにPUT しようとすると、エラーになるようにします。 043 * 044 * 引数文字列中に空白を含む場合は、ダブルコーテーション("") で括って下さい。 045 * 引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に 046 * 繋げてください。 047 * 048 * @og.formSample 049 * XXXConnect -host=サーバー -user=ユーザー -passwd=パスワード -remoteFile=接続先のファイル名 [-localFile=ローカルのファイル名] 050 * [-command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] ] [-display=[true/false] ] ・・・・ 051 * 052 * -host=サーバー :接続先のサーバーのアドレスまたは、サーバー名 053 * -user=ユーザー :接続するユーザー名 054 * -passwd=パスワード :接続するユーザーのパスワード 055 * -remoteFile=接続先のファイル名 :接続先のサーバー側のファイル名。PUT,GET 関係なくFTP側として指定します。 056 * [-localFile=ローカルのファイル名] :ローカルのファイル名。PUT,GET 関係なくローカルファイルを指定します。 057 * [-port=ポート ] :接続するサーバーのポートを指定します。 058 * [-command=[GET/PUT/DEL] ] :サーバー側での処理の方法を指定します。 059 * [GETDIR/PUTDIR/DELDIR]] GET:FTP⇒LOCAL、PUT:LOCAL⇒FTP への転送です(初期値:GET) 060 * DEL:FTPファイルを削除します。 061 * GETDIR,PUTDIR,DELDIR 指定のフォルダ以下のファイルを処理します。 062 * [-mkdirs=[true/false] ] :受け側ファイル(GET時:LOCAL、PUT時:サーバー)にディレクトリを作成するかどうか(初期値:true) 063 * (false:ディレクトリが無ければ、エラーにします。) 064 * [-encode=エンコード名 ] :日本語ファイル名などのエンコード名を指定します(初期値:Windows-31J) 065 * [-timeout=タイムアウト[秒] ] :Dataタイムアウト(初期値:600 [秒]) 066 * [-display=[false/true] ] :trueは、検索状況を表示します(初期値:false) 067 * [-debug=[false|true] ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 068 * 069 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 070 * 071 * @version 5.0 072 * @author Kazuhiko Hasegawa 073 * @since JDK5.0, 074 */ 075public abstract class AbstractConnect implements ConnectIF { 076 /** システムの改行コードを設定します。*/ 077 protected static final String CR = HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 078 /** StringBilderなどの初期値を設定します。 {@value} */ 079 protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 080 081 private final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE ); 082 083 /** 正常フラグ {@value} */ 084 public static final boolean FLAG_OK = true; 085 /** 異常フラグ {@value} */ 086 public static final boolean FLAG_NG = false; 087 /** Dataタイムアウト(初期値:{@value} [秒]) */ 088 public static final int TIMEOUT = 600 ; 089 090 /** サーバー */ 091 protected String host ; // サーバー 092 /** ユーザー */ 093 protected String user ; // ユーザー 094 /** パスワード */ 095 protected String passwd ; // パスワード 096 /** ポート */ 097 protected String port ; // ポート 098 099 /** ディレクトリを作成するかどうか */ 100 protected boolean isMkdirs = true; // 受け側ファイルにディレクトリを作成するかどうか。true:作成する / false:無ければエラー 101 /** Dataタイムアウト */ 102 protected int timeout = TIMEOUT; // Dataタイムアウト(初期値:600 [秒]) 103 /** 検索状況を表示するかどうか */ 104 protected boolean isDisplay ; // trueは、検索状況を表示します(初期値:false) 105 /** デバッグ情報を表示するかどうか */ 106 protected boolean isDebug ; // デバッグ情報を標準出力に表示する(true)かしない(false)か 107 108 /** 109 * デフォルトコンストラクター 110 * 111 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 112 */ 113 protected AbstractConnect() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 114 115 /** 116 * サーバーへの接続、ログインを行います。 117 */ 118 @Override // ConnectIF 119 public abstract void connect() ; 120 121 /** 122 * command , localFile , remoteFile を元に、FTP処理を行います。 123 * 124 * このメソッドは、connect( String , String , String )メソッド、および、 125 * paramInit() 実行後に、呼び出す必要があります。 126 * 127 * ※ 内部で、command に指定できない値をセットしたか、何らかのエラーが発生した場合。 128 * 129 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。 130 * 131 * @param command GET:HOST⇒LOCAL 、PUT:LOCAL⇒HOST 、DEL:HOSTファイルを削除 132 * @param localFile ローカルのファイル名 133 * @param remoteFile HOST接続先のファイル名 134 */ 135 @Override // ConnectIF 136 public void action( final String command, final String localFile, final String remoteFile ) { 137 final String rmtFile = remoteFile.replace( '\\','/' ); 138 if( isDisplay ) { 139 System.out.println( "ACTION: command=" + command + ",localFile=" + localFile + ",remoteFile=" + rmtFile ); 140 } 141 142 try { 143 // 実際の処理を行います。(GET/PUT/DEL) 144 if( "GET".equals( command ) ) { 145 actionGET( localFile, rmtFile ); 146 } 147 else if( "PUT".equals( command ) ) { 148 actionPUT( localFile, rmtFile ); 149 } 150 else if( "DEL".equals( command ) ) { 151 actionDEL( rmtFile ); 152 } 153 else if( "GETDIR".equals( command ) ) { 154 actionGETdir( localFile, rmtFile ); 155 } 156 else if( "PUTDIR".equals( command ) ) { 157 actionPUTdir( localFile, rmtFile ); 158 } 159 else if( "DELDIR".equals( command ) ) { 160 actionDELdir( rmtFile ); 161 } 162 else { 163 errAppend( "commandは、GET/PUT/DEL/GETDIR/PUTDIR/DELDIR から指定ください。" ); 164 errAppend( " command = [" , command , "]" ); 165 throw new OgRuntimeException( getErrMsg() ); 166 } 167 } 168 // 6.1.0.0 (2014/12/26) findBugs: Bug type REC_CATCH_EXCEPTION (click for details) 169 // 例外がスローされないのに例外をキャッチしています。 170 catch( final IOException ex ) { 171 errAppend( "Server action Error." ); 172 errAppend( " command = [" , command , "]" ); 173 errAppend( " localFile = [" , localFile , "]" ); 174 errAppend( " remoteFile = [" , remoteFile , "]" ); 175 errAppend( ex.getMessage() ); 176 if( isDebug ) { System.err.println( ThrowUtil.ogStackTrace( ex ) ); } // 6.4.2.0 (2016/01/29) 177 throw new OgRuntimeException( getErrMsg(),ex ); 178 } 179 } 180 181 /** 182 * サーバーとの接続をクローズします。 183 * 184 * ログインされている場合は、ログアウトも行います。 185 * コネクトされている場合は、ディスコネクトします。 186 */ 187 @Override // ConnectIF 188 public abstract void disconnect(); 189 190 /** 191 * command="GET" が指定されたときの処理を行います。 192 * 193 * 接続先のサーバー側のファイル名をローカルにダウンロードします。 194 * 195 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 196 * 197 * @param localFile ローカルのファイル名 198 * @param remoteFile 接続先のファイル名 199 * @throws IOException 何らかのエラーが発生した場合。 200 */ 201 protected abstract void actionGET( final String localFile, final String remoteFile ) throws IOException ; 202 203 /** 204 * command="GETDIR" が指定されたときの処理を行います。 205 * 206 * 接続先のサーバー側のディレクトリ以下をローカルディレクトリに階層構造のままダウンロードします。 207 * 208 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 209 * 210 * @param localDir ローカルのディレクトリ名 211 * @param remoteDir 接続先のディレクトリ名 212 * @throws IOException 何らかのエラーが発生した場合。 213 */ 214 protected abstract void actionGETdir( final String localDir, final String remoteDir ) throws IOException ; 215 216 /** 217 * command="PUT" が指定されたときの処理を行います。 218 * 219 * ローカルファイルを、接続先のサーバー側にアップロードします。 220 * 221 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 222 * 223 * @param localFile ローカルのファイル名 224 * @param remoteFile 接続先のファイル名 225 * @throws IOException 何らかのエラーが発生した場合。 226 */ 227 protected abstract void actionPUT( final String localFile, final String remoteFile ) throws IOException ; 228 229 /** 230 * command="PUTDIR" が指定されたときの処理を行います。 231 * 232 * ローカルファイルのディレクトリ以下を、接続先のサーバー側のディレクトリに階層構造のままアップロードします。 233 * 234 * @og.rev 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラーを返します。 235 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 236 * 237 * @param localDir ローカルのディレクトリ名 238 * @param remoteDir 接続先のディレクトリ名 239 * @throws IOException 何らかのエラーが発生した場合。 240 */ 241 protected void actionPUTdir( final String localDir, final String remoteDir ) throws IOException { 242 final File[] lclFiles = new File( localDir ).listFiles(); 243 244 // 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラーを返します。 245 if( lclFiles == null ) { 246 errAppend( "指定のディレクトリは、アクセスできません。" ); 247 errAppend( " localDir = [" , localDir , "]" ); 248 throw new OgRuntimeException( getErrMsg() ); 249 } 250 251 for( int i=0; i<lclFiles.length; i++ ) { 252 final String lcl = lclFiles[i].getName(); 253 if( lclFiles[i].isDirectory() ) { 254 actionPUTdir( addFile( localDir,lcl ),addFile( remoteDir,lcl ) ); 255 } 256 else { 257 actionPUT( addFile( localDir,lcl ),addFile( remoteDir,lcl ) ); 258 } 259 } 260 } 261 262 /** 263 * command="DEL" が指定されたときの処理を行います。 264 * 265 * 接続先のサーバー側のファイル名を削除します。 266 * 267 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 268 * 269 * @param remoteFile 接続先のファイル名 270 * @throws IOException 何らかのエラーが発生した場合。 271 */ 272 protected abstract void actionDEL( final String remoteFile ) throws IOException ; 273 274 /** 275 * command="DELDIR" が指定されたときの処理を行います。 276 * 277 * 接続先のサーバー側のディレクトリ名を削除します。 278 * 279 * @og.rev 6.0.2.5 (2014/10/31) throws で、Exception を返していたのを、IOException に限定します。 280 * 281 * @param remoteDir 接続先のディレクトリ名 282 * @throws IOException 何らかのエラーが発生した場合。 283 */ 284 protected abstract void actionDELdir( final String remoteDir ) throws IOException ; 285 286 /** 287 * ローカルファイルのディレクトリを作成します。 288 * 289 * 引数のファイル名は、ファイル名です。作成するディレクトリは、そのファイルオブジェクトの 290 * getParentFile() で取得されるディレクトリまでを作成します。 291 * 292 * ※ ローカルファイルのディレクトリの作成に失敗した場合は、RuntimeException が throw されます。 293 * 294 * @param localFile ローカルのファイル名 295 * @throws IOException File#getCanonicalFile() で発生する入出力エラー 296 */ 297 protected void makeLocalDir( final String localFile ) throws IOException { 298 final File fileDir = new File( localFile ).getCanonicalFile().getParentFile(); 299 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 300 if( !fileDir.exists() && !fileDir.mkdirs() ) { 301 errAppend( "ローカルファイルのディレクトリの作成に失敗しました。" ); 302 errAppend( " localFile = [" , localFile , "]" ); 303 throw new OgRuntimeException( getErrMsg() ); 304 } 305 } 306 307 /** 308 * ディレクトリとファイル名を合成します。 309 * 310 * 単純に、ディレクトリの最後と、ファイルの最初の、"/" をチェックし、 311 * 存在すれば、そのまま、結合し、存在しなければ、"/" を追加します。 312 * 両方に存在する場合は、片方をはずします。 313 * 314 * @param dir ディレクトリ名 315 * @param file ファイル名 316 * 317 * @return 合成されたファイル名 318 */ 319 protected String addFile( final String dir,final String file ) { 320 final String filepath ; 321 322 final char ch1 = dir.charAt( dir.length()-1 ) ; // ディレクトリの最後の文字 323 final char ch2 = file.charAt(0) ; // ファイルの最初の文字 324 325 if( ch1 == '/' || ch1 == '\\' ) { 326 if( ch2 == '/' || ch2 == '\\' ) { // 両方とも存在する。 327 filepath = dir + file.substring(1); 328 } 329 else { 330 filepath = dir + file; 331 } 332 } 333 else { 334 if( ch2 == '/' || ch2 == '\\' ) { // 片方のみ存在する。 335 filepath = dir + file; 336 } 337 else { 338 filepath = dir + "/" + file; 339 } 340 } 341 342 return filepath ; 343 } 344 345 /** 346 * サーバーの、ホスト、ユーザー、パスワードを設定します。 347 * 348 * @param host サーバー 349 * @param user ユーザー 350 * @param passwd パスワード 351 */ 352 @Override // ConnectIF 353 public void setHostUserPass( final String host , final String user , final String passwd ) { 354 this.host = host; 355 this.user = user; 356 this.passwd = passwd; 357 } 358 359 /** 360 * 接続に利用するポート番号を設定します。 361 * 362 * @param port 接続に利用するポート番号 363 */ 364 @Override // ConnectIF 365 public void setPort( final String port ) { 366 if( port != null ) { 367 this.port = port ; 368 } 369 } 370 371 /** 372 * ポートを取得します。 373 * 設定されている生のport属性(nullもありうる)を返します。 374 * 375 * @return ポート 376 */ 377 protected String getPort() { return port; } 378 379 /** 380 * ポートを取得します。 381 * 設定されているport属性が、nullの場合は、defPortを返します。 382 * 383 * @param defPort port が null の場合の初期値 384 * 385 * @return ポート 386 */ 387 protected int getPort( final int defPort) { 388 return ( port == null ) ? defPort : Integer.parseInt( port ); 389 } 390 391 /** 392 * それぞれの受け側ファイルにディレクトリを作成するかどうか(初期値:true:作成する)。 393 * 394 * -mkdirs=[true/false] は、受け側のファイル(GET時:LOCAL、PUT時:サーバー)に取り込むファイルのディレクトリが 395 * 存在しない場合に、作成するかどうかを指定します(初期値:true) 396 * 通常、サーバーに、フォルダ階層を作成してPUTする場合、動的にフォルダ階層を作成したいケースで便利です。 397 * 逆に、フォルダは確定しており、指定フォルダ以外に PUT するのはバグっていると事が分かっている場合には 398 * false に設定して、存在しないフォルダにPUT しようとすると、エラーになるようにします。 399 * 400 * @param isMkdirs 受け側ファイルにディレクトリを作成するかどうか。true:作成する 401 */ 402 @Override // ConnectIF 403 public void setMkdirs( final boolean isMkdirs ) { 404 this.isMkdirs = isMkdirs ; 405 } 406 407 /** 408 * タイムアウトを秒で指定します(初期値:600 [秒])。 409 * 410 * オリジナルの FTPClient#setDataTimeout( int ) は、ミリ秒でセット 411 * しますが、ここのメソッドでは、秒でセットします。 412 * 413 * @param timeout タイムアウト[秒] 414 * @throws RuntimeException タイムアウトの指定が大きすぎた場合 415 */ 416 @Override // ConnectIF 417 public void setTimeout( final int timeout ) { 418 if( Integer.MAX_VALUE / 1000 < timeout ) { 419 errAppend( "タイムアウトの指定が大きすぎます。" ); 420 errAppend( " timeout = [" , timeout , "]" ); 421 throw new OgRuntimeException( getErrMsg() ); 422 } 423 424 this.timeout = timeout ; 425 } 426 427 /** 428 * 実行状況の表示可否 を設定します(初期値:false:表示しない)。 429 * 430 * @param isDisplay 実行状況の表示可否 431 */ 432 @Override // ConnectIF 433 public void setDisplay( final boolean isDisplay ) { 434 this.isDisplay = isDisplay ; 435 } 436 437 /** 438 * デバッグ情報の表示可否 を設定します(初期値:false:表示しない)。 439 * 440 * @param isDebug デバッグ情報の表示可否 441 */ 442 @Override // ConnectIF 443 public void setDebug( final boolean isDebug ) { 444 this.isDebug = isDebug ; 445 } 446 447 /** 448 * 処理中に発生したエラーメッセージをセットします。 449 * 450 * @param msg メッセージ化したいオブジェクト 451 */ 452 protected void errAppend( final Object msg ) { 453 errMsg.append( String.valueOf(msg) ).append( CR ); 454 } 455 456 /** 457 * 処理中に発生したエラーメッセージをセットします。 458 * 459 * @param msgs Object... 460 */ 461 protected void errAppend( final Object... msgs ) { 462 for( int i=0; i<msgs.length; i++ ) { 463 errMsg.append( String.valueOf(msgs[i]) ); 464 } 465 466 errMsg.append( CR ); 467 } 468 469 /** 470 * 処理中に発生したエラーメッセージを取り出します。 471 * 472 * @return エラーメッセージ 473 * @og.rtnNotNull 474 */ 475 @Override // ConnectIF 476 public String getErrMsg() { 477 return errMsg.toString(); 478 } 479}