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