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.util;
017
018 import java.io.IOException;
019 import java.util.Map;
020 import java.util.LinkedHashMap ;
021 import java.util.Vector;
022 import java.util.Hashtable;
023
024 import com.jcraft.jsch.JSch;
025 import com.jcraft.jsch.Session;
026 import com.jcraft.jsch.ChannelSftp;
027 import com.jcraft.jsch.ChannelSftp.LsEntry;
028 import com.jcraft.jsch.SftpATTRS;
029 import com.jcraft.jsch.JSchException;
030 import com.jcraft.jsch.SftpException;
031
032
033 /**
034 * SFTPConnect.java は、å?通的に使用されã‚?SFTP関連の基本機è?を実è£?�—たã?クラスですã?
035 *
036 * これは、org.apache.commons.net.ftp.FTPClient をã?ースに開発されてã�?�¾すã?
037 * こã?クラスの実行には、commons-net-ftp-2.0.jar がå¿?¦�ですã?
038 *
039 * -host=SFTPサーバã? -user=ユーザー -passwd=パスワーãƒ?-remoteFile=SFTP先ã?ファイルå�?をå¿??設定しますã?
040 * -localFile=ローカルのファイル名ã?、å¿??ではありませんがã?-command=DEL の場合にのみ不要でありã€?
041 * それ以外ã? command の場合ã?、å¿?¦�ですã?
042 *
043 * -command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] は、SFTPサーバã?に対しての処ç�??方法をæŒ?®šしますã?
044 * GET:SFTPサーバã?からローカルにファイル転送しまã�?初期値)ã€?
045 * PUT:ローカルファイルをSFTPサーバã?に PUT(STORE、SAVE、UPLOAD、などと同意èª?しますã?
046 * DEL:SFTPサーバã?のæŒ?®šã?ファイルを削除しますã?こã?場合ã?みã€?localFile 属æ?のæŒ?®šã?不要ですã?
047 * GETDIR,PUTDIR,DELDIR:æŒ?®šã?フォルãƒ?»¥下ã?ファイルをå?ç�?�—ますã?
048 *
049 * -mkdirs=[true/false] は、受けå?のファイル(GETæ™?LOCAL、PUTæ™?SFTPサーバã?)に取り込ã‚?ƒ•ァイルのãƒ?‚£レクトリã�?
050 * 存在しなã�??合に、作æ?するかどã�?�‹を指定しまã�?初期値:true)ã€?
051 * 通常、SFTPサーバã?に、フォルãƒ?šŽ層を作æ?してPUTする場合ã?動的にフォルãƒ?šŽ層を作æ?したã�?‚±ースで便利ですã?
052 * é€?�«、フォルãƒ??確定しており、指定フォルãƒ?»¥外に PUT するのはバグってã�?‚‹と事がåˆ?�‹ってã�?‚‹場合には
053 * false に設定して、存在しなã�?ƒ•ォルãƒ?�«PUT しよã�?�¨すると、エラーになるよã�?�«しますã?
054 *
055 * 引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
056 * 引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に
057 * 繋げてくださいã€?
058 *
059 * @og.formSample
060 * SFTPConnect -host=SFTPサーバã? -user=ユーザー -passwd=パスワーãƒ?-remoteFile=SFTP先ã?ファイルå�?[-localFile=ローカルのファイル名]
061 * [-mode=[ASCII/BINARY] ] [-command=[GET/PUT/DEL/GETDIR/PUTDIR/DELDIR] ] [-passive=[true/false] ]
062 *
063 * -host=SFTPサーバã? ?š接続å?のSFTPサーバã?のアドレスまたã?、サーバã?å�?
064 * -user=ユーザー ?š接続するユーザーå�?
065 * -remoteFile=SFTP先ã?ファイルå�? ?š接続å?のSFTPサーバã?側のファイル名ã?PUT,GET 関係なくSFTP側としてæŒ?®šしますã?
066 * [-passwd=パスワード] ?š接続するユーザーのパスワーãƒ?
067 * [-localFile=ローカルのファイル名] ?šローカルのファイル名ã?PUT,GET 関係なくローカルファイルを指定しますã?
068 * [-port=ポã?ãƒ?] ?š接続するサーバã?のポã?トをæŒ?®šしますã?
069 * [-keyFile=秘å¯?‚ーファイル ] ?šå?開キー暗号化方式を利用する場合ã?キーファイル名をæŒ?®šしますã?
070 * [-command=[GET/PUT/DEL] ] ?šSFTPサーバã?側での処ç�??方法をæŒ?®šしますã?
071 * [GETDIR/PUTDIR/DELDIR]] GET:SFTP⇒LOCAL、PUT:LOCAL⇒SFTP への転送でã�?初期値:GET)
072 * DEL:SFTPファイルを削除しますã?
073 * GETDIR,PUTDIR,DELDIR æŒ?®šã?フォルãƒ?»¥下ã?ファイルをå?ç�?�—ますã?
074 * [-mkdirs=[true/false] ] ?š受けå?ファイル(GETæ™?LOCAL、PUTæ™?SFTPサーバã?)にãƒ?‚£レクトリを作æ?するかどã�?�‹(初期値:true)
075 * (false:ãƒ?‚£レクトリが無ければ、エラーにしますã?)
076 * [-timeout=タイãƒ?‚¢ウãƒ?秒] ] ?šDataタイãƒ?‚¢ウãƒ?初期値:600 [秒])
077 * [-display=[false/true] ] ?štrueは、検索状況を表示しまã�?初期値:false)
078 * [-debug=[false|true] ] ?šデバッグæƒ??を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
079 *
080 * @og.rev 5.1.6.0 (2010/05/01) 新規追åŠ?
081 *
082 * @version 5.0
083 * @author Kazuhiko Hasegawa
084 * @since JDK5.0,
085 */
086 public final class SFTPConnect extends AbstractConnect {
087 private final JSch jsch;
088
089 private static final int DEF_PORT = 22; // ポã?ãƒ?
090
091 private boolean isConnect = false; // コネクト済みかどã�?�‹ã€?
092
093 private String lastRemoteDir = "/"; // SFTP先ã?æœ?¾Œに登録したフォルãƒ?��(mkdir の高é?化ã?ため)
094 private String keyFile = null; // 公開キー暗号化方式を利用する場合ã?キーファイル名をæŒ?®šしますã?
095
096 private Session session = null;
097 private ChannelSftp channel = null;
098
099 /**
100 * ãƒ?ƒ•ォルトコンストラクター
101 */
102 public SFTPConnect() {
103 jsch = new JSch();
104 }
105
106 /**
107 * SFTPサーバã?への接続ã?ログインを行いますã?
108 *
109 * こã?メソãƒ?ƒ‰は、å?期化メソãƒ?ƒ‰ですã?
110 * SFTPサーバã?への接続ã?ログインを行いますã?で、è¤?•°ファイルを転送すã‚?
111 * ケースでは、最初に?‘度ã�?�‘呼び出すだけですã?
112 * 接続å?を変更する場合ã?、もã�?¸?º¦こã?メソãƒ?ƒ‰をコールするå¿?¦�がありますã?
113 * (そã?ような場合ã?ã€??常、オブジェクトを構築しなおす方がよã�?�¨思いますã?)
114 *
115 */
116 @Override
117 public void connect() {
118 if( isDisplay ) { System.out.println( "CONNECT: HOST=" + host + ",USER=" + user + ",PORT=" + port ); }
119
120 // もし、すでに接続されてã�?�Ÿ場合ã?、クロース処ç�?‚’行いますã?
121 if( isConnect ) { disconnect(); }
122
123 // HostKeyチェãƒ?‚¯を行わなã�?
124 Hashtable<String,String> config = new Hashtable<String,String>();
125 config.put( "StrictHostKeyChecking", "no" );
126 JSch.setConfig( config );
127
128 // サーバã?に対して接続を行いますã?
129 try {
130 if( keyFile == null ) {
131 // パスワード認証
132 session=jsch.getSession( user, host, getPort( DEF_PORT ) );
133 session.setPassword( passwd );
134 }
135 else {
136 // 公開キー、秘å¯?‚ー認証
137 jsch.addIdentity( keyFile );
138 session=jsch.getSession( user, host, getPort( DEF_PORT ) );
139 // session.setUserInfo(new MyUserInfo());
140 }
141
142 session.connect( timeout*1000 ); // タイãƒ?‚¢ウトã?設å®?
143
144 channel=(ChannelSftp)session.openChannel("sftp");
145 channel.connect();
146 }
147 catch ( JSchException ex ) {
148 errAppend( "SFTP server refused connection. " );
149 errAppend( " host = [" , host , "]" );
150 errAppend( " user = [" , user , "]" );
151 errAppend( " port = [" , port , "]" );
152 errAppend( ex );
153 if( isDebug ) { ex.printStackTrace(); }
154 disconnect();
155 throw new RuntimeException( getErrMsg(),ex );
156 }
157
158 isConnect = true;
159 }
160
161 /**
162 * SFTPサーバã?との接続をクローズしますã?
163 *
164 * ログインされてã�?‚‹場合ã?、ログアウトも行いますã?
165 * コネクトされてã�?‚‹場合ã?、ディスコネクトしますã?
166 *
167 */
168 @Override
169 public void disconnect() {
170 if( isDisplay ) { System.out.println( "DISCONNECT:" ); }
171
172 if( isConnect ) {
173 isConnect = false;
174 try {
175 channel.disconnect();
176 session.disconnect();
177 }
178 catch( Throwable th ) {
179 errAppend( "disconnect Error." );
180 errAppend( th );
181 if( isDebug ) { th.printStackTrace(); }
182 throw new RuntimeException( getErrMsg(),th );
183 }
184 }
185 }
186
187 /**
188 * command="GET" が指定されたときã?処ç�?‚’行いますã?
189 *
190 * ローカルファイルをã?接続å?のSFTPサーバã?側にアãƒ??ロードしますã?
191 *
192 * @param localFile ローカルのファイルå�?
193 * @param remoteFile SFTP先ã?ファイルå�?
194 * @throws JSchException JSCHエラーが発生したとã�?
195 * @throws SftpException SFTPエラーが発生したとã�?
196 * @throws IOException 入出力エラーが発生したとã�?
197 */
198 @Override
199 protected void actionGET( final String localFile, final String remoteFile ) throws JSchException, SftpException, IOException {
200 if( isDebug ) { System.out.println( "GET: " + remoteFile + " => " + localFile ); }
201
202 // GET(DOWNLOAD)取得時は、ローカルファイルのãƒ?‚£レクトリを作æ?するå¿?¦�があるã€?
203 if( isMkdirs ) {
204 makeLocalDir( localFile );
205 }
206
207 channel.get( remoteFile,localFile );
208 }
209
210 /**
211 * command="GETDIR" が指定されたときã?処ç�?‚’行いますã?
212 *
213 * 接続å?のSFTPサーバã?側のãƒ?‚£レクトリ以下をローカルãƒ?‚£レクトリに階層構é?のままãƒ?‚¦ンロードしますã?
214 *
215 * @param localDir ローカルのãƒ?‚£レクトリå�?
216 * @param remoteDir SFTP先ã?ãƒ?‚£レクトリå�?
217 * @throws JSchException JSCHエラーが発生したとã�?
218 * @throws SftpException SFTPエラーが発生したとã�?
219 * @throws IOException 入出力エラーが発生したとã�?
220 */
221 @Override
222 protected void actionGETdir( final String localDir, final String remoteDir ) throws IOException,JSchException,SftpException {
223 Vector<?> list = channel.ls( remoteDir );
224 for (int i=0;i<list.size();i++) {
225 LsEntry entry = (LsEntry)list.get(i);
226 String rmt = entry.getFilename();
227 if( ".".equals( rmt ) || "..".equals( rmt ) ) { continue; } // "." で始まるファイルもあるã?で、equasl 判å®?
228 SftpATTRS stat = entry.getAttrs();
229 if( stat.isDir() ) {
230 actionGETdir( addFile( localDir,rmt ),addFile( remoteDir,rmt ) );
231 }
232 else {
233 actionGET( addFile( localDir,rmt ),addFile( remoteDir,rmt ) );
234 }
235 }
236 }
237
238 /**
239 * command="PUT" が指定されたときã?処ç�?‚’行いますã?
240 *
241 * 接続å?のSFTPサーバã?側のファイル名をローカルにãƒ?‚¦ンロードしますã?
242 *
243 * @param localFile ローカルのファイルå�?
244 * @param remoteFile SFTP先ã?ファイルå�?
245 * @throws JSchException 処ç�?¸に JSch エラーが発生したå?å�?
246 * @throws SftpException 処ç�?¸に Sftp エラーが発生したå?å�?
247 */
248 @Override
249 protected void actionPUT( final String localFile, final String remoteFile ) throws JSchException,SftpException {
250 if( isDebug ) { System.out.println( "PUT: " + localFile + " => " + remoteFile ); }
251
252 // PUT(UPLOAD)登録時ã?、リモートファイルのãƒ?‚£レクトリを作æ?するå¿?¦�があるã€?
253 if( isMkdirs ) {
254 // 前回のDIRとの比è¼?�§、すでに存在してã�?‚Œば、makeDirectory 処ç�?‚’パスするã€?
255 int ad = remoteFile.lastIndexOf( '/' ) + 1; // 区åˆ?‚Šæ–?—を?‹1するã?
256 String tmp = remoteFile.substring( 0,ad );
257
258 if( ad > 0 && !lastRemoteDir.startsWith( tmp ) ) {
259 lastRemoteDir = tmp;
260 if( remoteFile.startsWith( "/" ) ) {
261 String[] fls = remoteFile.split( "/" );
262 channel.cd( "/" );
263 for( int i=1; i<fls.length-1; i++ ) {
264 try {
265 // SftpATTRS stat = channel.lstat(fls[i]); // 存在しなã�?�¨、SftpException
266 channel.cd( fls[i] ); // 存在しなã�?�¨、SftpException
267 continue;
268 } catch (SftpException ex) {
269 // ファイルが存在しなã�?�¨ã�?
270 channel.mkdir( fls[i] );
271 channel.cd( fls[i] );
272 }
273 }
274 }
275 }
276 }
277
278 channel.put( localFile,remoteFile );
279 }
280
281 /**
282 * command="DEL" が指定されたときã?処ç�?‚’行いますã?
283 *
284 * 接続å?のSFTPサーバã?側のファイル名を削除しますã?
285 *
286 * @param remoteFile SFTP先ã?ファイルå�?
287 * @throws SftpException SFTPサーバã?側のファイル名ã?削除に失敗したとã�?
288 */
289 @Override
290 protected void actionDEL( final String remoteFile ) throws SftpException {
291 if( isDebug ) { System.out.println( "DEL: " + remoteFile ); }
292
293 channel.rm( remoteFile );
294 }
295
296 /**
297 * command="DELDIR" が指定されたときã?処ç�?‚’行いますã?
298 *
299 * 接続å?のSFTPサーバã?側のãƒ?‚£レクトリ名を削除しますã?
300 *
301 * @param remoteDir SFTP先ã?ãƒ?‚£レクトリå�?
302 * @throws SftpException SFTPサーバã?側のãƒ?‚£レクトリ名ã?削除に失敗したとã�?
303 */
304 @Override
305 protected void actionDELdir( final String remoteDir ) throws SftpException {
306
307 Vector<?> list = channel.ls( remoteDir );
308 for (int i=0;i<list.size();i++) {
309 LsEntry entry = (LsEntry)list.get(i);
310 String rmt = entry.getFilename();
311 if( ".".equals( rmt ) || "..".equals( rmt ) ) { continue; } // "." で始まるファイルもあるã?で、equasl 判å®?
312 SftpATTRS stat = entry.getAttrs();
313 if( stat.isDir() ) {
314 actionDELdir( addFile( remoteDir,rmt ) );
315 }
316 else {
317 actionDEL( addFile( remoteDir,rmt ) );
318 // channel.rm( addFile( remoteDir,rmt ) );
319 }
320 }
321 channel.rmdir( remoteDir );
322 }
323
324 /**
325 * 公開キー暗号化方式を利用する場合ã?キーファイル名をæŒ?®šしますã?
326 *
327 * @param keyFile 秘å¯?‚ーファイルå�?
328 */
329 public void setKeyFile( final String keyFile ) {
330 if( keyFile != null ) {
331 this.keyFile = keyFile ;
332 }
333 }
334
335 // private static class MyUserInfo implements UserInfo {
336 // public String getPassword() {
337 // return null;
338 // }
339 // // パスフレーズは空
340 // public String getPassphrase() {
341 // return "";
342 // }
343 // public boolean promptPassword(String arg0) {
344 // return true;
345 // }
346 // public boolean promptPassphrase(String arg0) {
347 // return true;
348 // }
349 // public boolean promptYesNo(String arg0) {
350 // return true;
351 // }
352 // public void showMessage(String arg0) {
353 // }
354 // }
355
356 // ******************************************************************************************************* //
357 // 以下ã?単独で使用する場合ã? main処ç�?
358 // ******************************************************************************************************* //
359
360 private static final Map<String,String> mustProparty ; // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
361 private static final Map<String,String> usableProparty ; // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
362
363 static {
364 mustProparty = new LinkedHashMap<String,String>();
365 mustProparty.put( "host", "接続å?のSFTPサーバã?のアドレスまたã?、サーバã?å�?å¿??)" );
366 mustProparty.put( "user", "接続するユーザーå�?å¿??)" );
367 mustProparty.put( "remoteFile", "接続å?のSFTPサーバã?側のファイルå�?å¿??)" );
368
369 usableProparty = new LinkedHashMap<String,String>();
370 usableProparty.put( "passwd", "接続するユーザーのパスワーãƒ? );
371 usableProparty.put( "localFile", "ローカルのファイルå�? );
372 usableProparty.put( "port", "接続に利用するポã?ト番号を設定しますã?" );
373 usableProparty.put( "keyFile", "公開キー暗号化方式を利用する場合ã?キーファイル名をæŒ?®šしますã?" );
374 usableProparty.put( "command", "SFTPサーバã?側での処ç�??方æ³?GET/PUT/DEL)を指定しまã�?初期値:GET)" );
375 usableProparty.put( "mkdirs", "受け側ファイル(GETæ™?LOCAL、PUTæ™?SFTPサーバã?)にãƒ?‚£レクトリを作æ?するかどã�?�‹(初期値:true)" );
376 usableProparty.put( "timeout", "Dataタイãƒ?‚¢ウãƒ?初期値:600 [秒])" );
377 usableProparty.put( "display", "[false/true]:trueは、検索状況を表示しまã�?初期値:false)" );
378 usableProparty.put( "debug", "ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�? +
379 CR + "(初期値:false:表示しなã�?" );
380 }
381
382 private static final String[] CMD_LST = new String[] { "GET","PUT","DEL","GETDIR","PUTDIR","DELDIR" };
383
384 /**
385 * こã?クラスの動作確認用の、main メソãƒ?ƒ‰ですã?
386 *
387 * @param args コマンド引数配å?
388 */
389 public static void main( final String[] args ) {
390 Argument arg = new Argument( "org.opengion.fukurou.util.SFTPConnect" );
391 arg.setMustProparty( mustProparty );
392 arg.setUsableProparty( usableProparty );
393 arg.setArgument( args );
394
395 SFTPConnect sftp = new SFTPConnect();
396
397 String host = arg.getProparty( "host"); // SFTPサーバã?
398 String user = arg.getProparty( "user" ); // ユーザー
399 String passwd = arg.getProparty( "passwd" ); // パスワーãƒ?
400
401 sftp.setHostUserPass( host , user , passwd );
402
403 sftp.setPort( arg.getProparty( "port" ) ); // 接続に利用するポã?ト番号を設定しますã?
404 sftp.setKeyFile( arg.getProparty( "keyFile" ) ); // 公開キー暗号化方式を利用する場合ã?キーファイル名をæŒ?®šしますã?
405 sftp.setMkdirs( arg.getProparty( "mkdirs" ,true ) ); // 受け側ファイルにãƒ?‚£レクトリを作æ?するかどã�?�‹
406 sftp.setTimeout( arg.getProparty( "timeout" ,TIMEOUT ) ); // Dataタイãƒ?‚¢ウãƒ?初期値:600 [秒])
407 sftp.setDisplay( arg.getProparty( "display" ,false ) ); // trueは、検索状況を表示しまã�?初期値:false)
408 sftp.setDebug( arg.getProparty( "debug" ,false ) ); // ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�?
409
410 try {
411 // コネクトしますã?
412 sftp.connect();
413
414 String command = arg.getProparty( "command" ,"GET" ,CMD_LST ); // SFTP処ç�??方法をæŒ?®šしますã?
415 String localFile = arg.getProparty( "localFile" ); // ローカルのファイルå�?
416 String remoteFile = arg.getProparty( "remoteFile" ); // SFTP先ã?ファイルå�?
417
418 // command , localFile , remoteFile をå?に、SFTP処ç�?‚’行いますã?
419 sftp.action( command,localFile,remoteFile );
420 }
421 catch( RuntimeException ex ) {
422 System.err.println( sftp.getErrMsg() );
423 }
424 finally {
425 // ホストとの接続を終äº?�—ますã?
426 sftp.disconnect();
427 }
428 }
429 }