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 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 270 if( !fileDir.exists() && !fileDir.mkdirs() ) { 271 errAppend( "ローカルファイルのディレクトリの作成に失敗しました。" ); 272 errAppend( " localFile = [" , localFile , "]" ); 273 throw new RuntimeException( getErrMsg() ); 274 } 275 } 276 277 /** 278 * ディレクトリとファイル名を合成します。 279 * 280 * 単純に、ディレクトリの最後と、ファイルの最初の、"/" をチェックし、 281 * 存在すれば、そのまま、結合し、存在しなければ、"/" を追加します。 282 * 両方に存在する場合は、片方をはずします。 283 * 284 * @param dir ディレクトリ名 285 * @param file ファイル名 286 * 287 * @return 合成されたファイル名 288 */ 289 protected String addFile( final String dir,final String file ) { 290 final String filepath ; 291 292 char ch1 = dir.charAt( dir.length()-1 ) ; // ディレクトリの最後の文字 293 char ch2 = file.charAt( 0 ) ; // ファイルの最初の文字 294 295 if( ch1 == '/' || ch1 == '\\' ) { 296 if( ch2 == '/' || ch2 == '\\' ) { // 両方とも存在する。 297 filepath = dir + file.substring(1); 298 } 299 else { 300 filepath = dir + file; 301 } 302 } 303 else { 304 if( ch2 == '/' || ch2 == '\\' ) { // 片方のみ存在する。 305 filepath = dir + file; 306 } 307 else { 308 filepath = dir + "/" + file; 309 } 310 } 311 312 return filepath ; 313 } 314 315 /** 316 * サーバーの、ホスト、ユーザー、パスワードを設定します。 317 * 318 * @param host サーバー 319 * @param user ユーザー 320 * @param passwd パスワード 321 */ 322 @Override 323 public void setHostUserPass( final String host , final String user , final String passwd ) { 324 this.host = host; 325 this.user = user; 326 this.passwd = passwd; 327 } 328 329 /** 330 * 接続に利用するポート番号を設定します。 331 * 332 * @param port 接続に利用するポート番号 333 */ 334 @Override 335 public void setPort( final String port ) { 336 if( port != null ) { 337 this.port = port ; 338 } 339 } 340 341 /** 342 * ポートを取得します。 343 * 設定されている生のport属性(nullもありうる)を返します。 344 * 345 * @return ポート 346 */ 347 protected String getPort() { return port; } 348 349 /** 350 * ポートを取得します。 351 * 設定されているport属性が、nullの場合は、defPortを返します。 352 * 353 * @param defPort port が null の場合の初期値 354 * 355 * @return ポート 356 */ 357 protected int getPort( final int defPort) { 358 return ( port == null ) ? defPort : Integer.parseInt( port ); 359 } 360 361 /** 362 * それぞれの受け側ファイルにディレクトリを作成するかどうか(初期値:true:作成する)。 363 * 364 * -mkdirs=[true/false] は、受け側のファイル(GET時:LOCAL、PUT時:サーバー)に取り込むファイルのディレクトリが 365 * 存在しない場合に、作成するかどうかを指定します(初期値:true) 366 * 通常、サーバーに、フォルダ階層を作成してPUTする場合、動的にフォルダ階層を作成したいケースで便利です。 367 * 逆に、フォルダは確定しており、指定フォルダ以外に PUT するのはバグっていると事が分かっている場合には 368 * false に設定して、存在しないフォルダにPUT しようとすると、エラーになるようにします。 369 * 370 * @param isMkdirs 受け側ファイルにディレクトリを作成するかどうか。true:作成する 371 */ 372 @Override 373 public void setMkdirs( final boolean isMkdirs ) { 374 this.isMkdirs = isMkdirs ; 375 } 376 377 /** 378 * タイムアウトを秒で指定します(初期値:600 [秒])。 379 * 380 * オリジナルの FTPClient#setDataTimeout( int ) は、ミリ秒でセット 381 * しますが、ここのメソッドでは、秒でセットします。 382 * 383 * @param timeout タイムアウト[秒] 384 * @throws RuntimeException タイムアウトの指定が大きすぎた場合 385 */ 386 @Override 387 public void setTimeout( final int timeout ) { 388 if( Integer.MAX_VALUE / 1000 < timeout ) { 389 errAppend( "タイムアウトの指定が大きすぎます。" ); 390 errAppend( " timeout = [" , timeout , "]" ); 391 throw new RuntimeException( getErrMsg() ); 392 } 393 394 this.timeout = timeout ; 395 } 396 397 /** 398 * 実行状況の表示可否 を設定します(初期値:false:表示しない)。 399 * 400 * @param isDisplay 実行状況の表示可否 401 */ 402 @Override 403 public void setDisplay( final boolean isDisplay ) { 404 this.isDisplay = isDisplay ; 405 } 406 407 /** 408 * デバッグ情報の表示可否 を設定します(初期値:false:表示しない)。 409 * 410 * @param isDebug デバッグ情報の表示可否 411 */ 412 @Override 413 public void setDebug( final boolean isDebug ) { 414 this.isDebug = isDebug ; 415 } 416 417 /** 418 * 処理中に発生したエラーメッセージをセットします。 419 * 420 * @param msg メッセージ化したいオブジェクト 421 */ 422 protected void errAppend( final Object msg ) { 423 errMsg.append( String.valueOf(msg) ).append( CR ); 424 } 425 426 /** 427 * 処理中に発生したエラーメッセージをセットします。 428 * 429 * @param msgs Object... 430 */ 431 protected void errAppend( final Object... msgs ) { 432 for( int i=0; i<msgs.length; i++ ) { 433 errMsg.append( String.valueOf(msgs[i]) ); 434 } 435 436 errMsg.append( CR ); 437 } 438 439 /** 440 * 処理中に発生したエラーメッセージを取り出します。 441 * 442 * @return エラーメッセージ 443 */ 444 @Override 445 public String getErrMsg() { 446 return errMsg.toString(); 447 } 448}