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.FileInputStream; 019import java.io.FileOutputStream; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.io.BufferedInputStream; 023import java.io.BufferedOutputStream; 024import java.io.IOException; 025import java.util.Map; 026import java.util.LinkedHashMap ; 027import java.net.MalformedURLException ; 028 029import jcifs.smb.SmbFile; 030 031/** 032 * SMBConnect.java は、共通的に使用される Smb関連の基本機能を実装した、クラスです。 033 * 034 * これは、jcifs.smb パッケージをベースに開発されています。 035 * このクラスの実行には、jcifs-1.3.14.jar が必要です。 036 * 037 * 接続先のURL schemeは、以下の形式をしています。 038 * smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]] 039 * このURLは、内部的に自動作成します。/[[share/[dir/]file]] 部分が、remoteFile として指定する部分になります。 * 040 * 041 * -host=Smbサーバー -user=ユーザー -passwd=パスワード -remoteFile=Smb先のファイル名 を必須設定します。 042 * -localFile=ローカルのファイル名は、必須ではありませんが、-command=DEL の場合にのみ不要であり、 043 * それ以外の command の場合は、必要です。 044 * 045 * -command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] は、SFTPサーバーに対しての処理の方法を指定します。 046 * GET:Smbサーバーからローカルにファイル転送します(初期値) 047 * PUT:ローカルファイルをSmbサーバーに PUT(STORE、SAVE、UPLOAD、などと同意語)します。 048 * DEL:Smbサーバーの指定のファイルを削除します。この場合のみ、-localFile 属性の指定は不要です。 049 * GETDIR,PUTDIR,DELDIR:指定のフォルダ以下のファイルを処理します。 050 * 051 * -mkdirs=[true/false] は、受け側のファイル(GET時:LOCAL、PUT時:Smbサーバー)に取り込むファイルのディレクトリが 052 * 存在しない場合に、作成するかどうかを指定します(初期値:true)。 053 * 通常、Smbサーバーに、フォルダ階層を作成してPUTする場合、動的にフォルダ階層を作成したいケースで便利です。 054 * 逆に、フォルダは確定しており、指定フォルダ以外に PUT するのはバグっていると事が分かっている場合には 055 * false に設定して、存在しないフォルダにPUT しようとすると、エラーになるようにします。 056 * 057 * 引数文字列中に空白を含む場合は、ダブルコーテーション("") で括って下さい。 058 * 引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に 059 * 繋げてください。 060 * 061 * @og.formSample 062 * SMBConnect -host=Smbサーバー -user=ユーザー -passwd=パスワード -remoteFile=Smb先のファイル名 [-localFile=ローカルのファイル名] 063 * [-command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] ] ] 064 * 065 * -host=Smbサーバー :接続先のSmbサーバーのアドレスまたは、サーバー名 066 * -user=ユーザー :接続するユーザー名 067 * -passwd=パスワード :接続するユーザーのパスワード 068 * -remoteFile=Smb先のファイル名 :接続先のSmbサーバー側のファイル名。PUT,GET 関係なくSmb側として指定します。 069 * [-localFile=ローカルのファイル名] :ローカルのファイル名。PUT,GET 関係なくローカルファイルを指定します。 070 * [-domain=ドメイン ] :接続するサーバーのドメインを指定します。 071 * [-port=ポート ] :接続するサーバーのポートを指定します。 072 * [-command=[GET/PUT/DEL] ] :Smbサーバー側での処理の方法を指定します。 073 * [GETDIR/PUTDIR/DELDIR]] GET:Smb⇒LOCAL、PUT:LOCAL⇒Smb への転送です(初期値:GET) 074 * DEL:Smbファイルを削除します。 075 * GETDIR,PUTDIR,DELDIR 指定のフォルダ以下のファイルを処理します。 076 * [-mkdirs=[true/false] ] :受け側ファイル(GET時:LOCAL、PUT時:Smbサーバー)にディレクトリを作成するかどうか(初期値:true) 077 * (false:ディレクトリが無ければ、エラーにします。) 078 * [-display=[false/true] ] :trueは、検索状況を表示します(初期値:false) 079 * [-debug=[false|true] ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 080 * 081 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 082 * 083 * @version 5.0 084 * @author Kazuhiko Hasegawa 085 * @since JDK5.0, 086 */ 087public final class SMBConnect extends AbstractConnect { 088 private String domain = null; // ドメイン 089 private String connURI = null; // Smb接続する場合のURI文字列(の先頭) 090 091 /** 092 * デフォルトコンストラクター 093 */ 094// public SMBConnect() { 095// } 096 097 /** 098 * Smbサーバーへの接続、ログインを行います。 099 * 100 * このメソッドは、初期化メソッドです。 101 * Smbサーバーへの接続、ログインを行いますので、複数ファイルを転送する 102 * ケースでは、最初に1度だけ呼び出すだけです。 103 * 接続先を変更する場合は、もう一度このメソッドをコールする必要があります。 104 * (そのような場合は、通常、オブジェクトを構築しなおす方がよいと思います。) 105 * 接続時のアドレスは、下記の形式になりますが、ファイル名の箇所は、action 時に指定するため、 106 * ここでは、先頭部分を先に用意しておきます。 107 * smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]] 108 * 109 */ 110 @Override 111 public void connect() { 112 if( isDisplay ) { System.out.println( "CONNECT: HOST=" + host + ",USER=" + user + ",PORT=" + port ); } 113 114 if( host == null ) { 115 errAppend( "host は、必須です。" ); 116 throw new RuntimeException( getErrMsg() ); 117 } 118 119 // smb://[[[domain;]username[:password]@]server[:port] ここまで作成 120 connURI = "smb://" 121 + ((domain == null) ? "" : domain + ";" ) 122 + ((user == null) ? "" : user ) 123 + ((passwd == null) ? "" : ":" + passwd ) 124 + ((user == null) ? "" : "@" ) 125 + host 126 + ((port == null) ? "" : ":" + port ) ; 127 128 if( isDebug ) { System.out.println( "connURI=" + connURI ); } 129 } 130 131 /** 132 * Smbサーバーとの接続をクローズします。 133 * 134 * ここでは、何も処理を行いません。 135 * 136 */ 137 @Override 138 public void disconnect() { 139 if( isDisplay ) { System.out.println( "DISCONNECT:" ); } 140 } 141 142 /** 143 * command="GET" が指定されたときの処理を行います。 144 * 145 * 接続先のSmbサーバー側のファイル名をローカルにダウンロードします。 146 * 147 * @param localFile ローカルのファイル名 148 * @param remoteFile Smb先のファイル名 149 * @throws IOException 入出力エラーが発生したとき 150 */ 151 @Override 152 protected void actionGET( final String localFile, final String remoteFile ) throws IOException { 153 if( isDebug ) { System.out.println( "GET: " + remoteFile + " => " + localFile ); } 154 155 SmbFile rmtFile = makeSmbURI( remoteFile ); 156 157 // GET(DOWNLOAD)取得時は、ローカルファイルのディレクトリを作成する必要がある。 158 if( isMkdirs ) { 159 makeLocalDir( localFile ); 160 } 161 162 InputStream input = null; 163 OutputStream output = null; 164 try { 165// input = new BufferedInputStream( new SmbFileInputStream( remoteFile ) ); 166 input = new BufferedInputStream( rmtFile.getInputStream() ); 167 output = new FileOutputStream( localFile ); 168 FileUtil.copy( input,output ); 169 } 170 finally { 171 Closer.ioClose( input ); 172 Closer.ioClose( output ); 173 } 174 } 175 176 /** 177 * command="GETDIR" が指定されたときの処理を行います。 178 * 179 * 接続先のSmbサーバー側のディレクトリ以下をローカルディレクトリに階層構造のままダウンロードします。 180 * 181 * @param localDir ローカルのディレクトリ名 182 * @param remoteDir Smb先のディレクトリ名 183 * @throws IOException 入出力エラーが発生したとき 184 */ 185 @Override 186 protected void actionGETdir( final String localDir, final String remoteDir ) throws IOException { 187 SmbFile rmtFile = makeSmbURI( remoteDir ); 188 189 SmbFile[] rmtFiles = rmtFile.listFiles(); 190 for( int i=0; i<rmtFiles.length; i++ ) { 191 String rmt = rmtFiles[i].getName(); 192 if( rmtFiles[i].isDirectory() ) { 193 actionGETdir( addFile( localDir,rmt ),addFile( remoteDir,rmt ) ); 194 } 195 else { 196 actionGET( addFile( localDir,rmt ),addFile( remoteDir,rmt ) ); 197 } 198 } 199 } 200 201 /** 202 * command="PUT" が指定されたときの処理を行います。 203 * 204 * ローカルファイルを、接続先のSmbサーバー側にアップロードします。 205 * 206 * @param localFile ローカルのファイル名 207 * @param remoteFile Smb先のファイル名 208 * @throws IOException 入出力エラーが発生したとき 209 */ 210 @Override 211 protected void actionPUT( final String localFile, final String remoteFile ) throws IOException { 212 if( isDebug ) { System.out.println( "PUT: " + localFile + " => " + remoteFile ); } 213 214 SmbFile rmtFile = makeSmbURI( remoteFile ); 215 216 // 存在チェック:すでに存在している場合は、先に削除します。 217 if( rmtFile.exists() ) { rmtFile.delete() ; } 218 else { 219 // PUT(UPLOAD)登録時は、リモートファイルのディレクトリを作成する必要がある。 220 if( isMkdirs ) { 221 String tmp = rmtFile.getParent(); 222 SmbFile dir = new SmbFile( tmp ); 223 if( !dir.exists() ) { dir.mkdirs() ; } 224 } 225 } 226 227 InputStream input = null; 228 OutputStream output = null; 229 try { 230 input = new FileInputStream( localFile ); 231// output = new BufferedOutputStream( new SmbFileOutputStream( remoteFile ) ); 232 output = new BufferedOutputStream( rmtFile.getOutputStream() ); 233 234 FileUtil.copy( input,output ); 235 } 236 finally { 237 Closer.ioClose( input ); 238 Closer.ioClose( output ); 239 } 240 } 241 242 /** 243 * command="DEL" が指定されたときの処理を行います。 244 * 245 * 接続先のSmbサーバー側のファイル名を削除します。 246 * 247 * @param remoteFile Smb先のファイル名 248 * @throws IOException 入出力エラーが発生したとき 249 */ 250 @Override 251 protected void actionDEL( final String remoteFile ) throws IOException { 252 if( isDebug ) { System.out.println( "DEL: " + remoteFile ); } 253 254 SmbFile rmtFile = makeSmbURI( remoteFile ); 255 rmtFile.delete() ; 256 } 257 258 /** 259 * command="DELDIR" が指定されたときの処理を行います。 260 * 261 * 接続先のSmbサーバー側のディレクトリ以下をローカルディレクトリに階層構造のままダウンロードします。 262 * 263 * @param remoteDir Smb先のディレクトリ名 264 * @throws IOException 入出力エラーが発生したとき 265 */ 266 @Override 267 protected void actionDELdir( final String remoteDir ) throws IOException { 268 SmbFile rmtFile = makeSmbURI( remoteDir ); 269 SmbFile[] rmtFiles = rmtFile.listFiles(); 270 for( int i=0; i<rmtFiles.length; i++ ) { 271 String rmt = addFile( remoteDir,rmtFiles[i].getName() ); 272 if( rmtFiles[i].isDirectory() ) { 273 actionDELdir( rmt ); 274 } 275 else { 276 actionDEL( rmt ); 277// rmtFiles[i].delete(); 278 } 279 } 280 rmtFile.delete(); 281 } 282 283 /** 284 * SMB形式のURLを作成します。 285 * 286 * 処理的には、内部で先に作成済みの connURI と、引数のファイルパスを文字列連結します。 287 * connURI の最後には、"/" を付加していませんので、引数のファイルパスに、 288 * "/" を含まない場合は、"/" を付加します。 289 * 290 * smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]] 291 * 292 * @param remoteFile Smb先のファイル名 293 * 294 * @return SMB形式のURL 295 */ 296 private SmbFile makeSmbURI( final String remoteFile ) throws MalformedURLException { 297 final String smbFile ; 298 299 if( remoteFile.startsWith( "smb://" ) ) { 300 smbFile = remoteFile; 301 } 302 else if( remoteFile.startsWith( "/" ) ) { 303 smbFile = connURI + remoteFile ; 304 } 305 else { 306 smbFile = connURI + "/" + remoteFile ; 307 } 308 309// SmbFile rmtFile = new SmbFile( smbFile ); 310// return rmtFile; 311 return new SmbFile( smbFile ); 312 } 313 314 /** 315 * 接続先にログインするドメインを設定します。 316 * 317 * @param domain 接続先にログインするドメイン 318 */ 319 public void setDomain( final String domain ) { 320 this.domain = domain ; 321 } 322 323// ******************************************************************************************************* // 324// 以下、単独で使用する場合の main処理 325// ******************************************************************************************************* // 326 327 private static final Map<String,String> mustProparty ; // [プロパティ]必須チェック用 Map 328 private static final Map<String,String> usableProparty ; // [プロパティ]整合性チェック Map 329 330 static { 331 mustProparty = new LinkedHashMap<String,String>(); 332 mustProparty.put( "host", "接続先のSmbサーバーのアドレスまたは、サーバー名(必須)" ); 333 mustProparty.put( "user", "接続するユーザー名(必須)" ); 334 mustProparty.put( "passwd", "接続するユーザーのパスワード(必須)" ); 335 mustProparty.put( "command", "Smbサーバー側での処理の方法(GET/PUT/DEL/GETDIR/PUTDIR/DELDIR)を指定します。(必須)" ); 336 mustProparty.put( "remoteFile", "接続先のSmbサーバー側のファイル名(必須)" ); 337 338 usableProparty = new LinkedHashMap<String,String>(); 339 usableProparty.put( "localFile", "ローカルのファイル名" ); 340 usableProparty.put( "domain", "接続先にログインするドメインを指定します。" ); 341 usableProparty.put( "port", "接続に利用するポート番号を設定します。" ); 342 usableProparty.put( "mkdirs", "受け側ファイル(GET時:LOCAL、PUT時:Smbサーバー)にディレクトリを作成するかどうか(初期値:true)" ); 343 usableProparty.put( "display", "[false/true]:trueは、検索状況を表示します(初期値:false)" ); 344 usableProparty.put( "debug", "デバッグ情報を標準出力に表示する(true)かしない(false)か" + 345 CR + "(初期値:false:表示しない)" ); 346 } 347 348 private static final String[] CMD_LST = new String[] { "GET","PUT","DEL","GETDIR","PUTDIR","DELDIR" }; 349 350 /** 351 * このクラスの動作確認用の、main メソッドです。 352 * 353 * @param args コマンド引数配列 354 */ 355 public static void main( final String[] args ) { 356 Argument arg = new Argument( "org.opengion.fukurou.util.SMBConnect" ); 357 arg.setMustProparty( mustProparty ); 358 arg.setUsableProparty( usableProparty ); 359 arg.setArgument( args ); 360 361 SMBConnect smb = new SMBConnect(); 362 363 String host = arg.getProparty( "host"); // Smbサーバー 364 String user = arg.getProparty( "user" ); // ユーザー 365 String passwd = arg.getProparty( "passwd" ); // パスワード 366 367 smb.setHostUserPass( host,user,passwd ); 368 369 smb.setDomain( arg.getProparty( "domain" ) ); // 接続先にログインするドメインを指定します。 370 smb.setPort( arg.getProparty( "port" ) ); // 接続に利用するポート番号を設定します。 371 smb.setMkdirs( arg.getProparty( "mkdirs" ,true ) ); // 受け側ファイルにディレクトリを作成するかどうか 372 smb.setDisplay( arg.getProparty( "display" ,false ) ); // trueは、検索状況を表示します(初期値:false) 373 smb.setDebug( arg.getProparty( "debug" ,false ) ); // デバッグ情報を標準出力に表示する(true)かしない(false)か 374 375 try { 376 // コネクトします。 377 smb.connect(); 378 379 String command = arg.getProparty( "command" ,"GET" ,CMD_LST ); // Smb処理の方法を指定します。 380 String localFile = arg.getProparty( "localFile" ); // ローカルのファイル名 381 String remoteFile = arg.getProparty( "remoteFile" ); // Smb先のファイル名 382 383 // command , localFile , remoteFile を元に、SFTP処理を行います。 384 smb.action( command,localFile,remoteFile ); 385 } 386 catch( RuntimeException ex ) { 387 System.err.println( smb.getErrMsg() ); 388 } 389 finally { 390 // ホストとの接続を終了します。 391 smb.disconnect(); 392 } 393 } 394}